Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 4 Jun 2007 07:17:20 GMT
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 120885 for review
Message-ID:  <200706040717.l547HKfK044801@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=120885

Change 120885 by hselasky@hselasky_mini_itx on 2007/06/04 07:16:51

	This is the start of a completely new /dev/usbX backend
	that can be used to access any USB device on the USB bus.
	"/dev/usbX" now uses the "usb_cdev" system that makes it
	detach safe among other things. Remove support for "usbd",
	"/dev/usb" hence this utility has been replaced by "devd".

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb/usb.c#13 edit
.. //depot/projects/usb/src/sys/dev/usb/usb.h#10 edit
.. //depot/projects/usb/src/sys/dev/usb/usb_requests.c#5 edit
.. //depot/projects/usb/src/sys/dev/usb/usb_subr.c#37 edit

Differences ...

==== //depot/projects/usb/src/sys/dev/usb/usb.c#13 (text+ko) ====

@@ -50,11 +50,8 @@
 #include <sys/lock.h>
 #include <sys/malloc.h>
 
-#include <sys/uio.h> /* UIO_XXX */
 #include <sys/proc.h>
 #include <sys/unistd.h>
-#include <sys/filio.h> /* FXXX */
-#include <sys/ioccom.h> /* IOR()/IOW()/IORW() */
 #include <sys/kthread.h>
 #include <sys/poll.h>
 #include <sys/signalvar.h>
@@ -63,13 +60,7 @@
 #include <dev/usb/usb_port.h>
 #include <dev/usb/usb.h>
 #include <dev/usb/usb_subr.h>
-#include <dev/usb/usb_quirks.h>
-
-#define DEV2UNIT(d)	(minor(d))
-#define DEV2BUS(d)	(*((struct usbd_bus **)&((d)->si_drv1)))
 
-#define USB_DEV_MINOR	255		/* event queue device */
-
 MALLOC_DEFINE(M_USB, "USB", "USB");
 MALLOC_DEFINE(M_USBDEV, "USBdev", "USB device");
 MALLOC_DEFINE(M_USBHC, "USBHC", "USB host controller");
@@ -83,58 +74,82 @@
 int	usbdebug = 0;
 SYSCTL_INT(_hw_usb, OID_AUTO, debug, CTLFLAG_RW,
 	   &usbdebug, 0, "usb debug level");
+#endif
 
-/*
- * 0  - do usual exploration
- * 1  - do not use timeout exploration
- * >1 - do no exploration
- */
-int	usb_noexplore = 0;
+#if ((__FreeBSD_version >= 700001) || (__FreeBSD_version == 0) || \
+     ((__FreeBSD_version >= 600034) && (__FreeBSD_version < 700000)))
+#define USB_UCRED struct ucred *ucred,
+#else
+#define USB_UCRED
 #endif
 
-#define USB_MAX_EVENTS 100
-struct usb_event_wrapper
-{
-	struct usb_event ue;
-	TAILQ_ENTRY(usb_event_wrapper) next;
-};
+uint8_t usb_driver_added_refcount;
 
-static TAILQ_HEAD(, usb_event_wrapper) usb_events =
-	TAILQ_HEAD_INITIALIZER(usb_events);
+static uint8_t usb_post_init_called = 0;
 
-#ifndef usb_global_lock
-struct mtx usb_global_lock;
-#endif
-
 static device_probe_t usb_probe;
 static device_attach_t usb_attach;
 static device_detach_t usb_detach;
 
-/* these variables are protected by "usb_global_lock" */
-static int usb_nevents = 0;
-static struct selinfo usb_selevent;
-static struct proc *usb_async_proc;  /* process that wants USB SIGIO */
-static int usb_dev_open = 0;
+static int usb_dummy_open(struct cdev *dev, int oflags, int devtype, struct thread *td);
+static void usb_discover(struct usbd_bus *bus);
+static void usb_event_thread(struct usbd_bus *bus);
+static void usb_create_event_thread(struct usbd_bus *bus);
+static void __usb_attach(device_t dev, struct usbd_bus *bus);
+static void usb_post_init(void *arg);
+static struct usbd_clone *usb_clone_sub(struct usbd_bus *bus);
+static void usb_clone_remove(struct usbd_bus *bus);
+static void usb_clone(void *arg, USB_UCRED char *name, int namelen, struct cdev **dev);
+static int usb_ioctl(struct usb_cdev *dev, u_long cmd, caddr_t addr, int32_t fflags, struct thread *td);
+static void usb_init(void *arg);
+static void usb_uninit(void *arg);
+
+static devclass_t usb_devclass;
+static driver_t usb_driver =
+{
+	.name    = "usb",
+	.methods = (device_method_t [])
+	{
+	  DEVMETHOD(device_probe, usb_probe),
+	  DEVMETHOD(device_attach, usb_attach),
+	  DEVMETHOD(device_detach, usb_detach),
+	  DEVMETHOD(device_suspend, bus_generic_suspend),
+	  DEVMETHOD(device_resume, bus_generic_resume),
+	  DEVMETHOD(device_shutdown, bus_generic_shutdown),
+	  {0,0}
+	},
+	.size    = 0, /* the softc must be set by the attacher! */
+};
+
+DRIVER_MODULE(usb, ohci, usb_driver, usb_devclass, 0, 0);
+DRIVER_MODULE(usb, uhci, usb_driver, usb_devclass, 0, 0);
+DRIVER_MODULE(usb, ehci, usb_driver, usb_devclass, 0, 0);
+
+MODULE_DEPEND(usb, usb, 1, 1, 1);
+MODULE_VERSION(usb, 1);
+
+static cdevsw_t usb_dummy_cdevsw = {
+    .d_version = D_VERSION,
+    .d_open    = usb_dummy_open,
+    .d_name    = "usb_dummy_cdev",
+};
 
-/**/
-static const char * const usbrev_str[] = USBREV_STR;
+static int
+usb_dummy_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
+{
+	return ENODEV;
+}
 
-/* 
- * usb_discover - explore the device tree from the root
- * 
- * usb_discover device nodes, kthread
- */
+/*------------------------------------------------------------------------* 
+ *	usb_discover - explore the device tree from the root
+ *------------------------------------------------------------------------*/
 static void
 usb_discover(struct usbd_bus *bus)
 {
+	int32_t error;
+
 	PRINTFN(2,("\n"));
 
-#ifdef USB_DEBUG
-	if(usb_noexplore > 1)
-	{
-		return;
-	}
-#endif
 	mtx_assert(&usb_global_lock, MA_OWNED);
 
 	/* check that only one thread is exploring
@@ -144,8 +159,8 @@
 	{
 		bus->wait_explore = 1;
 
-		mtx_sleep(&bus->wait_explore, &usb_global_lock, PWAIT,
-		       "usb wait explore", 0);
+		error = mtx_sleep(&bus->wait_explore, &usb_global_lock, 0,
+				  "usb wait explore", 0);
 	}
 
 	bus->is_exploring = 1;
@@ -179,6 +194,8 @@
 static void
 usb_event_thread(struct usbd_bus *bus)
 {
+	int32_t error;
+
 	mtx_lock(&usb_global_lock);
 
 	while(1)
@@ -188,20 +205,11 @@
 			break;
 		}
 
-#ifdef USB_DEBUG
-		if(usb_noexplore < 2)
-#endif
-		{
-			usb_discover(bus);
-		}
+		usb_discover(bus);
+
+		error = mtx_sleep(&bus->needs_explore, &usb_global_lock,
+				  0, "usbevt", hz * 60);
 
-#ifdef USB_DEBUG
-		mtx_sleep(&bus->needs_explore, &usb_global_lock, PWAIT,
-		       "usbevt", usb_noexplore ? 0 : hz * 60);
-#else
-		mtx_sleep(&bus->needs_explore, &usb_global_lock, PWAIT,
-		       "usbevt", hz * 60);
-#endif
 		PRINTFN(2,("woke up\n"));
 	}
 
@@ -231,8 +239,6 @@
 	return;
 }
 
-u_int8_t usb_driver_added_refcount;
-
 void
 usb_needs_probe_and_attach(void)
 {
@@ -286,128 +292,8 @@
 	return;
 }
 
-static int
-usb_event_get_next(struct usb_event *ue)
-{
-	struct usb_event_wrapper *uew;
-	int err;
-
-	mtx_lock(&usb_global_lock);
-
-	uew = TAILQ_FIRST(&usb_events);
-
-	if(uew == NULL)
-	{
-		usb_nevents = 0;
-		err = 0;
-	}
-	else
-	{
-		*ue = uew->ue;
-
-		TAILQ_REMOVE(&usb_events, uew, next);
-
-		free(uew, M_USBDEV);
-
-		if(usb_nevents)
-		{
-		   usb_nevents--;
-		}
-		err = 1;
-	}
-	mtx_unlock(&usb_global_lock);
-	return (err);
-}
-
-static void
-usb_event_add(int type, struct usb_event *uep)
-{
-	struct usb_event_wrapper *uew;
-	struct timeval thetime;
+/* called from "{ehci,ohci,uhci}_pci_attach()" */
 
-	uew = malloc(sizeof *uew, M_USBDEV, M_WAITOK|M_ZERO);
-	if(uew == NULL)
-	{
-		return;
-	}
-	uew->ue = *uep;
-	uew->ue.ue_type = type;
-	microtime(&thetime);
-	TIMEVAL_TO_TIMESPEC(&thetime, &uew->ue.ue_time);
-
-	mtx_lock(&usb_global_lock);
-
-	if(USB_EVENT_IS_DETACH(type))
-	{
-		struct usb_event_wrapper *uewi, *uewi_next;
-
-		for (uewi = TAILQ_FIRST(&usb_events);
-		     uewi;
-		     uewi = uewi_next)
-		{
-			uewi_next = TAILQ_NEXT(uewi, next);
-			if(uewi->ue.u.ue_driver.ue_cookie.cookie ==
-			    uep->u.ue_device.udi_cookie.cookie)
-			{
-				TAILQ_REMOVE(&usb_events, uewi, next);
-				free(uewi, M_USBDEV);
-				usb_nevents--;
-				uewi_next = TAILQ_FIRST(&usb_events);
-			}
-		}
-	}
-	if(usb_nevents >= USB_MAX_EVENTS)
-	{
-		/* too many queued events, drop an old one */
-		PRINTF(("event dropped\n"));
-
-		struct usb_event ue;
-		(void)usb_event_get_next(&ue);
-	}
-	TAILQ_INSERT_TAIL(&usb_events, uew, next);
-	usb_nevents++;
-	wakeup(&usb_events);
-	selwakeuppri(&usb_selevent, PZERO);
-	if(usb_async_proc != NULL)
-	{
-		PROC_LOCK(usb_async_proc);
-		psignal(usb_async_proc, SIGIO);
-		PROC_UNLOCK(usb_async_proc);
-	}
-
-	mtx_unlock(&usb_global_lock);
-	return;
-}
-
-void
-usbd_add_dev_event(int type, struct usbd_device *udev)
-{
-	struct usb_event ue;
-
-	bzero(&ue, sizeof(ue));
-
-	usbd_fill_deviceinfo(udev, &ue.u.ue_device,
-			     USB_EVENT_IS_ATTACH(type));
-	usb_event_add(type, &ue);
-	return;
-}
-
-void
-usbd_add_drv_event(int type, struct usbd_device *udev, device_t dev)
-{
-	struct usb_event ue;
-
-	bzero(&ue, sizeof(ue));
-
-	ue.u.ue_driver.ue_cookie = udev->cookie;
-	strncpy(ue.u.ue_driver.ue_devname, device_get_nameunit(dev),
-		sizeof ue.u.ue_driver.ue_devname);
-	usb_event_add(type, &ue);
-	return;
-}
-
-/* called from uhci_pci_attach */
-
 static int
 usb_probe(device_t dev)
 {
@@ -415,15 +301,12 @@
 	return (UMATCH_GENERIC);
 }
 
-extern cdevsw_t usb_cdevsw;
-
 static void
 __usb_attach(device_t dev, struct usbd_bus *bus)
 {
+	dev_clone_fn usb_clone_ptr = &usb_clone;
 	usbd_status err;
 	u_int8_t speed;
-	struct usb_event ue;
-	struct cdev *cdev;
 
 	PRINTF(("\n"));
 
@@ -431,36 +314,38 @@
 
 	bus->root_port.power = USB_MAX_POWER;
 
-	device_printf(bus->bdev, "USB revision %s",
-		      usbrev_str[bus->usbrev]);
+	switch (bus->usbrev) {
+	case USBREV_1_0:
+		speed = USB_SPEED_FULL;
+		device_printf(bus->bdev, "12MBps Full Speed USB v1.0\n");
+		break;
 
-	switch (bus->usbrev)
-	{
-	case USBREV_1_0:
 	case USBREV_1_1:
 		speed = USB_SPEED_FULL;
+		device_printf(bus->bdev, "12MBps Full Speed USB v1.1\n");
 		break;
 
 	case USBREV_2_0:
 		speed = USB_SPEED_HIGH;
+		device_printf(bus->bdev, "480MBps High Speed USB v2.0\n");
+		break;
+
+	case USBREV_2_5:
+		speed = USB_SPEED_VARIABLE;
+		device_printf(bus->bdev, "Wireless USB v2.5\n");
 		break;
 
 	default:
-		printf(", not supported\n");
+		device_printf(bus->bdev, "Unsupported USB revision!\n");
 		return;
 	}
 
-	printf("\n");
-
 	/* make sure not to use tsleep() if we are cold booting */
 	if(cold)
 	{
 		bus->use_polling++;
 	}
 
-	ue.u.ue_ctrlr.ue_bus = device_get_unit(bus->bdev);
-	usb_event_add(USB_EVENT_CTRLR_ATTACH, &ue);
-
 	err = usbd_new_device(bus->bdev, bus, 0, speed, 0,
 			      &bus->root_port);
 	if(!err)
@@ -495,20 +380,24 @@
 
 	usb_create_event_thread(bus);
 
-	/* the per controller devices (used for usb_discover) */
-	/* XXX This is redundant now, but old usbd's will want it */
-	cdev = make_dev(&usb_cdevsw, device_get_unit(dev), UID_ROOT, GID_OPERATOR,
-			0660, "usb%d", device_get_unit(dev));
+	snprintf(bus->usb_name, sizeof(bus->usb_name), "usb%u", device_get_unit(dev));
+
+	bus->usb_clone_tag = EVENTHANDLER_REGISTER(dev_clone, usb_clone_ptr, bus, 1000);
+	if (bus->usb_clone_tag == NULL) {
+	    device_printf(dev, "Registering clone handler failed!\n");
+	}
+
+	/* create a dummy device so that we are visible */
+	bus->usb_cdev =
+	  make_dev(&usb_dummy_cdevsw, device_get_unit(dev), 
+		   UID_ROOT, GID_OPERATOR, 0660, "%s ", bus->usb_name);
 
-	if(cdev)
-	{
-		DEV2BUS(cdev) = bus;
+	if (bus->usb_cdev == NULL) {
+	    device_printf(dev, "Creating dummy device failed!\n");
 	}
 	return;
 }
 
-static u_int8_t usb_post_init_called = 0;
-
 static int
 usb_attach(device_t dev)
 {
@@ -572,7 +461,7 @@
 usb_detach(device_t dev)
 {
 	struct usbd_bus *bus = device_get_softc(dev);
-	struct usb_event ue;
+	int32_t error;
 
 	PRINTF(("start\n"));
 
@@ -583,8 +472,8 @@
 	{
 		bus->wait_explore = 1;
 
-		mtx_sleep(&bus->wait_explore, &usb_global_lock, PWAIT,
-		       "usb wait explore", 0);
+		mtx_sleep(&bus->wait_explore, &usb_global_lock, 0,
+			  "usb wait explore", 0);
 	}
 
 	/* detach children first */
@@ -604,19 +493,13 @@
 	{
 		wakeup(&bus->needs_explore);
 
-		if(mtx_sleep(bus, &usb_global_lock, PWAIT, "usbdet", hz * 60))
-		{
-			device_printf(bus->bdev,
-				      "event thread didn't die\n");
-		}
+		error = mtx_sleep(bus, &usb_global_lock, 0, "usbdet", 0);
+
 		PRINTF(("event thread dead\n"));
 	}
 
 	mtx_unlock(&usb_global_lock);
 
-	ue.u.ue_ctrlr.ue_bus = device_get_unit(bus->bdev);
-	usb_event_add(USB_EVENT_CTRLR_DETACH, &ue);
-
 	mtx_lock(&bus->mtx);
 	if(bus->bdev == dev)
 	{
@@ -632,351 +515,345 @@
 		device_printf(dev, "unexpected bus->bdev value!\n");
 	}
 	mtx_unlock(&bus->mtx);
+
+	if (bus->usb_cdev) {
+	    destroy_dev(bus->usb_cdev);
+	    bus->usb_cdev = NULL;
+	}
+
+	if (bus->usb_clone_tag) {
+	    EVENTHANDLER_DEREGISTER(dev_clone, bus->usb_clone_tag);
+	    bus->usb_clone_tag = NULL;
+	}
+
+	usb_clone_remove(bus);
+
 	return (0);
 }
 
-static int
-usbopen(struct cdev *dev, int flag, int mode, struct thread *proc)
+static struct usbd_clone *
+usb_clone_sub(struct usbd_bus *bus)
 {
-	int error = 0;
+	struct usbd_clone *sub;
+	int32_t error;
+	const char *p_name[2];
+	char n_name[64];
+
+	mtx_lock(&(bus->mtx));
+	sub = bus->usb_clone_root;
+	mtx_unlock(&(bus->mtx));
+
+	while (sub) {
+	    if (!usb_cdev_opened(&(sub->cdev))) {
+	        return sub;
+	    }
+	    sub = sub->next;
+	}
+
+	sub = malloc(sizeof(*sub), M_USBDEV, M_ZERO|M_WAITOK);
+	if (sub == NULL) {
+	    return NULL;
+	}
 
-	mtx_lock(&usb_global_lock);
+	mtx_lock(&(bus->mtx));
+ 	sub->unit = bus->usb_clone_count;
+	if (bus->usb_clone_count < USB_BUS_MAX_CLONES) {
+	    bus->usb_clone_count ++;
+	}
+	mtx_unlock(&(bus->mtx));
 
-	if(DEV2UNIT(dev) == USB_DEV_MINOR)
-	{
-		if(usb_dev_open)
-		{
-			error = EBUSY;
-			goto done;
-		}
-		usb_dev_open = 1;
-		usb_async_proc = 0;
+	if (sub->unit >= USB_BUS_MAX_CLONES) {
+	    /* limit reached */
+	    goto error;
 	}
-	else
-	{
-		struct usbd_bus *bus = DEV2BUS(dev);
+
+	snprintf(n_name, sizeof(n_name), "%s.%02x", bus->usb_name, sub->unit);
+
+	mtx_init(&(sub->mtx), "usb_clone", NULL, MTX_DEF|MTX_RECURSE);
+
+	p_name[0] = n_name;
+	p_name[1] = NULL;
+
+	sub->cdev.sc_ioctl = &usb_ioctl;
+	sub->bus = bus;
 
-		if(bus->root_port.device == NULL)
-		{
-			/* device is beeing detached */
-			error = EIO;
-			goto done;
-		}
+	error = usb_cdev_attach(&(sub->cdev), sub, &(sub->mtx),
+				p_name, UID_ROOT, GID_OPERATOR, 0660,
+				0, 0, 0, 0);
+	if (error) {
+	    goto error;
 	}
 
- done:
-	mtx_unlock(&usb_global_lock);
-	return (error);
+	/* insert sub-device into a one-way linked list */
+
+	mtx_lock(&(bus->mtx));
+	sub->next = bus->usb_clone_root;
+	bus->usb_clone_root = sub;
+	mtx_unlock(&(bus->mtx));
+	return sub;
+
+ error:
+	free(sub, M_USBDEV);
+	return NULL;
 }
 
-static int
-usbread(struct cdev *dev, struct uio *uio, int flag)
+static void
+usb_clone_remove(struct usbd_bus *bus)
 {
-	struct usb_event ue;
-	int error = 0;
+	struct usbd_clone *sub;
+	struct usbd_clone *next;
+	uint8_t done = 0;
 
-	if(DEV2UNIT(dev) != USB_DEV_MINOR)
-	{
-		return (ENODEV);
-	}
+	while (1) {
 
-	if(uio->uio_resid != sizeof(struct usb_event))
-	{
-		return (EINVAL);
-	}
+	    /* first prevent any further clones from 
+	     * being created:
+	     */
+	    mtx_lock(&(bus->mtx));
+	    bus->usb_clone_count = USB_BUS_MAX_CLONES;
+	    sub = bus->usb_clone_root;
+	    bus->usb_clone_root = NULL;
+	    mtx_unlock(&(bus->mtx));
 
-	mtx_lock(&usb_global_lock);
+	    /* XXX wait for any leftover VOP_LOOKUP() calls
+	     * to finish. Really we should lock some lock
+	     * here to lock that problem out! --hps
+	     */
+	    usb_delay_ms(bus, 500);
 
-	for(;;)
-	{
-		if(usb_event_get_next(&ue) != 0)
-		{
-			break;
+	    if (sub == NULL) {
+	        if (done) {
+		    break;
+		} else {
+		    done = 1;
 		}
-		if(flag & IO_NDELAY)
-		{
-			error = EWOULDBLOCK;
-			break;
-		}
-		error = mtx_sleep(&usb_events, &usb_global_lock,
-			       (PZERO|PCATCH), "usbrea", 0);
-		if(error)
-		{
-			break;
-		}
-	}
+	    } else {
+	        done = 0;
+	    }
+
+	    /* teardown all cloned devices */
+	    while (sub) {
+
+	        usb_cdev_detach(&(sub->cdev));
+
+		next = sub->next;
+
+		mtx_destroy(&(sub->mtx));
 
-	mtx_unlock(&usb_global_lock);
+		free(sub, M_USBDEV);
 
-	if(!error)
-	{
-		error = uiomove((void *)&ue, uio->uio_resid, uio);
+		sub = next;
+	    }
 	}
-	return (error);
+	return;
 }
 
-static int
-usbclose(struct cdev *dev, int flag, int mode, struct thread *proc)
+static void
+usb_clone(void *arg, USB_UCRED char *name, int namelen, struct cdev **dev)
 {
-	if(DEV2UNIT(dev) == USB_DEV_MINOR)
-	{
-		mtx_lock(&usb_global_lock);
+	struct usbd_bus *bus = arg;
+	struct usbd_clone *sub;
+
+        if (*dev) {
+	    return;
+	}
 
-		usb_async_proc = 0;
-		usb_dev_open = 0;
+        if (strcmp(name, bus->usb_name) != 0) {
+	    return;
+        }
 
-		mtx_unlock(&usb_global_lock);
+  	sub = usb_clone_sub(bus);
+	if (sub == NULL) {
+	    return;
 	}
-	return (0);
+
+	*dev = sub->cdev.sc_cdev[0];
+
+	dev_ref(*dev);
+	return;
 }
 
 static int
-usbioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *p)
+usb_ioctl(struct usb_cdev *dev, u_long cmd, caddr_t addr, 
+	  int32_t fflags, struct thread *td)
 {
+	struct usbd_clone *sub = dev->sc_priv_ptr;
+	struct usbd_bus *bus = sub->bus;
+	struct usbd_device *udev = 0;
 	int error = 0;
 
-	mtx_lock(&usb_global_lock);
+	usb_cdev_unlock(dev, fflags);
 
-	if(DEV2UNIT(dev) == USB_DEV_MINOR)
-	{
-		switch (cmd)
-		{
-		case FIONBIO:
-			/* all handled in the upper FS layer */
-			break;
+	switch (cmd) {
+	/* this part should be deleted */
+	case USB_DISCOVER:
+		break;
 
-		case FIOASYNC:
-			if(*(int *)data)
-				usb_async_proc = p->td_proc;
-			else
-				usb_async_proc = 0;
-
-			break;
-
-		default:
-			error = EINVAL;
-			break;
-		}
-	}
-	else
+	case USB_REQUEST:
 	{
-		struct usbd_bus *bus = DEV2BUS(dev);
+		struct usb_ctl_request *ur = (void *)addr;
+		uint16_t len = UGETW(ur->ucr_request.wLength);
+		uint8_t isread = (ur->ucr_request.bmRequestType & UT_READ) ? 1 : 0;
+		void *ptr = 0;
 
-		if(bus->root_port.device == NULL)
-		{
-			/* detached */
-			error = EIO;
+		udev = usbd_ref_device(bus, ur->ucr_addr);
+		if (udev == NULL) {
+			error = ENXIO;
 			goto done;
 		}
 
-		switch (cmd)
-		{
-		/* this part should be deleted */
-		case USB_DISCOVER:
-			break;
-		case USB_REQUEST:
-		{
-			struct usb_ctl_request *ur = (void *)data;
-			int len = UGETW(ur->ucr_request.wLength);
-			struct iovec iov;
-			struct uio uio;
-			void *ptr = 0;
-			int addr = ur->ucr_addr;
-			usbd_status err;
-			int error = 0;
+		PRINTF(("USB_REQUEST addr=%d len=%d\n", ur->ucr_addr, len));
 
-			PRINTF(("USB_REQUEST addr=%d len=%d\n", addr, len));
-			if((len < 0) ||
-			   (len > 32768))
-			{
-				error = EINVAL;
-				goto done;
+		if (len != 0) {
+			ptr = malloc(len, M_TEMP, M_WAITOK);
+			if (ptr == NULL) {
+				error = ENOMEM;
+				goto ret001;
 			}
-
-			if((addr < 0) || 
-			   (addr >= USB_MAX_DEVICES) ||
-			   (bus->devices[addr] == 0 /* might be checked by usbd_do_request_flags */))
-			{
-				error = EINVAL;
-				goto done;
-			}
-
-			if(len != 0)
-			{
-				iov.iov_base = (caddr_t)ur->ucr_data;
-				iov.iov_len = len;
-				uio.uio_iov = &iov;
-				uio.uio_iovcnt = 1;
-				uio.uio_resid = len;
-				uio.uio_offset = 0;
-				uio.uio_segflg = UIO_USERSPACE;
-				uio.uio_rw =
-				  ur->ucr_request.bmRequestType & UT_READ ?
-				  UIO_READ : UIO_WRITE;
-				uio.uio_procp = p;
-				ptr = malloc(len, M_TEMP, M_WAITOK);
-				if(uio.uio_rw == UIO_WRITE)
-				{
-					error = uiomove(ptr, len, &uio);
-					if(error)
-					{
-						goto ret;
-					}
-				}
-			}
-			err = usbd_do_request_flags
-			  (bus->devices[addr], &ur->ucr_request, ptr,
-			   ur->ucr_flags, &ur->ucr_actlen,
-			   USBD_DEFAULT_TIMEOUT);
-			if(err)
-			{
-				error = EIO;
-				goto ret;
-			}
-			if(len != 0)
-			{
-				if(uio.uio_rw == UIO_READ)
-				{
-					error = uiomove(ptr, len, &uio);
-					if(error)
-					{
-						goto ret;
-					}
+			if (isread == 0) {
+				error = copyin(ur->ucr_data, ptr, len);
+				if (error) {
+					goto ret001;
 				}
 			}
-		ret:
-			if(ptr)
-			{
-				free(ptr, M_TEMP);
-			}
-			goto done;
 		}
 
-		case USB_DEVICEINFO:
-		{
-			struct usb_device_info *di = (void *)data;
-			int addr = di->udi_addr;
+		mtx_lock(dev->sc_mtx_ptr);
+		error = usbd_do_request_flags_mtx
+		  (udev, dev->sc_mtx_ptr, &ur->ucr_request, ptr, ur->ucr_flags,
+		   &ur->ucr_actlen, USBD_DEFAULT_TIMEOUT);
+		mtx_unlock(dev->sc_mtx_ptr);
+
+		if (error) {
+			error = EIO;
+			goto ret001;
+		}
 
-			if((addr < 1) ||
-			   (addr >= USB_MAX_DEVICES))
-			{
-				error = EINVAL;
-				goto done;
+		if (len != 0) {
+			if (isread) {
+				error = copyout(ptr, ur->ucr_data, len);
+				if (error) {
+					goto ret001;
+				}
 			}
+		}
+	ret001:
+		if (ptr) {
+			free(ptr, M_TEMP);
+		}
+		usbd_unref_device(udev);
+		goto done;
+	}
 
-			if (bus->devices[addr] == 0)
-			{
-				error = ENXIO;
-				goto done;
-			}
+	case USB_DEVICEINFO:
+	{
+		struct usb_device_info *di = (void *)addr;
 
-			error = usbd_fill_deviceinfo(bus->devices[addr], di, 1);
-			goto done;
+		udev = usbd_ref_device(bus, di->udi_addr);
+		if (udev == NULL) {
+		    error = ENXIO;
+		    goto done;
 		}
 
-		case USB_DEVICESTATS:
-			*(struct usb_device_stats *)data = bus->stats;
-			break;
+		error = usbd_fill_deviceinfo(udev, di, 1);
 
-		default:
-			error = EINVAL;
-			break;
-		}
+		usbd_unref_device(udev);
+		goto done;
 	}
 
- done:
-	mtx_unlock(&usb_global_lock);
-	return (error);
-}
+	case USB_DEVICESTATS:
+		*(struct usb_device_stats *)addr = bus->stats;
+		break;
 
-static int
-usbpoll(struct cdev *dev, int events, struct thread *td)
-{
-	int revents, mask;
-	int unit = DEV2UNIT(dev);
+	case USB_DEVICEENUMERATE:
+	{
+		struct usb_device_enumerate *ude = (void *)addr;
+		struct usbd_port *pp;
+		usb_port_status_t ps;
+		uint8_t old_addr;
+		uint8_t buf[8];
 
-	if(unit == USB_DEV_MINOR)
-	{
-		revents = 0;
-		mask = POLLIN | POLLRDNORM;
+		udev = usbd_ref_device(bus, ude->ude_addr);
+		if (udev == NULL) {
+		    error = ENXIO;
+		    goto done;
+		}
 
-		mtx_lock(&usb_global_lock);
+		old_addr = udev->address;
+		pp = udev->powersrc;
+		if (pp == NULL) {
+		    error = EINVAL;
+		    goto ret002;
+		}
 
-		if((events & mask) && (usb_nevents > 0))
-		{
-			revents |= events & mask;
+		error = usbreq_reset_port(pp->parent, pp->portno, &ps);
+		if (error) {
+		    error = ENXIO;
+		    goto ret002;
 		}
-		if((revents == 0) && (events & mask))
-		{
-			selrecord(td, &usb_selevent);
+
+		/* After that the port has been reset
+		 * our device should be at address
+		 * zero:
+		 */
+		udev->address = 0;
+
+		/* It should be allowed to read some descriptors
+		 * from address zero:
+		 */
+		error = usbreq_get_desc(udev, UDESC_DEVICE, 0, 8, buf, 0);
+		if (error) {

>>> TRUNCATED FOR MAIL (1000 lines) <<<



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200706040717.l547HKfK044801>