diff --git a/lib/libusb/Makefile b/lib/libusb/Makefile --- a/lib/libusb/Makefile +++ b/lib/libusb/Makefile @@ -225,6 +225,7 @@ MLINKS += libusb20.3 libusb20_dev_get_stats.3 MLINKS += libusb20.3 libusb20_dev_close.3 MLINKS += libusb20.3 libusb20_dev_detach_kernel_driver.3 +MLINKS += libusb20.3 libusb20_dev_attach_kernel_driver.3 MLINKS += libusb20.3 libusb20_dev_set_config_index.3 MLINKS += libusb20.3 libusb20_dev_get_debug.3 MLINKS += libusb20.3 libusb20_dev_get_fd.3 diff --git a/lib/libusb/libusb.h b/lib/libusb/libusb.h --- a/lib/libusb/libusb.h +++ b/lib/libusb/libusb.h @@ -202,8 +202,8 @@ LIBUSB_CAP_HAS_HID_ACCESS, /* - * Supports detaching of the default USB driver with - * libusb_detach_kernel_driver(). + * Supports detaching and attaching of the default USB driver with + * libusb_detach_kernel_driver() and libusb_attach_kernel_driver(). */ LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER, }; diff --git a/lib/libusb/libusb.3 b/lib/libusb/libusb.3 --- a/lib/libusb/libusb.3 +++ b/lib/libusb/libusb.3 @@ -95,8 +95,10 @@ can access HID devices without requiring user intervention. .It Va LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER .Nm -supports detaching of the default USB driver with -.Fn libusb_detach_kernel_driver . +supports detaching and attaching of the default USB driver with +.Fn libusb_detach_kernel_driver +and +.Fn libusb_attach_kernel_driver . .El .Pp .Ft const char * @@ -869,6 +871,7 @@ .Fn usb_check_connected .Fn usb_get_driver_np .Fn usb_detach_kernel_driver_np +.Fn usb_attach_kernel_driver_np .Sh SEE ALSO .Xr libusb20 3 , .Xr usb 4 , diff --git a/lib/libusb/libusb01.c b/lib/libusb/libusb01.c --- a/lib/libusb/libusb01.c +++ b/lib/libusb/libusb01.c @@ -1023,3 +1023,21 @@ return (0); } + +int +usb_attach_kernel_driver_np(usb_dev_handle *dev, int interface) +{ + struct libusb20_device *pdev; + int err; + + pdev = (void *)dev; + + if (pdev == NULL) + return (-1); + + err = libusb20_dev_attach_kernel_driver(pdev, interface); + if (err != 0) + return (-1); + + return (0); +} diff --git a/lib/libusb/libusb10.c b/lib/libusb/libusb10.c --- a/lib/libusb/libusb10.c +++ b/lib/libusb/libusb10.c @@ -1052,10 +1052,14 @@ int libusb_attach_kernel_driver(struct libusb20_device *pdev, int interface) { + int err; + if (pdev == NULL) return (LIBUSB_ERROR_INVALID_PARAM); - /* stub - currently not supported by libusb20 */ - return (0); + + err = libusb20_dev_attach_kernel_driver(pdev, interface); + + return (err ? LIBUSB_ERROR_OTHER : 0); } int diff --git a/lib/libusb/libusb20.h b/lib/libusb/libusb20.h --- a/lib/libusb/libusb20.h +++ b/lib/libusb/libusb20.h @@ -246,6 +246,8 @@ const char *libusb20_dev_get_desc(struct libusb20_device *pdev); int libusb20_dev_close(struct libusb20_device *pdev); int libusb20_dev_detach_kernel_driver(struct libusb20_device *pdev, uint8_t iface_index); +int libusb20_dev_attach_kernel_driver(struct libusb20_device *pdev, + uint8_t iface_index); int libusb20_dev_set_config_index(struct libusb20_device *pdev, uint8_t configIndex); int libusb20_dev_get_debug(struct libusb20_device *pdev); int libusb20_dev_get_fd(struct libusb20_device *pdev); diff --git a/lib/libusb/libusb20.3 b/lib/libusb/libusb20.3 --- a/lib/libusb/libusb20.3 +++ b/lib/libusb/libusb20.3 @@ -126,6 +126,8 @@ .Ft int .Fn libusb20_dev_detach_kernel_driver "struct libusb20_device *pdev" "uint8_t iface_index" .Ft int +.Fn libusb20_dev_attach_kernel_driver "struct libusb20_device *pdev" "uint8_t iface_index" +.Ft int .Fn libusb20_dev_set_config_index "struct libusb20_device *pdev" "uint8_t configIndex" .Ft int .Fn libusb20_dev_get_debug "struct libusb20_device *pdev" @@ -623,6 +625,15 @@ . .Pp . +.Fn libusb20_dev_attach_kernel_driver +will try to attach the kernel driver for the USB interface given by +.Fa iface_index . +. +This function returns zero on success else a LIBUSB20_ERROR value is +returned. +. +.Pp +. .Fn libusb20_dev_set_config_index will try to set the configuration index on an USB device. diff --git a/lib/libusb/libusb20.c b/lib/libusb/libusb20.c --- a/lib/libusb/libusb20.c +++ b/lib/libusb/libusb20.c @@ -80,6 +80,7 @@ #define dummy_get_stats (void *)dummy_int #define dummy_kernel_driver_active (void *)dummy_int #define dummy_detach_kernel_driver (void *)dummy_int +#define dummy_attach_kernel_driver (void *)dummy_int #define dummy_do_request_sync (void *)dummy_int #define dummy_tr_open (void *)dummy_int #define dummy_tr_close (void *)dummy_int @@ -636,6 +637,16 @@ return (error); } +int +libusb20_dev_attach_kernel_driver(struct libusb20_device *pdev, + uint8_t ifaceIndex) +{ + int error; + + error = pdev->methods->attach_kernel_driver(pdev, ifaceIndex); + return (error); +} + struct LIBUSB20_DEVICE_DESC_DECODED * libusb20_dev_get_device_desc(struct libusb20_device *pdev) { diff --git a/lib/libusb/libusb20_int.h b/lib/libusb/libusb20_int.h --- a/lib/libusb/libusb20_int.h +++ b/lib/libusb/libusb20_int.h @@ -92,6 +92,7 @@ /* USB device specific */ typedef int (libusb20_detach_kernel_driver_t)(struct libusb20_device *pdev, uint8_t iface_index); +typedef int (libusb20_attach_kernel_driver_t)(struct libusb20_device *pdev, uint8_t iface_index); typedef int (libusb20_do_request_sync_t)(struct libusb20_device *pdev, struct LIBUSB20_CONTROL_SETUP_DECODED *setup, void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags); typedef int (libusb20_get_config_desc_full_t)(struct libusb20_device *pdev, uint8_t **ppbuf, uint16_t *plen, uint8_t index); typedef int (libusb20_get_config_index_t)(struct libusb20_device *pdev, uint8_t *pindex); @@ -116,6 +117,7 @@ #define LIBUSB20_DEVICE(m,n) \ m(n, detach_kernel_driver) \ + m(n, attach_kernel_driver) \ m(n, do_request_sync) \ m(n, get_config_desc_full) \ m(n, get_config_index) \ diff --git a/lib/libusb/libusb20_ugen20.c b/lib/libusb/libusb20_ugen20.c --- a/lib/libusb/libusb20_ugen20.c +++ b/lib/libusb/libusb20_ugen20.c @@ -82,6 +82,7 @@ static libusb20_get_stats_t ugen20_get_stats; static libusb20_kernel_driver_active_t ugen20_kernel_driver_active; static libusb20_detach_kernel_driver_t ugen20_detach_kernel_driver; +static libusb20_attach_kernel_driver_t ugen20_attach_kernel_driver; static libusb20_do_request_sync_t ugen20_do_request_sync; static libusb20_process_t ugen20_process; @@ -716,6 +717,17 @@ return (0); /* kernel driver is detached */ } +static int +ugen20_attach_kernel_driver(struct libusb20_device *pdev, uint8_t iface_index) +{ + int temp = iface_index; + + if (ioctl(pdev->file_ctrl, IOUSB(USB_IFACE_DRIVER_ATTACH), &temp)) { + return (LIBUSB20_ERROR_OTHER); + } + return (0); /* kernel driver is attached */ +} + static int ugen20_do_request_sync(struct libusb20_device *pdev, struct LIBUSB20_CONTROL_SETUP_DECODED *setup, diff --git a/lib/libusb/usb.h b/lib/libusb/usb.h --- a/lib/libusb/usb.h +++ b/lib/libusb/usb.h @@ -303,6 +303,7 @@ struct usb_bus *usb_get_busses(void); int usb_get_driver_np(usb_dev_handle * dev, int interface, char *name, int namelen); int usb_detach_kernel_driver_np(usb_dev_handle * dev, int interface); +int usb_attach_kernel_driver_np(usb_dev_handle *dev, int interface); #if 0 { /* style */ diff --git a/sys/dev/usb/usb_generic.c b/sys/dev/usb/usb_generic.c --- a/sys/dev/usb/usb_generic.c +++ b/sys/dev/usb/usb_generic.c @@ -2376,6 +2376,28 @@ */ usbd_set_parent_iface(f->udev, n, n); break; + case USB_IFACE_DRIVER_ATTACH: + + error = priv_check(curthread, PRIV_DRIVER); + + if (error) + break; + + n = *u.pint & 0xFF; + + if (n == USB_IFACE_INDEX_ANY) { + error = EINVAL; + break; + } + + /* + * Attach the currently detached driver. + */ + usbd_set_parent_iface(f->udev, n, USB_IFACE_INDEX_ANY); + + usb_probe_and_attach(f->udev, n); + + break; case USB_SET_POWER_MODE: error = ugen_set_power_mode(f, *u.pint); diff --git a/sys/dev/usb/usb_ioctl.h b/sys/dev/usb/usb_ioctl.h --- a/sys/dev/usb/usb_ioctl.h +++ b/sys/dev/usb/usb_ioctl.h @@ -273,7 +273,8 @@ #define USB_IFACE_DRIVER_DETACH _IOW ('U', 125, int) #define USB_GET_PLUGTIME _IOR ('U', 126, uint32_t) #define USB_READ_DIR _IOW ('U', 127, struct usb_read_dir) -/* 128 - 133 unused */ +#define USB_IFACE_DRIVER_ATTACH _IOW('U', 128, int) +/* 129 - 133 unused */ #define USB_GET_DEV_PORT_PATH _IOR ('U', 134, struct usb_device_port_path) #define USB_GET_POWER_USAGE _IOR ('U', 135, int) #define USB_SET_TX_FORCE_SHORT _IOW ('U', 136, int) diff --git a/usr.sbin/usbconfig/usbconfig.8 b/usr.sbin/usbconfig/usbconfig.8 --- a/usr.sbin/usbconfig/usbconfig.8 +++ b/usr.sbin/usbconfig/usbconfig.8 @@ -159,6 +159,11 @@ This command uses the .Fl i Ar interface_index option. +.It Cm attach_kernel_driver +Attach kernel driver for the selected interface and USB device. +This command uses the +.Fl i Ar interface_index +option. .It Cm suspend Force the device to suspend. .It Cm resume diff --git a/usr.sbin/usbconfig/usbconfig.c b/usr.sbin/usbconfig/usbconfig.c --- a/usr.sbin/usbconfig/usbconfig.c +++ b/usr.sbin/usbconfig/usbconfig.c @@ -93,6 +93,7 @@ uint8_t got_do_request:1; uint8_t got_detach_kernel_driver:1; uint8_t opt_dump_in_list_mode:1; + uint8_t got_attach_kernel_driver:1; }; struct token { @@ -129,6 +130,7 @@ T_RESET, T_LIST, T_DO_REQUEST, + T_ATTACH_KERNEL_DRIVER, }; static struct options options; @@ -143,6 +145,7 @@ {"add_quirk", T_ADD_QUIRK, 1}, {"remove_quirk", T_REMOVE_QUIRK, 1}, {"detach_kernel_driver", T_DETACH_KERNEL_DRIVER, 0}, + {"attach_kernel_driver", T_ATTACH_KERNEL_DRIVER, 0}, {"dump_quirk_names", T_DUMP_QUIRK_NAMES, 0}, {"dump_device_quirks", T_DUMP_DEVICE_QUIRKS, 0}, {"dump_all_desc", T_DUMP_ALL_DESC, 0}, @@ -283,6 +286,7 @@ " add_quirk " "\n" " remove_quirk " "\n" " detach_kernel_driver" "\n" + " attach_kernel_driver" "\n" " dump_quirk_names" "\n" " dump_device_quirks" "\n" " dump_all_desc" "\n" @@ -496,6 +500,11 @@ err(1, "could not detach kernel driver"); } } + if (opt->got_attach_kernel_driver) { + if (libusb20_dev_attach_kernel_driver(pdev, opt->iface)) { + err(1, "could not attach kernel driver"); + } + } dump_any = (opt->got_dump_all_desc || opt->got_dump_device_desc || @@ -688,6 +697,13 @@ opt->got_any++; break; + case T_ATTACH_KERNEL_DRIVER: + if (opt->got_attach_kernel_driver) + duplicate_option(argv[n]); + opt->got_attach_kernel_driver = 1; + opt->got_any++; + break; + case T_DUMP_QUIRK_NAMES: if (opt->got_dump_quirk_names) duplicate_option(argv[n]);