diff --git a/lib/libusb/Makefile b/lib/libusb/Makefile index 66dd7959caf4..ce50593734d9 100644 --- a/lib/libusb/Makefile +++ b/lib/libusb/Makefile @@ -203,6 +203,7 @@ MLINKS += libusb20.3 libusb20_dev_reset.3 MLINKS += libusb20.3 libusb20_dev_check_connected.3 MLINKS += libusb20.3 libusb20_dev_set_power_mode.3 MLINKS += libusb20.3 libusb20_dev_get_power_mode.3 +MLINKS += libusb20.3 libusb20_dev_get_port_path.3 MLINKS += libusb20.3 libusb20_dev_get_power_usage.3 MLINKS += libusb20.3 libusb20_dev_set_alt_index.3 MLINKS += libusb20.3 libusb20_dev_get_device_desc.3 diff --git a/lib/libusb/libusb20.3 b/lib/libusb/libusb20.3 index 8d286f13723f..e367bf36a874 100644 --- a/lib/libusb/libusb20.3 +++ b/lib/libusb/libusb20.3 @@ -26,7 +26,7 @@ .\" .\" $FreeBSD$ .\" -.Dd February 14, 2013 +.Dd May 3, 2013 .Dt LIBUSB20 3 .Os .Sh NAME @@ -114,6 +114,8 @@ USB access library (libusb -lusb) .Ft const char * .Fn libusb20_dev_get_backend_name "struct libusb20_device *" .Ft int +.Fn libusb20_dev_get_port_path "struct libusb20_device *pdev" "uint8_t *buf" "uint8_t bufsize" +.Ft int .Fn libusb20_dev_get_info "struct libusb20_device *pdev" "struct usb_device_info *pinfo" .Ft int .Fn libusb20_dev_get_iface_desc "struct libusb20_device *pdev" "uint8_t iface_index" "char *buf" "uint8_t len" @@ -552,6 +554,20 @@ returns a zero terminated string describing the backend used. . .Pp . +.Fn libusb20_dev_get_port_path +retrieves the list of USB port numbers which the datastream for a given USB device follows. +The first port number is the Root HUB port number. +Then children port numbers follow. +The Root HUB device itself has a port path length of zero. +Valid port numbers start at one and range until and including 255. +Typically there should not be more than 16 levels, due to electrical and protocol limitations. +This functions returns the number of actual port levels upon success +else a LIBUSB20_ERROR value is returned which are always negative. +If the actual number of port levels is greater than the maximum +specified, a LIBUSB20_ERROR value is returned. +. +.Pp +. .Fn libusb20_dev_get_info retrieves the BSD specific usb_device_info structure into the memory location given by .Fa pinfo . diff --git a/lib/libusb/libusb20.c b/lib/libusb/libusb20.c index 644eda4f5498..ed332a6a93c1 100644 --- a/lib/libusb/libusb20.c +++ b/lib/libusb/libusb20.c @@ -75,6 +75,7 @@ dummy_callback(struct libusb20_transfer *xfer) #define dummy_check_connected (void *)dummy_int #define dummy_set_power_mode (void *)dummy_int #define dummy_get_power_mode (void *)dummy_int +#define dummy_get_port_path (void *)dummy_int #define dummy_get_power_usage (void *)dummy_int #define dummy_kernel_driver_active (void *)dummy_int #define dummy_detach_kernel_driver (void *)dummy_int @@ -722,6 +723,12 @@ libusb20_dev_get_power_mode(struct libusb20_device *pdev) return (power_mode); } +int +libusb20_dev_get_port_path(struct libusb20_device *pdev, uint8_t *buf, uint8_t bufsize) +{ + return (pdev->methods->get_port_path(pdev, buf, bufsize)); +} + uint16_t libusb20_dev_get_power_usage(struct libusb20_device *pdev) { diff --git a/lib/libusb/libusb20.h b/lib/libusb/libusb20.h index 4a57b49710f6..6d1613e3e649 100644 --- a/lib/libusb/libusb20.h +++ b/lib/libusb/libusb20.h @@ -251,6 +251,7 @@ int libusb20_dev_reset(struct libusb20_device *pdev); int libusb20_dev_check_connected(struct libusb20_device *pdev); int libusb20_dev_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode); uint8_t libusb20_dev_get_power_mode(struct libusb20_device *pdev); +int libusb20_dev_get_port_path(struct libusb20_device *pdev, uint8_t *buf, uint8_t bufsize); uint16_t libusb20_dev_get_power_usage(struct libusb20_device *pdev); int libusb20_dev_set_alt_index(struct libusb20_device *pdev, uint8_t iface_index, uint8_t alt_index); int libusb20_dev_get_info(struct libusb20_device *pdev, struct usb_device_info *pinfo); diff --git a/lib/libusb/libusb20_int.h b/lib/libusb/libusb20_int.h index 6705c630c868..27adf008dea5 100644 --- a/lib/libusb/libusb20_int.h +++ b/lib/libusb/libusb20_int.h @@ -105,6 +105,7 @@ typedef int (libusb20_process_t)(struct libusb20_device *pdev); typedef int (libusb20_reset_device_t)(struct libusb20_device *pdev); typedef int (libusb20_set_power_mode_t)(struct libusb20_device *pdev, uint8_t power_mode); typedef int (libusb20_get_power_mode_t)(struct libusb20_device *pdev, uint8_t *power_mode); +typedef int (libusb20_get_port_path_t)(struct libusb20_device *pdev, uint8_t *buf, uint8_t bufsize); typedef int (libusb20_get_power_usage_t)(struct libusb20_device *pdev, uint16_t *power_usage); typedef int (libusb20_set_alt_index_t)(struct libusb20_device *pdev, uint8_t iface_index, uint8_t alt_index); typedef int (libusb20_set_config_index_t)(struct libusb20_device *pdev, uint8_t index); @@ -128,6 +129,7 @@ typedef void (libusb20_tr_cancel_async_t)(struct libusb20_transfer *xfer); m(n, check_connected) \ m(n, set_power_mode) \ m(n, get_power_mode) \ + m(n, get_port_path) \ m(n, get_power_usage) \ m(n, set_alt_index) \ m(n, set_config_index) \ diff --git a/lib/libusb/libusb20_ugen20.c b/lib/libusb/libusb20_ugen20.c index 0846eb4b7d52..a4c973e10725 100644 --- a/lib/libusb/libusb20_ugen20.c +++ b/lib/libusb/libusb20_ugen20.c @@ -73,6 +73,7 @@ static libusb20_reset_device_t ugen20_reset_device; static libusb20_check_connected_t ugen20_check_connected; static libusb20_set_power_mode_t ugen20_set_power_mode; static libusb20_get_power_mode_t ugen20_get_power_mode; +static libusb20_get_port_path_t ugen20_get_port_path; static libusb20_get_power_usage_t ugen20_get_power_usage; static libusb20_kernel_driver_active_t ugen20_kernel_driver_active; static libusb20_detach_kernel_driver_t ugen20_detach_kernel_driver; @@ -643,6 +644,22 @@ ugen20_get_power_mode(struct libusb20_device *pdev, uint8_t *power_mode) return (0); /* success */ } +static int +ugen20_get_port_path(struct libusb20_device *pdev, uint8_t *buf, uint8_t bufsize) +{ + struct usb_device_port_path udpp; + + if (ioctl(pdev->file_ctrl, USB_GET_DEV_PORT_PATH, &udpp)) + return (LIBUSB20_ERROR_OTHER); + + if (udpp.udp_port_level > bufsize) + return (LIBUSB20_ERROR_OVERFLOW); + + memcpy(buf, udpp.udp_port_no, udpp.udp_port_level); + + return (udpp.udp_port_level); /* success */ +} + static int ugen20_get_power_usage(struct libusb20_device *pdev, uint16_t *power_usage) { diff --git a/sys/dev/usb/usb_generic.c b/sys/dev/usb/usb_generic.c index 9557686e9416..013210aa7e05 100644 --- a/sys/dev/usb/usb_generic.c +++ b/sys/dev/usb/usb_generic.c @@ -1840,6 +1840,46 @@ ugen_get_power_mode(struct usb_fifo *f) return (udev->power_mode); } +static int +ugen_get_port_path(struct usb_fifo *f, struct usb_device_port_path *dpp) +{ + struct usb_device *udev = f->udev; + struct usb_device *next; + unsigned int nlevel = 0; + + if (udev == NULL) + goto error; + + dpp->udp_bus = device_get_unit(udev->bus->bdev); + dpp->udp_index = udev->device_index; + + /* count port levels */ + next = udev; + while (next->parent_hub != NULL) { + nlevel++; + next = next->parent_hub; + } + + /* check if too many levels */ + if (nlevel > USB_DEVICE_PORT_PATH_MAX) + goto error; + + /* store port index array */ + next = udev; + while (next->parent_hub != NULL) { + nlevel--; + + dpp->udp_port_no[nlevel] = next->port_no; + dpp->udp_port_level = nlevel; + + next = next->parent_hub; + } + return (0); /* success */ + +error: + return (EINVAL); /* failure */ +} + static int ugen_get_power_usage(struct usb_fifo *f) { @@ -2041,6 +2081,7 @@ ugen_ioctl_post(struct usb_fifo *f, u_long cmd, void *addr, int fflags) struct usb_device_stats *stat; struct usb_fs_init *pinit; struct usb_fs_uninit *puninit; + struct usb_device_port_path *dpp; uint32_t *ptime; void *addr; int *pint; @@ -2213,6 +2254,10 @@ ugen_ioctl_post(struct usb_fifo *f, u_long cmd, void *addr, int fflags) *u.pint = ugen_get_power_mode(f); break; + case USB_GET_DEV_PORT_PATH: + error = ugen_get_port_path(f, u.dpp); + break; + case USB_GET_POWER_USAGE: *u.pint = ugen_get_power_usage(f); break; diff --git a/sys/dev/usb/usb_ioctl.h b/sys/dev/usb/usb_ioctl.h index 979240f05734..4b7850a1a65b 100644 --- a/sys/dev/usb/usb_ioctl.h +++ b/sys/dev/usb/usb_ioctl.h @@ -131,6 +131,15 @@ struct usb_device_info { char udi_release[8]; }; +#define USB_DEVICE_PORT_PATH_MAX 32 + +struct usb_device_port_path { + uint8_t udp_bus; /* which bus we are on */ + uint8_t udp_index; /* which device index */ + uint8_t udp_port_level; /* how many levels: 0, 1, 2 ... */ + uint8_t udp_port_no[USB_DEVICE_PORT_PATH_MAX]; +}; + struct usb_device_stats { uint32_t uds_requests_ok[4]; /* Indexed by transfer type UE_XXX */ uint32_t uds_requests_fail[4]; /* Indexed by transfer type UE_XXX */ @@ -277,7 +286,8 @@ struct usb_gen_quirk { #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 - 134 unused */ +/* 128 - 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) #define USB_SET_TX_TIMEOUT _IOW ('U', 137, int)