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