PERFORCE change 153007 for review
Hans Petter Selasky
hselasky at FreeBSD.org
Sat Nov 15 07:40:00 PST 2008
http://perforce.freebsd.org/chv.cgi?CH=153007
Change 153007 by hselasky at hselasky_laptop001 on 2008/11/15 15:39:19
Cleanup USB IOCTL and USB reference handling.
Fix a corner case where USB-FS was left initialised after
setting a new configuration or alternate setting.
Affected files ...
.. //depot/projects/usb/src/sys/dev/usb2/core/usb2_dev.c#42 edit
.. //depot/projects/usb/src/sys/dev/usb2/core/usb2_dev.h#15 edit
.. //depot/projects/usb/src/sys/dev/usb2/core/usb2_device.c#31 edit
.. //depot/projects/usb/src/sys/dev/usb2/core/usb2_generic.c#31 edit
.. //depot/projects/usb/src/sys/dev/usb2/core/usb2_generic.h#7 edit
Differences ...
==== //depot/projects/usb/src/sys/dev/usb2/core/usb2_dev.c#42 (text+ko) ====
@@ -464,22 +464,16 @@
struct usb2_fifo **ppf;
struct usb2_fifo *f;
int fflags;
- uint8_t need_uref;
uint8_t dev_ep_index;
if (fp) {
- /* check if we need uref hint */
- need_uref = devloc ? 0 : 1;
+ /* check if we need uref */
+ ploc->is_uref = devloc ? 0 : 1;
/* get devloc - already verified */
devloc = USB_P2U(fp->f_data);
/* get file flags */
fflags = fp->f_flag;
- /* only ref FIFO */
- ploc->is_uref = 0;
- /* devloc should be valid */
} else {
- /* we need uref */
- need_uref = 1;
/* only ref device */
fflags = 0;
/* search for FIFO */
@@ -602,27 +596,14 @@
if (ploc->is_write) {
DPRINTFN(2, "ref write\n");
ploc->txfifo->refcount++;
- if (ploc->txfifo->flag_no_uref == 0) {
- /* we need extra locking */
- ploc->is_uref = 1;
- }
}
if (ploc->is_read) {
DPRINTFN(2, "ref read\n");
ploc->rxfifo->refcount++;
- if (ploc->rxfifo->flag_no_uref == 0) {
- /* we need extra locking */
- ploc->is_uref = 1;
- }
}
if (ploc->is_uref) {
- if (need_uref) {
- DPRINTFN(2, "ref udev - needed\n");
- ploc->udev->refcount++;
- } else {
- DPRINTFN(2, "ref udev - not needed\n");
- ploc->is_uref = 0;
- }
+ DPRINTFN(2, "ref udev - needed\n");
+ ploc->udev->refcount++;
}
mtx_unlock(&usb2_ref_lock);
@@ -643,6 +624,59 @@
}
/*------------------------------------------------------------------------*
+ * usb2_uref_location
+ *
+ * This function is used to upgrade an USB reference to include the
+ * USB device reference on a USB location.
+ *
+ * Return values:
+ * 0: Success, refcount incremented on the given USB device.
+ * Else: Failure.
+ *------------------------------------------------------------------------*/
+static usb2_error_t
+usb2_uref_location(struct usb2_location *ploc)
+{
+ /*
+ * Check if we already got an USB reference on this location:
+ */
+ if (ploc->is_uref) {
+ return (0); /* success */
+ }
+ mtx_lock(&usb2_ref_lock);
+ if (ploc->bus != devclass_get_softc(usb2_devclass_ptr, ploc->bus_index)) {
+ DPRINTFN(2, "bus changed at %u\n", ploc->bus_index);
+ goto error;
+ }
+ if (ploc->udev != ploc->bus->devices[ploc->dev_index]) {
+ DPRINTFN(2, "device changed at %u\n", ploc->dev_index);
+ goto error;
+ }
+ if (ploc->udev->refcount == USB_DEV_REF_MAX) {
+ DPRINTFN(2, "no dev ref\n");
+ goto error;
+ }
+ DPRINTFN(2, "ref udev\n");
+ ploc->udev->refcount++;
+ mtx_unlock(&usb2_ref_lock);
+
+ /* set "uref" */
+ ploc->is_uref = 1;
+
+ /*
+ * We are about to alter the bus-state. Apply the
+ * required locks.
+ */
+ sx_xlock(ploc->udev->default_sx + 1);
+ mtx_lock(&Giant); /* XXX */
+ return (0);
+
+error:
+ mtx_unlock(&usb2_ref_lock);
+ DPRINTFN(2, "fail\n");
+ return (USB_ERR_INVAL);
+}
+
+/*------------------------------------------------------------------------*
* usb2_unref_device
*
* This function will release the reference count by one unit for the
@@ -799,9 +833,6 @@
f->methods = &usb2_ugen_methods;
f->iface_index = iface_index;
f->udev = udev;
- if (dev_ep_index != 0) {
- f->flag_no_uref = 1;
- }
mtx_lock(&usb2_ref_lock);
udev->fifo[n + USB_FIFO_TX] = f;
mtx_unlock(&usb2_ref_lock);
@@ -827,9 +858,6 @@
f->methods = &usb2_ugen_methods;
f->iface_index = iface_index;
f->udev = udev;
- if (dev_ep_index != 0) {
- f->flag_no_uref = 1;
- }
mtx_lock(&usb2_ref_lock);
udev->fifo[n + USB_FIFO_RX] = f;
mtx_unlock(&usb2_ref_lock);
@@ -1490,7 +1518,7 @@
DPRINTFN(2, "fflags=%u\n", fflags);
- err = usb2_ref_device(fp, &loc, 0);;
+ err = usb2_ref_device(fp, &loc, 0 /* need uref */ );;
/* restore some file variables */
fp->f_ops = usb2_old_f_ops;
@@ -1555,7 +1583,7 @@
}
break;
default:
- return (ENOTTY);
+ return (ENOIOCTL);
}
return (error);
}
@@ -1565,13 +1593,11 @@
struct ucred *cred, struct thread *td)
{
struct usb2_location loc;
+ struct usb2_fifo *f;
int fflags;
- int err_rx;
- int err_tx;
int err;
- uint8_t is_common = 0;
- err = usb2_ref_device(fp, &loc, 0);;
+ err = usb2_ref_device(fp, &loc, 1 /* no uref */ );;
if (err) {
return (ENXIO);
}
@@ -1579,43 +1605,31 @@
DPRINTFN(2, "fflags=%u, cmd=0x%lx\n", fflags, cmd);
+ f = NULL; /* set default value */
+ err = ENOIOCTL; /* set default value */
+
+ if (fflags & FWRITE) {
+ f = loc.txfifo;
+ err = usb2_ioctl_f_sub(f, cmd, addr, td);
+ }
if (fflags & FREAD) {
- if (fflags & FWRITE) {
- /*
- * Make sure that the IOCTL is not
- * duplicated:
- */
- is_common = 1;
- }
- err_rx = usb2_ioctl_f_sub(loc.rxfifo, cmd, addr, td);
- if (err_rx == ENOTTY) {
- err_rx = (loc.rxfifo->methods->f_ioctl) (
- loc.rxfifo, cmd, addr,
- is_common ? fflags : (fflags & ~FWRITE), td);
- }
- } else {
- err_rx = 0;
+ f = loc.rxfifo;
+ err = usb2_ioctl_f_sub(f, cmd, addr, td);
}
- if (fflags & FWRITE) {
- err_tx = usb2_ioctl_f_sub(loc.txfifo, cmd, addr, td);
- if (err_tx == ENOTTY) {
- if (is_common)
- err_tx = 0; /* already handled this IOCTL */
- else
- err_tx = (loc.txfifo->methods->f_ioctl) (
- loc.txfifo, cmd, addr, fflags & ~FREAD, td);
+ if (err == ENOIOCTL) {
+ err = (f->methods->f_ioctl) (f, cmd, addr, fflags, td);
+ if (err == ENOIOCTL) {
+ if (usb2_uref_location(&loc)) {
+ err = ENXIO;
+ goto done;
+ }
+ err = (f->methods->f_ioctl_post) (f, cmd, addr, fflags, td);
}
- } else {
- err_tx = 0;
}
-
- if (err_rx) {
- err = err_rx;
- } else if (err_tx) {
- err = err_tx;
- } else {
- err = 0; /* no error */
+ if (err == ENOIOCTL) {
+ err = ENOTTY;
}
+done:
usb2_unref_device(&loc);
return (err);
}
@@ -2113,7 +2127,7 @@
usb2_fifo_dummy_ioctl(struct usb2_fifo *fifo, u_long cmd, void *addr,
int fflags, struct thread *td)
{
- return (ENOTTY);
+ return (ENOIOCTL);
}
static void
@@ -2137,6 +2151,9 @@
if (pm->f_ioctl == NULL)
pm->f_ioctl = &usb2_fifo_dummy_ioctl;
+ if (pm->f_ioctl_post == NULL)
+ pm->f_ioctl_post = &usb2_fifo_dummy_ioctl;
+
if (pm->f_start_read == NULL)
pm->f_start_read = &usb2_fifo_dummy_cmd;
@@ -2220,7 +2237,6 @@
f_tx->methods = pm;
f_tx->iface_index = iface_index;
f_tx->udev = udev;
- f_tx->flag_no_uref = 1;
f_rx->fifo_index = n + USB_FIFO_RX;
f_rx->dev_ep_index = (n / 2) + (USB_EP_MAX / 2);
@@ -2229,7 +2245,6 @@
f_rx->methods = pm;
f_rx->iface_index = iface_index;
f_rx->udev = udev;
- f_rx->flag_no_uref = 1;
f_sc->fp[USB_FIFO_TX] = f_tx;
f_sc->fp[USB_FIFO_RX] = f_rx;
==== //depot/projects/usb/src/sys/dev/usb2/core/usb2_dev.h#15 (text+ko) ====
@@ -66,6 +66,11 @@
usb2_fifo_open_t *f_open;
usb2_fifo_close_t *f_close;
usb2_fifo_ioctl_t *f_ioctl;
+ /*
+ * NOTE: The post-ioctl callback is called after the USB reference
+ * gets locked in the IOCTL handler:
+ */
+ usb2_fifo_ioctl_t *f_ioctl_post;
usb2_fifo_cmd_t *f_start_read;
usb2_fifo_cmd_t *f_stop_read;
usb2_fifo_cmd_t *f_start_write;
@@ -102,7 +107,6 @@
uint32_t bufsize; /* BULK and INTERRUPT buffer size */
uint16_t nframes; /* for isochronous mode */
uint16_t dev_ep_index; /* our device endpoint index */
- uint8_t flag_no_uref; /* set if FIFO is not control endpoint */
uint8_t flag_sleeping; /* set if FIFO is sleeping */
uint8_t flag_iscomplete; /* set if a USB transfer is complete */
uint8_t flag_iserror; /* set if FIFO error happened */
==== //depot/projects/usb/src/sys/dev/usb2/core/usb2_device.c#31 (text+ko) ====
@@ -677,7 +677,7 @@
* Free all generic FIFOs for this interface, except control
* endpoint FIFOs:
*/
- usb2_fifo_free_wrap(udev, iface_index, 2);
+ usb2_fifo_free_wrap(udev, iface_index, 0);
err = usb2_fill_iface_data(udev, iface_index, alt_index);
if (err) {
@@ -2081,13 +2081,14 @@
/*------------------------------------------------------------------------*
* usb2_fifo_free_wrap
*
- * The function will free the FIFOs.
+ * This function will free the FIFOs.
+ *
+ * Flag values, if "iface_index" is equal to "USB_IFACE_INDEX_ANY".
+ * 0: Free all FIFOs except generic control endpoints.
+ * 1: Free all FIFOs.
*
- * Flag values:
- * 0: Free all FIFOs except control endpoints matching "iface_index".
- * 1: Free all FIFOs matching "iface_index".
- * 2: Free all generic FIFOs except control endpoints matching
- * "iface_index".
+ * Flag values, if "iface_index" is not equal to "USB_IFACE_INDEX_ANY".
+ * Not used.
*------------------------------------------------------------------------*/
static void
usb2_fifo_free_wrap(struct usb2_device *udev,
@@ -2104,25 +2105,48 @@
if (f == NULL) {
continue;
}
- /* Check if the FIFO is of generic type */
- if (f->methods == &usb2_ugen_methods) {
- if ((f->dev_ep_index == 0) &&
- ((flag == 0) || (flag == 2))) {
- /* don't free UGEN control endpoint yet */
+ /* Check if the interface index matches */
+ if (iface_index == f->iface_index) {
+ if (f->methods != &usb2_ugen_methods) {
+ /*
+ * Don't free any non-generic FIFOs in
+ * this case.
+ */
+ continue;
+ }
+ if (f->dev_ep_index == 0) {
+ /*
+ * Don't free the generic control endpoint
+ * yet and make sure that any USB-FS
+ * activity is stopped!
+ */
+ if (ugen_fs_uninit(f)) {
+ /* ignore any failures */
+ DPRINTFN(10, "udev=%p ugen_fs_uninit() "
+ "failed! (ignored)\n", udev);
+ }
continue;
}
- } else {
- if (flag == 2) {
- /* don't free non-generic FIFO */
+ } else if (iface_index == USB_IFACE_INDEX_ANY) {
+ if ((f->methods == &usb2_ugen_methods) &&
+ (f->dev_ep_index == 0) && (flag == 0)) {
+ /*
+ * Don't free the generic control endpoint
+ * yet, but make sure that any USB-FS
+ * activity is stopped!
+ */
+ if (ugen_fs_uninit(f)) {
+ /* ignore any failures */
+ DPRINTFN(10, "udev=%p ugen_fs_uninit() "
+ "failed! (ignored)\n", udev);
+ }
continue;
}
+ } else {
+ continue;
}
-
- /* Check if the interface index matches */
- if ((iface_index == f->iface_index) ||
- (iface_index == USB_IFACE_INDEX_ANY)) {
- usb2_fifo_free(f);
- }
+ /* free the FIFO */
+ usb2_fifo_free(f);
}
return;
}
==== //depot/projects/usb/src/sys/dev/usb2/core/usb2_generic.c#31 (text+ko) ====
@@ -67,6 +67,7 @@
static usb2_fifo_open_t ugen_open;
static usb2_fifo_close_t ugen_close;
static usb2_fifo_ioctl_t ugen_ioctl;
+static usb2_fifo_ioctl_t ugen_ioctl_post;
static usb2_fifo_cmd_t ugen_start_read;
static usb2_fifo_cmd_t ugen_start_write;
static usb2_fifo_cmd_t ugen_stop_io;
@@ -81,8 +82,6 @@
static int usb2_gen_fill_deviceinfo(struct usb2_fifo *f, struct usb2_device_info *di);
static int ugen_re_enumerate(struct usb2_fifo *f);
static int ugen_iface_ioctl(struct usb2_fifo *f, u_long cmd, void *addr, int fflags);
-static int ugen_ctrl_ioctl(struct usb2_fifo *f, u_long cmd, void *addr, int fflags);
-static int ugen_fs_uninit(struct usb2_fifo *f);
static uint8_t ugen_fs_get_complete(struct usb2_fifo *f, uint8_t *pindex);
@@ -92,6 +91,7 @@
.f_open = &ugen_open,
.f_close = &ugen_close,
.f_ioctl = &ugen_ioctl,
+ .f_ioctl_post = &ugen_ioctl_post,
.f_start_read = &ugen_start_read,
.f_stop_read = &ugen_stop_io,
.f_start_write = &ugen_start_write,
@@ -583,10 +583,6 @@
{
DPRINTFN(2, "index %u\n", index);
- if (f->flag_no_uref) {
- /* not the control endpoint - just forget it */
- return (EINVAL);
- }
if (f->udev->flags.usb2_mode != USB_MODE_HOST) {
/* not possible in device side mode */
return (ENOTTY);
@@ -612,10 +608,6 @@
{
DPRINTFN(2, "%u, %u\n", iface_index, alt_index);
- if (f->flag_no_uref) {
- /* not the control endpoint - just forget it */
- return (EINVAL);
- }
if (f->udev->flags.usb2_mode != USB_MODE_HOST) {
/* not possible in device side mode */
return (ENOTTY);
@@ -648,10 +640,6 @@
DPRINTFN(6, "\n");
- if (f->flag_no_uref) {
- /* control endpoint only */
- return (EINVAL);
- }
if (ugd->ugd_data == NULL) {
/* userland pointer should not be zero */
return (EINVAL);
@@ -697,10 +685,6 @@
uint16_t size = sizeof(f->udev->bus->scratch[0].data);
int error;
- if (f->flag_no_uref) {
- /* control endpoint only */
- return (EINVAL);
- }
if (usb2_req_get_string_desc(f->udev, &Giant, ptr,
size, ugd->ugd_lang_id, ugd->ugd_string_index)) {
error = EINVAL;
@@ -743,10 +727,6 @@
uint8_t i;
uint8_t first = 1;
- if (f->flag_no_uref) {
- /* control endpoint only */
- return (EINVAL);
- }
max_len = dn->udn_devnames_len;
dst = dn->udn_devnames_ptr;
@@ -805,10 +785,6 @@
struct usb2_device *udev;
struct usb2_device *hub;
- if (f->flag_no_uref) {
- /* control endpoint only */
- return (EINVAL);
- }
udev = f->udev;
bzero(di, sizeof(di[0]));
@@ -911,10 +887,6 @@
uint16_t len;
uint16_t actlen;
- if (f->flag_no_uref) {
- /* control endpoint only */
- return (EINVAL);
- }
if (ugen_check_request(f->udev, &ur->ucr_request)) {
return (EPERM);
}
@@ -950,10 +922,6 @@
struct usb2_device *udev = f->udev;
int error;
- if (f->flag_no_uref) {
- /* control endpoint only */
- return (EINVAL);
- }
/*
* This request can be useful for testing USB drivers:
*/
@@ -971,7 +939,7 @@
return (0);
}
-static int
+int
ugen_fs_uninit(struct usb2_fifo *f)
{
if (f->fs_xfer == NULL) {
@@ -983,7 +951,6 @@
f->fs_ep_max = 0;
f->fs_ep_ptr = NULL;
f->flag_iscomplete = 0;
- f->flag_no_uref = 0; /* restore operation */
usb2_fifo_free_buffer(f);
return (0);
}
@@ -1385,7 +1352,8 @@
}
static int
-ugen_fs_ioctl(struct usb2_fifo *f, u_long cmd, void *addr, int fflags)
+ugen_ioctl(struct usb2_fifo *f, u_long cmd, void *addr, int fflags,
+ struct thread *td)
{
struct usb2_config usb2_config[1];
struct usb2_device_request req;
@@ -1393,8 +1361,6 @@
struct usb2_fs_complete *pcomp;
struct usb2_fs_start *pstart;
struct usb2_fs_stop *pstop;
- struct usb2_fs_init *pinit;
- struct usb2_fs_uninit *puninit;
struct usb2_fs_open *popen;
struct usb2_fs_close *pclose;
struct usb2_fs_clear_stall_sync *pstall;
@@ -1409,6 +1375,8 @@
u.addr = addr;
+ DPRINTFN(6, "cmd=0x%08lx\n", cmd);
+
switch (cmd) {
case USB_FS_COMPLETE:
mtx_lock(f->priv_mtx);
@@ -1443,59 +1411,6 @@
mtx_unlock(f->priv_mtx);
break;
- case USB_FS_INIT:
- /* verify input parameters */
- if (u.pinit->pEndpoints == NULL) {
- error = EINVAL;
- break;
- }
- if (u.pinit->ep_index_max > 127) {
- error = EINVAL;
- break;
- }
- if (u.pinit->ep_index_max == 0) {
- error = EINVAL;
- break;
- }
- if (f->fs_xfer != NULL) {
- error = EBUSY;
- break;
- }
- if (f->flag_no_uref) {
- error = EINVAL;
- break;
- }
- if (f->dev_ep_index != 0) {
- error = EINVAL;
- break;
- }
- if (ugen_fifo_in_use(f, fflags)) {
- error = EBUSY;
- break;
- }
- error = usb2_fifo_alloc_buffer(f, 1, u.pinit->ep_index_max);
- if (error) {
- break;
- }
- f->fs_xfer = malloc(sizeof(f->fs_xfer[0]) *
- u.pinit->ep_index_max, M_USB, M_WAITOK | M_ZERO);
- if (f->fs_xfer == NULL) {
- usb2_fifo_free_buffer(f);
- error = ENOMEM;
- break;
- }
- f->fs_ep_max = u.pinit->ep_index_max;
- f->fs_ep_ptr = u.pinit->pEndpoints;
- break;
-
- case USB_FS_UNINIT:
- if (u.puninit->dummy != 0) {
- error = EINVAL;
- break;
- }
- error = ugen_fs_uninit(f);
- break;
-
case USB_FS_OPEN:
if (u.popen->ep_index >= f->fs_ep_max) {
error = EINVAL;
@@ -1583,11 +1498,6 @@
f->fs_xfer[u.popen->ep_index]->max_data_length;
f->fs_xfer[u.popen->ep_index]->priv_fifo =
((uint8_t *)0) + u.popen->ep_index;
- /*
- * Increase performance by dropping locks we
- * don't need:
- */
- f->flag_no_uref = 1;
} else {
error = ENOMEM;
}
@@ -1644,9 +1554,12 @@
break;
default:
- error = ENOTTY;
+ error = ENOIOCTL;
break;
}
+
+ DPRINTFN(6, "error=%d\n", error);
+
return (error);
}
@@ -1999,14 +1912,15 @@
break;
default:
- error = ENOTTY;
+ error = ENOIOCTL;
break;
}
return (error);
}
static int
-ugen_ctrl_ioctl(struct usb2_fifo *f, u_long cmd, void *addr, int fflags)
+ugen_ioctl_post(struct usb2_fifo *f, u_long cmd, void *addr, int fflags,
+ struct thread *td)
{
union {
struct usb2_interface_descriptor *idesc;
@@ -2014,6 +1928,8 @@
struct usb2_device_descriptor *ddesc;
struct usb2_config_descriptor *cdesc;
struct usb2_device_stats *stat;
+ struct usb2_fs_init *pinit;
+ struct usb2_fs_uninit *puninit;
uint32_t *ptime;
void *addr;
int *pint;
@@ -2026,6 +1942,8 @@
u.addr = addr;
+ DPRINTFN(6, "cmd=0x%08lx\n", cmd);
+
switch (cmd) {
case USB_DISCOVER:
usb2_needs_explore_all();
@@ -2170,29 +2088,60 @@
*u.pint, 0, UHF_PORT_ENABLE);
break;
- default:
- error = EINVAL;
+ case USB_FS_INIT:
+ /* verify input parameters */
+ if (u.pinit->pEndpoints == NULL) {
+ error = EINVAL;
+ break;
+ }
+ if (u.pinit->ep_index_max > 127) {
+ error = EINVAL;
+ break;
+ }
+ if (u.pinit->ep_index_max == 0) {
+ error = EINVAL;
+ break;
+ }
+ if (f->fs_xfer != NULL) {
+ error = EBUSY;
+ break;
+ }
+ if (f->dev_ep_index != 0) {
+ error = EINVAL;
+ break;
+ }
+ if (ugen_fifo_in_use(f, fflags)) {
+ error = EBUSY;
+ break;
+ }
+ error = usb2_fifo_alloc_buffer(f, 1, u.pinit->ep_index_max);
+ if (error) {
+ break;
+ }
+ f->fs_xfer = malloc(sizeof(f->fs_xfer[0]) *
+ u.pinit->ep_index_max, M_USB, M_WAITOK | M_ZERO);
+ if (f->fs_xfer == NULL) {
+ usb2_fifo_free_buffer(f);
+ error = ENOMEM;
+ break;
+ }
+ f->fs_ep_max = u.pinit->ep_index_max;
+ f->fs_ep_ptr = u.pinit->pEndpoints;
break;
- }
- return (error);
-}
-static int
-ugen_ioctl(struct usb2_fifo *f, u_long cmd, void *addr, int fflags,
- struct thread *td)
-{
- int error;
+ case USB_FS_UNINIT:
+ if (u.puninit->dummy != 0) {
+ error = EINVAL;
+ break;
+ }
+ error = ugen_fs_uninit(f);
+ break;
- DPRINTFN(6, "cmd=%08lx\n", cmd);
- error = ugen_fs_ioctl(f, cmd, addr, fflags);
- if (error == ENOTTY) {
- if (f->flag_no_uref) {
- mtx_lock(f->priv_mtx);
- error = ugen_iface_ioctl(f, cmd, addr, fflags);
- mtx_unlock(f->priv_mtx);
- } else {
- error = ugen_ctrl_ioctl(f, cmd, addr, fflags);
- }
+ default:
+ mtx_lock(f->priv_mtx);
+ error = ugen_iface_ioctl(f, cmd, addr, fflags);
+ mtx_unlock(f->priv_mtx);
+ break;
}
DPRINTFN(6, "error=%d\n", error);
return (error);
==== //depot/projects/usb/src/sys/dev/usb2/core/usb2_generic.h#7 (text+ko) ====
@@ -29,5 +29,6 @@
extern struct usb2_fifo_methods usb2_ugen_methods;
int ugen_do_request(struct usb2_fifo *f, struct usb2_ctl_request *ur);
+int ugen_fs_uninit(struct usb2_fifo *f);
#endif /* _USB2_GENERIC_H_ */
More information about the p4-projects
mailing list