Index: usb/ohci.c
===================================================================
RCS file: /usr/local/share/cvsroot/kame/netbsd/sys/dev/usb/ohci.c,v
retrieving revision 1.1.1.1
diff -c -r1.1.1.1 ohci.c
*** usb/ohci.c	2001/05/24 07:12:31	1.1.1.1
--- usb/ohci.c	2001/10/08 09:36:11
***************
*** 134,140 ****
  Static void		ohci_power(int, void *);
  Static usbd_status	ohci_open(usbd_pipe_handle);
  Static void		ohci_poll(struct usbd_bus *);
! Static void		ohci_softintr(struct usbd_bus *);
  Static void		ohci_waitintr(ohci_softc_t *, usbd_xfer_handle);
  Static void		ohci_add_done(ohci_softc_t *, ohci_physaddr_t);
  Static void		ohci_rhsc(ohci_softc_t *, usbd_xfer_handle);
--- 134,140 ----
  Static void		ohci_power(int, void *);
  Static usbd_status	ohci_open(usbd_pipe_handle);
  Static void		ohci_poll(struct usbd_bus *);
! Static void		ohci_softintr(void *);
  Static void		ohci_waitintr(ohci_softc_t *, usbd_xfer_handle);
  Static void		ohci_add_done(ohci_softc_t *, ohci_physaddr_t);
  Static void		ohci_rhsc(ohci_softc_t *, usbd_xfer_handle);
***************
*** 1156,1164 ****
  }
  
  void
! ohci_softintr(struct usbd_bus *bus)
  {
! 	ohci_softc_t *sc = (ohci_softc_t *)bus;
  	ohci_soft_itd_t *sitd, *sidone, *sitdnext;
  	ohci_soft_td_t  *std,  *sdone,  *stdnext;
  	usbd_xfer_handle xfer;
--- 1156,1164 ----
  }
  
  void
! ohci_softintr(void *v)
  {
! 	ohci_softc_t *sc = v;
  	ohci_soft_itd_t *sitd, *sidone, *sitdnext;
  	ohci_soft_td_t  *std,  *sdone,  *stdnext;
  	usbd_xfer_handle xfer;
Index: usb/uhci.c
===================================================================
RCS file: /usr/local/share/cvsroot/kame/netbsd/sys/dev/usb/uhci.c,v
retrieving revision 1.1.1.2
diff -c -r1.1.1.2 uhci.c
*** usb/uhci.c	2001/07/23 14:10:46	1.1.1.2
--- usb/uhci.c	2001/10/08 09:36:19
***************
*** 231,237 ****
  
  Static usbd_status	uhci_open(usbd_pipe_handle);
  Static void		uhci_poll(struct usbd_bus *);
! Static void		uhci_softintr(struct usbd_bus *);
  
  Static usbd_status	uhci_device_request(usbd_xfer_handle xfer);
  
--- 231,237 ----
  
  Static usbd_status	uhci_open(usbd_pipe_handle);
  Static void		uhci_poll(struct usbd_bus *);
! Static void		uhci_softintr(void *);
  
  Static usbd_status	uhci_device_request(usbd_xfer_handle xfer);
  
***************
*** 1088,1096 ****
  }
  
  void
! uhci_softintr(struct usbd_bus *bus)
  {
! 	uhci_softc_t *sc = (uhci_softc_t *)bus;
  	uhci_intr_info_t *ii;
  
  	DPRINTFN(10,("%s: uhci_softintr\n", USBDEVNAME(sc->sc_bus.bdev)));
--- 1088,1096 ----
  }
  
  void
! uhci_softintr(void *v)
  {
! 	uhci_softc_t *sc = v;
  	uhci_intr_info_t *ii;
  
  	DPRINTFN(10,("%s: uhci_softintr\n", USBDEVNAME(sc->sc_bus.bdev)));
Index: usb/usb.c
===================================================================
RCS file: /usr/local/share/cvsroot/kame/netbsd/sys/dev/usb/usb.c,v
retrieving revision 1.1.1.1
diff -c -r1.1.1.1 usb.c
*** usb/usb.c	2001/05/24 07:12:33	1.1.1.1
--- usb/usb.c	2001/10/08 09:36:22
***************
*** 109,114 ****
--- 109,116 ----
  	usbd_bus_handle sc_bus;		/* USB controller */
  	struct usbd_port sc_port;	/* dummy port for root hub */
  
+ 	TAILQ_HEAD(, usb_task) sc_tasks;
+ 
  #if defined(__FreeBSD__)
  	/* This part should be deleted when kthreads is available */
  	struct selinfo	sc_consel;	/* waiting for connect change */
***************
*** 116,121 ****
--- 118,125 ----
  	struct proc    *sc_event_thread;
  #endif
  
+ 	struct usb_task sc_exp_task;
+ 
  	char		sc_dying;
  };
  
***************
*** 146,152 ****
  };
  #endif
  
! Static usbd_status usb_discover(struct usb_softc *);
  Static void	usb_create_event_thread(void *);
  Static void	usb_event_thread(void *);
  
--- 150,156 ----
  };
  #endif
  
! Static void	usb_discover(void *);
  Static void	usb_create_event_thread(void *);
  Static void	usb_event_thread(void *);
  
***************
*** 204,210 ****
--- 208,217 ----
  	sc->sc_bus = aux;
  	sc->sc_bus->usbctl = sc;
  	sc->sc_port.power = USB_MAX_POWER;
+ 	TAILQ_INIT(&sc->sc_tasks);
  
+ 	usb_init_task(&sc->sc_exp_task, usb_discover, sc);
+ 
  	usbrev = sc->sc_bus->usbrev;
  	printf(": USB revision %s", usbrev_str[usbrev]);
  	if (usbrev != USBREV_1_0 && usbrev != USBREV_1_1) {
***************
*** 273,308 ****
  	}
  }
  
  void
  usb_event_thread(void *arg)
  {
  	struct usb_softc *sc = arg;
! 	int first = 1;
  
  	DPRINTF(("usb_event_thread: start\n"));
  
  	/* Make sure first discover does something. */
  	sc->sc_bus->needs_explore = 1;
  
  	while (!sc->sc_dying) {
! #ifdef USB_DEBUG
! 		if (usb_noexplore < 2)
! #endif
! 		usb_discover(sc);
! 		if (first) {
! 			config_pending_decr();
! 			first = 0;
  		}
! #ifdef USB_DEBUG
! 		(void)tsleep(&sc->sc_bus->needs_explore, PWAIT, "usbevt",
! 		    usb_noexplore ? 0 : hz * 60);
! #else
! 		(void)tsleep(&sc->sc_bus->needs_explore, PWAIT, "usbevt",
! 		    hz * 60);
! #endif
! 		DPRINTFN(2,("usb_event_thread: woke up\n"));
  	}
! 	sc->sc_event_thread = 0;
  
  	/* In case parent is waiting for us to exit. */
  	wakeup(sc);
--- 280,352 ----
  	}
  }
  
+ /*
+  * Add a task to be performed by the event 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)
+ {
+ 	struct usb_softc *sc = dev->bus->usbctl;
+ 	int s;
+ 
+ 	s = splusb();
+ 	if (!task->onqueue) {
+ 		DPRINTFN(2,("usb_add_task: sc=%p task=%p\n", sc, task));
+ 		TAILQ_INSERT_TAIL(&sc->sc_tasks, task, next);
+ 		task->onqueue = 1;
+ 	} else
+ 		DPRINTFN(3,("usb_add_task: sc=%p task=%p on q\n", sc, task));
+ 	wakeup(&sc->sc_tasks);
+ 	splx(s);
+ }
+ 
  void
+ usb_rem_task(usbd_device_handle dev, struct usb_task *task)
+ {
+ 	struct usb_softc *sc = dev->bus->usbctl;
+ 	int s;
+ 
+ 	s = splusb();
+ 	if (task->onqueue) {
+ 		TAILQ_REMOVE(&sc->sc_tasks, task, next);
+ 		task->onqueue = 0;
+ 	}
+ 	splx(s);
+ }
+ 
+ void
  usb_event_thread(void *arg)
  {
  	struct usb_softc *sc = arg;
! 	struct usb_task *task;
! 	int s;
  
  	DPRINTF(("usb_event_thread: start\n"));
  
  	/* Make sure first discover does something. */
  	sc->sc_bus->needs_explore = 1;
+ 	usb_discover(sc);
+ 	config_pending_decr();
  
  	while (!sc->sc_dying) {
! 		s = splusb();
! 		task = TAILQ_FIRST(&sc->sc_tasks);
! 		if (task == NULL) {
! 			tsleep(&sc->sc_tasks, PWAIT, "usbevt", 0);
! 			task = TAILQ_FIRST(&sc->sc_tasks);
  		}
! 		DPRINTFN(2,("usb_event_thread: woke up task=%p\n", task));
! 		if (task != NULL && !sc->sc_dying) {
! 			TAILQ_REMOVE(&sc->sc_tasks, task, next);
! 			task->onqueue = 0;
! 			splx(s);
! 			task->fun(task->arg);
! 		} else
! 			splx(s);
  	}
! 	sc->sc_event_thread = NULL;
  
  	/* In case parent is waiting for us to exit. */
  	wakeup(sc);
***************
*** 503,509 ****
  		dev = sc->sc_bus->devices[addr];
  		if (dev == NULL)
  			return (ENXIO);
! 		usbd_fill_deviceinfo(dev, di);
  		break;
  	}
  
--- 547,553 ----
  		dev = sc->sc_bus->devices[addr];
  		if (dev == NULL)
  			return (ENXIO);
! 		usbd_fill_deviceinfo(dev, di, 1);
  		break;
  	}
  
***************
*** 560,568 ****
  }
  
  /* Explore device tree from the root. */
! usbd_status
! usb_discover(struct usb_softc *sc)
  {
  #if defined(__FreeBSD__)
  	/* The splxxx parts should be deleted when kthreads is available */
  	int s;
--- 604,613 ----
  }
  
  /* Explore device tree from the root. */
! Static void
! usb_discover(void *v)
  {
+ 	struct usb_softc *sc = v;
  #if defined(__FreeBSD__)
  	/* The splxxx parts should be deleted when kthreads is available */
  	int s;
***************
*** 589,607 ****
  #if defined(__FreeBSD__)
  	splx(s);
  #endif
- 
- 	return (USBD_NORMAL_COMPLETION);
  }
  
  void
! usb_needs_explore(usbd_bus_handle bus)
  {
! 	bus->needs_explore = 1;
! #if defined(__FreeBSD__)
! 	/* This part should be deleted when kthreads is available */
! 	selwakeup(&bus->usbctl->sc_consel);
! #endif
! 	wakeup(&bus->needs_explore);
  }
  
  /* Called at splusb() */
--- 634,647 ----
  #if defined(__FreeBSD__)
  	splx(s);
  #endif
  }
  
  void
! usb_needs_explore(usbd_device_handle dev)
  {
! 	DPRINTFN(2,("usb_needs_explore\n"));
! 	dev->bus->needs_explore = 1;
! 	usb_add_task(dev, &dev->bus->usbctl->sc_exp_task);
  }
  
  /* Called at splusb() */
***************
*** 625,631 ****
  {
  	struct usb_event ue;
  
! 	usbd_fill_deviceinfo(udev, &ue.u.ue_device);
  	usb_add_event(type, &ue);
  }
  
--- 665,671 ----
  {
  	struct usb_event ue;
  
! 	usbd_fill_deviceinfo(udev, &ue.u.ue_device, USB_EVENT_IS_ATTACH(type));
  	usb_add_event(type, &ue);
  }
  
Index: usb/usb.h
===================================================================
RCS file: /usr/local/share/cvsroot/kame/netbsd/sys/dev/usb/usb.h,v
retrieving revision 1.1.1.1
diff -c -r1.1.1.1 usb.h
*** usb/usb.h	2001/05/24 07:12:33	1.1.1.1
--- usb/usb.h	2001/10/08 09:36:24
***************
*** 560,565 ****
--- 561,567 ----
  #define USB_EVENT_DEVICE_DETACH 4
  #define USB_EVENT_DRIVER_ATTACH 5
  #define USB_EVENT_DRIVER_DETACH 6
+ #define USB_EVENT_IS_ATTACH(n) ((n) == USB_EVENT_CTRLR_ATTACH || (n) == USB_EVENT_DEVICE_ATTACH || (n) == USB_EVENT_DRIVER_ATTACH)
  	struct timespec		ue_time;
  	union {
  		struct {
Index: usbdevs
===================================================================
RCS file: /usr/local/share/cvsroot/kame/netbsd/sys/dev/usb/usbdevs,v
retrieving revision 1.1.1.1
diff -c -r1.1.1.1 usbdevs
*** usbdevs     2001/05/24 07:12:34     1.1.1.1
--- usbdevs     2001/10/26 13:55:42
***************
*** 743,748 ****
--- 743,749 ----
  product MCT DU_H3SP_USB232    0x0200  D-Link DU-H3SP USB BAY Hub
  
  /* Melco, Inc products */
+ product MELCO LUATX		0x0001  LUA-TX Ethernet
  product MELCO LUATX1		0x0001  LUA-TX Ethernet
  product MELCO LUATX5		0x0005  LUA-TX Ethernet
  product MELCO LUA2TX5		0x0009  LUA2-TX Ethernet
Index: usb/usbdi.c
===================================================================
RCS file: /usr/local/share/cvsroot/kame/netbsd/sys/dev/usb/usbdi.c,v
retrieving revision 1.1.1.1
diff -c -r1.1.1.1 usbdi.c
*** usb/usbdi.c	2001/05/24 07:12:34	1.1.1.1
--- usb/usbdi.c	2001/10/08 09:36:39
***************
*** 1002,1008 ****
  	return (USBD_NORMAL_COMPLETION);
  }
  
! struct usbd_quirks *
  usbd_get_quirks(usbd_device_handle dev)
  {
  	return (dev->quirks);
--- 1002,1008 ----
  	return (USBD_NORMAL_COMPLETION);
  }
  
! const struct usbd_quirks *
  usbd_get_quirks(usbd_device_handle dev)
  {
  	return (dev->quirks);
Index: usb/usbdi.h
===================================================================
RCS file: /usr/local/share/cvsroot/kame/netbsd/sys/dev/usb/usbdi.h,v
retrieving revision 1.1.1.1
diff -c -r1.1.1.1 usbdi.h
*** usb/usbdi.h	2001/05/24 07:12:34	1.1.1.1
--- usb/usbdi.h	2001/10/08 09:36:40
***************
*** 149,155 ****
  usbd_status usbd_set_interface(usbd_interface_handle, int);
  int usbd_get_no_alts(usb_config_descriptor_t *, int);
  usbd_status  usbd_get_interface(usbd_interface_handle iface, u_int8_t *aiface);
! void usbd_fill_deviceinfo(usbd_device_handle dev, struct usb_device_info *di);
  int usbd_get_interface_altindex(usbd_interface_handle iface);
  
  usb_interface_descriptor_t *usbd_find_idesc(usb_config_descriptor_t *cd,
--- 149,155 ----
  usbd_status usbd_set_interface(usbd_interface_handle, int);
  int usbd_get_no_alts(usb_config_descriptor_t *, int);
  usbd_status  usbd_get_interface(usbd_interface_handle iface, u_int8_t *aiface);
! void usbd_fill_deviceinfo(usbd_device_handle dev, struct usb_device_info *di, int);
  int usbd_get_interface_altindex(usbd_interface_handle iface);
  
  usb_interface_descriptor_t *usbd_find_idesc(usb_config_descriptor_t *cd,
***************
*** 167,173 ****
  void usbd_add_drv_event(int, usbd_device_handle, device_ptr_t);
  
  void usbd_devinfo(usbd_device_handle, int, char *);
! struct usbd_quirks *usbd_get_quirks(usbd_device_handle);
  usb_endpoint_descriptor_t *usbd_get_endpoint_descriptor
  			(usbd_interface_handle iface, u_int8_t address);
  
--- 167,173 ----
  void usbd_add_drv_event(int, usbd_device_handle, device_ptr_t);
  
  void usbd_devinfo(usbd_device_handle, int, char *);
! const struct usbd_quirks *usbd_get_quirks(usbd_device_handle);
  usb_endpoint_descriptor_t *usbd_get_endpoint_descriptor
  			(usbd_interface_handle iface, u_int8_t address);
  
***************
*** 175,180 ****
--- 175,197 ----
  
  int usbd_ratecheck(struct timeval *last);
  
+ /*
+  * The usb_task structs form a queue of things to run in the USB event
+  * thread.  Normally this is just device discovery when a connect/disconnect
+  * has been detected.  But it may also be used by drivers that need to
+  * perform (short) tasks that must have a process context.
+  */
+ struct usb_task {
+ 	TAILQ_ENTRY(usb_task) next;
+ 	void (*fun)(void *);
+ 	void *arg;
+ 	char onqueue;
+ };
+ 
+ void usb_add_task(usbd_device_handle dev, struct usb_task *task);
+ void usb_rem_task(usbd_device_handle dev, struct usb_task *task);
+ #define usb_init_task(t, f, a) ((t)->fun = (f), (t)->arg = (a), (t)->onqueue = 0)
+ 
  /* NetBSD attachment information */
  
  /* Attach data */
***************
*** 185,190 ****
--- 202,208 ----
  	int			vendor;
  	int			product;
  	int			release;
+ 	int			matchlvl;
  	usbd_device_handle	device;	/* current device */
  	usbd_interface_handle	iface; /* current interface */
  	int			usegeneric;
Index: usb/usbdivar.h
===================================================================
RCS file: /usr/local/share/cvsroot/kame/netbsd/sys/dev/usb/usbdivar.h,v
retrieving revision 1.1.1.1
diff -c -r1.1.1.1 usbdivar.h
*** usb/usbdivar.h	2001/05/24 07:12:34	1.1.1.1
--- usb/usbdivar.h	2001/10/08 09:36:40
***************
*** 1,4 ****
! /*	$NetBSD: usbdivar.h,v 1.57.2.1 2000/06/27 19:28:19 thorpej Exp $	*/
  /*	$FreeBSD: src/sys/dev/usb/usbdivar.h,v 1.11 1999/11/17 22:33:51 n_hibma Exp $	*/
  
  /*
--- 1,4 ----
! /*	$NetBSD: usbdivar.h,v 1.62 2001/01/21 02:39:53 augustss Exp $	*/
  /*	$FreeBSD: src/sys/dev/usb/usbdivar.h,v 1.11 1999/11/17 22:33:51 n_hibma Exp $	*/
  
  /*
***************
*** 55,61 ****
  
  struct usbd_bus_methods {
  	usbd_status	      (*open_pipe)(struct usbd_pipe *pipe);
! 	void		      (*soft_intr)(struct usbd_bus *);
  	void		      (*do_poll)(struct usbd_bus *);
  	usbd_status	      (*allocm)(struct usbd_bus *, usb_dma_t *,
  					u_int32_t bufsize);
--- 55,61 ----
  
  struct usbd_bus_methods {
  	usbd_status	      (*open_pipe)(struct usbd_pipe *pipe);
! 	void		      (*soft_intr)(void *);
  	void		      (*do_poll)(struct usbd_bus *);
  	usbd_status	      (*allocm)(struct usbd_bus *, usb_dma_t *,
  					u_int32_t bufsize);
***************
*** 113,120 ****
  #define USBREV_PRE_1_0	1
  #define USBREV_1_0	2
  #define USBREV_1_1	3
! #define USBREV_STR { "unknown", "pre 1.0", "1.0", "1.1" }
  
  #if defined(__NetBSD__) || defined(__OpenBSD__)
  	bus_dma_tag_t		dmatag;	/* DMA tag */
  #endif
--- 113,129 ----
  #define USBREV_PRE_1_0	1
  #define USBREV_1_0	2
  #define USBREV_1_1	3
! #define USBREV_2_0	4
! #define USBREV_STR { "unknown", "pre 1.0", "1.0", "1.1", "2.0" }
  
+ #ifdef USB_USE_SOFTINTR
+ #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
+ 	void		       *soft; /* soft interrupt cookie */
+ #else
+ 	struct callout		softi;
+ #endif
+ #endif
+ 
  #if defined(__NetBSD__) || defined(__OpenBSD__)
  	bus_dma_tag_t		dmatag;	/* DMA tag */
  #endif
***************
*** 138,144 ****
  	struct usbd_interface  *ifaces;        /* array of all interfaces */
  	usb_device_descriptor_t ddesc;         /* device descriptor */
  	usb_config_descriptor_t *cdesc;	       /* full config descr */
! 	struct usbd_quirks     *quirks;        /* device quirks, always set */
  	struct usbd_hub	       *hub;           /* only if this is a hub */
  	device_ptr_t	       *subdevs;       /* sub-devices, 0 terminated */
  };
--- 147,153 ----
  	struct usbd_interface  *ifaces;        /* array of all interfaces */
  	usb_device_descriptor_t ddesc;         /* device descriptor */
  	usb_config_descriptor_t *cdesc;	       /* full config descr */
! 	const struct usbd_quirks     *quirks;  /* device quirks, always set */
  	struct usbd_hub	       *hub;           /* only if this is a hub */
  	device_ptr_t	       *subdevs;       /* sub-devices, 0 terminated */
  };
***************
*** 219,225 ****
  /* Routines from usb_subr.c */
  int		usbctlprint(void *, const char *);
  void		usb_delay_ms(usbd_bus_handle, u_int);
- void		usbd_devinfo_vp(usbd_device_handle, char *, char *);
  usbd_status	usbd_reset_port(usbd_device_handle dev,
  				int port, usb_port_status_t *ps);
  usbd_status	usbd_setup_pipe(usbd_device_handle dev,
--- 228,233 ----
***************
*** 240,246 ****
  void		usb_disconnect_port(struct usbd_port *up, device_ptr_t);
  
  /* Routines from usb.c */
! void		usb_needs_explore(usbd_bus_handle);
  void		usb_schedsoftintr(struct usbd_bus *);
  
  /*
--- 248,254 ----
  void		usb_disconnect_port(struct usbd_port *up, device_ptr_t);
  
  /* Routines from usb.c */
! void		usb_needs_explore(usbd_device_handle);
  void		usb_schedsoftintr(struct usbd_bus *);
  
  /*
