Skip to content

Commit 5e0bc9b

Browse files
core3ext: reattach assigned USB devices on resume from suspend
This patch ensures USB devices are reattached on resume, which is necessary for S0ix since we don't detach the USB controller drivers and hence the udev rules aren't retriggered automatically.
1 parent c3ca2a3 commit 5e0bc9b

1 file changed

Lines changed: 36 additions & 28 deletions

File tree

qubesusbproxy/core3ext.py

Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,36 @@ def __init__(self):
522522
)
523523
self.devices_cache = collections.defaultdict(dict)
524524

525+
async def _auto_attach_devices(self, vm):
526+
# pylint: disable=unused-argument
527+
to_attach = {}
528+
assignments = get_assigned_devices(vm.devices["usb"])
529+
# the most specific assignments first
530+
for assignment in reversed(sorted(assignments)):
531+
for device in assignment.devices:
532+
if isinstance(device, qubes.device_protocol.UnknownDevice):
533+
continue
534+
if device.attachment:
535+
continue
536+
if not assignment.matches(device):
537+
print(
538+
"Unrecognized identity, skipping attachment of device "
539+
f"from the port {assignment}",
540+
file=sys.stderr,
541+
)
542+
continue
543+
# chose first assignment (the most specific) and ignore rest
544+
if device not in to_attach:
545+
# make it unique
546+
to_attach[device] = assignment.clone(device=device)
547+
in_progress = set()
548+
for assignment in to_attach.values():
549+
in_progress.add(
550+
asyncio.ensure_future(self.attach_and_notify(vm, assignment))
551+
)
552+
if in_progress:
553+
await asyncio.wait(in_progress)
554+
525555
@qubes.ext.handler("domain-init", "domain-load")
526556
def on_domain_init_load(self, vm, event):
527557
"""Initialize watching for changes"""
@@ -743,41 +773,19 @@ async def on_device_assign_usb(self, vm, event, device, options):
743773

744774
@qubes.ext.handler("domain-start")
745775
async def on_domain_start(self, vm, _event, **_kwargs):
746-
# pylint: disable=unused-argument
747-
to_attach = {}
748-
assignments = get_assigned_devices(vm.devices["usb"])
749-
# the most specific assignments first
750-
for assignment in reversed(sorted(assignments)):
751-
for device in assignment.devices:
752-
if isinstance(device, qubes.device_protocol.UnknownDevice):
753-
continue
754-
if device.attachment:
755-
continue
756-
if not assignment.matches(device):
757-
print(
758-
"Unrecognized identity, skipping attachment of device "
759-
f"from the port {assignment}",
760-
file=sys.stderr,
761-
)
762-
continue
763-
# chose first assignment (the most specific) and ignore rest
764-
if device not in to_attach:
765-
# make it unique
766-
to_attach[device] = assignment.clone(device=device)
767-
in_progress = set()
768-
for assignment in to_attach.values():
769-
in_progress.add(
770-
asyncio.ensure_future(self.attach_and_notify(vm, assignment))
771-
)
772-
if in_progress:
773-
await asyncio.wait(in_progress)
776+
await self._auto_attach_devices(vm)
774777

775778
@qubes.ext.handler("domain-shutdown")
776779
async def on_domain_shutdown(self, vm, _event, **_kwargs):
777780
# pylint: disable=unused-argument
778781
vm.fire_event("device-list-change:usb")
779782
utils.device_list_change(self, {}, vm, None, USBDevice)
780783

784+
@qubes.ext.handler("domain-unpaused")
785+
async on_domain_unpaused(self, vm, _event, **_kwargs):
786+
loop = asyncio.get_running_loop()
787+
asyncio.run_coroutine_threadsafe(self._auto_attach_devices(vm), loop)
788+
781789
@qubes.ext.handler("qubes-close", system=True)
782790
def on_qubes_close(self, app, event):
783791
# pylint: disable=unused-argument

0 commit comments

Comments
 (0)