/* usbdi.h */ struct usb_task { struct task ut_task; void (*ut_fn)(void *); void *ut_arg; int ut_flags; #define USB_TASKQ_MPSAFE 0x01 }; void usb_task(struct task *); static inline void usb_init_task(struct usb_task *ut, void (*fn)(void *), void *arg, int flags) { task_init(&ut->ut_task, &usb_task); ut->ut_fn = fn; ut->ut_arg = arg; ut->ut_flags = flags; } void usb_add_task(usbd_device_handle, struct usb_task *, int); void usb_rem_task(usbd_device_handle, struct usb_task *); void usb_rem_task_async(usbd_device_handle, struct usb_task *); /* usb.c */ void usb_attach(device_t parent, device_t self, void *aux) { ... error = taskqueue_create(&sc->sc_bus->hc_taskq, "usbhci", PRI_NONE, IPL_USB, TASKQUEUE_PERCPU); if (error) goto fail2; error = taskqueue_create(&sc->sc_bus->driver_taskq, "usbdrv", PRI_NONE, IPL_USB, TASKQUEUE_PERCPU); if (error) goto fail3; ... } void usb_detach(device_t self, int flags) { ... taskqueue_destroy(sc->sc_bus->driver_taskq); taskqueue_destroy(sc->sc_bus->hc_taskq); ... } void usb_task(struct task *task) { struct usb_task *ut = container_of(task, struct usb_task, ut_task); const bool mpsafe = ISSET(ut->ut_flags, USB_TASKQ_MPSAFE); if (!mpsafe) KERNEL_LOCK(1, curlwp); (*ut->ut_fn)(ut->ut_arg); if (!mpsafe) KERNEL_UNLOCK_ONE(curlwp); } void usb_add_task(usbd_device_handle dev, struct usb_task *ut, int queue) { struct taskqueue *taskqueue; switch (queue) { case USB_TASKQ_HC: taskqueue = dev->bus->hc_taskq; case USB_TASKQ_DRIVER: taskqueue = dev->bus->driver_taskq; default: panic("invalid USB task queue: %d", queue); } taskqueue_schedule(taskqueue, &ut->ut_task); } void usb_rem_task(usbd_device_handle dev __unused, struct usb_task *ut, kmutex_t *interlock) { task_cancel(&ut->ut_task, interlock); } void usb_rem_task_async(usbd_device_handle dev __unused, struct usb_task *ut) { task_cancel_async(&ut->ut_task); }