summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb
diff options
context:
space:
mode:
authorhselasky <hselasky@FreeBSD.org>2010-10-27 17:38:05 +0000
committerhselasky <hselasky@FreeBSD.org>2010-10-27 17:38:05 +0000
commit37e36d28fc56fffa91de881e7e6b4c1aca45fc0c (patch)
tree4299a00a332e6c0147de5063dd625a377ca73151 /sys/dev/usb
parentd3a1fbe16a8cdea57e3c9f83e2ce71936e4de376 (diff)
downloadFreeBSD-src-37e36d28fc56fffa91de881e7e6b4c1aca45fc0c.zip
FreeBSD-src-37e36d28fc56fffa91de881e7e6b4c1aca45fc0c.tar.gz
Add support for setting per-interface PnP information.
Submitted by: Nick Hibma Approved by: thompsa (mentor)
Diffstat (limited to 'sys/dev/usb')
-rw-r--r--sys/dev/usb/usb_device.c50
-rw-r--r--sys/dev/usb/usb_hub.c6
-rw-r--r--sys/dev/usb/usbdi.h3
3 files changed, 53 insertions, 6 deletions
diff --git a/sys/dev/usb/usb_device.c b/sys/dev/usb/usb_device.c
index 8887fc1..495bd82 100644
--- a/sys/dev/usb/usb_device.c
+++ b/sys/dev/usb/usb_device.c
@@ -88,7 +88,7 @@ static void usb_init_endpoint(struct usb_device *, uint8_t,
struct usb_endpoint *);
static void usb_unconfigure(struct usb_device *, uint8_t);
static void usb_detach_device_sub(struct usb_device *, device_t *,
- uint8_t);
+ char **, uint8_t);
static uint8_t usb_probe_and_attach_sub(struct usb_device *,
struct usb_attach_arg *);
static void usb_init_attach_arg(struct usb_device *,
@@ -1035,9 +1035,10 @@ usb_reset_iface_endpoints(struct usb_device *udev, uint8_t iface_index)
*------------------------------------------------------------------------*/
static void
usb_detach_device_sub(struct usb_device *udev, device_t *ppdev,
- uint8_t flag)
+ char **ppnpinfo, uint8_t flag)
{
device_t dev;
+ char *pnpinfo;
int err;
dev = *ppdev;
@@ -1069,11 +1070,17 @@ usb_detach_device_sub(struct usb_device *udev, device_t *ppdev,
goto error;
}
}
+
+ pnpinfo = *ppnpinfo;
+ if (pnpinfo != NULL) {
+ *ppnpinfo = NULL;
+ free(pnpinfo, M_USBDEV);
+ }
return;
error:
/* Detach is not allowed to fail in the USB world */
- panic("A USB driver would not detach\n");
+ panic("usb_detach_device_sub: A USB driver would not detach\n");
}
/*------------------------------------------------------------------------*
@@ -1122,7 +1129,8 @@ usb_detach_device(struct usb_device *udev, uint8_t iface_index,
/* looks like the end of the USB interfaces */
break;
}
- usb_detach_device_sub(udev, &iface->subdev, flag);
+ usb_detach_device_sub(udev, &iface->subdev,
+ &iface->pnpinfo, flag);
}
}
@@ -2714,3 +2722,37 @@ usbd_enum_is_locked(struct usb_device *udev)
{
return (sx_xlocked(&udev->enum_sx));
}
+
+/*
+ * The following function is used to set the per-interface specific
+ * plug and play information. The string referred to by the pnpinfo
+ * argument can safely be freed after calling this function. The
+ * pnpinfo of an interface will be reset at device detach or when
+ * passing a NULL argument to this function. This function
+ * returns zero on success, else a USB_ERR_XXX failure code.
+ */
+
+usb_error_t
+usbd_set_pnpinfo(struct usb_device *udev, uint8_t iface_index, const char *pnpinfo)
+{
+ struct usb_interface *iface;
+
+ iface = usbd_get_iface(udev, iface_index);
+ if (iface == NULL)
+ return (USB_ERR_INVAL);
+
+ if (iface->pnpinfo != NULL) {
+ free(iface->pnpinfo, M_USBDEV);
+ iface->pnpinfo = NULL;
+ }
+
+ if (pnpinfo == NULL || pnpinfo[0] == 0)
+ return (0); /* success */
+
+ iface->pnpinfo = strdup(pnpinfo, M_USBDEV);
+ if (iface->pnpinfo == NULL)
+ return (USB_ERR_NOMEM);
+
+ return (0); /* success */
+}
+
diff --git a/sys/dev/usb/usb_hub.c b/sys/dev/usb/usb_hub.c
index afeadaa..b2870a3 100644
--- a/sys/dev/usb/usb_hub.c
+++ b/sys/dev/usb/usb_hub.c
@@ -1330,7 +1330,7 @@ uhub_child_pnpinfo_string(device_t parent, device_t child,
"devclass=0x%02x devsubclass=0x%02x "
"sernum=\"%s\" "
"release=0x%04x "
- "intclass=0x%02x intsubclass=0x%02x",
+ "intclass=0x%02x intsubclass=0x%02x" "%s%s",
UGETW(res.udev->ddesc.idVendor),
UGETW(res.udev->ddesc.idProduct),
res.udev->ddesc.bDeviceClass,
@@ -1338,7 +1338,9 @@ uhub_child_pnpinfo_string(device_t parent, device_t child,
usb_get_serial(res.udev),
UGETW(res.udev->ddesc.bcdDevice),
iface->idesc->bInterfaceClass,
- iface->idesc->bInterfaceSubClass);
+ iface->idesc->bInterfaceSubClass,
+ iface->pnpinfo ? " " : "",
+ iface->pnpinfo ? iface->pnpinfo : "");
} else {
if (buflen) {
buf[0] = '\0';
diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h
index 1c2d412..6d4a911 100644
--- a/sys/dev/usb/usbdi.h
+++ b/sys/dev/usb/usbdi.h
@@ -171,6 +171,7 @@ struct usb_interface {
struct usb_host_interface *cur_altsetting;
struct usb_device *linux_udev;
void *bsd_priv_sc; /* device specific information */
+ char *pnpinfo; /* additional PnP-info for this interface */
uint8_t num_altsetting; /* number of alternate settings */
uint8_t bsd_iface_index;
};
@@ -444,6 +445,8 @@ enum usb_hc_mode usbd_get_mode(struct usb_device *udev);
enum usb_dev_speed usbd_get_speed(struct usb_device *udev);
void device_set_usb_desc(device_t dev);
void usb_pause_mtx(struct mtx *mtx, int _ticks);
+usb_error_t usbd_set_pnpinfo(struct usb_device *udev,
+ uint8_t iface_index, const char *pnpinfo);
const struct usb_device_id *usbd_lookup_id_by_info(
const struct usb_device_id *id, usb_size_t sizeof_id,
OpenPOWER on IntegriCloud