Diff for /src/sys/bus/usb/usb.c between versions 1.8 and 1.9

version 1.8, 2003/08/07 21:16:47 version 1.9, 2003/12/30 01:01:44
Line 1 Line 1
/*        $NetBSD: usb.c,v 1.33 1999/11/22 21:57:09 augustss Exp $ *//*
/*        $FreeBSD: src/sys/dev/usb/usb.c,v 1.26.2.9 2002/11/13 15:15:22 joe Exp $      */ * $NetBSD: usb.c,v 1.68 2002/02/20 20:30:12 christos Exp $
/*        $DragonFly$     */ * $FreeBSD: src/sys/dev/usb/usb.c,v 1.95 2003/11/09 23:54:21 joe Exp $
  * $DragonFly$
  */
 
 /* Also already merged from NetBSD:
  *      $NetBSD: usb.c,v 1.70 2002/05/09 21:54:32 augustss Exp $
  *      $NetBSD: usb.c,v 1.71 2002/06/01 23:51:04 lukem Exp $
  *      $NetBSD: usb.c,v 1.73 2002/09/23 05:51:19 simonb Exp $
  */
   
 /*  /*
  * Copyright (c) 1998 The NetBSD Foundation, Inc.   * Copyright (c) 1998 The NetBSD Foundation, Inc.
Line 48 Line 56
 #include <sys/param.h>  #include <sys/param.h>
 #include <sys/systm.h>  #include <sys/systm.h>
 #include <sys/kernel.h>  #include <sys/kernel.h>
   #include <sys/lock.h>
 #include <sys/malloc.h>  #include <sys/malloc.h>
   #if __FreeBSD_version >= 500000
   #include <sys/mutex.h>
   #endif
 #if defined(__NetBSD__) || defined(__OpenBSD__)  #if defined(__NetBSD__) || defined(__OpenBSD__)
 #include <sys/device.h>  #include <sys/device.h>
 #include <sys/kthread.h>  
 #include <sys/proc.h>  
 #elif defined(__FreeBSD__)  #elif defined(__FreeBSD__)
   #include <sys/unistd.h>
 #include <sys/module.h>  #include <sys/module.h>
 #include <sys/bus.h>  #include <sys/bus.h>
 #include <sys/filio.h>  #include <sys/filio.h>
 #include <sys/uio.h>  #include <sys/uio.h>
 #endif  #endif
   #include <sys/kthread.h>
   #include <sys/proc.h>
 #include <sys/conf.h>  #include <sys/conf.h>
 #include <sys/poll.h>  #include <sys/poll.h>
   #if __FreeBSD_version >= 500014
   #include <sys/selinfo.h>
   #else
 #include <sys/select.h>  #include <sys/select.h>
   #endif
 #include <sys/vnode.h>  #include <sys/vnode.h>
 #include <sys/signalvar.h>  #include <sys/signalvar.h>
 #include <sys/sysctl.h>  #include <sys/sysctl.h>
Line 97  SYSCTL_NODE(_hw, OID_AUTO, usb, CTLFLAG_ Line 114  SYSCTL_NODE(_hw, OID_AUTO, usb, CTLFLAG_
 int     usbdebug = 0;  int     usbdebug = 0;
 SYSCTL_INT(_hw_usb, OID_AUTO, debug, CTLFLAG_RW,  SYSCTL_INT(_hw_usb, OID_AUTO, debug, CTLFLAG_RW,
            &usbdebug, 0, "usb debug level");             &usbdebug, 0, "usb debug level");
#ifdef USB_DEBUG/*
extern int uhcidebug; 
#endif 
#ifdef USB_DEBUG 
extern int ohcidebug; 
#endif 
/*  
  * 0  - do usual exploration   * 0  - do usual exploration
  * 1  - do not use timeout exploration   * 1  - do not use timeout exploration
  * >1 - do no exploration   * >1 - do no exploration
Line 119  struct usb_softc { Line 130  struct usb_softc {
         usbd_bus_handle sc_bus;         /* USB controller */          usbd_bus_handle sc_bus;         /* USB controller */
         struct usbd_port sc_port;       /* dummy port for root hub */          struct usbd_port sc_port;       /* dummy port for root hub */
   
#if defined(__FreeBSD__)        struct thread        *sc_event_thread;
        /* This part should be deleted when kthreads is available */ 
        struct selinfo sc_consel;      /* waiting for connect change */ 
#else 
        struct proc    *sc_event_thread; 
#endif 
   
         char            sc_dying;          char            sc_dying;
 };  };
   
   TAILQ_HEAD(, usb_task) usb_all_tasks;
   
 #if defined(__NetBSD__) || defined(__OpenBSD__)  #if defined(__NetBSD__) || defined(__OpenBSD__)
 cdev_decl(usb);  cdev_decl(usb);
 #elif defined(__FreeBSD__)  #elif defined(__FreeBSD__)
d_open_t  usbopen; d_open_t  usbopen;
 d_close_t usbclose;  d_close_t usbclose;
 d_read_t usbread;  d_read_t usbread;
 d_ioctl_t usbioctl;  d_ioctl_t usbioctl;
Line 158  struct cdevsw usb_cdevsw = { Line 166  struct cdevsw usb_cdevsw = {
 };  };
 #endif  #endif
   
Static usbd_status usb_discover(struct usb_softc *);Static void        usb_discover(void *);
#if defined(__NetBSD__) || defined(__OpenBSD__) 
 Static void     usb_create_event_thread(void *);  Static void     usb_create_event_thread(void *);
 Static void     usb_event_thread(void *);  Static void     usb_event_thread(void *);
#endifStatic void     usb_task_thread(void *);
 Static usb_proc_ptr     usb_task_thread_proc = NULL;
   
#define USB_MAX_EVENTS 50#define USB_MAX_EVENTS 100
 struct usb_event_q {  struct usb_event_q {
         struct usb_event ue;          struct usb_event ue;
        SIMPLEQ_ENTRY(usb_event_q) next;        TAILQ_ENTRY(usb_event_q) next;
 };  };
Static SIMPLEQ_HEAD(, usb_event_q) usb_events =Static TAILQ_HEAD(, usb_event_q) usb_events =
        SIMPLEQ_HEAD_INITIALIZER(usb_events);        TAILQ_HEAD_INITIALIZER(usb_events);
 Static int usb_nevents = 0;  Static int usb_nevents = 0;
 Static struct selinfo usb_selevent;  Static struct selinfo usb_selevent;
Static struct thread *usb_async_proc;  /* process who wants USB SIGIO */Static struct proc *usb_async_proc;  /* process that wants USB SIGIO */
 Static int usb_dev_open = 0;  Static int usb_dev_open = 0;
   Static void usb_add_event(int, struct usb_event *);
   
 Static int usb_get_next_event(struct usb_event *);  Static int usb_get_next_event(struct usb_event *);
   
Line 191  USB_DECLARE_DRIVER_INIT(usb, Line 200  USB_DECLARE_DRIVER_INIT(usb,
                         DEVMETHOD(device_shutdown, bus_generic_shutdown)                          DEVMETHOD(device_shutdown, bus_generic_shutdown)
                         );                          );
   
   #if defined(__FreeBSD__)
   MODULE_VERSION(usb, 1);
   #endif
   
 USB_MATCH(usb)  USB_MATCH(usb)
 {  {
         DPRINTF(("usbd_match\n"));          DPRINTF(("usbd_match\n"));
Line 209  USB_ATTACH(usb) Line 222  USB_ATTACH(usb)
         usbd_device_handle dev;          usbd_device_handle dev;
         usbd_status err;          usbd_status err;
         int usbrev;          int usbrev;
           int speed;
           struct usb_event ue;
   
         sc->sc_dev = self;          sc->sc_dev = self;
   
Line 224  USB_ATTACH(usb) Line 239  USB_ATTACH(usb)
 #endif  #endif
         usbrev = sc->sc_bus->usbrev;          usbrev = sc->sc_bus->usbrev;
         printf(": USB revision %s", usbrev_str[usbrev]);          printf(": USB revision %s", usbrev_str[usbrev]);
        if (usbrev != USBREV_1_0 && usbrev != USBREV_1_1) {        switch (usbrev) {
         case USBREV_1_0:
         case USBREV_1_1:
                 speed = USB_SPEED_FULL;
                 break;
         case USBREV_2_0:
                 speed = USB_SPEED_HIGH;
                 break;
         default:
                 printf(", not supported\n");                  printf(", not supported\n");
                   sc->sc_dying = 1;
                 USB_ATTACH_ERROR_RETURN;                  USB_ATTACH_ERROR_RETURN;
         }          }
         printf("\n");          printf("\n");
   
        err = usbd_new_device(USBDEV(sc->sc_dev), sc->sc_bus, 0, 0, 0,        /* Make sure not to use tsleep() if we are cold booting. */
         if (cold)
                 sc->sc_bus->use_polling++;
 
         ue.u.ue_ctrlr.ue_bus = USBDEVUNIT(sc->sc_dev);
         usb_add_event(USB_EVENT_CTRLR_ATTACH, &ue);
 
 #ifdef USB_USE_SOFTINTR
 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
         /* XXX we should have our own level */
         sc->sc_bus->soft = softintr_establish(IPL_SOFTNET,
             sc->sc_bus->methods->soft_intr, sc->sc_bus);
         if (sc->sc_bus->soft == NULL) {
                 printf("%s: can't register softintr\n", USBDEVNAME(sc->sc_dev));
                 sc->sc_dying = 1;
                 USB_ATTACH_ERROR_RETURN;
         }
 #else
         usb_callout_init(sc->sc_bus->softi);
 #endif
 #endif
 
         err = usbd_new_device(USBDEV(sc->sc_dev), sc->sc_bus, 0, speed, 0,
                   &sc->sc_port);                    &sc->sc_port);
         if (!err) {          if (!err) {
                 dev = sc->sc_port.device;                  dev = sc->sc_port.device;
                 if (dev->hub == NULL) {                  if (dev->hub == NULL) {
                         sc->sc_dying = 1;                          sc->sc_dying = 1;
                        printf("%s: root device is not a hub\n",                         printf("%s: root device is not a hub\n",
                                USBDEVNAME(sc->sc_dev));                                 USBDEVNAME(sc->sc_dev));
                         USB_ATTACH_ERROR_RETURN;                          USB_ATTACH_ERROR_RETURN;
                 }                  }
                 sc->sc_bus->root_hub = dev;                  sc->sc_bus->root_hub = dev;
 #if 1  #if 1
                /*                 /*
                  * Turning this code off will delay attachment of USB devices                   * Turning this code off will delay attachment of USB devices
                  * until the USB event thread is running, which means that                   * until the USB event thread is running, which means that
                  * the keyboard will not work until after cold boot.                   * the keyboard will not work until after cold boot.
                  */                   */
                if (cold) {#if defined(__FreeBSD__)
                        sc->sc_bus->use_polling++;                if (cold)
 #else
                 if (cold && (sc->sc_dev.dv_cfdata->cf_flags & 1))
 #endif
                         dev->hub->explore(sc->sc_bus->root_hub);                          dev->hub->explore(sc->sc_bus->root_hub);
                         sc->sc_bus->use_polling--;  
                 }  
 #endif  #endif
         } else {          } else {
                printf("%s: root hub problem, error=%d\n",                 printf("%s: root hub problem, error=%d\n",
                       USBDEVNAME(sc->sc_dev), err);                        USBDEVNAME(sc->sc_dev), err);
                 sc->sc_dying = 1;                  sc->sc_dying = 1;
         }          }
           if (cold)
                   sc->sc_bus->use_polling--;
   
        kthread_create(usb_create_event_thread, sc);        config_pending_incr();
 #if defined(__NetBSD__) || defined(__OpenBSD__)
         usb_kthread_create(usb_create_event_thread, sc);
 #endif
   
 #if defined(__FreeBSD__)  #if defined(__FreeBSD__)
           usb_create_event_thread(sc);
         /* The per controller devices (used for usb_discover) */          /* The per controller devices (used for usb_discover) */
           /* XXX This is redundant now, but old usbd's will want it */
         make_dev(&usb_cdevsw, device_get_unit(self), UID_ROOT, GID_OPERATOR,          make_dev(&usb_cdevsw, device_get_unit(self), UID_ROOT, GID_OPERATOR,
                0644, "usb%d", device_get_unit(self));                0660, "usb%d", device_get_unit(self));
         if (!global_init_done) {          if (!global_init_done) {
                 /* The device spitting out events */                  /* The device spitting out events */
                 make_dev(&usb_cdevsw, USB_DEV_MINOR, UID_ROOT, GID_OPERATOR,                  make_dev(&usb_cdevsw, USB_DEV_MINOR, UID_ROOT, GID_OPERATOR,
                        0644, "usb");                        0660, "usb");
                 global_init_done = 1;                  global_init_done = 1;
         }          }
 #endif  #endif
Line 276  USB_ATTACH(usb) Line 330  USB_ATTACH(usb)
         USB_ATTACH_SUCCESS_RETURN;          USB_ATTACH_SUCCESS_RETURN;
 }  }
   
 #if defined(__NetBSD__) || defined(__OpenBSD__)  
 void  void
 usb_create_event_thread(void *arg)  usb_create_event_thread(void *arg)
 {  {
         struct usb_softc *sc = arg;          struct usb_softc *sc = arg;
           static int created = 0;
   
        if (kthread_create1(usb_event_thread, sc, &sc->sc_event_thread,        if (usb_kthread_create1(usb_event_thread, sc, &sc->sc_event_thread,
                           "%s", sc->sc_dev.dv_xname)) {                           "%s", USBDEVNAME(sc->sc_dev))) {
                 printf("%s: unable to create event thread for\n",                  printf("%s: unable to create event thread for\n",
                       sc->sc_dev.dv_xname);                       USBDEVNAME(sc->sc_dev));
                 panic("usb_create_event_thread");                  panic("usb_create_event_thread");
         }          }
           if (!created) {
                   created = 1;
                   TAILQ_INIT(&usb_all_tasks);
                   if (usb_kthread_create2(usb_task_thread, NULL,
                                           &usb_task_thread_proc, "usbtask")) {
                           printf("unable to create task thread\n");
                           panic("usb_create_event_thread task");
                   }
           }
   }
   
   /*
    * Add a task to be performed by the task thread.  This function can be
    * called from any context and the task will be executed in a process
    * context ASAP.
    */
   void
   usb_add_task(usbd_device_handle dev, struct usb_task *task)
   {
           int s;
   
           s = splusb();
           if (!task->onqueue) {
                   DPRINTFN(2,("usb_add_task: task=%p\n", task));
                   TAILQ_INSERT_TAIL(&usb_all_tasks, task, next);
                   task->onqueue = 1;
           } else {
                   DPRINTFN(3,("usb_add_task: task=%p on q\n", task));
           }
           wakeup(&usb_all_tasks);
           splx(s);
   }
   
   void
   usb_rem_task(usbd_device_handle dev, struct usb_task *task)
   {
           int s;
   
           s = splusb();
           if (task->onqueue) {
                   TAILQ_REMOVE(&usb_all_tasks, task, next);
                   task->onqueue = 0;
           }
           splx(s);
 }  }
   
 void  void
Line 297  usb_event_thread(void *arg) Line 395  usb_event_thread(void *arg)
   
         DPRINTF(("usb_event_thread: start\n"));          DPRINTF(("usb_event_thread: start\n"));
   
           /*
            * In case this controller is a companion controller to an
            * EHCI controller we need to wait until the EHCI controller
            * has grabbed the port.
            * XXX It would be nicer to do this with a tsleep(), but I don't
            * know how to synchronize the creation of the threads so it
            * will work.
            */
           usb_delay_ms(sc->sc_bus, 500);
   
           /* Make sure first discover does something. */
           sc->sc_bus->needs_explore = 1;
           usb_discover(sc);
           config_pending_decr();
   
         while (!sc->sc_dying) {          while (!sc->sc_dying) {
 #ifdef USB_DEBUG  #ifdef USB_DEBUG
                 if (usb_noexplore < 2)                  if (usb_noexplore < 2)
 #endif  #endif
                 usb_discover(sc);                  usb_discover(sc);
                 (void)tsleep(&sc->sc_bus->needs_explore, 0, "usbevt",  
 #ifdef USB_DEBUG  #ifdef USB_DEBUG
                             usb_noexplore ? 0 :                (void)tsleep(&sc->sc_bus->needs_explore, 0, "usbevt",
                         usb_noexplore ? 0 : hz * 60);
 #else
                 (void)tsleep(&sc->sc_bus->needs_explore, 0, "usbevt",
                         hz * 60);
 #endif  #endif
                              hz*60  
                        );  
                 DPRINTFN(2,("usb_event_thread: woke up\n"));                  DPRINTFN(2,("usb_event_thread: woke up\n"));
         }          }
        sc->sc_event_thread = 0;        sc->sc_event_thread = NULL;
   
         /* In case parent is waiting for us to exit. */          /* In case parent is waiting for us to exit. */
         wakeup(sc);          wakeup(sc);
Line 319  usb_event_thread(void *arg) Line 433  usb_event_thread(void *arg)
         kthread_exit();          kthread_exit();
 }  }
   
   void
   usb_task_thread(void *arg)
   {
           struct usb_task *task;
           int s;
   
   #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
           mtx_lock(&Giant);
   #endif
   
           DPRINTF(("usb_task_thread: start\n"));
   
           s = splusb();
           for (;;) {
                   task = TAILQ_FIRST(&usb_all_tasks);
                   if (task == NULL) {
                           tsleep(&usb_all_tasks, 0, "usbtsk", 0);
                           task = TAILQ_FIRST(&usb_all_tasks);
                   }
                   DPRINTFN(2,("usb_task_thread: woke up task=%p\n", task));
                   if (task != NULL) {
                           TAILQ_REMOVE(&usb_all_tasks, task, next);
                           task->onqueue = 0;
                           splx(s);
                           task->fun(task->arg);
                           s = splusb();
                   }
           }
   }
   
   #if defined(__NetBSD__) || defined(__OpenBSD__)
 int  int
 usbctlprint(void *aux, const char *pnp)  usbctlprint(void *aux, const char *pnp)
 {  {
Line 342  usbopen(dev_t dev, int flag, int mode, u Line 487  usbopen(dev_t dev, int flag, int mode, u
                 usb_dev_open = 1;                  usb_dev_open = 1;
                 usb_async_proc = NULL;                  usb_async_proc = NULL;
                 return (0);                  return (0);
        } else {        }
                USB_GET_SC_OPEN(usb, unit, sc); 
   
                if (sc->sc_dying)        USB_GET_SC_OPEN(usb, unit, sc);
                        return (EIO); 
   
                return (0);        if (sc->sc_dying)
        }                return (EIO);
 
         return (0);
 }  }
   
 int  int
Line 410  usbioctl(dev_t devt, u_long cmd, caddr_t Line 555  usbioctl(dev_t devt, u_long cmd, caddr_t
                 case FIONBIO:                  case FIONBIO:
                         /* All handled in the upper FS layer. */                          /* All handled in the upper FS layer. */
                         return (0);                          return (0);
                        
                 case FIOASYNC:                  case FIOASYNC:
                         if (*(int *)data)                          if (*(int *)data)
   #if defined(__DragonFly__)
                                   usb_async_proc = p->td_proc;
   #elif __FreeBSD_version >= 500000
                                   usb_async_proc = p->td_proc;
   #else
                                 usb_async_proc = p;                                  usb_async_proc = p;
   #endif
                         else                          else
                                 usb_async_proc = NULL;                                  usb_async_proc = NULL;
                         return (0);                          return (0);
Line 429  usbioctl(dev_t devt, u_long cmd, caddr_t Line 580  usbioctl(dev_t devt, u_long cmd, caddr_t
                 return (EIO);                  return (EIO);
   
         switch (cmd) {          switch (cmd) {
#if defined(__FreeBSD__) #if defined(__FreeBSD__)
        /* This part should be deleted when kthreads is available */        /* This part should be deleted */
         case USB_DISCOVER:          case USB_DISCOVER:
                 usb_discover(sc);  
                 break;                  break;
 #endif  #endif
 #ifdef USB_DEBUG  
         case USB_SETDEBUG:  
                 usbdebug  = ((*(int *)data) & 0x000000ff);  
                 uhcidebug = ((*(int *)data) & 0x0000ff00) >> 8;  
                 ohcidebug = ((*(int *)data) & 0x00ff0000) >> 16;  
                 break;  
 #endif  
         case USB_REQUEST:          case USB_REQUEST:
         {          {
                 struct usb_ctl_request *ur = (void *)data;                  struct usb_ctl_request *ur = (void *)data;
Line 456  usbioctl(dev_t devt, u_long cmd, caddr_t Line 599  usbioctl(dev_t devt, u_long cmd, caddr_t
                 DPRINTF(("usbioctl: USB_REQUEST addr=%d len=%d\n", addr, len));                  DPRINTF(("usbioctl: USB_REQUEST addr=%d len=%d\n", addr, len));
                 if (len < 0 || len > 32768)                  if (len < 0 || len > 32768)
                         return (EINVAL);                          return (EINVAL);
                if (addr < 0 || addr >= USB_MAX_DEVICES ||                 if (addr < 0 || addr >= USB_MAX_DEVICES ||
                     sc->sc_bus->devices[addr] == 0)                      sc->sc_bus->devices[addr] == 0)
                         return (EINVAL);                          return (EINVAL);
                 if (len != 0) {                  if (len != 0) {
Line 468  usbioctl(dev_t devt, u_long cmd, caddr_t Line 611  usbioctl(dev_t devt, u_long cmd, caddr_t
                         uio.uio_offset = 0;                          uio.uio_offset = 0;
                         uio.uio_segflg = UIO_USERSPACE;                          uio.uio_segflg = UIO_USERSPACE;
                         uio.uio_rw =                          uio.uio_rw =
                                ur->ucr_request.bmRequestType & UT_READ ?                                 ur->ucr_request.bmRequestType & UT_READ ?
                                 UIO_READ : UIO_WRITE;                                  UIO_READ : UIO_WRITE;
                         uio.uio_td = p;                          uio.uio_td = p;
                         ptr = malloc(len, M_TEMP, M_WAITOK);                          ptr = malloc(len, M_TEMP, M_WAITOK);
Line 479  usbioctl(dev_t devt, u_long cmd, caddr_t Line 622  usbioctl(dev_t devt, u_long cmd, caddr_t
                         }                          }
                 }                  }
                 err = usbd_do_request_flags(sc->sc_bus->devices[addr],                  err = usbd_do_request_flags(sc->sc_bus->devices[addr],
                          &ur->ucr_request, ptr, ur->ucr_flags, &ur->ucr_actlen);                          &ur->ucr_request, ptr, ur->ucr_flags, &ur->ucr_actlen,
                           USBD_DEFAULT_TIMEOUT);
                 if (err) {                  if (err) {
                         error = EIO;                          error = EIO;
                         goto ret;                          goto ret;
Line 506  usbioctl(dev_t devt, u_long cmd, caddr_t Line 650  usbioctl(dev_t devt, u_long cmd, caddr_t
                 if (addr < 1 || addr >= USB_MAX_DEVICES)                  if (addr < 1 || addr >= USB_MAX_DEVICES)
                         return (EINVAL);                          return (EINVAL);
                 dev = sc->sc_bus->devices[addr];                  dev = sc->sc_bus->devices[addr];
                if (dev == 0)                if (dev == NULL)
                         return (ENXIO);                          return (ENXIO);
                usbd_fill_deviceinfo(dev, di);                usbd_fill_deviceinfo(dev, di, 1);
                 break;                  break;
         }          }
   
Line 533  usbpoll(dev_t dev, int events, usb_proc_ Line 677  usbpoll(dev_t dev, int events, usb_proc_
                 mask = POLLIN | POLLRDNORM;                  mask = POLLIN | POLLRDNORM;
   
                 s = splusb();                  s = splusb();
                if ((events & mask) && usb_nevents > 0)                if (events & mask && usb_nevents > 0)
                         revents |= events & mask;                          revents |= events & mask;
                if (revents == 0 && (events & mask)) {                if (revents == 0 && events & mask)
                        DPRINTFN(2,("usb: sleeping on %p\n", &usb_selevent)); 
                         selrecord(p, &usb_selevent);                          selrecord(p, &usb_selevent);
                 }  
                 splx(s);                  splx(s);
   
                 return (revents);                  return (revents);
         } else {          } else {
 #if defined(__FreeBSD__)  #if defined(__FreeBSD__)
                /* This part should be deleted when kthreads is available */                return (0);     /* select/poll never wakes up - back compat */
                struct usb_softc *sc; 
 
                USB_GET_SC(usb, unit, sc); 
 
                revents = 0; 
                mask = POLLOUT | POLLRDNORM; 
 
                s = splusb(); 
                if ((events & mask) && sc->sc_bus->needs_explore) 
                        revents |= events & mask; 
                if (revents == 0 && (events & mask)) 
                        selrecord(p, &sc->sc_consel); 
                splx(s); 
 
                return (revents); 
 #else  #else
                 return (ENXIO);                  return (ENXIO);
 #endif  #endif
Line 567  usbpoll(dev_t dev, int events, usb_proc_ Line 694  usbpoll(dev_t dev, int events, usb_proc_
 }  }
   
 /* Explore device tree from the root. */  /* Explore device tree from the root. */
usbd_statusStatic void
usb_discover(struct usb_softc *sc)usb_discover(void *v)
 {  {
           struct usb_softc *sc = v;
   
 #if defined(__FreeBSD__)  #if defined(__FreeBSD__)
        /* The splxxx parts should be deleted when kthreads is available */        /* splxxx should be changed to mutexes for preemption safety some day */
         int s;          int s;
 #endif  #endif
   
        /*         DPRINTFN(2,("usb_discover\n"));
 #ifdef USB_DEBUG
         if (usb_noexplore > 1)
                 return;
 #endif
 
         /*
          * We need mutual exclusion while traversing the device tree,           * We need mutual exclusion while traversing the device tree,
          * but this is guaranteed since this function is only called           * but this is guaranteed since this function is only called
          * from the event thread for the controller.           * from the event thread for the controller.
Line 596  usb_discover(struct usb_softc *sc) Line 731  usb_discover(struct usb_softc *sc)
 #if defined(__FreeBSD__)  #if defined(__FreeBSD__)
         splx(s);          splx(s);
 #endif  #endif
   
         return (USBD_NORMAL_COMPLETION);  
 }  }
   
 void  void
usb_needs_explore(usbd_bus_handle bus)usb_needs_explore(usbd_device_handle dev)
 {  {
        bus->needs_explore = 1;        DPRINTFN(2,("usb_needs_explore\n"));
#if defined(__FreeBSD__)        dev->bus->needs_explore = 1;
        /* This part should be deleted when kthreads is available */        wakeup(&dev->bus->needs_explore);
        selwakeup(&bus->usbctl->sc_consel); 
#endif 
        wakeup(&bus->needs_explore); 
 }  }
   
 /* Called at splusb() */  /* Called at splusb() */
Line 619  usb_get_next_event(struct usb_event *ue) Line 749  usb_get_next_event(struct usb_event *ue)
   
         if (usb_nevents <= 0)          if (usb_nevents <= 0)
                 return (0);                  return (0);
        ueq = SIMPLEQ_FIRST(&usb_events);        ueq = TAILQ_FIRST(&usb_events);
 #ifdef DIAGNOSTIC
         if (ueq == NULL) {
                 printf("usb: usb_nevents got out of sync! %d\n", usb_nevents);
                 usb_nevents = 0;
                 return (0);
         }
 #endif
         *ue = ueq->ue;          *ue = ueq->ue;
        SIMPLEQ_REMOVE_HEAD(&usb_events, ueq, next);        TAILQ_REMOVE(&usb_events, ueq, next);
         free(ueq, M_USBDEV);          free(ueq, M_USBDEV);
         usb_nevents--;          usb_nevents--;
         return (1);          return (1);
 }  }
   
 void  void
usbd_add_event(int type, usbd_device_handle dev)usbd_add_dev_event(int type, usbd_device_handle udev)
 {
         struct usb_event ue;
 
         usbd_fill_deviceinfo(udev, &ue.u.ue_device, USB_EVENT_IS_ATTACH(type));
         usb_add_event(type, &ue);
 }
 
 void
 usbd_add_drv_event(int type, usbd_device_handle udev, device_ptr_t dev)
 {
         struct usb_event ue;
 
         ue.u.ue_driver.ue_cookie = udev->cookie;
         strncpy(ue.u.ue_driver.ue_devname, USBDEVPTRNAME(dev),
                 sizeof ue.u.ue_driver.ue_devname);
         usb_add_event(type, &ue);
 }
 
 void
 usb_add_event(int type, struct usb_event *uep)
 {  {
         struct usb_event_q *ueq;          struct usb_event_q *ueq;
         struct usb_event ue;          struct usb_event ue;
         struct timeval thetime;          struct timeval thetime;
         int s;          int s;
   
           ueq = malloc(sizeof *ueq, M_USBDEV, M_WAITOK);
           ueq->ue = *uep;
           ueq->ue.ue_type = type;
           microtime(&thetime);
           TIMEVAL_TO_TIMESPEC(&thetime, &ueq->ue.ue_time);
   
         s = splusb();          s = splusb();
        if (++usb_nevents >= USB_MAX_EVENTS) {        if (USB_EVENT_IS_DETACH(type)) {
                 struct usb_event_q *ueqi, *ueqi_next;
 
                 for (ueqi = TAILQ_FIRST(&usb_events); ueqi; ueqi = ueqi_next) {
                         ueqi_next = TAILQ_NEXT(ueqi, next);
                         if (ueqi->ue.u.ue_driver.ue_cookie.cookie ==
                             uep->u.ue_device.udi_cookie.cookie) {
                                 TAILQ_REMOVE(&usb_events, ueqi, next);
                                 free(ueqi, M_USBDEV);
                                 usb_nevents--;
                                 ueqi_next = TAILQ_FIRST(&usb_events);
                         }
                 }
         }
         if (usb_nevents >= USB_MAX_EVENTS) {
                 /* Too many queued events, drop an old one. */                  /* Too many queued events, drop an old one. */
                 DPRINTF(("usb: event dropped\n"));                  DPRINTF(("usb: event dropped\n"));
                 (void)usb_get_next_event(&ue);                  (void)usb_get_next_event(&ue);
         }          }
        /* Don't want to wait here inside splusb() */        TAILQ_INSERT_TAIL(&usb_events, ueq, next);
        ueq = malloc(sizeof *ueq, M_USBDEV, M_NOWAIT);        usb_nevents++;
        if (ueq == NULL) { 
                printf("usb: no memory, event dropped\n"); 
                splx(s); 
                return; 
        } 
        ueq->ue.ue_type = type; 
        ueq->ue.u.ue_driver.ue_cookie = dev->cookie; 
        usbd_fill_deviceinfo(dev, &ueq->ue.u.ue_device); 
        microtime(&thetime); 
        TIMEVAL_TO_TIMESPEC(&thetime, &ueq->ue.ue_time); 
        SIMPLEQ_INSERT_TAIL(&usb_events, ueq, next); 
         wakeup(&usb_events);          wakeup(&usb_events);
        selwakeup(&usb_selevent);        selwakeuppri(&usb_selevent, PZERO);
        if (usb_async_proc != NULL && usb_async_proc->td_proc)        if (usb_async_proc != NULL) {
                psignal(usb_async_proc->td_proc, SIGIO);                PROC_LOCK(usb_async_proc);
                 psignal(usb_async_proc, SIGIO);
                 PROC_UNLOCK(usb_async_proc);
         }
         splx(s);          splx(s);
 }  }
   
   void
   usb_schedsoftintr(usbd_bus_handle bus)
   {
           DPRINTFN(10,("usb_schedsoftintr: polling=%d\n", bus->use_polling));
   #ifdef USB_USE_SOFTINTR
           if (bus->use_polling) {
                   bus->methods->soft_intr(bus);
           } else {
   #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
                   softintr_schedule(bus->soft);
   #else
                   if (!callout_pending(&bus->softi))
                           callout_reset(&bus->softi, 0, bus->methods->soft_intr,
                               bus);
   #endif /* __HAVE_GENERIC_SOFT_INTERRUPTS */
           }
   #else
           bus->methods->soft_intr(bus);
   #endif /* USB_USE_SOFTINTR */
   }
   
   
 #if defined(__NetBSD__) || defined(__OpenBSD__)  #if defined(__NetBSD__) || defined(__OpenBSD__)
 int  int
usb_activate(device_ptr_t self, devact act)usb_activate(device_ptr_t self, enum devact act)
 {  {
         struct usb_softc *sc = (struct usb_softc *)self;          struct usb_softc *sc = (struct usb_softc *)self;
         usbd_device_handle dev = sc->sc_port.device;          usbd_device_handle dev = sc->sc_port.device;
Line 672  usb_activate(device_ptr_t self, devact a Line 863  usb_activate(device_ptr_t self, devact a
         switch (act) {          switch (act) {
         case DVACT_ACTIVATE:          case DVACT_ACTIVATE:
                 return (EOPNOTSUPP);                  return (EOPNOTSUPP);
                 break;  
   
         case DVACT_DEACTIVATE:          case DVACT_DEACTIVATE:
                 sc->sc_dying = 1;                  sc->sc_dying = 1;
                if (dev && dev->cdesc && dev->subdevs) {                if (dev != NULL && dev->cdesc != NULL && dev->subdevs != NULL) {
                         for (i = 0; dev->subdevs[i]; i++)                          for (i = 0; dev->subdevs[i]; i++)
                                 rv |= config_deactivate(dev->subdevs[i]);                                  rv |= config_deactivate(dev->subdevs[i]);
                 }                  }
Line 689  int Line 879  int
 usb_detach(device_ptr_t self, int flags)  usb_detach(device_ptr_t self, int flags)
 {  {
         struct usb_softc *sc = (struct usb_softc *)self;          struct usb_softc *sc = (struct usb_softc *)self;
           struct usb_event ue;
   
         DPRINTF(("usb_detach: start\n"));          DPRINTF(("usb_detach: start\n"));
   
         sc->sc_dying = 1;          sc->sc_dying = 1;
   
         /* Make all devices disconnect. */          /* Make all devices disconnect. */
        if (sc->sc_port.device)        if (sc->sc_port.device != NULL)
                 usb_disconnect_port(&sc->sc_port, self);                  usb_disconnect_port(&sc->sc_port, self);
   
         /* Kill off event thread. */          /* Kill off event thread. */
        if (sc->sc_event_thread) {        if (sc->sc_event_thread != NULL) {
                 wakeup(&sc->sc_bus->needs_explore);                  wakeup(&sc->sc_bus->needs_explore);
                 if (tsleep(sc, 0, "usbdet", hz * 60))                  if (tsleep(sc, 0, "usbdet", hz * 60))
                         printf("%s: event thread didn't die\n",                          printf("%s: event thread didn't die\n",
Line 708  usb_detach(device_ptr_t self, int flags) Line 899  usb_detach(device_ptr_t self, int flags)
         }          }
   
         usbd_finish();          usbd_finish();
   
   #ifdef USB_USE_SOFTINTR
   #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
           if (sc->sc_bus->soft != NULL) {
                   softintr_disestablish(sc->sc_bus->soft);
                   sc->sc_bus->soft = NULL;
           }
   #else
           callout_stop(&sc->sc_bus->softi);
   #endif
   #endif
   
           ue.u.ue_ctrlr.ue_bus = USBDEVUNIT(sc->sc_dev);
           usb_add_event(USB_EVENT_CTRLR_DETACH, &ue);
   
         return (0);          return (0);
 }  }
 #elif defined(__FreeBSD__)  #elif defined(__FreeBSD__)
Line 724  usb_detach(device_t self) Line 930  usb_detach(device_t self)
 #if defined(__FreeBSD__)  #if defined(__FreeBSD__)
 DRIVER_MODULE(usb, ohci, usb_driver, usb_devclass, 0, 0);  DRIVER_MODULE(usb, ohci, usb_driver, usb_devclass, 0, 0);
 DRIVER_MODULE(usb, uhci, 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);
 #endif  #endif

Removed from v.1.8  
changed lines
  Added in v.1.9