Add new USB API to get the port path of a USB device.

MFC after:	2 weeks
Requested by:	emaste @
This commit is contained in:
Hans Petter Selasky 2013-05-03 07:44:58 +00:00
parent 3b48e348d5
commit c77a24c24a
8 changed files with 101 additions and 2 deletions

View File

@ -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

View File

@ -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 .

View File

@ -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)
{

View File

@ -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);

View File

@ -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) \

View File

@ -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)
{

View File

@ -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;

View File

@ -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)