Skip to content

Commit c1226c2

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 c1226c2

File tree

1 file changed

+39
-28
lines changed

1 file changed

+39
-28
lines changed

qubesusbproxy/core3ext.py

Lines changed: 39 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,38 @@ def __init__(self):
521521
"/etc/qubes-rpc/qubes.USB"
522522
)
523523
self.devices_cache = collections.defaultdict(dict)
524+
self.autoattach_locks = collections.defaultdict(asyncio.Lock)
525+
526+
async def _auto_attach_devices(self, vm):
527+
# pylint: disable=unused-argument
528+
async with self.autoattach_locks[vm.uuid]:
529+
to_attach = {}
530+
assignments = get_assigned_devices(vm.devices["usb"])
531+
# the most specific assignments first
532+
for assignment in reversed(sorted(assignments)):
533+
for device in assignment.devices:
534+
if isinstance(device, qubes.device_protocol.UnknownDevice):
535+
continue
536+
if device.attachment:
537+
continue
538+
if not assignment.matches(device):
539+
print(
540+
"Unrecognized identity, skipping attachment of device "
541+
f"from the port {assignment}",
542+
file=sys.stderr,
543+
)
544+
continue
545+
# chose first assignment (the most specific) and ignore rest
546+
if device not in to_attach:
547+
# make it unique
548+
to_attach[device] = assignment.clone(device=device)
549+
in_progress = set()
550+
for assignment in to_attach.values():
551+
in_progress.add(
552+
asyncio.ensure_future(self.attach_and_notify(vm, assignment))
553+
)
554+
if in_progress:
555+
await asyncio.wait(in_progress)
524556

525557
@qubes.ext.handler("domain-init", "domain-load")
526558
def on_domain_init_load(self, vm, event):
@@ -743,42 +775,21 @@ async def on_device_assign_usb(self, vm, event, device, options):
743775

744776
@qubes.ext.handler("domain-start")
745777
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)
778+
await self._auto_attach_devices(vm)
774779

775780
@qubes.ext.handler("domain-shutdown")
776781
async def on_domain_shutdown(self, vm, _event, **_kwargs):
777782
# pylint: disable=unused-argument
778783
vm.fire_event("device-list-change:usb")
779784
utils.device_list_change(self, {}, vm, None, USBDevice)
785+
del self.autoattach_locks[vm.uuid]
786+
787+
@qubes.ext.handler("domain-resumed")
788+
async def on_domain_resumed(self, vm, _event, **_kwargs):
789+
await self._auto_attach_devices(vm)
780790

781791
@qubes.ext.handler("qubes-close", system=True)
782792
def on_qubes_close(self, app, event):
783793
# pylint: disable=unused-argument
784794
self.devices_cache.clear()
795+
self.autoattach_locks.clear()

0 commit comments

Comments
 (0)