summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/usb/FILES47
-rw-r--r--sys/dev/usb/hid.c6
-rw-r--r--sys/dev/usb/hid.h2
-rw-r--r--sys/dev/usb/ohci.c949
-rw-r--r--sys/dev/usb/ohcireg.h8
-rw-r--r--sys/dev/usb/ohcivar.h25
-rw-r--r--sys/dev/usb/ugen.c411
-rw-r--r--sys/dev/usb/uhci.c3481
-rw-r--r--sys/dev/usb/uhcireg.h20
-rw-r--r--sys/dev/usb/uhcivar.h89
-rw-r--r--sys/dev/usb/uhid.c261
-rw-r--r--sys/dev/usb/uhub.c311
-rw-r--r--sys/dev/usb/ulpt.c270
-rw-r--r--sys/dev/usb/umass.c11
-rw-r--r--sys/dev/usb/umodem.c1
-rw-r--r--sys/dev/usb/usb.c213
-rw-r--r--sys/dev/usb/usb.h130
-rw-r--r--sys/dev/usb/usb_mem.h17
-rw-r--r--sys/dev/usb/usb_port.h207
-rw-r--r--sys/dev/usb/usb_quirks.c12
-rw-r--r--sys/dev/usb/usb_quirks.h7
-rw-r--r--sys/dev/usb/usb_subr.c601
-rw-r--r--sys/dev/usb/usbcdc.h40
-rw-r--r--sys/dev/usb/usbdevs.h45
-rw-r--r--sys/dev/usb/usbdevs_data.h122
-rw-r--r--sys/dev/usb/usbdi.c998
-rw-r--r--sys/dev/usb/usbdi.h195
-rw-r--r--sys/dev/usb/usbdi_util.c22
-rw-r--r--sys/dev/usb/usbdi_util.h6
-rw-r--r--sys/dev/usb/usbdivar.h100
-rw-r--r--sys/dev/usb/usbhid.h25
31 files changed, 4674 insertions, 3958 deletions
diff --git a/sys/dev/usb/FILES b/sys/dev/usb/FILES
new file mode 100644
index 0000000..a6884d8
--- /dev/null
+++ b/sys/dev/usb/FILES
@@ -0,0 +1,47 @@
+$FreeBSD$
+
+A small roadmap of the USB files:
+
+FILES this file
+Makefile to install .h files
+Makefile.usbdevs to run devlist2h.awk
+TODO just a list of things to do
+devlist2h.awk script to generate usbdevs*.h
+files.usb config inclued file
+hid.c subroutines to parse and access HID data
+hid.h API for hid.c
+ohci.c Host controller driver for OHCI
+ohcireg.h Hardware definitions for OHCI
+ohcivar.h API for ohci.c
+uaudio.c USB audio class driver
+uaudioreg.h and definitions for it
+ugen.c generic driver that can handle access to any USB device
+uhci.c Host controller driver for UHCI
+uhcireg.h Hardware definitions for UHCI
+uhcivar.h API for uhci.c
+uhid.c USB HID class driver
+uhub.c USB hub driver
+ukbd.c USB keyboard driver
+ukbdmap.c wscons key mapping for ukbd
+ukbdvar.h API for ukbd.c
+ulpt.c USB printer class driver
+umodem.c USB modem (CDC ACM) driver
+ums.c USB mouse driver
+usb.c usb (bus) device driver
+usb.h general USB defines
+usb_mem.c memory allocation for DMAable memory
+usb_mem.h API for usb_mem.c
+usb_port.h compatibility defines for different OSs
+usb_quirks.c table of non-conforming USB devices and their problems
+usb_quirks.h API for usb_quirks.c
+usb_subr.c various subroutines used by USB code
+usbcdc.h USB CDC class definitions
+usbdevs data base of known device
+usbdevs.h generated from usbdevs
+usbdevs_data.h generated from usbdevs
+usbdi.c implementation of the USBDI API, which all drivers use
+usbdi.h API for usbdi.c
+usbdi_util.c utilities built on top of usbdi.h
+usbdi_util.h API for usbdi_util.c
+usbdivar.h internal defines and structures for usbdi.c
+usbhid.h USB HID class definitions
diff --git a/sys/dev/usb/hid.c b/sys/dev/usb/hid.c
index bb852b7..1437d69 100644
--- a/sys/dev/usb/hid.c
+++ b/sys/dev/usb/hid.c
@@ -1,5 +1,5 @@
-/* $NetBSD: hid.c,v 1.7 1999/01/08 11:58:25 augustss Exp $ */
-/* $FreeBSD$ */
+/* $NetBSD: hid.c,v 1.8 1999/08/14 14:49:31 augustss Exp $ */
+/* $FreeBSD$ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -45,7 +45,7 @@
#if defined(__FreeBSD__)
#include <sys/bus.h>
#endif
-
+
#include <dev/usb/usb.h>
#include <dev/usb/usbhid.h>
diff --git a/sys/dev/usb/hid.h b/sys/dev/usb/hid.h
index 68ca0b4..cd3a053 100644
--- a/sys/dev/usb/hid.h
+++ b/sys/dev/usb/hid.h
@@ -1,5 +1,5 @@
/* $NetBSD: hid.h,v 1.3 1998/11/25 22:32:04 augustss Exp $ */
-/* $FreeBSD$ */
+/* $FreeBSD$ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
diff --git a/sys/dev/usb/ohci.c b/sys/dev/usb/ohci.c
index d3d5281..76c1f66 100644
--- a/sys/dev/usb/ohci.c
+++ b/sys/dev/usb/ohci.c
@@ -1,4 +1,4 @@
-/* $NetBSD: ohci.c,v 1.27 1999/01/13 10:33:53 augustss Exp $ */
+/* $NetBSD: ohci.c,v 1.43 1999/09/11 08:19:26 augustss Exp $ */
/* $FreeBSD$ */
/*
@@ -49,7 +49,7 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
-#if defined(__NetBSD__)
+#if defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/device.h>
#elif defined(__FreeBSD__)
#include <sys/module.h>
@@ -63,14 +63,15 @@
#include <machine/bus_pio.h>
#include <machine/bus_memio.h>
#endif
+
#include <machine/bus.h>
#include <machine/endian.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdivar.h>
-#include <dev/usb/usb_quirks.h>
#include <dev/usb/usb_mem.h>
+#include <dev/usb/usb_quirks.h>
#include <dev/usb/ohcireg.h>
#include <dev/usb/ohcivar.h>
@@ -91,6 +92,12 @@ int ohcidebug = 1;
#endif
+#if defined(__OpenBSD__)
+struct cfdriver ohci_cd = {
+ NULL, "ohci", DV_DULL
+};
+#endif
+
/*
* The OHCI controller is little endian, so on big endian machines
* the data strored in memory needs to be swapped.
@@ -109,15 +116,12 @@ void ohci_free_sed __P((ohci_softc_t *, ohci_soft_ed_t *));
ohci_soft_td_t *ohci_alloc_std __P((ohci_softc_t *));
void ohci_free_std __P((ohci_softc_t *, ohci_soft_td_t *));
+void ohci_power __P((int, void *));
usbd_status ohci_open __P((usbd_pipe_handle));
void ohci_poll __P((struct usbd_bus *));
void ohci_waitintr __P((ohci_softc_t *, usbd_request_handle));
void ohci_rhsc __P((ohci_softc_t *, usbd_request_handle));
void ohci_process_done __P((ohci_softc_t *, ohci_physaddr_t));
-void ohci_ii_done __P((ohci_softc_t *, usbd_request_handle));
-void ohci_ctrl_done __P((ohci_softc_t *, usbd_request_handle));
-void ohci_intr_done __P((ohci_softc_t *, usbd_request_handle));
-void ohci_bulk_done __P((ohci_softc_t *, usbd_request_handle));
usbd_status ohci_device_request __P((usbd_request_handle reqh));
void ohci_add_ed __P((ohci_soft_ed_t *, ohci_soft_ed_t *));
@@ -126,6 +130,9 @@ void ohci_hash_add_td __P((ohci_softc_t *, ohci_soft_td_t *));
void ohci_hash_rem_td __P((ohci_softc_t *, ohci_soft_td_t *));
ohci_soft_td_t *ohci_hash_find_td __P((ohci_softc_t *, ohci_physaddr_t));
+usbd_status ohci_allocm __P((struct usbd_bus *, usb_dma_t *, u_int32_t));
+void ohci_freem __P((struct usbd_bus *, usb_dma_t *));
+
usbd_status ohci_root_ctrl_transfer __P((usbd_request_handle));
usbd_status ohci_root_ctrl_start __P((usbd_request_handle));
void ohci_root_ctrl_abort __P((usbd_request_handle));
@@ -135,21 +142,32 @@ usbd_status ohci_root_intr_transfer __P((usbd_request_handle));
usbd_status ohci_root_intr_start __P((usbd_request_handle));
void ohci_root_intr_abort __P((usbd_request_handle));
void ohci_root_intr_close __P((usbd_pipe_handle));
+void ohci_root_intr_done __P((usbd_request_handle));
usbd_status ohci_device_ctrl_transfer __P((usbd_request_handle));
usbd_status ohci_device_ctrl_start __P((usbd_request_handle));
void ohci_device_ctrl_abort __P((usbd_request_handle));
void ohci_device_ctrl_close __P((usbd_pipe_handle));
+void ohci_device_ctrl_done __P((usbd_request_handle));
usbd_status ohci_device_bulk_transfer __P((usbd_request_handle));
usbd_status ohci_device_bulk_start __P((usbd_request_handle));
void ohci_device_bulk_abort __P((usbd_request_handle));
void ohci_device_bulk_close __P((usbd_pipe_handle));
+void ohci_device_bulk_done __P((usbd_request_handle));
usbd_status ohci_device_intr_transfer __P((usbd_request_handle));
usbd_status ohci_device_intr_start __P((usbd_request_handle));
void ohci_device_intr_abort __P((usbd_request_handle));
void ohci_device_intr_close __P((usbd_pipe_handle));
+void ohci_device_intr_done __P((usbd_request_handle));
+
+usbd_status ohci_device_isoc_transfer __P((usbd_request_handle));
+usbd_status ohci_device_isoc_start __P((usbd_request_handle));
+void ohci_device_isoc_abort __P((usbd_request_handle));
+void ohci_device_isoc_close __P((usbd_pipe_handle));
+void ohci_device_isoc_done __P((usbd_request_handle));
+
usbd_status ohci_device_setintr __P((ohci_softc_t *sc,
struct ohci_pipe *pipe, int ival));
@@ -158,6 +176,15 @@ int ohci_str __P((usb_string_descriptor_t *, int, char *));
void ohci_timeout __P((void *));
void ohci_rhsc_able __P((ohci_softc_t *, int));
+void ohci_close_pipe __P((usbd_pipe_handle pipe,
+ ohci_soft_ed_t *head));
+void ohci_abort_req __P((usbd_request_handle reqh,
+ usbd_status status));
+void ohci_abort_req_end __P((void *));
+
+void ohci_device_clear_toggle __P((usbd_pipe_handle pipe));
+void ohci_noop __P((usbd_pipe_handle pipe));
+
#ifdef OHCI_DEBUG
ohci_softc_t *thesc;
void ohci_dumpregs __P((ohci_softc_t *));
@@ -185,66 +212,92 @@ struct ohci_pipe {
union {
/* Control pipe */
struct {
- usb_dma_t datadma;
usb_dma_t reqdma;
u_int length;
ohci_soft_td_t *setup, *xfer, *stat;
} ctl;
/* Interrupt pipe */
struct {
- usb_dma_t datadma;
int nslots;
int pos;
} intr;
/* Bulk pipe */
struct {
- usb_dma_t datadma;
u_int length;
+ int isread;
} bulk;
+ /* Iso pipe */
+ struct iso {
+ int xxxxx;
+ } iso;
} u;
};
#define OHCI_INTR_ENDPT 1
-struct usbd_methods ohci_root_ctrl_methods = {
+struct usbd_bus_methods ohci_bus_methods = {
+ ohci_open,
+ ohci_poll,
+ ohci_allocm,
+ ohci_freem,
+};
+
+struct usbd_pipe_methods ohci_root_ctrl_methods = {
ohci_root_ctrl_transfer,
ohci_root_ctrl_start,
ohci_root_ctrl_abort,
ohci_root_ctrl_close,
+ ohci_noop,
0,
};
-struct usbd_methods ohci_root_intr_methods = {
+struct usbd_pipe_methods ohci_root_intr_methods = {
ohci_root_intr_transfer,
ohci_root_intr_start,
ohci_root_intr_abort,
ohci_root_intr_close,
- 0,
+ ohci_noop,
+ ohci_root_intr_done,
};
-struct usbd_methods ohci_device_ctrl_methods = {
+struct usbd_pipe_methods ohci_device_ctrl_methods = {
ohci_device_ctrl_transfer,
ohci_device_ctrl_start,
ohci_device_ctrl_abort,
ohci_device_ctrl_close,
- 0,
+ ohci_noop,
+ ohci_device_ctrl_done,
};
-struct usbd_methods ohci_device_intr_methods = {
+struct usbd_pipe_methods ohci_device_intr_methods = {
ohci_device_intr_transfer,
ohci_device_intr_start,
ohci_device_intr_abort,
ohci_device_intr_close,
+ ohci_device_clear_toggle,
+ ohci_device_intr_done,
};
-struct usbd_methods ohci_device_bulk_methods = {
+struct usbd_pipe_methods ohci_device_bulk_methods = {
ohci_device_bulk_transfer,
ohci_device_bulk_start,
ohci_device_bulk_abort,
ohci_device_bulk_close,
- 0,
+ ohci_device_clear_toggle,
+ ohci_device_bulk_done,
};
+#if 0
+struct usbd_pipe_methods ohci_device_isoc_methods = {
+ ohci_device_isoc_transfer,
+ ohci_device_isoc_start,
+ ohci_device_isoc_abort,
+ ohci_device_isoc_close,
+ ohci_noop,
+ ohci_device_isoc_done,
+};
+#endif
+
ohci_soft_ed_t *
ohci_alloc_sed(sc)
ohci_softc_t *sc;
@@ -256,30 +309,23 @@ ohci_alloc_sed(sc)
if (!sc->sc_freeeds) {
DPRINTFN(2, ("ohci_alloc_sed: allocating chunk\n"));
- sed = malloc(sizeof(ohci_soft_ed_t) * OHCI_ED_CHUNK,
- M_USBDEV, M_NOWAIT);
- if (!sed)
- return 0;
- r = usb_allocmem(sc->sc_dmatag, OHCI_ED_SIZE * OHCI_ED_CHUNK,
+ r = usb_allocmem(sc->sc_dmatag, OHCI_SED_SIZE * OHCI_SED_CHUNK,
OHCI_ED_ALIGN, &dma);
- if (r != USBD_NORMAL_COMPLETION) {
- free(sed, M_USBDEV);
- return 0;
- }
- for(i = 0; i < OHCI_ED_CHUNK; i++, sed++) {
- offs = i * OHCI_ED_SIZE;
+ if (r != USBD_NORMAL_COMPLETION)
+ return (0);
+ for(i = 0; i < OHCI_SED_CHUNK; i++) {
+ offs = i * OHCI_SED_SIZE;
+ sed = (ohci_soft_ed_t *)((char *)KERNADDR(&dma) +offs);
sed->physaddr = DMAADDR(&dma) + offs;
- sed->ed = (ohci_ed_t *)
- ((char *)KERNADDR(&dma) + offs);
sed->next = sc->sc_freeeds;
sc->sc_freeeds = sed;
}
}
sed = sc->sc_freeeds;
sc->sc_freeeds = sed->next;
- memset(sed->ed, 0, OHCI_ED_SIZE);
+ memset(&sed->ed, 0, sizeof(ohci_ed_t));
sed->next = 0;
- return sed;
+ return (sed);
}
void
@@ -302,28 +348,21 @@ ohci_alloc_std(sc)
if (!sc->sc_freetds) {
DPRINTFN(2, ("ohci_alloc_std: allocating chunk\n"));
- std = malloc(sizeof(ohci_soft_td_t) * OHCI_TD_CHUNK,
- M_USBDEV, M_NOWAIT);
- if (!std)
- return 0;
- r = usb_allocmem(sc->sc_dmatag, OHCI_TD_SIZE * OHCI_TD_CHUNK,
+ r = usb_allocmem(sc->sc_dmatag, OHCI_STD_SIZE * OHCI_STD_CHUNK,
OHCI_TD_ALIGN, &dma);
- if (r != USBD_NORMAL_COMPLETION) {
- free(std, M_USBDEV);
- return 0;
- }
- for(i = 0; i < OHCI_TD_CHUNK; i++, std++) {
- offs = i * OHCI_TD_SIZE;
+ if (r != USBD_NORMAL_COMPLETION)
+ return (0);
+ for(i = 0; i < OHCI_STD_CHUNK; i++) {
+ offs = i * OHCI_STD_SIZE;
+ std = (ohci_soft_td_t *)((char *)KERNADDR(&dma) +offs);
std->physaddr = DMAADDR(&dma) + offs;
- std->td = (ohci_td_t *)
- ((char *)KERNADDR(&dma) + offs);
std->nexttd = sc->sc_freetds;
sc->sc_freetds = std;
}
}
std = sc->sc_freetds;
sc->sc_freetds = std->nexttd;
- memset(std->td, 0, OHCI_TD_SIZE);
+ memset(&std->td, 0, sizeof(ohci_td_t));
std->nexttd = 0;
return (std);
}
@@ -349,7 +388,11 @@ ohci_init(sc)
DPRINTF(("ohci_init: start\n"));
rev = OREAD4(sc, OHCI_REVISION);
+#if defined(__OpenBSD__)
+ printf(", OHCI version %d.%d%s\n",
+#else
printf("%s: OHCI version %d.%d%s\n", USBDEVNAME(sc->sc_bus.bdev),
+#endif
OHCI_REV_HI(rev), OHCI_REV_LO(rev),
OHCI_REV_LEGACY(rev) ? ", legacy support" : "");
if (OHCI_REV_HI(rev) != 1 || OHCI_REV_LO(rev) != 0) {
@@ -376,13 +419,14 @@ ohci_init(sc)
r = USBD_NOMEM;
goto bad1;
}
- sc->sc_ctrl_head->ed->ed_flags |= LE(OHCI_ED_SKIP);
+ sc->sc_ctrl_head->ed.ed_flags |= LE(OHCI_ED_SKIP);
+
sc->sc_bulk_head = ohci_alloc_sed(sc);
if (!sc->sc_bulk_head) {
r = USBD_NOMEM;
goto bad2;
}
- sc->sc_bulk_head->ed->ed_flags |= LE(OHCI_ED_SKIP);
+ sc->sc_bulk_head->ed.ed_flags |= LE(OHCI_ED_SKIP);
/* Allocate all the dummy EDs that make up the interrupt tree. */
for (i = 0; i < OHCI_NO_EDS; i++) {
@@ -395,11 +439,11 @@ ohci_init(sc)
}
/* All ED fields are set to 0. */
sc->sc_eds[i] = sed;
- sed->ed->ed_flags |= LE(OHCI_ED_SKIP);
+ sed->ed.ed_flags |= LE(OHCI_ED_SKIP);
if (i != 0) {
psed = sc->sc_eds[(i-1) / 2];
sed->next = psed;
- sed->ed->ed_nexted = LE(psed->physaddr);
+ sed->ed.ed_nexted = LE(psed->physaddr);
}
}
/*
@@ -507,9 +551,12 @@ ohci_init(sc)
#endif
/* Set up the bus struct. */
- sc->sc_bus.open_pipe = ohci_open;
+ sc->sc_bus.methods = &ohci_bus_methods;
sc->sc_bus.pipe_size = sizeof(struct ohci_pipe);
- sc->sc_bus.do_poll = ohci_poll;
+
+#if defined(__NetBSD__)
+ powerhook_establish(ohci_power, sc);
+#endif
return (USBD_NORMAL_COMPLETION);
@@ -522,6 +569,47 @@ ohci_init(sc)
return (r);
}
+usbd_status
+ohci_allocm(bus, dma, size)
+ struct usbd_bus *bus;
+ usb_dma_t *dma;
+ u_int32_t size;
+{
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ struct ohci_softc *sc = (struct ohci_softc *)bus;
+#endif
+
+ return (usb_allocmem(sc->sc_dmatag, size, 0, dma));
+}
+
+void
+ohci_freem(bus, dma)
+ struct usbd_bus *bus;
+ usb_dma_t *dma;
+{
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ struct ohci_softc *sc = (struct ohci_softc *)bus;
+#endif
+
+ usb_freemem(sc->sc_dmatag, dma);
+}
+
+#if defined(__NetBSD__)
+void
+ohci_power(why, v)
+ int why;
+ void *v;
+{
+#ifdef OHCI_DEBUG
+ ohci_softc_t *sc = v;
+
+ DPRINTF(("ohci_power: sc=%p, why=%d\n", sc, why));
+ /* XXX should suspend/resume */
+ ohci_dumpregs(sc);
+#endif
+}
+#endif /* !defined(__OpenBSD__) */
+
#ifdef OHCI_DEBUG
void ohcidump(void);
void ohcidump(void) { ohci_dumpregs(thesc); }
@@ -530,40 +618,40 @@ void
ohci_dumpregs(sc)
ohci_softc_t *sc;
{
- printf("ohci_dumpregs: rev=0x%08x control=0x%08x command=0x%08x\n",
- OREAD4(sc, OHCI_REVISION),
- OREAD4(sc, OHCI_CONTROL),
- OREAD4(sc, OHCI_COMMAND_STATUS));
- printf(" intrstat=0x%08x intre=0x%08x intrd=0x%08x\n",
- OREAD4(sc, OHCI_INTERRUPT_STATUS),
- OREAD4(sc, OHCI_INTERRUPT_ENABLE),
- OREAD4(sc, OHCI_INTERRUPT_DISABLE));
- printf(" hcca=0x%08x percur=0x%08x ctrlhd=0x%08x\n",
- OREAD4(sc, OHCI_HCCA),
- OREAD4(sc, OHCI_PERIOD_CURRENT_ED),
- OREAD4(sc, OHCI_CONTROL_HEAD_ED));
- printf(" ctrlcur=0x%08x bulkhd=0x%08x bulkcur=0x%08x\n",
- OREAD4(sc, OHCI_CONTROL_CURRENT_ED),
- OREAD4(sc, OHCI_BULK_HEAD_ED),
- OREAD4(sc, OHCI_BULK_CURRENT_ED));
- printf(" done=0x%08x fmival=0x%08x fmrem=0x%08x\n",
- OREAD4(sc, OHCI_DONE_HEAD),
- OREAD4(sc, OHCI_FM_INTERVAL),
- OREAD4(sc, OHCI_FM_REMAINING));
- printf(" fmnum=0x%08x perst=0x%08x lsthrs=0x%08x\n",
- OREAD4(sc, OHCI_FM_NUMBER),
- OREAD4(sc, OHCI_PERIODIC_START),
- OREAD4(sc, OHCI_LS_THRESHOLD));
- printf(" desca=0x%08x descb=0x%08x stat=0x%08x\n",
- OREAD4(sc, OHCI_RH_DESCRIPTOR_A),
- OREAD4(sc, OHCI_RH_DESCRIPTOR_B),
- OREAD4(sc, OHCI_RH_STATUS));
- printf(" port1=0x%08x port2=0x%08x\n",
- OREAD4(sc, OHCI_RH_PORT_STATUS(1)),
- OREAD4(sc, OHCI_RH_PORT_STATUS(2)));
- printf(" HCCA: frame_number=0x%04x done_head=0x%08x\n",
- LE(sc->sc_hcca->hcca_frame_number),
- LE(sc->sc_hcca->hcca_done_head));
+ DPRINTF(("ohci_dumpregs: rev=0x%08x control=0x%08x command=0x%08x\n",
+ OREAD4(sc, OHCI_REVISION),
+ OREAD4(sc, OHCI_CONTROL),
+ OREAD4(sc, OHCI_COMMAND_STATUS)));
+ DPRINTF((" intrstat=0x%08x intre=0x%08x intrd=0x%08x\n",
+ OREAD4(sc, OHCI_INTERRUPT_STATUS),
+ OREAD4(sc, OHCI_INTERRUPT_ENABLE),
+ OREAD4(sc, OHCI_INTERRUPT_DISABLE)));
+ DPRINTF((" hcca=0x%08x percur=0x%08x ctrlhd=0x%08x\n",
+ OREAD4(sc, OHCI_HCCA),
+ OREAD4(sc, OHCI_PERIOD_CURRENT_ED),
+ OREAD4(sc, OHCI_CONTROL_HEAD_ED)));
+ DPRINTF((" ctrlcur=0x%08x bulkhd=0x%08x bulkcur=0x%08x\n",
+ OREAD4(sc, OHCI_CONTROL_CURRENT_ED),
+ OREAD4(sc, OHCI_BULK_HEAD_ED),
+ OREAD4(sc, OHCI_BULK_CURRENT_ED)));
+ DPRINTF((" done=0x%08x fmival=0x%08x fmrem=0x%08x\n",
+ OREAD4(sc, OHCI_DONE_HEAD),
+ OREAD4(sc, OHCI_FM_INTERVAL),
+ OREAD4(sc, OHCI_FM_REMAINING)));
+ DPRINTF((" fmnum=0x%08x perst=0x%08x lsthrs=0x%08x\n",
+ OREAD4(sc, OHCI_FM_NUMBER),
+ OREAD4(sc, OHCI_PERIODIC_START),
+ OREAD4(sc, OHCI_LS_THRESHOLD)));
+ DPRINTF((" desca=0x%08x descb=0x%08x stat=0x%08x\n",
+ OREAD4(sc, OHCI_RH_DESCRIPTOR_A),
+ OREAD4(sc, OHCI_RH_DESCRIPTOR_B),
+ OREAD4(sc, OHCI_RH_STATUS)));
+ DPRINTF((" port1=0x%08x port2=0x%08x\n",
+ OREAD4(sc, OHCI_RH_PORT_STATUS(1)),
+ OREAD4(sc, OHCI_RH_PORT_STATUS(2))));
+ DPRINTF((" HCCA: frame_number=0x%04x done_head=0x%08x\n",
+ LE(sc->sc_hcca->hcca_frame_number),
+ LE(sc->sc_hcca->hcca_done_head)));
}
#endif
@@ -576,14 +664,14 @@ ohci_intr(p)
ohci_physaddr_t done;
/* In case the interrupt occurs before initialization has completed. */
- if (sc == NULL || sc->sc_hcca == NULL) { /* NWH added sc==0 */
+ if (sc == NULL || sc->sc_hcca == NULL) {
#ifdef DIAGNOSTIC
printf("ohci_intr: sc->sc_hcca == NULL\n");
#endif
return (0);
}
- intrs = 0;
+ intrs = 0;
done = LE(sc->sc_hcca->hcca_done_head);
if (done != 0) {
sc->sc_hcca->hcca_done_head = 0;
@@ -616,6 +704,7 @@ ohci_intr(p)
intrs &= ~OHCI_WDH;
}
if (eintrs & OHCI_RD) {
+ printf("%s: resume detect\n", USBDEVNAME(sc->sc_bus.bdev));
/* XXX process resume detect */
}
if (eintrs & OHCI_UE) {
@@ -687,15 +776,15 @@ ohci_process_done(sc, done)
DPRINTFN(10,("ohci_process_done: done=0x%08lx\n", (u_long)done));
/* Reverse the done list. */
- for (sdone = 0; done; done = LE(std->td->td_nexttd)) {
+ for (sdone = 0; done; done = LE(std->td.td_nexttd)) {
std = ohci_hash_find_td(sc, done);
std->dnext = sdone;
sdone = std;
}
#ifdef OHCI_DEBUG
- if (ohcidebug > 11) {
- printf("ohci_process_done: TD done:\n");
+ if (ohcidebug > 10) {
+ DPRINTF(("ohci_process_done: TD done:\n"));
ohci_dump_tds(sdone);
}
#endif
@@ -704,40 +793,32 @@ ohci_process_done(sc, done)
reqh = std->reqh;
DPRINTFN(10, ("ohci_process_done: std=%p reqh=%p hcpriv=%p\n",
std, reqh, reqh->hcpriv));
- cc = OHCI_TD_GET_CC(LE(std->td->td_flags));
- if (cc == OHCI_CC_NO_ERROR) {
- if (std->td->td_cbp == 0)
- len = std->len;
- else
- len = LE(std->td->td_be) -
- LE(std->td->td_cbp) + 1;
- /*
- * Only do a callback on the last stage of a transfer.
- * Others have hcpriv = 0.
- */
- if ((reqh->pipe->endpoint->edesc->bmAttributes &
- UE_XFERTYPE) == UE_CONTROL) {
- /* For a control transfer the length is in
- * the xfer stage */
- if (reqh->hcpriv == std) {
- reqh->status = USBD_NORMAL_COMPLETION;
- ohci_ii_done(sc, reqh);
- } else
- reqh->actlen = len;
- } else {
- if (reqh->hcpriv == std) {
- reqh->actlen = len;
- reqh->status = USBD_NORMAL_COMPLETION;
- ohci_ii_done(sc, reqh);
- }
+ cc = OHCI_TD_GET_CC(LE(std->td.td_flags));
+ usb_untimeout(ohci_timeout, reqh, reqh->timo_handle);
+ if (reqh->status == USBD_CANCELLED ||
+ reqh->status == USBD_TIMEOUT) {
+ DPRINTF(("ohci_process_done: cancel/timeout %p\n",
+ reqh));
+ /* Handled by abort routine. */
+ continue;
+ } else if (cc == OHCI_CC_NO_ERROR) {
+ len = std->len;
+ if (std->td.td_cbp != 0)
+ len -= LE(std->td.td_be) -
+ LE(std->td.td_cbp) + 1;
+ if (std->flags & OHCI_SET_LEN)
+ reqh->actlen = len;
+ if (std->flags & OHCI_CALL_DONE) {
+ reqh->status = USBD_NORMAL_COMPLETION;
+ usb_transfer_complete(reqh);
}
} else {
ohci_soft_td_t *p, *n;
struct ohci_pipe *opipe =
(struct ohci_pipe *)reqh->pipe;
DPRINTFN(-1,("ohci_process_done: error cc=%d (%s)\n",
- OHCI_TD_GET_CC(LE(std->td->td_flags)),
- ohci_cc_strs[OHCI_TD_GET_CC(LE(std->td->td_flags))]));
+ OHCI_TD_GET_CC(LE(std->td.td_flags)),
+ ohci_cc_strs[OHCI_TD_GET_CC(LE(std->td.td_flags))]));
/*
* Endpoint is halted. First unlink all the TDs
* belonging to the failed transfer, and then restart
@@ -749,14 +830,14 @@ ohci_process_done(sc, done)
ohci_free_std(sc, p);
}
/* clear halt */
- opipe->sed->ed->ed_headp = LE(p->physaddr);
+ opipe->sed->ed.ed_headp = LE(p->physaddr);
OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF);
if (cc == OHCI_CC_STALL)
reqh->status = USBD_STALLED;
else
reqh->status = USBD_IOERROR;
- ohci_ii_done(sc, reqh);
+ usb_transfer_complete(reqh);
}
ohci_hash_rem_td(sc, std);
ohci_free_std(sc, std);
@@ -764,64 +845,25 @@ ohci_process_done(sc, done)
}
void
-ohci_ii_done(sc, reqh)
- ohci_softc_t *sc;
- usbd_request_handle reqh;
-{
- switch (reqh->pipe->endpoint->edesc->bmAttributes & UE_XFERTYPE) {
- case UE_CONTROL:
- ohci_ctrl_done(sc, reqh);
- usb_start_next(reqh->pipe);
- break;
- case UE_INTERRUPT:
- ohci_intr_done(sc, reqh);
- break;
- case UE_BULK:
- ohci_bulk_done(sc, reqh);
- usb_start_next(reqh->pipe);
- break;
- case UE_ISOCHRONOUS:
- printf("ohci_process_done: ISO done?\n");
- usb_start_next(reqh->pipe);
- break;
- }
-
- /* And finally execute callback. */
- reqh->xfercb(reqh);
-}
-
-void
-ohci_ctrl_done(sc, reqh)
- ohci_softc_t *sc;
+ohci_device_ctrl_done(reqh)
usbd_request_handle reqh;
{
- struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe;
- u_int len = opipe->u.ctl.length;
- usb_dma_t *dma;
-
DPRINTFN(10,("ohci_ctrl_done: reqh=%p\n", reqh));
- if (!reqh->isreq) {
+#ifdef DIAGNOSTIC
+ if (!(reqh->rqflags & URQ_REQUEST)) {
panic("ohci_ctrl_done: not a request\n");
- return;
- }
-
- if (len != 0) {
- dma = &opipe->u.ctl.datadma;
- if (reqh->request.bmRequestType & UT_READ)
- memcpy(reqh->buffer, KERNADDR(dma), len);
- usb_freemem(sc->sc_dmatag, dma);
}
- usb_untimeout(ohci_timeout, reqh, reqh->timeout_handle);
+#endif
+ reqh->hcpriv = 0;
}
void
-ohci_intr_done(sc, reqh)
- ohci_softc_t *sc;
+ohci_device_intr_done(reqh)
usbd_request_handle reqh;
{
struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe;
- usb_dma_t *dma;
+ ohci_softc_t *sc = (ohci_softc_t *)opipe->pipe.device->bus;
ohci_soft_ed_t *sed = opipe->sed;
ohci_soft_td_t *xfer, *tail;
@@ -829,10 +871,9 @@ ohci_intr_done(sc, reqh)
DPRINTFN(10,("ohci_intr_done: reqh=%p, actlen=%d\n",
reqh, reqh->actlen));
- dma = &opipe->u.intr.datadma;
- memcpy(reqh->buffer, KERNADDR(dma), reqh->actlen);
+ reqh->hcpriv = 0;
- if (reqh->pipe->intrreqh == reqh) {
+ if (reqh->pipe->repeat) {
xfer = opipe->tail;
tail = ohci_alloc_std(sc); /* XXX should reuse TD */
if (!tail) {
@@ -841,46 +882,34 @@ ohci_intr_done(sc, reqh)
}
tail->reqh = 0;
- xfer->td->td_flags = LE(
+ xfer->td.td_flags = LE(
OHCI_TD_IN | OHCI_TD_NOCC |
OHCI_TD_SET_DI(1) | OHCI_TD_TOGGLE_CARRY);
if (reqh->flags & USBD_SHORT_XFER_OK)
- xfer->td->td_flags |= LE(OHCI_TD_R);
- xfer->td->td_cbp = LE(DMAADDR(dma));
+ xfer->td.td_flags |= LE(OHCI_TD_R);
+ xfer->td.td_cbp = LE(DMAADDR(&reqh->dmabuf));
xfer->nexttd = tail;
- xfer->td->td_nexttd = LE(tail->physaddr);
- xfer->td->td_be = LE(LE(xfer->td->td_cbp) + reqh->length - 1);
+ xfer->td.td_nexttd = LE(tail->physaddr);
+ xfer->td.td_be = LE(LE(xfer->td.td_cbp) + reqh->length - 1);
xfer->len = reqh->length;
xfer->reqh = reqh;
-
+ xfer->flags = OHCI_CALL_DONE | OHCI_SET_LEN;
reqh->hcpriv = xfer;
ohci_hash_add_td(sc, xfer);
- sed->ed->ed_tailp = LE(tail->physaddr);
+ sed->ed.ed_tailp = LE(tail->physaddr);
opipe->tail = tail;
- } else {
- usb_freemem(sc->sc_dmatag, dma);
- usb_start_next(reqh->pipe);
}
}
void
-ohci_bulk_done(sc, reqh)
- ohci_softc_t *sc;
+ohci_device_bulk_done(reqh)
usbd_request_handle reqh;
{
- struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe;
- usb_dma_t *dma;
-
-
DPRINTFN(10,("ohci_bulk_done: reqh=%p, actlen=%d\n",
reqh, reqh->actlen));
- dma = &opipe->u.bulk.datadma;
- if (reqh->request.bmRequestType & UT_READ)
- memcpy(reqh->buffer, KERNADDR(dma), reqh->actlen);
- usb_freemem(sc->sc_dmatag, dma);
- usb_untimeout(ohci_timeout, reqh, reqh->timeout_handle);
+ reqh->hcpriv = 0;
}
void
@@ -906,7 +935,7 @@ ohci_rhsc(sc, reqh)
pipe = reqh->pipe;
opipe = (struct ohci_pipe *)pipe;
- p = KERNADDR(&opipe->u.intr.datadma);
+ p = KERNADDR(&reqh->dmabuf);
m = min(sc->sc_noport, reqh->length * 8 - 1);
memset(p, 0, reqh->length);
for (i = 1; i <= m; i++) {
@@ -916,13 +945,15 @@ ohci_rhsc(sc, reqh)
DPRINTF(("ohci_rhsc: change=0x%02x\n", *p));
reqh->actlen = reqh->length;
reqh->status = USBD_NORMAL_COMPLETION;
- reqh->xfercb(reqh);
- if (reqh->pipe->intrreqh != reqh) {
- sc->sc_intrreqh = 0;
- usb_freemem(sc->sc_dmatag, &opipe->u.intr.datadma);
- usb_start_next(reqh->pipe);
- }
+ usb_transfer_complete(reqh);
+}
+
+void
+ohci_root_intr_done(reqh)
+ usbd_request_handle reqh;
+{
+ reqh->hcpriv = 0;
}
/*
@@ -958,7 +989,7 @@ ohci_waitintr(sc, reqh)
/* Timeout */
DPRINTF(("ohci_waitintr: timeout\n"));
reqh->status = USBD_TIMEOUT;
- ohci_ii_done(sc, reqh);
+ usb_transfer_complete(reqh);
/* XXX should free TD */
}
@@ -983,7 +1014,6 @@ ohci_device_request(reqh)
int addr = dev->address;
ohci_soft_td_t *setup, *xfer = 0, *stat, *next, *tail;
ohci_soft_ed_t *sed;
- usb_dma_t *dmap;
int isread;
int len;
usbd_status r;
@@ -1012,13 +1042,12 @@ ohci_device_request(reqh)
tail->reqh = 0;
sed = opipe->sed;
- dmap = &opipe->u.ctl.datadma;
opipe->u.ctl.length = len;
/* Update device address and length since they may have changed. */
/* XXX This only needs to be done once, but it's too early in open. */
- sed->ed->ed_flags = LE(
- (LE(sed->ed->ed_flags) & ~(OHCI_ED_ADDRMASK | OHCI_ED_MAXPMASK)) |
+ sed->ed.ed_flags = LE(
+ (LE(sed->ed.ed_flags) & ~(OHCI_ED_ADDRMASK | OHCI_ED_MAXPMASK)) |
OHCI_ED_SET_FA(addr) |
OHCI_ED_SET_MAXP(UGETW(opipe->pipe.endpoint->edesc->wMaxPacketSize)));
@@ -1029,52 +1058,51 @@ ohci_device_request(reqh)
r = USBD_NOMEM;
goto bad3;
}
- r = usb_allocmem(sc->sc_dmatag, len, 0, dmap);
- if (r != USBD_NORMAL_COMPLETION)
- goto bad4;
- xfer->td->td_flags = LE(
+ xfer->td.td_flags = LE(
(isread ? OHCI_TD_IN : OHCI_TD_OUT) | OHCI_TD_NOCC |
OHCI_TD_TOGGLE_1 | OHCI_TD_NOINTR |
(reqh->flags & USBD_SHORT_XFER_OK ? OHCI_TD_R : 0));
- xfer->td->td_cbp = LE(DMAADDR(dmap));
+ xfer->td.td_cbp = LE(DMAADDR(&reqh->dmabuf));
xfer->nexttd = stat;
- xfer->td->td_nexttd = LE(stat->physaddr);
- xfer->td->td_be = LE(LE(xfer->td->td_cbp) + len - 1);
+ xfer->td.td_nexttd = LE(stat->physaddr);
+ xfer->td.td_be = LE(LE(xfer->td.td_cbp) + len - 1);
xfer->len = len;
xfer->reqh = reqh;
+ xfer->flags = OHCI_SET_LEN;
next = xfer;
- } else
+ stat->flags = OHCI_CALL_DONE;
+ } else {
next = stat;
+ stat->flags = OHCI_CALL_DONE | OHCI_SET_LEN;
+ }
memcpy(KERNADDR(&opipe->u.ctl.reqdma), req, sizeof *req);
- if (!isread && len != 0)
- memcpy(KERNADDR(dmap), reqh->buffer, len);
- setup->td->td_flags = LE(OHCI_TD_SETUP | OHCI_TD_NOCC |
+ setup->td.td_flags = LE(OHCI_TD_SETUP | OHCI_TD_NOCC |
OHCI_TD_TOGGLE_0 | OHCI_TD_NOINTR);
- setup->td->td_cbp = LE(DMAADDR(&opipe->u.ctl.reqdma));
+ setup->td.td_cbp = LE(DMAADDR(&opipe->u.ctl.reqdma));
setup->nexttd = next;
- setup->td->td_nexttd = LE(next->physaddr);
- setup->td->td_be = LE(LE(setup->td->td_cbp) + sizeof *req - 1);
+ setup->td.td_nexttd = LE(next->physaddr);
+ setup->td.td_be = LE(LE(setup->td.td_cbp) + sizeof *req - 1);
setup->len = 0; /* XXX The number of byte we count */
setup->reqh = reqh;
+ setup->flags = 0;
+ reqh->hcpriv = setup;
- stat->td->td_flags = LE(
+ stat->td.td_flags = LE(
(isread ? OHCI_TD_OUT : OHCI_TD_IN) | OHCI_TD_NOCC |
OHCI_TD_TOGGLE_1 | OHCI_TD_SET_DI(1));
- stat->td->td_cbp = 0;
+ stat->td.td_cbp = 0;
stat->nexttd = tail;
- stat->td->td_nexttd = LE(tail->physaddr);
- stat->td->td_be = 0;
+ stat->td.td_nexttd = LE(tail->physaddr);
+ stat->td.td_be = 0;
stat->len = 0;
stat->reqh = reqh;
- reqh->hcpriv = stat;
-
#ifdef OHCI_DEBUG
if (ohcidebug > 5) {
- printf("ohci_device_request:\n");
+ DPRINTF(("ohci_device_request:\n"));
ohci_dump_ed(sed);
ohci_dump_tds(setup);
}
@@ -1086,21 +1114,24 @@ ohci_device_request(reqh)
if (len != 0)
ohci_hash_add_td(sc, xfer);
ohci_hash_add_td(sc, stat);
- sed->ed->ed_tailp = LE(tail->physaddr);
+ sed->ed.ed_tailp = LE(tail->physaddr);
opipe->tail = tail;
OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF);
if (reqh->timeout && !sc->sc_bus.use_polling) {
usb_timeout(ohci_timeout, reqh,
- MS_TO_TICKS(reqh->timeout), reqh->timeout_handle);
+ MS_TO_TICKS(reqh->timeout), reqh->timo_handle);
}
splx(s);
#if 0
+ This goes horribly wrong, printing thousands of descriptors,
+ because false references are followed due to the fact that the
+ TD is gone.
#ifdef OHCI_DEBUG
- if (ohcidebug > 15) {
+ if (ohcidebug > 5) {
delay(5000);
- printf("ohci_device_request: status=%x\n",
- OREAD4(sc, OHCI_COMMAND_STATUS));
+ DPRINTF(("ohci_device_request: status=%x\n",
+ OREAD4(sc, OHCI_COMMAND_STATUS)));
ohci_dump_ed(sed);
ohci_dump_tds(setup);
}
@@ -1109,8 +1140,6 @@ ohci_device_request(reqh)
return (USBD_NORMAL_COMPLETION);
- bad4:
- ohci_free_std(sc, xfer);
bad3:
ohci_free_std(sc, tail);
bad2:
@@ -1128,9 +1157,9 @@ ohci_add_ed(sed, head)
ohci_soft_ed_t *head;
{
sed->next = head->next;
- sed->ed->ed_nexted = head->ed->ed_nexted;
+ sed->ed.ed_nexted = head->ed.ed_nexted;
head->next = sed;
- head->ed->ed_nexted = LE(sed->physaddr);
+ head->ed.ed_nexted = LE(sed->physaddr);
}
/*
@@ -1149,7 +1178,7 @@ ohci_rem_ed(sed, head)
if (!p)
panic("ohci_rem_ed: ED not found\n");
p->next = sed->next;
- p->ed->ed_nexted = sed->ed->ed_nexted;
+ p->ed.ed_nexted = sed->ed.ed_nexted;
}
/*
@@ -1203,19 +1232,10 @@ void
ohci_timeout(addr)
void *addr;
{
-#ifdef OHCI_DEBUG
- usbd_request_handle *reqh = addr;
-#endif
+ usbd_request_handle reqh = addr;
DPRINTF(("ohci_timeout: reqh=%p\n", reqh));
-#if 0
- int s;
-
- s = splusb();
- /* XXX need to inactivate TD before calling interrupt routine */
- ohci_XXX_done(reqh);
- splx(s);
-#endif
+ ohci_abort_req(reqh, USBD_TIMEOUT);
}
#ifdef OHCI_DEBUG
@@ -1231,33 +1251,34 @@ void
ohci_dump_td(std)
ohci_soft_td_t *std;
{
- printf("TD(%p) at %08lx: %b delay=%d ec=%d cc=%d\ncbp=0x%08lx "
- "nexttd=0x%08lx be=0x%08lx\n",
- std, (u_long)std->physaddr,
- (int)LE(std->td->td_flags),
- "\20\23R\24OUT\25IN\31TOG1\32SETTOGGLE",
- OHCI_TD_GET_DI(LE(std->td->td_flags)),
- OHCI_TD_GET_EC(LE(std->td->td_flags)),
- OHCI_TD_GET_CC(LE(std->td->td_flags)),
- (u_long)LE(std->td->td_cbp),
- (u_long)LE(std->td->td_nexttd), (u_long)LE(std->td->td_be));
+ DPRINTF(("TD(%p) at %08lx: %b delay=%d ec=%d cc=%d\ncbp=0x%08lx "
+ "nexttd=0x%08lx be=0x%08lx\n",
+ std, (u_long)std->physaddr,
+ (int)LE(std->td.td_flags),
+ "\20\23R\24OUT\25IN\31TOG1\32SETTOGGLE",
+ OHCI_TD_GET_DI(LE(std->td.td_flags)),
+ OHCI_TD_GET_EC(LE(std->td.td_flags)),
+ OHCI_TD_GET_CC(LE(std->td.td_flags)),
+ (u_long)LE(std->td.td_cbp),
+ (u_long)LE(std->td.td_nexttd), (u_long)LE(std->td.td_be)));
}
void
ohci_dump_ed(sed)
ohci_soft_ed_t *sed;
{
- printf("ED(%p) at %08lx: addr=%d endpt=%d maxp=%d %b\ntailp=0x%08lx "
- "headp=%b nexted=0x%08lx\n",
- sed, (u_long)sed->physaddr,
- OHCI_ED_GET_FA(LE(sed->ed->ed_flags)),
- OHCI_ED_GET_EN(LE(sed->ed->ed_flags)),
- OHCI_ED_GET_MAXP(LE(sed->ed->ed_flags)),
- (int)LE(sed->ed->ed_flags),
- "\20\14OUT\15IN\16LOWSPEED\17SKIP\20ISO",
- (u_long)LE(sed->ed->ed_tailp),
- (int)LE(sed->ed->ed_headp), "\20\1HALT\2CARRY",
- (u_long)LE(sed->ed->ed_nexted));
+ DPRINTF(("ED(%p) at %08lx: addr=%d endpt=%d maxp=%d %b\ntailp=0x%08lx "
+ "headp=%b nexted=0x%08lx\n",
+ sed, (u_long)sed->physaddr,
+ OHCI_ED_GET_FA(LE(sed->ed.ed_flags)),
+ OHCI_ED_GET_EN(LE(sed->ed.ed_flags)),
+ OHCI_ED_GET_MAXP(LE(sed->ed.ed_flags)),
+ (int)LE(sed->ed.ed_flags),
+ "\20\14OUT\15IN\16LOWSPEED\17SKIP\20ISO",
+ (u_long)LE(sed->ed.ed_tailp),
+ (int)LE(sed->ed.ed_headp),
+ "\20\1HALT\2CARRY",
+ (u_long)LE(sed->ed.ed_nexted)));
}
#endif
@@ -1282,7 +1303,7 @@ ohci_open(pipe)
case USB_CONTROL_ENDPOINT:
pipe->methods = &ohci_root_ctrl_methods;
break;
- case UE_IN | OHCI_INTR_ENDPT:
+ case UE_DIR_IN | OHCI_INTR_ENDPT:
pipe->methods = &ohci_root_intr_methods;
break;
default:
@@ -1297,7 +1318,7 @@ ohci_open(pipe)
goto bad1;
opipe->sed = sed;
opipe->tail = std;
- sed->ed->ed_flags = LE(
+ sed->ed.ed_flags = LE(
OHCI_ED_SET_FA(addr) |
OHCI_ED_SET_EN(ed->bEndpointAddress) |
OHCI_ED_DIR_TD |
@@ -1305,7 +1326,7 @@ ohci_open(pipe)
((ed->bmAttributes & UE_XFERTYPE) == UE_ISOCHRONOUS ?
OHCI_ED_FORMAT_ISO : OHCI_ED_FORMAT_GEN) |
OHCI_ED_SET_MAXP(UGETW(ed->wMaxPacketSize)));
- sed->ed->ed_headp = sed->ed->ed_tailp = LE(std->physaddr);
+ sed->ed.ed_headp = sed->ed.ed_tailp = LE(std->physaddr);
switch (ed->bmAttributes & UE_XFERTYPE) {
case UE_CONTROL:
@@ -1324,7 +1345,7 @@ ohci_open(pipe)
return (ohci_device_setintr(sc, opipe, ed->bInterval));
case UE_ISOCHRONOUS:
printf("ohci_open: open iso unimplemented\n");
- return (USBD_XXX);
+ return (USBD_INVAL);
case UE_BULK:
pipe->methods = &ohci_device_bulk_methods;
s = splusb();
@@ -1345,6 +1366,121 @@ ohci_open(pipe)
}
/*
+ * Close a reqular pipe.
+ * Assumes that there are no pending transactions.
+ */
+void
+ohci_close_pipe(pipe, head)
+ usbd_pipe_handle pipe;
+ ohci_soft_ed_t *head;
+{
+ struct ohci_pipe *opipe = (struct ohci_pipe *)pipe;
+ ohci_softc_t *sc = (ohci_softc_t *)pipe->device->bus;
+ ohci_soft_ed_t *sed = opipe->sed;
+ int s;
+
+ s = splusb();
+#ifdef DIAGNOSTIC
+ sed->ed.ed_flags |= LE(OHCI_ED_SKIP);
+ if ((sed->ed.ed_tailp & LE(OHCI_TAILMASK)) !=
+ (sed->ed.ed_headp & LE(OHCI_TAILMASK))) {
+ ohci_physaddr_t td = sed->ed.ed_headp;
+ ohci_soft_td_t *std;
+ for (std = LIST_FIRST(&sc->sc_hash_tds[HASH(td)]);
+ std != 0;
+ std = LIST_NEXT(std, hnext))
+ if (std->physaddr == td)
+ break;
+ printf("ohci_close_pipe: pipe not empty sed=%p hd=0x%x "
+ "tl=0x%x pipe=%p, std=%p\n", sed,
+ (int)LE(sed->ed.ed_headp), (int)LE(sed->ed.ed_tailp),
+ pipe, std);
+ usb_delay_ms(&sc->sc_bus, 2);
+ if ((sed->ed.ed_tailp & LE(OHCI_TAILMASK)) !=
+ (sed->ed.ed_headp & LE(OHCI_TAILMASK)))
+ printf("ohci_close_pipe: pipe still not empty\n");
+ }
+#endif
+ ohci_rem_ed(sed, head);
+ splx(s);
+ ohci_free_std(sc, opipe->tail);
+ ohci_free_sed(sc, opipe->sed);
+}
+
+/*
+ * Abort a device request.
+ * If this routine is called at splusb() it guarantees that the request
+ * will be removed from the hardware scheduling and that the callback
+ * for it will be called with USBD_CANCELLED status.
+ * It's impossible to guarantee that the requested transfer will not
+ * have happened since the hardware runs concurrently.
+ * If the transaction has already happened we rely on the ordinary
+ * interrupt processing to process it.
+ */
+void
+ohci_abort_req(reqh, status)
+ usbd_request_handle reqh;
+ usbd_status status;
+{
+ struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe;
+ ohci_soft_ed_t *sed;
+
+ DPRINTF(("ohci_abort_req: reqh=%p pipe=%p\n", reqh, opipe));
+
+ reqh->status = status;
+
+ usb_untimeout(ohci_timeout, reqh, reqh->timo_handle);
+
+ sed = opipe->sed;
+ DPRINTFN(1,("ohci_abort_req: stop ed=%p\n", sed));
+ sed->ed.ed_flags |= LE(OHCI_ED_SKIP); /* force hardware skip */
+
+ if (curproc) {
+ usb_delay_ms(opipe->pipe.device->bus, 1);
+ ohci_abort_req_end(reqh);
+ } else {
+ timeout(ohci_abort_req_end, reqh, hz / USB_FRAMES_PER_SECOND);
+ }
+}
+
+void
+ohci_abort_req_end(v)
+ void *v;
+{
+ usbd_request_handle reqh = v;
+ struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe;
+ ohci_softc_t *sc = (ohci_softc_t *)opipe->pipe.device->bus;
+ ohci_soft_ed_t *sed;
+ ohci_soft_td_t *p, *n;
+ int s;
+
+ s = splusb();
+
+ p = reqh->hcpriv;
+#ifdef DIAGNOSTIC
+ if (!p) {
+ printf("ohci_abort_req: hcpriv==0\n");
+ return;
+ }
+#endif
+ for (; p->reqh == reqh; p = n) {
+ n = p->nexttd;
+ ohci_hash_rem_td(sc, p);
+ ohci_free_std(sc, p);
+ }
+
+ sed = opipe->sed;
+ DPRINTFN(2,("ohci_abort_req: set hd=%x, tl=%x\n",
+ (int)LE(p->physaddr), (int)LE(sed->ed.ed_tailp)));
+ sed->ed.ed_headp = p->physaddr; /* unlink TDs */
+ sed->ed.ed_flags &= LE(~OHCI_ED_SKIP); /* remove hardware skip */
+
+ usb_transfer_complete(reqh);
+
+ splx(s);
+}
+
+/*
* Data structures and routines to emulate the root hub.
*/
usb_device_descriptor_t ohci_devd = {
@@ -1388,7 +1524,7 @@ usb_interface_descriptor_t ohci_ifcd = {
usb_endpoint_descriptor_t ohci_endpd = {
USB_ENDPOINT_DESCRIPTOR_SIZE,
UDESC_ENDPOINT,
- UE_IN | OHCI_INTR_ENDPT,
+ UE_DIR_IN | OHCI_INTR_ENDPT,
UE_INTERRUPT,
{8, 0}, /* max packet */
255
@@ -1431,12 +1567,9 @@ usbd_status
ohci_root_ctrl_transfer(reqh)
usbd_request_handle reqh;
{
- int s;
usbd_status r;
- s = splusb();
r = usb_insert_transfer(reqh);
- splx(s);
if (r != USBD_NORMAL_COMPLETION)
return (r);
else
@@ -1449,7 +1582,7 @@ ohci_root_ctrl_start(reqh)
{
ohci_softc_t *sc = (ohci_softc_t *)reqh->pipe->device->bus;
usb_device_request_t *req;
- void *buf;
+ void *buf = NULL;
int port, i;
int len, value, index, l, totlen = 0;
usb_port_status_t ps;
@@ -1457,11 +1590,12 @@ ohci_root_ctrl_start(reqh)
usbd_status r;
u_int32_t v;
- if (!reqh->isreq)
+#ifdef DIAGNOSTIC
+ if (!(reqh->rqflags & URQ_REQUEST))
/* XXX panic */
return (USBD_INVAL);
+#endif
req = &reqh->request;
- buf = reqh->buffer;
DPRINTFN(4,("ohci_root_ctrl_control type=0x%02x request=%02x\n",
req->bmRequestType, req->bRequest));
@@ -1469,6 +1603,10 @@ ohci_root_ctrl_start(reqh)
len = UGETW(req->wLength);
value = UGETW(req->wValue);
index = UGETW(req->wIndex);
+
+ if (len != 0)
+ buf = KERNADDR(&reqh->dmabuf);
+
#define C(x,y) ((x) | ((y) << 8))
switch(C(req->bRequest, req->bmRequestType)) {
case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
@@ -1494,6 +1632,7 @@ ohci_root_ctrl_start(reqh)
goto ret;
}
totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
+ USETW(ohci_devd.idVendor, sc->sc_id_vendor);
memcpy(buf, &ohci_devd, l);
break;
case UDESC_CONFIG:
@@ -1730,8 +1869,7 @@ ohci_root_ctrl_start(reqh)
r = USBD_NORMAL_COMPLETION;
ret:
reqh->status = r;
- reqh->xfercb(reqh);
- usb_start_next(reqh->pipe);
+ usb_transfer_complete(reqh);
return (USBD_IN_PROGRESS);
}
@@ -1749,18 +1887,16 @@ ohci_root_ctrl_close(pipe)
usbd_pipe_handle pipe;
{
DPRINTF(("ohci_root_ctrl_close\n"));
+ /* Nothing to do. */
}
usbd_status
ohci_root_intr_transfer(reqh)
usbd_request_handle reqh;
{
- int s;
usbd_status r;
- s = splusb();
r = usb_insert_transfer(reqh);
- splx(s);
if (r != USBD_NORMAL_COMPLETION)
return (r);
else
@@ -1773,19 +1909,7 @@ ohci_root_intr_start(reqh)
{
usbd_pipe_handle pipe = reqh->pipe;
ohci_softc_t *sc = (ohci_softc_t *)pipe->device->bus;
- struct ohci_pipe *upipe = (struct ohci_pipe *)pipe;
- usb_dma_t *dmap;
- usbd_status r;
- int len;
- len = reqh->length;
- dmap = &upipe->u.intr.datadma;
- if (len == 0)
- return (USBD_INVAL); /* XXX should it be? */
-
- r = usb_allocmem(sc->sc_dmatag, len, 0, dmap);
- if (r != USBD_NORMAL_COMPLETION)
- return (r);
sc->sc_intrreqh = reqh;
return (USBD_IN_PROGRESS);
@@ -1805,9 +1929,10 @@ ohci_root_intr_close(pipe)
usbd_pipe_handle pipe;
{
ohci_softc_t *sc = (ohci_softc_t *)pipe->device->bus;
- sc->sc_intrreqh = 0;
DPRINTF(("ohci_root_intr_close\n"));
+
+ sc->sc_intrreqh = 0;
}
/************************/
@@ -1816,12 +1941,9 @@ usbd_status
ohci_device_ctrl_transfer(reqh)
usbd_request_handle reqh;
{
- int s;
usbd_status r;
- s = splusb();
r = usb_insert_transfer(reqh);
- splx(s);
if (r != USBD_NORMAL_COMPLETION)
return (r);
else
@@ -1835,11 +1957,13 @@ ohci_device_ctrl_start(reqh)
ohci_softc_t *sc = (ohci_softc_t *)reqh->pipe->device->bus;
usbd_status r;
- if (!reqh->isreq) {
+#ifdef DIAGNOSTIC
+ if (!(reqh->rqflags & URQ_REQUEST)) {
/* XXX panic */
printf("ohci_device_ctrl_transfer: not a request\n");
return (USBD_INVAL);
}
+#endif
r = ohci_device_request(reqh);
if (r != USBD_NORMAL_COMPLETION)
@@ -1855,9 +1979,8 @@ void
ohci_device_ctrl_abort(reqh)
usbd_request_handle reqh;
{
- /* XXX inactivate */
- usb_delay_ms(reqh->pipe->device->bus, 1); /* make sure it is donw */
- /* XXX call done */
+ DPRINTF(("ohci_device_ctrl_abort: reqh=%p\n", reqh));
+ ohci_abort_req(reqh, USBD_CANCELLED);
}
/* Close a device control pipe. */
@@ -1865,34 +1988,36 @@ void
ohci_device_ctrl_close(pipe)
usbd_pipe_handle pipe;
{
- struct ohci_pipe *opipe = (struct ohci_pipe *)pipe;
ohci_softc_t *sc = (ohci_softc_t *)pipe->device->bus;
- ohci_soft_ed_t *sed = opipe->sed;
- int s;
- s = splusb();
- sed->ed->ed_flags |= LE(OHCI_ED_SKIP);
- if ((LE(sed->ed->ed_tailp) & OHCI_TAILMASK) != LE(sed->ed->ed_headp))
- usb_delay_ms(&sc->sc_bus, 2);
- ohci_rem_ed(sed, sc->sc_ctrl_head);
- splx(s);
- ohci_free_std(sc, opipe->tail);
- ohci_free_sed(sc, opipe->sed);
- /* XXX free other resources */
+ DPRINTF(("ohci_device_ctrl_close: pipe=%p\n", pipe));
+ ohci_close_pipe(pipe, sc->sc_ctrl_head);
}
/************************/
+void
+ohci_device_clear_toggle(pipe)
+ usbd_pipe_handle pipe;
+{
+ struct ohci_pipe *opipe = (struct ohci_pipe *)pipe;
+
+ opipe->sed->ed.ed_tailp &= LE(~OHCI_TOGGLECARRY);
+}
+
+void
+ohci_noop(pipe)
+ usbd_pipe_handle pipe;
+{
+}
+
usbd_status
ohci_device_bulk_transfer(reqh)
usbd_request_handle reqh;
{
- int s;
usbd_status r;
- s = splusb();
r = usb_insert_transfer(reqh);
- splx(s);
if (r != USBD_NORMAL_COMPLETION)
return (r);
else
@@ -1909,108 +2034,111 @@ ohci_device_bulk_start(reqh)
int addr = dev->address;
ohci_soft_td_t *xfer, *tail;
ohci_soft_ed_t *sed;
- usb_dma_t *dmap;
- usbd_status r;
- int s, len, isread;
+ int s, len, isread, endpt;
- if (reqh->isreq) {
+#ifdef DIAGNOSTIC
+ if (reqh->rqflags & URQ_REQUEST) {
/* XXX panic */
- printf("ohci_device_bulk_transfer: a request\n");
+ printf("ohci_device_bulk_start: a request\n");
return (USBD_INVAL);
}
+#endif
len = reqh->length;
- dmap = &opipe->u.bulk.datadma;
- isread = reqh->pipe->endpoint->edesc->bEndpointAddress & UE_IN;
+ endpt = reqh->pipe->endpoint->edesc->bEndpointAddress;
+ isread = UE_GET_DIR(endpt) == UE_DIR_IN;
sed = opipe->sed;
- opipe->u.bulk.length = len;
+ DPRINTFN(4,("ohci_device_bulk_start: reqh=%p len=%d isread=%d "
+ "flags=%d endpt=%d\n", reqh, len, isread, reqh->flags,
+ endpt));
- r = usb_allocmem(sc->sc_dmatag, len, 0, dmap);
- if (r != USBD_NORMAL_COMPLETION)
- goto ret1;
+ opipe->u.bulk.isread = isread;
+ opipe->u.bulk.length = len;
tail = ohci_alloc_std(sc);
- if (!tail) {
- r = USBD_NOMEM;
- goto ret2;
- }
+ if (!tail)
+ return (USBD_NOMEM);
tail->reqh = 0;
/* Update device address */
- sed->ed->ed_flags = LE(
- (LE(sed->ed->ed_flags) & ~OHCI_ED_ADDRMASK) |
+ sed->ed.ed_flags = LE(
+ (LE(sed->ed.ed_flags) & ~OHCI_ED_ADDRMASK) |
OHCI_ED_SET_FA(addr));
/* Set up data transaction */
xfer = opipe->tail;
- xfer->td->td_flags = LE(
+ xfer->td.td_flags = LE(
(isread ? OHCI_TD_IN : OHCI_TD_OUT) | OHCI_TD_NOCC |
OHCI_TD_SET_DI(1) | OHCI_TD_TOGGLE_CARRY |
(reqh->flags & USBD_SHORT_XFER_OK ? OHCI_TD_R : 0));
- xfer->td->td_cbp = LE(DMAADDR(dmap));
+ xfer->td.td_cbp = LE(DMAADDR(&reqh->dmabuf));
xfer->nexttd = tail;
- xfer->td->td_nexttd = LE(tail->physaddr);
- xfer->td->td_be = LE(LE(xfer->td->td_cbp) + len - 1);
+ xfer->td.td_nexttd = LE(tail->physaddr);
+ xfer->td.td_be = LE(LE(xfer->td.td_cbp) + len - 1);
xfer->len = len;
xfer->reqh = reqh;
-
+ xfer->flags = OHCI_CALL_DONE | OHCI_SET_LEN;
reqh->hcpriv = xfer;
- if (!isread)
- memcpy(KERNADDR(dmap), reqh->buffer, len);
+ DPRINTFN(4,("ohci_device_bulk_start: ed_flags=0x%08x td_flags=0x%08x "
+ "td_cbp=0x%08x td_be=0x%08x\n",
+ (int)LE(sed->ed.ed_flags), (int)LE(xfer->td.td_flags),
+ (int)LE(xfer->td.td_cbp), (int)LE(xfer->td.td_be)));
+
+#ifdef OHCI_DEBUG
+ if (ohcidebug > 4) {
+ ohci_dump_ed(sed);
+ ohci_dump_tds(xfer);
+ }
+#endif
/* Insert ED in schedule */
s = splusb();
ohci_hash_add_td(sc, xfer);
- sed->ed->ed_tailp = LE(tail->physaddr);
+ sed->ed.ed_tailp = LE(tail->physaddr);
opipe->tail = tail;
+ sed->ed.ed_flags &= LE(~OHCI_ED_SKIP);
OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF);
if (reqh->timeout && !sc->sc_bus.use_polling) {
usb_timeout(ohci_timeout, reqh,
- MS_TO_TICKS(reqh->timeout), reqh->timeout_handle);
+ MS_TO_TICKS(reqh->timeout), reqh->timo_handle);
}
+
+#ifdef OHCI_DEBUG
+ if (ohcidebug > 5) {
+ delay(5000);
+ DPRINTF(("ohci_device_intr_transfer: status=%x\n",
+ OREAD4(sc, OHCI_COMMAND_STATUS)));
+ ohci_dump_ed(sed);
+ ohci_dump_tds(xfer);
+ }
+#endif
+
splx(s);
return (USBD_IN_PROGRESS);
-
- ret2:
- usb_freemem(sc->sc_dmatag, dmap);
- ret1:
- return (r);
}
-/* Abort a device bulk request. */
void
ohci_device_bulk_abort(reqh)
usbd_request_handle reqh;
{
-#if 0
- sed->ed->ed_flags |= LE(OHCI_ED_SKIP);
- if ((LE(sed->ed->ed_tailp) & OHCI_TAILMASK) != LE(sed->ed->ed_headp))
- usb_delay_ms(reqh->pipe->device->bus, 2);
-#endif
- /* XXX inactivate */
- usb_delay_ms(reqh->pipe->device->bus, 1); /* make sure it is done */
- /* XXX call done */
+ DPRINTF(("ohci_device_bulk_abort: reqh=%p\n", reqh));
+ ohci_abort_req(reqh, USBD_CANCELLED);
}
-/* Close a device bulk pipe. */
+/*
+ * Close a device bulk pipe.
+ */
void
ohci_device_bulk_close(pipe)
usbd_pipe_handle pipe;
{
- struct ohci_pipe *opipe = (struct ohci_pipe *)pipe;
- usbd_device_handle dev = opipe->pipe.device;
- ohci_softc_t *sc = (ohci_softc_t *)dev->bus;
- int s;
+ ohci_softc_t *sc = (ohci_softc_t *)pipe->device->bus;
- s = splusb();
- ohci_rem_ed(opipe->sed, sc->sc_bulk_head);
- splx(s);
- ohci_free_std(sc, opipe->tail);
- ohci_free_sed(sc, opipe->sed);
- /* XXX free other resources */
+ DPRINTF(("ohci_device_bulk_close: pipe=%p\n", pipe));
+ ohci_close_pipe(pipe, sc->sc_bulk_head);
}
/************************/
@@ -2019,12 +2147,9 @@ usbd_status
ohci_device_intr_transfer(reqh)
usbd_request_handle reqh;
{
- int s;
usbd_status r;
- s = splusb();
r = usb_insert_transfer(reqh);
- splx(s);
if (r != USBD_NORMAL_COMPLETION)
return (r);
else
@@ -2040,52 +2165,43 @@ ohci_device_intr_start(reqh)
ohci_softc_t *sc = (ohci_softc_t *)dev->bus;
ohci_soft_ed_t *sed = opipe->sed;
ohci_soft_td_t *xfer, *tail;
- usb_dma_t *dmap;
- usbd_status r;
int len;
int s;
- DPRINTFN(3, ("ohci_device_intr_transfer: reqh=%p buf=%p len=%d "
+ DPRINTFN(3, ("ohci_device_intr_transfer: reqh=%p len=%d "
"flags=%d priv=%p\n",
- reqh, reqh->buffer, reqh->length, reqh->flags, reqh->priv));
+ reqh, reqh->length, reqh->flags, reqh->priv));
- if (reqh->isreq)
+#ifdef DIAGNOSTIC
+ if (reqh->rqflags & URQ_REQUEST)
panic("ohci_device_intr_transfer: a request\n");
+#endif
len = reqh->length;
- dmap = &opipe->u.intr.datadma;
- if (len == 0)
- return (USBD_INVAL); /* XXX should it be? */
xfer = opipe->tail;
tail = ohci_alloc_std(sc);
- if (!tail) {
- r = USBD_NOMEM;
- goto ret1;
- }
+ if (!tail)
+ return (USBD_NOMEM);
tail->reqh = 0;
- r = usb_allocmem(sc->sc_dmatag, len, 0, dmap);
- if (r != USBD_NORMAL_COMPLETION)
- goto ret2;
-
- xfer->td->td_flags = LE(
+ xfer->td.td_flags = LE(
OHCI_TD_IN | OHCI_TD_NOCC |
OHCI_TD_SET_DI(1) | OHCI_TD_TOGGLE_CARRY);
if (reqh->flags & USBD_SHORT_XFER_OK)
- xfer->td->td_flags |= LE(OHCI_TD_R);
- xfer->td->td_cbp = LE(DMAADDR(dmap));
+ xfer->td.td_flags |= LE(OHCI_TD_R);
+ xfer->td.td_cbp = LE(DMAADDR(&reqh->dmabuf));
xfer->nexttd = tail;
- xfer->td->td_nexttd = LE(tail->physaddr);
- xfer->td->td_be = LE(LE(xfer->td->td_cbp) + len - 1);
+ xfer->td.td_nexttd = LE(tail->physaddr);
+ xfer->td.td_be = LE(LE(xfer->td.td_cbp) + len - 1);
xfer->len = len;
xfer->reqh = reqh;
-
+ xfer->flags = OHCI_CALL_DONE | OHCI_SET_LEN;
reqh->hcpriv = xfer;
#ifdef OHCI_DEBUG
if (ohcidebug > 5) {
- printf("ohci_device_intr_transfer:\n");
+ DPRINTF(("ohci_device_intr_transfer:\n"));
ohci_dump_ed(sed);
ohci_dump_tds(xfer);
}
@@ -2094,22 +2210,17 @@ ohci_device_intr_start(reqh)
/* Insert ED in schedule */
s = splusb();
ohci_hash_add_td(sc, xfer);
- sed->ed->ed_tailp = LE(tail->physaddr);
+ sed->ed.ed_tailp = LE(tail->physaddr);
opipe->tail = tail;
-#if 0
- if (reqh->timeout && !sc->sc_bus.use_polling) {
- usb_timeout(ohci_timeout, reqh,
- MS_TO_TICKS(reqh->timeout), reqh->timeout_handle);
- }
-#endif
- sed->ed->ed_flags &= LE(~OHCI_ED_SKIP);
+ sed->ed.ed_flags &= LE(~OHCI_ED_SKIP);
#if 0
+ this goes wrong if we are too slow with dumping the TDs
#ifdef OHCI_DEBUG
- if (ohcidebug > 15) {
+ if (ohcidebug > 5) {
delay(5000);
- printf("ohci_device_intr_transfer: status=%x\n",
- OREAD4(sc, OHCI_COMMAND_STATUS));
+ DPRINTF(("ohci_device_intr_transfer: status=%x\n",
+ OREAD4(sc, OHCI_COMMAND_STATUS)));
ohci_dump_ed(sed);
ohci_dump_tds(xfer);
}
@@ -2118,11 +2229,6 @@ ohci_device_intr_start(reqh)
splx(s);
return (USBD_IN_PROGRESS);
-
- ret2:
- ohci_free_std(sc, xfer);
- ret1:
- return (r);
}
/* Abort a device control request. */
@@ -2130,12 +2236,11 @@ void
ohci_device_intr_abort(reqh)
usbd_request_handle reqh;
{
- /* XXX inactivate */
- usb_delay_ms(reqh->pipe->device->bus, 1); /* make sure it is done */
if (reqh->pipe->intrreqh == reqh) {
DPRINTF(("ohci_device_intr_abort: remove\n"));
reqh->pipe->intrreqh = 0;
}
+ ohci_abort_req(reqh, USBD_CANCELLED);
}
/* Close a device interrupt pipe. */
@@ -2154,8 +2259,9 @@ ohci_device_intr_close(pipe)
DPRINTFN(1,("ohci_device_intr_close: pipe=%p nslots=%d pos=%d\n",
pipe, nslots, pos));
s = splusb();
- sed->ed->ed_flags |= LE(OHCI_ED_SKIP);
- if ((sed->ed->ed_tailp & LE(OHCI_TAILMASK)) != sed->ed->ed_headp)
+ sed->ed.ed_flags |= LE(OHCI_ED_SKIP);
+ if ((sed->ed.ed_tailp & LE(OHCI_TAILMASK)) !=
+ (sed->ed.ed_headp & LE(OHCI_TAILMASK)))
usb_delay_ms(&sc->sc_bus, 2);
for (p = sc->sc_eds[pos]; p && p->next != sed; p = p->next)
@@ -2163,15 +2269,14 @@ ohci_device_intr_close(pipe)
if (!p)
panic("ohci_device_intr_close: ED not found\n");
p->next = sed->next;
- p->ed->ed_nexted = sed->ed->ed_nexted;
+ p->ed.ed_nexted = sed->ed.ed_nexted;
splx(s);
for (j = 0; j < nslots; j++)
- --sc->sc_bws[pos * nslots + j];
+ --sc->sc_bws[(pos * nslots + j) % OHCI_NO_INTRS];
ohci_free_std(sc, opipe->tail);
ohci_free_sed(sc, opipe->sed);
- /* XXX free other resources */
}
usbd_status
@@ -2213,7 +2318,7 @@ ohci_device_setintr(sc, opipe, ival)
for (best = i = slow, bestbw = ~0; i < shigh; i++) {
bw = 0;
for (j = 0; j < nslots; j++)
- bw += sc->sc_bws[i * nslots + j];
+ bw += sc->sc_bws[(i * nslots + j) % OHCI_NO_INTRS];
if (bw < bestbw) {
best = i;
bestbw = bw;
@@ -2225,13 +2330,13 @@ ohci_device_setintr(sc, opipe, ival)
s = splusb();
hsed = sc->sc_eds[best];
sed->next = hsed->next;
- sed->ed->ed_nexted = hsed->ed->ed_nexted;
+ sed->ed.ed_nexted = hsed->ed.ed_nexted;
hsed->next = sed;
- hsed->ed->ed_nexted = LE(sed->physaddr);
+ hsed->ed.ed_nexted = LE(sed->physaddr);
splx(s);
for (j = 0; j < nslots; j++)
- ++sc->sc_bws[best * nslots + j];
+ ++sc->sc_bws[(best * nslots + j) % OHCI_NO_INTRS];
opipe->u.intr.nslots = nslots;
opipe->u.intr.pos = best;
diff --git a/sys/dev/usb/ohcireg.h b/sys/dev/usb/ohcireg.h
index c84c71e..b56b017 100644
--- a/sys/dev/usb/ohcireg.h
+++ b/sys/dev/usb/ohcireg.h
@@ -1,5 +1,5 @@
-/* $NetBSD: ohcireg.h,v 1.7 1998/12/10 23:16:47 augustss Exp $ */
-/* $FreeBSD$ */
+/* $NetBSD: ohcireg.h,v 1.8 1999/08/22 23:41:00 augustss Exp $ */
+/* $FreeBSD$ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -165,7 +165,7 @@ typedef struct {
ohci_physaddr_t ed_headp;
ohci_physaddr_t ed_nexted;
} ohci_ed_t;
-#define OHCI_ED_SIZE 16
+/* #define OHCI_ED_SIZE 16 */
#define OHCI_ED_ALIGN 16
typedef struct {
@@ -188,7 +188,7 @@ typedef struct {
ohci_physaddr_t td_nexttd; /* Next TD */
ohci_physaddr_t td_be; /* Buffer End */
} ohci_td_t;
-#define OHCI_TD_SIZE 16
+/* #define OHCI_TD_SIZE 16 */
#define OHCI_TD_ALIGN 16
#define OHCI_CC_NO_ERROR 0
diff --git a/sys/dev/usb/ohcivar.h b/sys/dev/usb/ohcivar.h
index cd0e561..b0abd15 100644
--- a/sys/dev/usb/ohcivar.h
+++ b/sys/dev/usb/ohcivar.h
@@ -1,5 +1,5 @@
-/* $NetBSD: ohcivar.h,v 1.4 1998/12/26 12:53:01 augustss Exp $ */
-/* $FreeBSD$ */
+/* $NetBSD: ohcivar.h,v 1.8 1999/08/22 23:41:00 augustss Exp $ */
+/* $FreeBSD$ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -39,23 +39,27 @@
*/
typedef struct ohci_soft_ed {
- ohci_ed_t *ed;
+ ohci_ed_t ed;
struct ohci_soft_ed *next;
ohci_physaddr_t physaddr;
} ohci_soft_ed_t;
-#define OHCI_ED_CHUNK 256
+#define OHCI_SED_SIZE ((sizeof (struct ohci_soft_ed) + OHCI_ED_ALIGN - 1) / OHCI_ED_ALIGN * OHCI_ED_ALIGN)
+#define OHCI_SED_CHUNK 128
typedef struct ohci_soft_td {
- ohci_td_t *td;
+ ohci_td_t td;
struct ohci_soft_td *nexttd; /* mirrors nexttd in TD */
struct ohci_soft_td *dnext; /* next in done list */
ohci_physaddr_t physaddr;
LIST_ENTRY(ohci_soft_td) hnext;
- /*ohci_soft_ed_t *sed;*/
usbd_request_handle reqh;
u_int16_t len;
+ u_int16_t flags;
+#define OHCI_CALL_DONE 0x0001
+#define OHCI_SET_LEN 0x0002
} ohci_soft_td_t;
-#define OHCI_TD_CHUNK 256
+#define OHCI_STD_SIZE ((sizeof (struct ohci_soft_td) + OHCI_TD_ALIGN - 1) / OHCI_TD_ALIGN * OHCI_TD_ALIGN)
+#define OHCI_STD_CHUNK 128
#define OHCI_NO_EDS (2*OHCI_NO_INTRS-1)
@@ -65,12 +69,12 @@ typedef struct ohci_softc {
struct usbd_bus sc_bus; /* base device */
bus_space_tag_t iot;
bus_space_handle_t ioh;
-#if defined(__NetBSD__)
+#if defined(__NetBSD__) || defined(__OpenBSD__)
void *sc_ih; /* interrupt vectoring */
bus_dma_tag_t sc_dmatag; /* DMA tag */
/* XXX should keep track of all DMA memory */
-#endif /* __FreeBSD__ */
+#endif /* __NetBSD__ || defined(__OpenBSD__) */
usb_dma_t sc_hccadma;
struct ohci_hcca *sc_hcca;
@@ -93,11 +97,12 @@ typedef struct ohci_softc {
usbd_request_handle sc_intrreqh;
int sc_intrs;
+
char sc_vendor[16];
+ int sc_id_vendor;
} ohci_softc_t;
usbd_status ohci_init __P((ohci_softc_t *));
int ohci_intr __P((void *));
#define MS_TO_TICKS(ms) ((ms) * hz / 1000)
-
diff --git a/sys/dev/usb/ugen.c b/sys/dev/usb/ugen.c
index 882a3a1..0b950ef 100644
--- a/sys/dev/usb/ugen.c
+++ b/sys/dev/usb/ugen.c
@@ -1,4 +1,4 @@
-/* $NetBSD: ugen.c,v 1.11 1999/01/08 11:58:25 augustss Exp $ */
+/* $NetBSD: ugen.c,v 1.23 1999/09/09 12:26:44 augustss Exp $ */
/* $FreeBSD$ */
/*
@@ -43,7 +43,7 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
-#if defined(__NetBSD__)
+#if defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/device.h>
#include <sys/ioctl.h>
#elif defined(__FreeBSD__)
@@ -54,6 +54,7 @@
#include <sys/fcntl.h>
#include <sys/filio.h>
#endif
+#include <sys/conf.h>
#include <sys/tty.h>
#include <sys/file.h>
#include <sys/select.h>
@@ -68,7 +69,7 @@
#ifdef UGEN_DEBUG
#define DPRINTF(x) if (ugendebug) logprintf x
#define DPRINTFN(n,x) if (ugendebug>(n)) logprintf x
-int ugendebug = 1;
+int ugendebug = 0;
#else
#define DPRINTF(x)
#define DPRINTFN(n,x)
@@ -79,13 +80,13 @@ struct ugen_endpoint {
usb_endpoint_descriptor_t *edesc;
usbd_interface_handle iface;
int state;
-#define UGEN_OPEN 0x01 /* device is open */
#define UGEN_ASLP 0x02 /* waiting for data */
#define UGEN_SHORT_OK 0x04 /* short xfers are OK */
usbd_pipe_handle pipeh;
struct clist q;
struct selinfo rsel;
void *ibuf;
+ u_int32_t timeout;
};
#define UGEN_CHUNK 128 /* chunk size for read */
@@ -93,23 +94,20 @@ struct ugen_endpoint {
#define UGEN_BBSIZE 1024
struct ugen_softc {
- bdevice sc_dev; /* base device */
- struct usbd_device *sc_udev;
+ USBBASEDEVICE sc_dev; /* base device */
+ usbd_device_handle sc_udev;
+ char sc_is_open[USB_MAX_ENDPOINTS][2];
struct ugen_endpoint sc_endpoints[USB_MAX_ENDPOINTS][2];
-#define OUT 0 /* index order is important, from UE_OUT */
-#define IN 1 /* from UE_IN */
+#define OUT 0
+#define IN 1
- int sc_disconnected; /* device is gone */
+ int sc_refcnt;
+ u_char sc_dying;
};
-#if defined(__NetBSD__)
-int ugenopen __P((dev_t, int, int, struct proc *));
-int ugenclose __P((dev_t, int, int, struct proc *p));
-int ugenread __P((dev_t, struct uio *uio, int));
-int ugenwrite __P((dev_t, struct uio *uio, int));
-int ugenioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
-int ugenpoll __P((dev_t, int, struct proc *));
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+cdev_decl(ugen);
#elif defined(__FreeBSD__)
d_open_t ugenopen;
d_close_t ugenclose;
@@ -140,11 +138,11 @@ static struct cdevsw ugen_cdevsw = {
void ugenintr __P((usbd_request_handle reqh, usbd_private_handle addr,
usbd_status status));
-void ugen_disco __P((void *));
-
-
-
+int ugen_do_read __P((struct ugen_softc *, int, struct uio *, int));
+int ugen_do_write __P((struct ugen_softc *, int, struct uio *, int));
+int ugen_do_ioctl __P((struct ugen_softc *, int, u_long,
+ caddr_t, int, struct proc *));
int ugen_set_config __P((struct ugen_softc *sc, int configno));
usb_config_descriptor_t *ugen_get_cdesc __P((struct ugen_softc *sc, int index,
int *lenp));
@@ -153,6 +151,7 @@ int ugen_get_alt_index __P((struct ugen_softc *sc, int ifaceidx));
#define UGENUNIT(n) ((minor(n) >> 4) & 0xf)
#define UGENENDPOINT(n) (minor(n) & 0xf)
+#define UGENDEV(u, e) (makedev(0, ((u) << 4) | (e)))
USB_DECLARE_DRIVER(ugen);
@@ -183,9 +182,10 @@ USB_ATTACH(ugen)
if (r != USBD_NORMAL_COMPLETION) {
printf("%s: setting configuration %d failed\n",
USBDEVNAME(sc->sc_dev), conf);
- sc->sc_disconnected = 1;
+ sc->sc_dying = 1;
USB_ATTACH_ERROR_RETURN;
}
+
USB_ATTACH_SUCCESS_RETURN;
}
@@ -201,6 +201,7 @@ ugen_set_config(sc, configno)
u_int8_t niface, nendpt;
int ifaceno, endptno, endpt;
usbd_status r;
+ int dir;
DPRINTFN(1,("ugen_set_config: %s to configno %d, sc=%p\n",
USBDEVNAME(sc->sc_dev), configno, sc));
@@ -226,12 +227,12 @@ ugen_set_config(sc, configno)
for (endptno = 0; endptno < nendpt; endptno++) {
ed = usbd_interface2endpoint_descriptor(iface,endptno);
endpt = ed->bEndpointAddress;
- sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)]
- [UE_GET_IN(endpt)];
+ dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
+ sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
DPRINTFN(1,("ugen_set_config: endptno %d, endpt=0x%02x"
"(%d,%d), sce=%p\n",
endptno, endpt, UE_GET_ADDR(endpt),
- UE_GET_IN(endpt), sce));
+ UE_GET_DIR(endpt), sce));
sce->sc = sc;
sce->edesc = ed;
sce->iface = iface;
@@ -240,14 +241,6 @@ ugen_set_config(sc, configno)
return (USBD_NORMAL_COMPLETION);
}
-void
-ugen_disco(p)
- void *p;
-{
- struct ugen_softc *sc = p;
- sc->sc_disconnected = 1;
-}
-
int
ugenopen(dev, flag, mode, p)
dev_t dev;
@@ -263,34 +256,38 @@ ugenopen(dev, flag, mode, p)
usbd_status r;
USB_GET_SC_OPEN(ugen, unit, sc);
- DPRINTFN(5, ("ugenopen: flag=%d, mode=%d, unit=%d endpt=%d\n",
+ DPRINTFN(5, ("ugenopen: flag=%d, mode=%d, unit=%d endpt=%d\n",
flag, mode, unit, endpt));
- if (sc->sc_disconnected)
- return (EIO);
+ if (!sc || sc->sc_dying)
+ return (ENXIO);
if (endpt == USB_CONTROL_ENDPOINT) {
- /*if ((flag & (FWRITE|FREAD)) != (FWRITE|FREAD))
- return (EACCES);*/
- sce = &sc->sc_endpoints[USB_CONTROL_ENDPOINT][OUT];
- if (sce->state & UGEN_OPEN)
+ sc->sc_is_open[USB_CONTROL_ENDPOINT][IN] = 1;
+ return (0);
+ }
+ /* Make sure there are pipes for all directions. */
+ for (dir = OUT; dir <= IN; dir++) {
+ if (sc->sc_is_open[endpt][dir])
return (EBUSY);
- } else {
- switch (flag & (FWRITE|FREAD)) {
- case FWRITE:
- dir = OUT;
- break;
- case FREAD:
- dir = IN;
- break;
- default:
- return (EACCES);
+
+ if (flag & (dir == OUT ? FWRITE : FREAD)) {
+ sce = &sc->sc_endpoints[endpt][dir];
+ if (sce == 0 || sce->edesc == 0)
+ return (ENXIO);
}
+ }
+
+ /* Actually open the pipes. */
+ /* XXX Should back out properly if it fails. */
+ for (dir = OUT; dir <= IN; dir++) {
+ if (!(flag & (dir == OUT ? FWRITE : FREAD)))
+ continue;
sce = &sc->sc_endpoints[endpt][dir];
+ sce->state = 0;
+ sce->timeout = USBD_NO_TIMEOUT;
DPRINTFN(5, ("ugenopen: sc=%p, endpt=%d, dir=%d, sce=%p\n",
sc, endpt, dir, sce));
- if (sce->state & UGEN_OPEN)
- return (EBUSY);
edesc = sce->edesc;
if (!edesc)
return (ENXIO);
@@ -299,12 +296,12 @@ ugenopen(dev, flag, mode, p)
isize = UGETW(edesc->wMaxPacketSize);
if (isize == 0) /* shouldn't happen */
return (EINVAL);
- sce->ibuf = malloc(isize, M_USB, M_WAITOK);
+ sce->ibuf = malloc(isize, M_USBDEV, M_WAITOK);
DPRINTFN(5, ("ugenopen: intr endpt=%d,isize=%d\n",
endpt, isize));
-#if defined(__NetBSD__)
- if (clalloc(&sce->q, UGEN_IBSIZE, 0) == -1)
- return (ENOMEM);
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ if (clalloc(&sce->q, UGEN_IBSIZE, 0) == -1)
+ return (ENOMEM);
#elif defined(__FreeBSD__)
clist_alloc_cblocks(&sce->q, UGEN_IBSIZE, 0);
#endif
@@ -313,15 +310,14 @@ ugenopen(dev, flag, mode, p)
USBD_SHORT_XFER_OK, &sce->pipeh, sce,
sce->ibuf, isize, ugenintr);
if (r != USBD_NORMAL_COMPLETION) {
- free(sce->ibuf, M_USB);
-#if defined(__NetBSD__)
+ free(sce->ibuf, M_USBDEV);
+#if defined(__NetBSD__) || defined(__OpenBSD__)
clfree(&sce->q);
#elif defined(__FreeBSD__)
clist_free_cblocks(&sce->q);
#endif
return (EIO);
}
- usbd_set_disco(sce->pipeh, ugen_disco, sc);
DPRINTFN(5, ("ugenopen: interrupt open done\n"));
break;
case UE_BULK:
@@ -335,8 +331,8 @@ ugenopen(dev, flag, mode, p)
case UE_ISOCHRONOUS:
return (EINVAL);
}
+ sc->sc_is_open[endpt][dir] = 1;
}
- sce->state |= UGEN_OPEN;
return (0);
}
@@ -352,52 +348,58 @@ ugenclose(dev, flag, mode, p)
struct ugen_endpoint *sce;
int dir;
- DPRINTFN(5, ("ugenclose: flag=%d, mode=%d\n", flag, mode));
+ DPRINTFN(5, ("ugenclose: flag=%d, mode=%d, unit=%d, endpt=%d\n",
+ flag, mode, UGENUNIT(dev), endpt));
- if (!sc || sc->sc_disconnected)
- return (EIO);
+#ifdef DIAGNOSTIC
+ if (!sc->sc_is_open[endpt][IN] || !sc->sc_is_open[endpt][OUT] ) {
+ printf("ugenclose: not open\n");
+ return (EINVAL);
+ }
+#endif
if (endpt == USB_CONTROL_ENDPOINT) {
DPRINTFN(5, ("ugenclose: close control\n"));
- sc->sc_endpoints[endpt][OUT].state = 0;
+ sc->sc_is_open[USB_CONTROL_ENDPOINT][IN] = 0;
return (0);
}
- flag = FWRITE | FREAD; /* XXX bug if generic open/close */
-
- /* The open modes have been joined, so check for both modes. */
for (dir = OUT; dir <= IN; dir++) {
- if (flag & (dir == OUT ? FWRITE : FREAD)) {
- sce = &sc->sc_endpoints[endpt][dir];
- if (!sce || !sce->pipeh) /* XXX */
- continue; /* XXX */
- DPRINTFN(5, ("ugenclose: endpt=%d dir=%d sce=%p\n",
- endpt, dir, sce));
- sce->state = 0;
-
- usbd_abort_pipe(sce->pipeh);
- usbd_close_pipe(sce->pipeh);
- sce->pipeh = 0;
-
- if (sce->ibuf) {
- free(sce->ibuf, M_USB);
- sce->ibuf = 0;
- }
+ if (!(flag & (dir == OUT ? FWRITE : FREAD)))
+ continue;
+ sce = &sc->sc_endpoints[endpt][dir];
+ if (!sce || !sce->pipeh)
+ continue;
+ DPRINTFN(5, ("ugenclose: endpt=%d dir=%d sce=%p\n",
+ endpt, dir, sce));
+
+ usbd_abort_pipe(sce->pipeh);
+ usbd_close_pipe(sce->pipeh);
+ sce->pipeh = 0;
+
+ if (sce->ibuf) {
+ free(sce->ibuf, M_USBDEV);
+ sce->ibuf = 0;
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ clfree(&sce->q);
+#elif defined(__FreeBSD__)
+ clist_free_cblocks(&sce->q);
+#endif
}
+ sc->sc_is_open[endpt][dir] = 0;
}
return (0);
}
int
-ugenread(dev, uio, flag)
- dev_t dev;
+ugen_do_read(sc, endpt, uio, flag)
+ struct ugen_softc *sc;
+ int endpt;
struct uio *uio;
int flag;
{
- USB_GET_SC(ugen, UGENUNIT(dev), sc);
- int endpt = UGENENDPOINT(dev);
- struct ugen_endpoint *sce;
+ struct ugen_endpoint *sce = &sc->sc_endpoints[endpt][IN];
u_int32_t n, tn;
char buf[UGEN_BBSIZE];
usbd_request_handle reqh;
@@ -406,12 +408,12 @@ ugenread(dev, uio, flag)
int error = 0;
u_char buffer[UGEN_CHUNK];
- DPRINTFN(5, ("ugenread: %d:%d\n", UGENUNIT(dev), UGENENDPOINT(dev)));
- if (!sc || sc->sc_disconnected)
+#ifdef __NetBSD__
+ DPRINTFN(5, ("ugenread: %d:%d\n", sc->sc_dev.dv_unit, endpt));
+#endif
+ if (sc->sc_dying)
return (EIO);
- sce = &sc->sc_endpoints[endpt][IN];
-
#ifdef DIAGNOSTIC
if (!sce->edesc) {
printf("ugenread: no edesc\n");
@@ -434,19 +436,19 @@ ugenread(dev, uio, flag)
}
sce->state |= UGEN_ASLP;
DPRINTFN(5, ("ugenread: sleep on %p\n", sc));
- error = tsleep((caddr_t)sce, PZERO | PCATCH,
- "ugenri", 0);
+ error = tsleep(sce, PZERO | PCATCH, "ugenri", 0);
DPRINTFN(5, ("ugenread: woke, error=%d\n", error));
+ if (sc->sc_dying)
+ error = EIO;
if (error) {
sce->state &= ~UGEN_ASLP;
- splx(s);
- return (error);
+ break;
}
}
splx(s);
/* Transfer as many chunks as possible. */
- while (sce->q.c_cc > 0 && uio->uio_resid > 0) {
+ while (sce->q.c_cc > 0 && uio->uio_resid > 0 && !error) {
n = min(sce->q.c_cc, uio->uio_resid);
if (n > sizeof(buffer))
n = sizeof(buffer);
@@ -462,18 +464,22 @@ ugenread(dev, uio, flag)
}
break;
case UE_BULK:
- reqh = usbd_alloc_request();
+ reqh = usbd_alloc_request(sc->sc_udev);
if (reqh == 0)
return (ENOMEM);
while ((n = min(UGEN_BBSIZE, uio->uio_resid)) != 0) {
- DPRINTFN(1, ("ugenread: start transfer %d bytes\n", n));
+ DPRINTFN(1, ("ugenread: start transfer %d bytes\n",n));
tn = n;
- r = usbd_bulk_transfer(reqh, sce->pipeh, 0,
- USBD_NO_TIMEOUT, buf,
- &tn, "ugenrb");
+ r = usbd_bulk_transfer(
+ reqh, sce->pipeh,
+ sce->state & UGEN_SHORT_OK ?
+ USBD_SHORT_XFER_OK : 0,
+ sce->timeout, buf, &tn, "ugenrb");
if (r != USBD_NORMAL_COMPLETION) {
if (r == USBD_INTERRUPTED)
error = EINTR;
+ else if (r == USBD_TIMEOUT)
+ error = ETIMEDOUT;
else
error = EIO;
break;
@@ -488,30 +494,43 @@ ugenread(dev, uio, flag)
default:
return (ENXIO);
}
-
return (error);
}
int
-ugenwrite(dev, uio, flag)
+ugenread(dev, uio, flag)
dev_t dev;
struct uio *uio;
int flag;
{
USB_GET_SC(ugen, UGENUNIT(dev), sc);
int endpt = UGENENDPOINT(dev);
- struct ugen_endpoint *sce;
- size_t n;
+ int error;
+
+ sc->sc_refcnt++;
+ error = ugen_do_read(sc, endpt, uio, flag);
+ if (--sc->sc_refcnt < 0)
+ usb_detach_wakeup(USBDEV(sc->sc_dev));
+ return (error);
+}
+
+int
+ugen_do_write(sc, endpt, uio, flag)
+ struct ugen_softc *sc;
+ int endpt;
+ struct uio *uio;
+ int flag;
+{
+ struct ugen_endpoint *sce = &sc->sc_endpoints[endpt][OUT];
+ u_int32_t n;
int error = 0;
char buf[UGEN_BBSIZE];
usbd_request_handle reqh;
usbd_status r;
- if (!sc || sc->sc_disconnected)
+ if (sc->sc_dying)
return (EIO);
- sce = &sc->sc_endpoints[endpt][OUT];
-
#ifdef DIAGNOSTIC
if (!sce->edesc) {
printf("ugenwrite: no edesc\n");
@@ -526,7 +545,7 @@ ugenwrite(dev, uio, flag)
DPRINTF(("ugenwrite\n"));
switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
case UE_BULK:
- reqh = usbd_alloc_request();
+ reqh = usbd_alloc_request(sc->sc_udev);
if (reqh == 0)
return (EIO);
while ((n = min(UGEN_BBSIZE, uio->uio_resid)) != 0) {
@@ -534,9 +553,8 @@ ugenwrite(dev, uio, flag)
if (error)
break;
DPRINTFN(1, ("ugenwrite: transfer %d bytes\n", n));
- r = usbd_bulk_transfer(reqh, sce->pipeh, 0,
- USBD_NO_TIMEOUT, buf,
- &n, "ugenwb");
+ r = usbd_bulk_transfer(reqh, sce->pipeh, 0,
+ sce->timeout, buf, &n,"ugenwb");
if (r != USBD_NORMAL_COMPLETION) {
if (r == USBD_INTERRUPTED)
error = EINTR;
@@ -553,6 +571,94 @@ ugenwrite(dev, uio, flag)
return (error);
}
+int
+ugenwrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ USB_GET_SC(ugen, UGENUNIT(dev), sc);
+ int endpt = UGENENDPOINT(dev);
+ int error;
+
+ sc->sc_refcnt++;
+ error = ugen_do_write(sc, endpt, uio, flag);
+ if (--sc->sc_refcnt < 0)
+ usb_detach_wakeup(USBDEV(sc->sc_dev));
+ return (error);
+}
+
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+int
+ugen_activate(self, act)
+ device_ptr_t self;
+ enum devact act;
+{
+ struct ugen_softc *sc = (struct ugen_softc *)self;
+
+ switch (act) {
+ case DVACT_ACTIVATE:
+ return (EOPNOTSUPP);
+ break;
+
+ case DVACT_DEACTIVATE:
+ sc->sc_dying = 1;
+ break;
+ }
+ return (0);
+}
+#endif
+
+USB_DETACH(ugen)
+{
+ USB_DETACH_START(ugen, sc);
+ struct ugen_endpoint *sce;
+ int i, dir;
+ int s;
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ int maj, mn;
+
+ DPRINTF(("ugen_detach: sc=%p flags=%d\n", sc, flags));
+#elif defined(__FreeBSD__)
+ DPRINTF(("ugen_detach: sc=%p\n", sc));
+#endif
+
+ sc->sc_dying = 1;
+ /* Abort all pipes. Causes processes waiting for transfer to wake. */
+ for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
+ for (dir = OUT; dir <= IN; dir++) {
+ sce = &sc->sc_endpoints[i][dir];
+ if (sce && sce->pipeh)
+ usbd_abort_pipe(sce->pipeh);
+ }
+ }
+
+ s = splusb();
+ if (--sc->sc_refcnt >= 0) {
+ /* Wake everyone */
+ for (i = 0; i < USB_MAX_ENDPOINTS; i++)
+ wakeup(&sc->sc_endpoints[i][IN]);
+ /* Wait for processes to go away. */
+ usb_detach_wait(USBDEV(sc->sc_dev));
+ }
+ splx(s);
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ /* locate the major number */
+ for (maj = 0; maj < nchrdev; maj++)
+ if (cdevsw[maj].d_open == ugenopen)
+ break;
+
+ /* Nuke the vnodes for any open instances (calls close). */
+ mn = self->dv_unit * USB_MAX_ENDPOINTS;
+ vdevgone(maj, mn, mn + USB_MAX_ENDPOINTS - 1, VCHR);
+#elif defined(__FreeBSD__)
+ /* XXX not implemented yet */
+#endif
+
+ return (0);
+}
void
ugenintr(reqh, addr, status)
@@ -562,10 +668,7 @@ ugenintr(reqh, addr, status)
{
struct ugen_endpoint *sce = addr;
/*struct ugen_softc *sc = sce->sc;*/
- usbd_private_handle priv;
- void *buffer;
u_int32_t count;
- usbd_status xstatus;
u_char *ibuf;
if (status == USBD_CANCELLED)
@@ -577,11 +680,11 @@ ugenintr(reqh, addr, status)
return;
}
- (void)usbd_get_request_status(reqh, &priv, &buffer, &count, &xstatus);
+ usbd_get_request_status(reqh, 0, 0, &count, 0);
ibuf = sce->ibuf;
DPRINTFN(5, ("ugenintr: reqh=%p status=%d count=%d\n",
- reqh, xstatus, count));
+ reqh, status, count));
DPRINTFN(5, (" data = %02x %02x %02x\n",
ibuf[0], ibuf[1], ibuf[2]));
@@ -590,7 +693,7 @@ ugenintr(reqh, addr, status)
if (sce->state & UGEN_ASLP) {
sce->state &= ~UGEN_ASLP;
DPRINTFN(5, ("ugen_intr: waking %p\n", sce));
- wakeup((caddr_t)sce);
+ wakeup(sce);
}
selwakeup(&sce->rsel);
}
@@ -605,6 +708,7 @@ ugen_set_interface(sc, ifaceidx, altno)
usbd_status r;
struct ugen_endpoint *sce;
u_int8_t niface, nendpt, endptno, endpt;
+ int dir;
DPRINTFN(15, ("ugen_set_interface %d %d\n", ifaceidx, altno));
@@ -623,7 +727,8 @@ ugen_set_interface(sc, ifaceidx, altno)
for (endptno = 0; endptno < nendpt; endptno++) {
ed = usbd_interface2endpoint_descriptor(iface,endptno);
endpt = ed->bEndpointAddress;
- sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][UE_GET_IN(endpt)];
+ dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
+ sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
sce->sc = 0;
sce->edesc = 0;
sce->iface = 0;
@@ -640,7 +745,8 @@ ugen_set_interface(sc, ifaceidx, altno)
for (endptno = 0; endptno < nendpt; endptno++) {
ed = usbd_interface2endpoint_descriptor(iface,endptno);
endpt = ed->bEndpointAddress;
- sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][UE_GET_IN(endpt)];
+ dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
+ sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
sce->sc = sc;
sce->edesc = ed;
sce->iface = iface;
@@ -700,15 +806,14 @@ ugen_get_alt_index(sc, ifaceidx)
}
int
-ugenioctl(dev, cmd, addr, flag, p)
- dev_t dev;
+ugen_do_ioctl(sc, endpt, cmd, addr, flag, p)
+ struct ugen_softc *sc;
+ int endpt;
u_long cmd;
caddr_t addr;
int flag;
struct proc *p;
{
- USB_GET_SC(ugen, UGENUNIT(dev), sc);
- int endpt = UGENENDPOINT(dev);
struct ugen_endpoint *sce;
usbd_status r;
usbd_interface_handle iface;
@@ -723,7 +828,7 @@ ugenioctl(dev, cmd, addr, flag, p)
u_int8_t conf, alt;
DPRINTFN(5, ("ugenioctl: cmd=%08lx\n", cmd));
- if (!sc || sc->sc_disconnected)
+ if (sc->sc_dying)
return (EIO);
switch (cmd) {
@@ -732,10 +837,12 @@ ugenioctl(dev, cmd, addr, flag, p)
return (0);
case USB_SET_SHORT_XFER:
/* This flag only affects read */
+ if (endpt == USB_CONTROL_ENDPOINT)
+ return (EINVAL);
sce = &sc->sc_endpoints[endpt][IN];
#ifdef DIAGNOSTIC
if (!sce->pipeh) {
- printf("ugenioctl: no pipe\n");
+ printf("ugenioctl: USB_SET_SHORT_XFER, no pipe\n");
return (EIO);
}
#endif
@@ -744,6 +851,16 @@ ugenioctl(dev, cmd, addr, flag, p)
else
sce->state &= ~UGEN_SHORT_OK;
return (0);
+ case USB_SET_TIMEOUT:
+ sce = &sc->sc_endpoints[endpt][IN];
+#ifdef DIAGNOSTIC
+ if (!sce->pipeh) {
+ printf("ugenioctl: USB_SET_TIMEOUT, no pipe\n");
+ return (EIO);
+ }
+#endif
+ sce->timeout = *(int *)addr;
+ return (0);
default:
break;
}
@@ -799,9 +916,12 @@ ugenioctl(dev, cmd, addr, flag, p)
if (!cdesc)
return (EINVAL);
idesc = usbd_find_idesc(cdesc, ai->interface_index, 0);
- if (!idesc)
+ if (!idesc) {
+ free(cdesc, M_TEMP);
return (EINVAL);
+ }
ai->alt_no = usbd_get_no_alts(cdesc, idesc->bInterfaceNumber);
+ free(cdesc, M_TEMP);
break;
case USB_GET_DEVICE_DESC:
*(usb_device_descriptor_t *)addr =
@@ -872,7 +992,11 @@ ugenioctl(dev, cmd, addr, flag, p)
uio.uio_segflg = UIO_USERSPACE;
uio.uio_rw = UIO_READ;
uio.uio_procp = p;
+#if defined(__NetBSD__) || defined(__OpenBSD__)
error = uiomove((caddr_t)cdesc, len, &uio);
+#elif defined(__FreeBSD__)
+ error = uiomove((void *)cdesc, len, &uio);
+#endif
free(cdesc, M_TEMP);
return (error);
}
@@ -927,7 +1051,7 @@ ugenioctl(dev, cmd, addr, flag, p)
}
r = usbd_do_request_flags(sc->sc_udev, &ur->request,
ptr, ur->flags, &ur->actlen);
- if (r) {
+ if (r != USBD_NORMAL_COMPLETION) {
error = EIO;
goto ret;
}
@@ -954,20 +1078,39 @@ ugenioctl(dev, cmd, addr, flag, p)
}
int
+ugenioctl(dev, cmd, addr, flag, p)
+ dev_t dev;
+ u_long cmd;
+ caddr_t addr;
+ int flag;
+ struct proc *p;
+{
+ USB_GET_SC(ugen, UGENUNIT(dev), sc);
+ int endpt = UGENENDPOINT(dev);
+ int error;
+
+ sc->sc_refcnt++;
+ error = ugen_do_ioctl(sc, endpt, cmd, addr, flag, p);
+ if (--sc->sc_refcnt < 0)
+ usb_detach_wakeup(USBDEV(sc->sc_dev));
+ return (error);
+}
+
+int
ugenpoll(dev, events, p)
dev_t dev;
int events;
struct proc *p;
{
USB_GET_SC(ugen, UGENUNIT(dev), sc);
- /* XXX */
struct ugen_endpoint *sce;
int revents = 0;
int s;
- if (!sc || sc->sc_disconnected)
+ if (sc->sc_dying)
return (EIO);
+ /* XXX always IN */
sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN];
#ifdef DIAGNOSTIC
if (!sce->edesc) {
@@ -1006,13 +1149,5 @@ ugenpoll(dev, events, p)
}
#if defined(__FreeBSD__)
-static int
-ugen_detach(device_t self)
-{
- DPRINTF(("%s: disconnected\n", USBDEVNAME(self)));
-
- return 0;
-}
-
DEV_DRIVER_MODULE(ugen, uhub, ugen_driver, ugen_devclass, ugen_cdevsw, usbd_driver_load, 0);
#endif
diff --git a/sys/dev/usb/uhci.c b/sys/dev/usb/uhci.c
index dfedf52..48e660d 100644
--- a/sys/dev/usb/uhci.c
+++ b/sys/dev/usb/uhci.c
@@ -1,4 +1,4 @@
-/* $NetBSD: uhci.c,v 1.24 1999/02/20 23:26:16 augustss Exp $ */
+/* $NetBSD: uhci.c,v 1.49 1999/09/11 08:19:26 augustss Exp $ */
/* $FreeBSD$ */
/*
@@ -40,20 +40,19 @@
/*
* USB Universal Host Controller driver.
- * Handles PIIX3 and PIIX4.
+ * Handles e.g. PIIX3 and PIIX4.
*
* Data sheets: ftp://download.intel.com/design/intarch/datashts/29055002.pdf
* ftp://download.intel.com/design/intarch/datashts/29056201.pdf
* UHCI spec: http://www.intel.com/design/usb/uhci11d.pdf
- * USB spec: http://www.usb.org/cgi-usb/mailmerge.cgi/home/usb/docs/developers/
-cgiform.tpl
+ * USB spec: http://www.usb.org/developers/data/usb11.pdf
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
-#if defined(__NetBSD__)
+#if defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/device.h>
#elif defined(__FreeBSD__)
#include <sys/module.h>
@@ -67,6 +66,7 @@ cgiform.tpl
#include <machine/bus_pio.h>
#endif
#include <machine/bus.h>
+#include <machine/endian.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
@@ -84,187 +84,176 @@ cgiform.tpl
#endif
#ifdef UHCI_DEBUG
-#define DPRINTF(x) if (uhcidebug) logprintf x
-#define DPRINTFN(n,x) if (uhcidebug>(n)) logprintf x
-int uhcidebug = 1;
+#define DPRINTF(x) if (uhcidebug) printf x
+#define DPRINTFN(n,x) if (uhcidebug>(n)) printf x
+int uhcidebug = 0;
#else
#define DPRINTF(x)
#define DPRINTFN(n,x)
#endif
+
#define MS_TO_TICKS(ms) ((ms) * hz / 1000)
+#if defined(__OpenBSD__)
+struct cfdriver uhci_cd = {
+ NULL, "uhci", DV_DULL
+};
+#endif
+
+/*
+ * The UHCI controller is little endian, so on big endian machines
+ * the data strored in memory needs to be swapped.
+ */
+#if BYTE_ORDER == BIG_ENDIAN
+#define LE(x) (bswap32(x))
+#else
+#define LE(x) (x)
+#endif
+
struct uhci_pipe {
struct usbd_pipe pipe;
uhci_intr_info_t *iinfo;
int nexttoggle;
-
+ /* Info needed for different pipe kinds. */
union {
/* Control pipe */
struct {
uhci_soft_qh_t *sqh;
usb_dma_t reqdma;
- usb_dma_t datadma;
uhci_soft_td_t *setup, *stat;
u_int length;
} ctl;
/* Interrupt pipe */
struct {
- usb_dma_t datadma;
int npoll;
uhci_soft_qh_t **qhs;
} intr;
/* Bulk pipe */
struct {
uhci_soft_qh_t *sqh;
- usb_dma_t datadma;
u_int length;
int isread;
} bulk;
/* Iso pipe */
struct iso {
- u_int bufsize;
- u_int nbuf;
- usb_dma_t *bufs;
uhci_soft_td_t **stds;
+ int next, inuse;
} iso;
} u;
};
/*
* The uhci_intr_info free list can be global since they contain
- * no dma specific data. The other free lists do.
+ * no dma specific data. The other free lists do.
*/
-LIST_HEAD(, uhci_intr_info) uhci_ii_free = LIST_HEAD_INITIALIZER(uhci_ii_free);
-
-/* initialisation */
-usbd_status uhci_init_framelist __P((uhci_softc_t *sc));
-
-/* modification of the host controller's status */
-void uhci_busreset __P((uhci_softc_t *sc));
-usbd_status uhci_run __P((uhci_softc_t *sc, int run));
-
-/* resource management */
-uhci_soft_td_t *uhci_alloc_std __P((uhci_softc_t *sc));
-void uhci_free_std __P((uhci_softc_t *sc,
- uhci_soft_td_t *std));
-usbd_status uhci_alloc_std_chain __P((uhci_softc_t *sc,
- struct uhci_pipe *upipe,
- int datalen, int isread, int spd,
- usb_dma_t *dma,
- uhci_soft_td_t **std,
- uhci_soft_td_t **stdend));
-void uhci_free_std_chain __P((uhci_softc_t *sc,
- uhci_soft_td_t *std,
- uhci_soft_td_t *stdend));
-uhci_soft_qh_t *uhci_alloc_sqh __P((uhci_softc_t *sc));
-void uhci_free_sqh __P((uhci_softc_t *sc,
- uhci_soft_qh_t *sqh));
-uhci_intr_info_t *uhci_alloc_intr_info __P((uhci_softc_t *sc));
-void uhci_free_intr_info __P((uhci_intr_info_t *ii));
-
-/* locking of the framelist */
-void uhci_lock_frames __P((uhci_softc_t *sc));
-void uhci_unlock_frames __P((uhci_softc_t *sc));
-
-/* handling of interrupts */
-void uhci_poll __P((struct usbd_bus *bus));
-void uhci_waitintr __P((uhci_softc_t *sc,
- usbd_request_handle reqh));
-void uhci_timeout __P((void *priv));
-
-/* check the list of TDs for an interrupt */
-void uhci_check_intr __P((uhci_softc_t *sc,
- uhci_intr_info_t *ii));
-
-/* handle a completed request */
-void uhci_ii_done __P((uhci_intr_info_t *ii, int timedout));
-void uhci_ctrl_done __P((uhci_intr_info_t *ii));
-void uhci_bulk_done __P((uhci_intr_info_t *ii));
-void uhci_intr_done __P((uhci_intr_info_t *ii));
-void uhci_isoc_done __P((uhci_intr_info_t *ii));
-
-/* pipe methods for devices and root hub; the latter doesn't use iso or bulk */
-usbd_status uhci_open __P((usbd_pipe_handle pipe));
-
-usbd_status uhci_device_request __P((usbd_request_handle reqh));
-
-usbd_status uhci_device_ctrl_transfer __P((usbd_request_handle reqh));
-usbd_status uhci_device_ctrl_start __P((usbd_request_handle reqh));
-void uhci_device_ctrl_abort __P((usbd_request_handle reqh));
-void uhci_device_ctrl_close __P((usbd_pipe_handle pipe));
-
-usbd_status uhci_device_bulk_transfer __P((usbd_request_handle reqh));
-usbd_status uhci_device_bulk_start __P((usbd_request_handle reqh));
-void uhci_device_bulk_abort __P((usbd_request_handle reqh));
-void uhci_device_bulk_close __P((usbd_pipe_handle pipe));
-
-usbd_status uhci_device_intr_transfer __P((usbd_request_handle reqh));
-usbd_status uhci_device_intr_start __P((usbd_request_handle reqh));
-void uhci_device_intr_abort __P((usbd_request_handle reqh));
-void uhci_device_intr_close __P((usbd_pipe_handle pipe));
-usbd_status uhci_device_intr_interval __P((uhci_softc_t *sc,
- struct uhci_pipe *upipe,
- int ival));
-
-usbd_status uhci_device_isoc_transfer __P((usbd_request_handle reqh));
-usbd_status uhci_device_isoc_start __P((usbd_request_handle reqh));
-void uhci_device_isoc_abort __P((usbd_request_handle reqh));
-void uhci_device_isoc_close __P((usbd_pipe_handle pipe));
-usbd_status uhci_device_isoc_setbuf __P((usbd_pipe_handle pipe,
- u_int bufsize, u_int nbuf));
-
-usbd_status uhci_root_ctrl_transfer __P((usbd_request_handle reqh));
-usbd_status uhci_root_ctrl_start __P((usbd_request_handle reqh));
-void uhci_root_ctrl_abort __P((usbd_request_handle reqh));
-void uhci_root_ctrl_close __P((usbd_pipe_handle pipe));
-
-usbd_status uhci_root_intr_transfer __P((usbd_request_handle reqh));
-usbd_status uhci_root_intr_start __P((usbd_request_handle reqh));
-void uhci_root_intr_abort __P((usbd_request_handle reqh));
-void uhci_root_intr_close __P((usbd_pipe_handle pipe));
-void uhci_root_intr_sim __P((void *priv));
-
-
-void uhci_add_ctrl __P((uhci_softc_t *sc, uhci_soft_qh_t *sqh));
-void uhci_remove_ctrl __P((uhci_softc_t *sc, uhci_soft_qh_t *sqh));
-
-void uhci_add_bulk __P((uhci_softc_t *sc, uhci_soft_qh_t *sqh));
-void uhci_remove_bulk __P((uhci_softc_t *sc, uhci_soft_qh_t *sqh));
-
-void uhci_add_intr __P((uhci_softc_t *, int pos, uhci_soft_qh_t *sqh));
-void uhci_remove_intr __P((uhci_softc_t *, int pos, uhci_soft_qh_t *sqh));
-/* isochroneous mode transfers not yet supported */
-
-/* the simulated root hub */
-usbd_status uhci_roothub_ctrl_transfer __P((uhci_softc_t *sc,
- usb_device_request_t *req,
- void *buf, int *actlen));
-usbd_status uhci_roothub_intr_transfer __P((uhci_softc_t *sc,
- u_int8_t *buf, int buflen, int *actlen));
-int uhci_roothub_string_descriptor __P((usb_string_descriptor_t *sd,
- int datalen, char *string));
+LIST_HEAD(, uhci_intr_info) uhci_ii_free;
+
+void uhci_busreset __P((uhci_softc_t *));
+void uhci_power __P((int, void *));
+usbd_status uhci_run __P((uhci_softc_t *, int run));
+uhci_soft_td_t *uhci_alloc_std __P((uhci_softc_t *));
+void uhci_free_std __P((uhci_softc_t *, uhci_soft_td_t *));
+uhci_soft_qh_t *uhci_alloc_sqh __P((uhci_softc_t *));
+void uhci_free_sqh __P((uhci_softc_t *, uhci_soft_qh_t *));
+uhci_intr_info_t *uhci_alloc_intr_info __P((uhci_softc_t *));
+void uhci_free_intr_info __P((uhci_intr_info_t *ii));
+#if 0
+void uhci_enter_ctl_q __P((uhci_softc_t *, uhci_soft_qh_t *,
+ uhci_intr_info_t *));
+void uhci_exit_ctl_q __P((uhci_softc_t *, uhci_soft_qh_t *));
+#endif
+
+void uhci_free_std_chain __P((uhci_softc_t *,
+ uhci_soft_td_t *, uhci_soft_td_t *));
+usbd_status uhci_alloc_std_chain __P((struct uhci_pipe *, uhci_softc_t *,
+ int, int, int, usb_dma_t *,
+ uhci_soft_td_t **,
+ uhci_soft_td_t **));
+void uhci_timo __P((void *));
+void uhci_waitintr __P((uhci_softc_t *, usbd_request_handle));
+void uhci_check_intr __P((uhci_softc_t *, uhci_intr_info_t *));
+void uhci_idone __P((uhci_intr_info_t *));
+void uhci_abort_req __P((usbd_request_handle, usbd_status status));
+void uhci_abort_req_end __P((void *v));
+void uhci_timeout __P((void *));
+void uhci_wakeup_ctrl __P((void *, int, int, void *, int));
+void uhci_lock_frames __P((uhci_softc_t *));
+void uhci_unlock_frames __P((uhci_softc_t *));
+void uhci_add_ctrl __P((uhci_softc_t *, uhci_soft_qh_t *));
+void uhci_add_bulk __P((uhci_softc_t *, uhci_soft_qh_t *));
+void uhci_remove_ctrl __P((uhci_softc_t *, uhci_soft_qh_t *));
+void uhci_remove_bulk __P((uhci_softc_t *, uhci_soft_qh_t *));
+int uhci_str __P((usb_string_descriptor_t *, int, char *));
+usbd_status uhci_setup_isoc __P((usbd_pipe_handle pipe));
+void uhci_device_isoc_enter __P((usbd_request_handle));
+
+void uhci_wakeup_cb __P((usbd_request_handle reqh));
+
+usbd_status uhci_allocm __P((struct usbd_bus *, usb_dma_t *, u_int32_t));
+void uhci_freem __P((struct usbd_bus *, usb_dma_t *));
+
+usbd_status uhci_device_ctrl_transfer __P((usbd_request_handle));
+usbd_status uhci_device_ctrl_start __P((usbd_request_handle));
+void uhci_device_ctrl_abort __P((usbd_request_handle));
+void uhci_device_ctrl_close __P((usbd_pipe_handle));
+void uhci_device_ctrl_done __P((usbd_request_handle));
+
+usbd_status uhci_device_intr_transfer __P((usbd_request_handle));
+usbd_status uhci_device_intr_start __P((usbd_request_handle));
+void uhci_device_intr_abort __P((usbd_request_handle));
+void uhci_device_intr_close __P((usbd_pipe_handle));
+void uhci_device_intr_done __P((usbd_request_handle));
+
+usbd_status uhci_device_bulk_transfer __P((usbd_request_handle));
+usbd_status uhci_device_bulk_start __P((usbd_request_handle));
+void uhci_device_bulk_abort __P((usbd_request_handle));
+void uhci_device_bulk_close __P((usbd_pipe_handle));
+void uhci_device_bulk_done __P((usbd_request_handle));
+
+usbd_status uhci_device_isoc_transfer __P((usbd_request_handle));
+usbd_status uhci_device_isoc_start __P((usbd_request_handle));
+void uhci_device_isoc_abort __P((usbd_request_handle));
+void uhci_device_isoc_close __P((usbd_pipe_handle));
+void uhci_device_isoc_done __P((usbd_request_handle));
+
+usbd_status uhci_root_ctrl_transfer __P((usbd_request_handle));
+usbd_status uhci_root_ctrl_start __P((usbd_request_handle));
+void uhci_root_ctrl_abort __P((usbd_request_handle));
+void uhci_root_ctrl_close __P((usbd_pipe_handle));
+
+usbd_status uhci_root_intr_transfer __P((usbd_request_handle));
+usbd_status uhci_root_intr_start __P((usbd_request_handle));
+void uhci_root_intr_abort __P((usbd_request_handle));
+void uhci_root_intr_close __P((usbd_pipe_handle));
+void uhci_root_intr_done __P((usbd_request_handle));
+
+usbd_status uhci_open __P((usbd_pipe_handle));
+void uhci_poll __P((struct usbd_bus *));
+
+usbd_status uhci_device_request __P((usbd_request_handle reqh));
+
+void uhci_add_intr __P((uhci_softc_t *, int, uhci_soft_qh_t *));
+void uhci_remove_intr __P((uhci_softc_t *, int, uhci_soft_qh_t *));
+usbd_status uhci_device_setintr __P((uhci_softc_t *sc,
+ struct uhci_pipe *pipe, int ival));
+
+void uhci_device_clear_toggle __P((usbd_pipe_handle pipe));
+void uhci_noop __P((usbd_pipe_handle pipe));
#ifdef UHCI_DEBUG
-void uhci_dumpregs __P((uhci_softc_t *));
+static void uhci_dumpregs __P((uhci_softc_t *));
void uhci_dump_tds __P((uhci_soft_td_t *));
void uhci_dump_qh __P((uhci_soft_qh_t *));
void uhci_dump __P((void));
void uhci_dump_td __P((uhci_soft_td_t *));
#endif
-#if defined(__NetBSD__)
-#define UWRITE2(sc, r, x) bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x))
-#define UWRITE4(sc, r, x) bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x))
-#define UREAD2(sc, r) bus_space_read_2((sc)->iot, (sc)->ioh, (r))
-#define UREAD4(sc, r) bus_space_read_4((sc)->iot, (sc)->ioh, (r))
-#elif defined(__FreeBSD__)
#define UWRITE2(sc, r, x) bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x))
#define UWRITE4(sc, r, x) bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x))
#define UREAD1(sc, r) bus_space_read_1((sc)->iot, (sc)->ioh, (r))
#define UREAD2(sc, r) bus_space_read_2((sc)->iot, (sc)->ioh, (r))
#define UREAD4(sc, r) bus_space_read_4((sc)->iot, (sc)->ioh, (r))
-#endif
#define UHCICMD(sc, cmd) UWRITE2(sc, UHCI_CMD, cmd)
#define UHCISTS(sc) UREAD2(sc, UHCI_STS)
@@ -275,340 +264,572 @@ void uhci_dump_td __P((uhci_soft_td_t *));
#define UHCI_INTR_ENDPT 1
+struct usbd_bus_methods uhci_bus_methods = {
+ uhci_open,
+ uhci_poll,
+ uhci_allocm,
+ uhci_freem,
+};
+struct usbd_pipe_methods uhci_root_ctrl_methods = {
+ uhci_root_ctrl_transfer,
+ uhci_root_ctrl_start,
+ uhci_root_ctrl_abort,
+ uhci_root_ctrl_close,
+ uhci_noop,
+ 0,
+};
-usbd_status
-uhci_init(uhci_softc_t *sc)
-{
- usbd_status err;
- usb_dma_t dma;
-
- DPRINTFN(1,("uhci_init: start\n"));
-
- uhci_run(sc, 0); /* stop the controller */
-#if defined(__NetBSD__)
- UWRITE2(sc, UHCI_INTR, 0); /* disable interrupts */
-#elif defined(__FreeBSD__)
- /*
- * FreeBSD does this in the probe of the chip. Otherwise we
- * get spurious interrupts
- */
-#endif
-
- uhci_busreset(sc);
-
- /* Allocate and initialize real frame array. */
- err = usb_allocmem(sc->sc_dmatag,
- UHCI_FRAMELIST_COUNT * sizeof(uhci_physaddr_t),
- UHCI_FRAMELIST_ALIGN, &dma);
- if (err)
- return(err);
+struct usbd_pipe_methods uhci_root_intr_methods = {
+ uhci_root_intr_transfer,
+ uhci_root_intr_start,
+ uhci_root_intr_abort,
+ uhci_root_intr_close,
+ uhci_noop,
+ uhci_root_intr_done,
+};
- sc->sc_pframes = KERNADDR(&dma);
- sc->sc_flbase = DMAADDR(&dma);
+struct usbd_pipe_methods uhci_device_ctrl_methods = {
+ uhci_device_ctrl_transfer,
+ uhci_device_ctrl_start,
+ uhci_device_ctrl_abort,
+ uhci_device_ctrl_close,
+ uhci_noop,
+ uhci_device_ctrl_done,
+};
- err = uhci_init_framelist(sc);
- if (err) {
- usb_freemem(sc->sc_dmatag, &dma);
- return(err);
- }
+struct usbd_pipe_methods uhci_device_intr_methods = {
+ uhci_device_intr_transfer,
+ uhci_device_intr_start,
+ uhci_device_intr_abort,
+ uhci_device_intr_close,
+ uhci_device_clear_toggle,
+ uhci_device_intr_done,
+};
- LIST_INIT(&sc->sc_intrhead);
+struct usbd_pipe_methods uhci_device_bulk_methods = {
+ uhci_device_bulk_transfer,
+ uhci_device_bulk_start,
+ uhci_device_bulk_abort,
+ uhci_device_bulk_close,
+ uhci_device_clear_toggle,
+ uhci_device_bulk_done,
+};
- /* Set up the bus struct. */
- sc->sc_bus.open_pipe = uhci_open;
- sc->sc_bus.pipe_size = sizeof(struct uhci_pipe);
- sc->sc_bus.do_poll = uhci_poll;
+struct usbd_pipe_methods uhci_device_isoc_methods = {
+ uhci_device_isoc_transfer,
+ uhci_device_isoc_start,
+ uhci_device_isoc_abort,
+ uhci_device_isoc_close,
+ uhci_noop,
+ uhci_device_isoc_done,
+};
- DPRINTFN(1,("uhci_init: enabling\n"));
- return uhci_reset(sc);
+void
+uhci_busreset(sc)
+ uhci_softc_t *sc;
+{
+ UHCICMD(sc, UHCI_CMD_GRESET); /* global reset */
+ usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); /* wait a little */
+ UHCICMD(sc, 0); /* do nothing */
}
usbd_status
-uhci_init_framelist(uhci_softc_t *sc)
+uhci_init(sc)
+ uhci_softc_t *sc;
{
+ usbd_status r;
+ int i, j;
uhci_soft_qh_t *csqh, *bsqh, *sqh;
uhci_soft_td_t *std;
- int i, j;
- /* see uhcivar.h for an explanation of the queuing used */
+ DPRINTFN(1,("uhci_init: start\n"));
+
+#ifdef UHCI_DEBUG
+ if (uhcidebug > 2)
+ uhci_dumpregs(sc);
+#endif
+
+ uhci_run(sc, 0); /* stop the controller */
+ UWRITE2(sc, UHCI_INTR, 0); /* disable interrupts */
+
+ uhci_busreset(sc);
- /* Allocate the QH where bulk traffic will be queued. */
+ /* Allocate and initialize real frame array. */
+ r = usb_allocmem(sc->sc_dmatag,
+ UHCI_FRAMELIST_COUNT * sizeof(uhci_physaddr_t),
+ UHCI_FRAMELIST_ALIGN, &sc->sc_dma);
+ if (r != USBD_NORMAL_COMPLETION)
+ return (r);
+ sc->sc_pframes = KERNADDR(&sc->sc_dma);
+ UWRITE2(sc, UHCI_FRNUM, 0); /* set frame number to 0 */
+ UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma)); /* set frame list*/
+
+ /* Allocate the dummy QH where bulk traffic will be queued. */
bsqh = uhci_alloc_sqh(sc);
if (!bsqh)
- return(USBD_NOMEM);
- bsqh->qh->qh_hlink = UHCI_PTR_T; /* end of QH chain */
- bsqh->qh->qh_elink = UHCI_PTR_T;
+ return (USBD_NOMEM);
+ bsqh->qh.qh_hlink = LE(UHCI_PTR_T); /* end of QH chain */
+ bsqh->qh.qh_elink = LE(UHCI_PTR_T);
sc->sc_bulk_start = sc->sc_bulk_end = bsqh;
- /* Allocate the QH where control traffic will be queued. */
+ /* Allocate the dummy QH where control traffic will be queued. */
csqh = uhci_alloc_sqh(sc);
- if (!csqh) {
- uhci_free_sqh(sc, bsqh);
- return(USBD_NOMEM);
- }
- csqh->qh->hlink = bsqh; /* link to bulk QH */
- csqh->qh->qh_hlink = bsqh->physaddr | UHCI_PTR_Q;
- csqh->qh->qh_elink = UHCI_PTR_T;
+ if (!csqh)
+ return (USBD_NOMEM);
+ csqh->hlink = bsqh;
+ csqh->qh.qh_hlink = LE(bsqh->physaddr | UHCI_PTR_Q);
+ csqh->qh.qh_elink = LE(UHCI_PTR_T);
sc->sc_ctl_start = sc->sc_ctl_end = csqh;
/*
* Make all (virtual) frame list pointers point to the interrupt
- * queue heads and the interrupt queue heads point to the control
- * queue head. Insert the elements for the virtual frame list multiple
- * times in the physical framelist
- * (UHCI_FRAMELIST_COUNT/UHCI_VFRAMELIST_COUNT times).
+ * queue heads and the interrupt queue heads at the control
+ * queue head and point the physical frame list to the virtual.
*/
for(i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
- /* Allocate the iso TD and the interrupt QH */
std = uhci_alloc_std(sc);
sqh = uhci_alloc_sqh(sc);
- if (!std || !sqh) {
- /* not allocated -> free the lot we've done previously */
- if (std)
- uhci_free_std(sc, std);
- for (i--; i >= 0; i--) {
- std = sc->sc_vframes[i].htd;
- sqh = std->td->link.sqh;
- uhci_free_sqh(sc, sqh);
- uhci_free_std(sc, std);
- }
- uhci_free_sqh(sc, csqh);
- uhci_free_sqh(sc, bsqh);
- return(USBD_NOMEM);
- }
-
- /* QH for interrupt transfers */
- sqh->qh->hlink = csqh; /* link to control QH */
- sqh->qh->qh_hlink = csqh->physaddr | UHCI_PTR_Q;
- sqh->qh->elink = NULL;
- sqh->qh->qh_elink = UHCI_PTR_T;
-
- /* dummy TD for isochroneous transfers */
- std->td->link.sqh = sqh; /* link to inter. QH */
- std->td->td_link = sqh->physaddr | UHCI_PTR_Q;
- std->td->td_status = UHCI_TD_IOS; /* iso, inactive */
- std->td->td_token = 0;
- std->td->td_buffer = NULL;
-
- /* enter the iso TD in the virtual frame list */
+ if (!std || !sqh)
+ return (USBD_NOMEM);
+ std->link.sqh = sqh;
+ std->td.td_link = LE(sqh->physaddr | UHCI_PTR_Q);
+ std->td.td_status = LE(UHCI_TD_IOS); /* iso, inactive */
+ std->td.td_token = LE(0);
+ std->td.td_buffer = LE(0);
+ sqh->hlink = csqh;
+ sqh->qh.qh_hlink = LE(csqh->physaddr | UHCI_PTR_Q);
+ sqh->elink = 0;
+ sqh->qh.qh_elink = LE(UHCI_PTR_T);
sc->sc_vframes[i].htd = std;
sc->sc_vframes[i].etd = std;
sc->sc_vframes[i].hqh = sqh;
sc->sc_vframes[i].eqh = sqh;
-
- /*
- * copy the entry in the virtual frame list
- * UHCI_FRAMELIST_COUNT/UHCI_VFRAMELIST_COUNT times
- */
-
for (j = i;
j < UHCI_FRAMELIST_COUNT;
j += UHCI_VFRAMELIST_COUNT)
- sc->sc_pframes[j] = std->physaddr;
+ sc->sc_pframes[j] = LE(std->physaddr);
}
- return(USBD_NORMAL_COMPLETION);
-}
+ LIST_INIT(&sc->sc_intrhead);
-void
-uhci_busreset(sc)
- uhci_softc_t *sc;
-{
- UHCICMD(sc, UHCI_CMD_GRESET); /* global reset */
- usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); /* wait a little */
- UHCICMD(sc, 0); /* do nothing */
+ /* Set up the bus struct. */
+ sc->sc_bus.methods = &uhci_bus_methods;
+ sc->sc_bus.pipe_size = sizeof(struct uhci_pipe);
+
+#if defined(__NetBSD__)
+ sc->sc_suspend = PWR_RESUME;
+ powerhook_establish(uhci_power, sc);
+#endif
+
+ DPRINTFN(1,("uhci_init: enabling\n"));
+ UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE |
+ UHCI_INTR_IOCE | UHCI_INTR_SPIE); /* enable interrupts */
+
+ return (uhci_run(sc, 1)); /* and here we go... */
}
usbd_status
-uhci_reset(sc)
- uhci_softc_t *sc;
+uhci_allocm(bus, dma, size)
+ struct usbd_bus *bus;
+ usb_dma_t *dma;
+ u_int32_t size;
{
- int n;
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ struct uhci_softc *sc = (struct uhci_softc *)bus;
+#endif
- /* Reset the host controller */
+ return (usb_allocmem(sc->sc_dmatag, size, 0, dma));
+}
- UHCICMD(sc, UHCI_CMD_HCRESET);
- /* The reset bit goes low when the controller is done. */
- for (n = 0; n < UHCI_RESET_TIMEOUT &&
- (UREAD2(sc, UHCI_CMD) & UHCI_CMD_HCRESET); n++)
- delay(100);
- if (n >= UHCI_RESET_TIMEOUT)
- printf("%s: controller did not reset\n",
- USBDEVNAME(sc->sc_bus.bdev));
- UWRITE2(sc, UHCI_FRNUM, 0); /* set frame number to 0 */
- UWRITE4(sc, UHCI_FLBASEADDR, sc->sc_flbase); /* set frame list address */
- UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE |
- UHCI_INTR_IOCE | UHCI_INTR_SPIE); /* enable interrupts */
+void
+uhci_freem(bus, dma)
+ struct usbd_bus *bus;
+ usb_dma_t *dma;
+{
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ struct uhci_softc *sc = (struct uhci_softc *)bus;
+#endif
- return(uhci_run(sc, 1)); /* and here we go... */
+ usb_freemem(sc->sc_dmatag, dma);
}
-usbd_status
-uhci_run(sc, run)
- uhci_softc_t *sc;
- int run;
+#if defined(__NetBSD__)
+/*
+ * Handle suspend/resume.
+ *
+ * We need to switch to polling mode here, because this routine is
+ * called from an intterupt context. This is all right since we
+ * are almost suspended anyway.
+ */
+void
+uhci_power(why, v)
+ int why;
+ void *v;
{
- int s, n, running;
+ uhci_softc_t *sc = v;
+ int cmd;
+ int s;
s = splusb();
- running = ((UREAD2(sc, UHCI_STS) & UHCI_STS_HCH) == 0);
- if (run == running) {
- splx(s);
- return(USBD_NORMAL_COMPLETION);
- }
- UWRITE2(sc, UHCI_CMD, run ? UHCI_CMD_RS : 0);
- for(n = 0; n < 10; n++) {
- running = ((UREAD2(sc, UHCI_STS) & UHCI_STS_HCH) == 0);
- /* return when we've entered the state we want */
- if (run == running) {
- splx(s);
- return(USBD_NORMAL_COMPLETION);
- }
- usb_delay_ms(&sc->sc_bus, 1);
+ cmd = UREAD2(sc, UHCI_CMD);
+
+ DPRINTF(("uhci_power: sc=%p, why=%d (was %d), cmd=0x%x\n",
+ sc, why, sc->sc_suspend, cmd));
+
+ if (why != PWR_RESUME) {
+#ifdef UHCI_DEBUG
+ if (uhcidebug > 2)
+ uhci_dumpregs(sc);
+#endif
+ if (sc->sc_has_timo)
+ usb_untimeout(uhci_timo, sc->sc_has_timo,
+ sc->sc_has_timo->timo_handle);
+ sc->sc_bus.use_polling = 1;
+ uhci_run(sc, 0); /* stop the controller */
+ UHCICMD(sc, cmd | UHCI_CMD_EGSM); /* enter global suspend */
+ usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT);
+ sc->sc_suspend = why;
+ DPRINTF(("uhci_power: cmd=0x%x\n", UREAD2(sc, UHCI_CMD)));
+ } else {
+ /*
+ * XXX We should really do much more here in case the
+ * controller registers have been lost and BIOS has
+ * not restored them.
+ */
+ sc->sc_suspend = why;
+ if (cmd & UHCI_CMD_RS)
+ uhci_run(sc, 0); /* in case BIOS has started it */
+ UHCICMD(sc, cmd | UHCI_CMD_FGR); /* force global resume */
+ usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY);
+ UHCICMD(sc, cmd & ~UHCI_CMD_EGSM); /* back to normal */
+ UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE |
+ UHCI_INTR_IOCE | UHCI_INTR_SPIE); /* re-enable intrs */
+ uhci_run(sc, 1); /* and start traffic again */
+ usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY);
+ sc->sc_bus.use_polling = 0;
+ if (sc->sc_has_timo)
+ usb_timeout(uhci_timo, sc->sc_has_timo,
+ sc->sc_ival, sc->sc_has_timo->timo_handle);
+#ifdef UHCI_DEBUG
+ if (uhcidebug > 2)
+ uhci_dumpregs(sc);
+#endif
}
splx(s);
- printf("%s: cannot %s\n", USBDEVNAME(sc->sc_bus.bdev),
- run ? "start" : "stop");
- return(USBD_IOERROR);
}
+#endif /* !defined(__OpenBSD__) */
+#ifdef UHCI_DEBUG
+static void
+uhci_dumpregs(sc)
+ uhci_softc_t *sc;
+{
+ DPRINTFN(-1,("%s regs: cmd=%04x, sts=%04x, intr=%04x, frnum=%04x, "
+ "flbase=%08x, sof=%04x, portsc1=%04x, portsc2=%04x\n",
+ USBDEVNAME(sc->sc_bus.bdev),
+ UREAD2(sc, UHCI_CMD),
+ UREAD2(sc, UHCI_STS),
+ UREAD2(sc, UHCI_INTR),
+ UREAD2(sc, UHCI_FRNUM),
+ UREAD4(sc, UHCI_FLBASEADDR),
+ UREAD1(sc, UHCI_SOF),
+ UREAD2(sc, UHCI_PORTSC1),
+ UREAD2(sc, UHCI_PORTSC2)));
+}
-/*
- * check whether the host controller has flagged an
- * interrupt.
- */
void
-uhci_poll(bus)
- struct usbd_bus *bus;
+uhci_dump_td(p)
+ uhci_soft_td_t *p;
{
- uhci_softc_t *sc = (uhci_softc_t *)bus;
+ DPRINTFN(-1,("TD(%p) at %08lx = link=0x%08lx status=0x%08lx "
+ "token=0x%08lx buffer=0x%08lx\n",
+ p, (long)p->physaddr,
+ (long)LE(p->td.td_link),
+ (long)LE(p->td.td_status),
+ (long)LE(p->td.td_token),
+ (long)LE(p->td.td_buffer)));
+ DPRINTFN(-1,(" %b %b,errcnt=%d,actlen=%d pid=%02x,addr=%d,endpt=%d,"
+ "D=%d,maxlen=%d\n",
+ (int)LE(p->td.td_link),
+ "\20\1T\2Q\3VF",
+ (int)LE(p->td.td_status),
+ "\20\22BITSTUFF\23CRCTO\24NAK\25BABBLE\26DBUFFER\27"
+ "STALLED\30ACTIVE\31IOC\32ISO\33LS\36SPD",
+ UHCI_TD_GET_ERRCNT(LE(p->td.td_status)),
+ UHCI_TD_GET_ACTLEN(LE(p->td.td_status)),
+ UHCI_TD_GET_PID(LE(p->td.td_token)),
+ UHCI_TD_GET_DEVADDR(LE(p->td.td_token)),
+ UHCI_TD_GET_ENDPT(LE(p->td.td_token)),
+ UHCI_TD_GET_DT(LE(p->td.td_token)),
+ UHCI_TD_GET_MAXLEN(LE(p->td.td_token))));
+}
- if (UREAD2(sc, UHCI_STS) & UHCI_STS_USBINT)
- uhci_intr(sc);
+void
+uhci_dump_qh(p)
+ uhci_soft_qh_t *p;
+{
+ DPRINTFN(-1,("QH(%p) at %08x: hlink=%08x elink=%08x\n", p,
+ (int)p->physaddr, LE(p->qh.qh_hlink), LE(p->qh.qh_elink)));
}
+
+#if 0
+void
+uhci_dump()
+{
+ uhci_softc_t *sc = uhci;
+
+ uhci_dumpregs(sc);
+ printf("intrs=%d\n", sc->sc_intrs);
+ printf("framelist[i].link = %08x\n", sc->sc_framelist[0].link);
+ uhci_dump_qh(sc->sc_ctl_start->qh.hlink);
+}
+#endif
+
+void
+uhci_dump_tds(std)
+ uhci_soft_td_t *std;
+{
+ uhci_soft_td_t *p;
+
+ for(p = std; p; p = p->link.std)
+ uhci_dump_td(p);
+}
+#endif
+
/*
- * Wait here until controller claims to have an interrupt.
- * Then call uhci_intr and return. Use timeout to avoid waiting
- * too long.
- * Only used during boot when interrupts are not enabled yet.
- * XXX this function is not re-entrant *
+ * This routine is executed periodically and simulates interrupts
+ * from the root controller interrupt pipe for port status change.
*/
void
-uhci_waitintr(sc, reqh)
- uhci_softc_t *sc;
+uhci_timo(addr)
+ void *addr;
+{
+ usbd_request_handle reqh = addr;
+ usbd_pipe_handle pipe = reqh->pipe;
+ uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;
+ int s;
+ u_char *p;
+
+ DPRINTFN(15, ("uhci_timo\n"));
+
+ usb_timeout(uhci_timo, reqh, sc->sc_ival, reqh->timo_handle);
+
+ p = KERNADDR(&reqh->dmabuf);
+ p[0] = 0;
+ if (UREAD2(sc, UHCI_PORTSC1) & (UHCI_PORTSC_CSC|UHCI_PORTSC_OCIC))
+ p[0] |= 1<<1;
+ if (UREAD2(sc, UHCI_PORTSC2) & (UHCI_PORTSC_CSC|UHCI_PORTSC_OCIC))
+ p[0] |= 1<<2;
+ if (p[0] == 0)
+ /* No change, try again in a while */
+ return;
+
+ reqh->actlen = 1;
+ reqh->status = USBD_NORMAL_COMPLETION;
+ s = splusb();
+ reqh->hcpriv = 0;
+ usb_transfer_complete(reqh);
+ splx(s);
+}
+
+void
+uhci_root_intr_done(reqh)
usbd_request_handle reqh;
{
- int timeout = reqh->timeout;
- int usecs;
- uhci_intr_info_t *ii;
+}
- DPRINTFN(15,("uhci_waitintr: timeout = %ds\n", timeout));
- /* XXX NWH setting status here might give race condition */
- reqh->status = USBD_IN_PROGRESS;
+void
+uhci_lock_frames(sc)
+ uhci_softc_t *sc;
+{
+ int s = splusb();
+ while (sc->sc_vflock) {
+ sc->sc_vflock |= UHCI_WANT_LOCK;
+ tsleep(&sc->sc_vflock, PRIBIO, "uhcqhl", 0);
+ }
+ sc->sc_vflock = UHCI_HAS_LOCK;
+ splx(s);
+}
- for (usecs = timeout * 1000000 / hz; usecs > 0; usecs -= 1000) {
- uhci_poll(&sc->sc_bus);
- if (reqh->status != USBD_IN_PROGRESS)
- return;
+void
+uhci_unlock_frames(sc)
+ uhci_softc_t *sc;
+{
+ int s = splusb();
+ sc->sc_vflock &= ~UHCI_HAS_LOCK;
+ if (sc->sc_vflock & UHCI_WANT_LOCK)
+ wakeup(&sc->sc_vflock);
+ splx(s);
+}
- usb_delay_ms(&sc->sc_bus, 1);
+/*
+ * Allocate an interrupt information struct. A free list is kept
+ * for fast allocation.
+ */
+uhci_intr_info_t *
+uhci_alloc_intr_info(sc)
+ uhci_softc_t *sc;
+{
+ uhci_intr_info_t *ii;
+
+ ii = LIST_FIRST(&uhci_ii_free);
+ if (ii)
+ LIST_REMOVE(ii, list);
+ else {
+ ii = malloc(sizeof(uhci_intr_info_t), M_USBHC, M_NOWAIT);
}
+ ii->sc = sc;
+#if defined(__FreeBSD__)
+ callout_handle_init(&ii->timeout_handle);
+#endif
- /* Timeout */
+ return ii;
+}
- DPRINTF(("uhci_waitintr: timeout\n"));
+void
+uhci_free_intr_info(ii)
+ uhci_intr_info_t *ii;
+{
+ LIST_INSERT_HEAD(&uhci_ii_free, ii, list); /* and put on free list */
+}
- /* Find the intr info in the queue */
- for (ii = LIST_FIRST(&sc->sc_intrhead);
- ii && ii->reqh != reqh;
- ii = LIST_NEXT(ii, list))
- /* noop */ ;
+/* Add control QH, called at splusb(). */
+void
+uhci_add_ctrl(sc, sqh)
+ uhci_softc_t *sc;
+ uhci_soft_qh_t *sqh;
+{
+ uhci_soft_qh_t *eqh;
- if (ii)
- uhci_ii_done(ii, 1);
- else
- /* this can only happen if there are 2 or more tasks
- * polling or interrupts are enabled. This is not
- * possible during boot.
- * In that case the request has been handled already.
- * If it does happen this should be non-fatal.
- */
-#ifdef UHCI_DEBUG
- panic("lost intr_info\n");
+ DPRINTFN(10, ("uhci_add_ctrl: sqh=%p\n", sqh));
+ eqh = sc->sc_ctl_end;
+ sqh->hlink = eqh->hlink;
+ sqh->qh.qh_hlink = eqh->qh.qh_hlink;
+ eqh->hlink = sqh;
+ eqh->qh.qh_hlink = LE(sqh->physaddr | UHCI_PTR_Q);
+ sc->sc_ctl_end = sqh;
+}
+
+/* Remove control QH, called at splusb(). */
+void
+uhci_remove_ctrl(sc, sqh)
+ uhci_softc_t *sc;
+ uhci_soft_qh_t *sqh;
+{
+ uhci_soft_qh_t *pqh;
+
+ DPRINTFN(10, ("uhci_remove_ctrl: sqh=%p\n", sqh));
+ for (pqh = sc->sc_ctl_start; pqh->hlink != sqh; pqh=pqh->hlink)
+#if defined(DIAGNOSTIC) || defined(UHCI_DEBUG)
+ if (LE(pqh->qh.qh_hlink) & UHCI_PTR_T) {
+ printf("uhci_remove_ctrl: QH not found\n");
+ return;
+ }
#else
- printf("lost intr_info\n");
+ ;
#endif
+ pqh->hlink = sqh->hlink;
+ pqh->qh.qh_hlink = sqh->qh.qh_hlink;
+ if (sc->sc_ctl_end == sqh)
+ sc->sc_ctl_end = pqh;
}
+/* Add bulk QH, called at splusb(). */
+void
+uhci_add_bulk(sc, sqh)
+ uhci_softc_t *sc;
+ uhci_soft_qh_t *sqh;
+{
+ uhci_soft_qh_t *eqh;
+
+ DPRINTFN(10, ("uhci_add_bulk: sqh=%p\n", sqh));
+ eqh = sc->sc_bulk_end;
+ sqh->hlink = eqh->hlink;
+ sqh->qh.qh_hlink = eqh->qh.qh_hlink;
+ eqh->hlink = sqh;
+ eqh->qh.qh_hlink = LE(sqh->physaddr | UHCI_PTR_Q);
+ sc->sc_bulk_end = sqh;
+}
-/*
- * Called when a request does not complete.
- */
+/* Remove bulk QH, called at splusb(). */
void
-uhci_timeout(priv)
- void *priv;
+uhci_remove_bulk(sc, sqh)
+ uhci_softc_t *sc;
+ uhci_soft_qh_t *sqh;
{
- uhci_intr_info_t *ii = priv;
+ uhci_soft_qh_t *pqh;
- uhci_ii_done(ii, 1);
+ DPRINTFN(10, ("uhci_remove_bulk: sqh=%p\n", sqh));
+ for (pqh = sc->sc_bulk_start; pqh->hlink != sqh; pqh = pqh->hlink)
+#if defined(DIAGNOSTIC) || defined(UHCI_DEBUG)
+ if (LE(pqh->qh.qh_hlink) & UHCI_PTR_T) {
+ printf("uhci_remove_bulk: QH not found\n");
+ return;
+ }
+#else
+ ;
+#endif
+ pqh->hlink = sqh->hlink;
+ pqh->qh.qh_hlink = sqh->qh.qh_hlink;
+ if (sc->sc_bulk_end == sqh)
+ sc->sc_bulk_end = pqh;
}
-/*
- * Handle interrupt from the host controller. We search the list of TDs
- * for completed ones and call uhci_ii_done for those.
- */
int
-uhci_intr(priv)
- void *priv;
+uhci_intr(arg)
+ void *arg;
{
- uhci_softc_t *sc = priv;
+ uhci_softc_t *sc = arg;
int status;
- int ack = 0;
+ int ack;
uhci_intr_info_t *ii;
sc->sc_intrs++;
-#if defined(UHCI_DEBUG)
+#ifdef UHCI_DEBUG
if (uhcidebug > 15) {
DPRINTF(("%s: uhci_intr\n", USBDEVNAME(sc->sc_bus.bdev)));
uhci_dumpregs(sc);
}
#endif
- status = UREAD2(sc, UHCI_STS);
+#if defined(DIAGNOSTIC) && defined(__NetBSD__)
+ if (sc->sc_suspend != PWR_RESUME)
+ printf("uhci_intr: suspended sts=0x%x\n", status);
+#endif
+ status = UREAD2(sc, UHCI_STS);
+ ack = 0;
if (status & UHCI_STS_USBINT)
ack |= UHCI_STS_USBINT;
if (status & UHCI_STS_USBEI)
ack |= UHCI_STS_USBEI;
if (status & UHCI_STS_RD) {
ack |= UHCI_STS_RD;
- printf("%s: resume detect\n",
- USBDEVNAME(sc->sc_bus.bdev));
+ printf("%s: resume detect\n", USBDEVNAME(sc->sc_bus.bdev));
}
if (status & UHCI_STS_HSE) {
ack |= UHCI_STS_HSE;
- printf("%s: host controller process error\n",
- USBDEVNAME(sc->sc_bus.bdev));
+ printf("%s: host controller process error\n",
+ USBDEVNAME(sc->sc_bus.bdev));
}
if (status & UHCI_STS_HCPE) {
ack |= UHCI_STS_HCPE;
- printf("%s: host system error\n",
- USBDEVNAME(sc->sc_bus.bdev));
+ printf("%s: host system error\n", USBDEVNAME(sc->sc_bus.bdev));
}
if (status & UHCI_STS_HCH) {
/* no acknowledge needed */
- printf("%s: host controller halted\n",
- USBDEVNAME(sc->sc_bus.bdev));
+ printf("%s: host controller halted\n",
+ USBDEVNAME(sc->sc_bus.bdev));
}
if (ack) /* acknowledge the ints */
UWRITE2(sc, UHCI_STS, ack);
else /* nothing to acknowledge */
- return 0;
+ return (0);
/*
* Interrupts on UHCI really suck. When the host controller
@@ -626,21 +847,16 @@ uhci_intr(priv)
DPRINTFN(10, ("uhci_intr: exit\n"));
- return 1;
+ return (1);
}
-
-/*
- * Check the list of TDs for completeness.
- * If there is an error in the middle of the list of TDs or
- * a short packet, retire the list and call uhci_ii_done for the ii
- */
+/* Check for an interrupt. */
void
uhci_check_intr(sc, ii)
uhci_softc_t *sc;
uhci_intr_info_t *ii;
{
- uhci_soft_td_t *std;
+ uhci_soft_td_t *std, *lstd;
u_int32_t status;
DPRINTFN(15, ("uhci_check_intr: ii=%p\n", ii));
@@ -649,58 +865,55 @@ uhci_check_intr(sc, ii)
printf("uhci_check_intr: no ii? %p\n", ii);
return;
}
- if (!ii->stdend) {
- printf("uhci_check_intr: ii->stdend==0\n");
- return;
- }
#endif
-
if (!ii->stdstart)
return;
-
- if (ii->stdend->td->td_status & UHCI_TD_ACTIVE) {
- /*
- * If the last TD is still active we need to check whether there
- * is a an error somewhere in the middle or whether there was a
- * short packet (SPD and not ACTIVE).
- */
-
- for (std = ii->stdstart;
- std != ii->stdend;
- std = std->td->link.std) {
- status = std->td->td_status;
+ lstd = ii->stdend;
+#ifdef DIAGNOSTIC
+ if (!lstd) {
+ printf("uhci_check_intr: std==0\n");
+ return;
+ }
+#endif
+ /*
+ * If the last TD is still active we need to check whether there
+ * is a an error somewhere in the middle, or whether there was a
+ * short packet (SPD and not ACTIVE).
+ */
+ if (LE(lstd->td.td_status) & UHCI_TD_ACTIVE) {
+ DPRINTFN(15, ("uhci_check_intr: active ii=%p\n", ii));
+ for (std = ii->stdstart; std != lstd; std = std->link.std) {
+ status = LE(std->td.td_status);
if ((status & UHCI_TD_STALLED) ||
- (status&(UHCI_TD_SPD|UHCI_TD_ACTIVE))==UHCI_TD_SPD)
+ (status & (UHCI_TD_SPD | UHCI_TD_ACTIVE)) ==
+ UHCI_TD_SPD)
goto done;
}
+ DPRINTFN(15, ("uhci_check_intr: ii=%p std=%p still active\n",
+ ii, ii->stdstart));
return;
}
-
-done:
+ done:
usb_untimeout(uhci_timeout, ii, ii->timeout_handle);
- uhci_ii_done(ii, 0);
+ uhci_idone(ii);
}
-
void
-uhci_ii_done(ii, timedout)
+uhci_idone(ii)
uhci_intr_info_t *ii;
- int timedout; /* timeout that triggered function call? */
{
usbd_request_handle reqh = ii->reqh;
+ struct uhci_pipe *upipe = (struct uhci_pipe *)reqh->pipe;
uhci_soft_td_t *std;
- /* error status of last inactive transfer */
- usbd_status err = USBD_NORMAL_COMPLETION;
- int actlen = 0; /* accumulated actual length for queue */
- int s;
+ u_int32_t status = 0;
+ int actlen;
#ifdef DIAGNOSTIC
{
- /* avoid finishing a transfer more than once */
- int s = splusb();
+ int s = splhigh();
if (ii->isdone) {
splx(s);
- printf("uhci_ii_done: is done!\n");
+ printf("uhci_idone: ii=%p is done!\n", ii);
return;
}
ii->isdone = 1;
@@ -708,228 +921,201 @@ uhci_ii_done(ii, timedout)
}
#endif
- /*
- * The transfer is done; compute actual length and status
- * XXX Is this correct for control transfers? Should not
- * only the data stage be calculated?
- */
- for (std = ii->stdstart; std; std = std->td->link.std) {
- if (std->td->td_status & UHCI_TD_ACTIVE)
- break;
+ if (reqh->status == USBD_CANCELLED ||
+ reqh->status == USBD_TIMEOUT) {
+ DPRINTF(("uhci_idone: aborted reqh=%p\n", reqh));
+ return;
+ }
- /* error status of last TD for error handling below */
- err = std->td->td_status & UHCI_TD_ERROR;
+ if (reqh->nframes) {
+ /* Isoc transfer, do things differently. */
+ uhci_soft_td_t **stds = upipe->u.iso.stds;
+ int i, n, nframes;
- if (UHCI_TD_GET_PID(std->td->td_token) != UHCI_TD_PID_SETUP)
- actlen += UHCI_TD_GET_ACTLEN(std->td->td_status);
+ DPRINTFN(5,("uhci_idone: ii=%p isoc ready\n", ii));
+
+ nframes = reqh->nframes;
+ actlen = 0;
+ n = reqh->hcprivint;
+ for (i = 0; i < nframes; i++) {
+ std = stds[n];
+#ifdef UHCI_DEBUG
+ if (uhcidebug > 5) {
+ DPRINTFN(-1,("uhci_idone: isoc TD %d\n", i));
+ uhci_dump_td(std);
+ }
+#endif
+ if (++n >= UHCI_VFRAMELIST_COUNT)
+ n = 0;
+ status = LE(std->td.td_status);
+ actlen += UHCI_TD_GET_ACTLEN(status);
+ }
+ upipe->u.iso.inuse -= nframes;
+ reqh->actlen = actlen;
+ reqh->status = USBD_NORMAL_COMPLETION;
+ reqh->hcpriv = ii;
+ usb_transfer_complete(reqh);
+ return;
}
- DPRINTFN(10, ("uhci_ii_done: ii=%p%s, actlen=%d err=0x%x\n",
- ii, timedout? " timed out":"", actlen, err));
#ifdef UHCI_DEBUG
- if (uhcidebug > 10 && (err || timedout))
+ DPRINTFN(10, ("uhci_idone: ii=%p ready\n", ii));
+ if (uhcidebug > 10)
uhci_dump_tds(ii->stdstart);
#endif
- if (err) {
- DPRINTFN(-1+((err & ~UHCI_TD_STALLED) != 0),
- ("uhci_ii_done: error, addr=%d, endpt=0x%02x, "
- "err=0x%b\n",
+ /* The transfer is done, compute actual length and status. */
+ /* XXX Is this correct for control xfers? */
+ actlen = 0;
+ for (std = ii->stdstart; std; std = std->link.std) {
+ status = LE(std->td.td_status);
+ if (status & UHCI_TD_ACTIVE)
+ break;
+ if (UHCI_TD_GET_PID(LE(std->td.td_token)) !=
+ UHCI_TD_PID_SETUP)
+ actlen += UHCI_TD_GET_ACTLEN(status);
+ }
+ /* If there are left over TDs we need to update the toggle. */
+ if (std)
+ upipe->nexttoggle = UHCI_TD_GET_DT(LE(std->td.td_token));
+
+ status &= UHCI_TD_ERROR;
+ DPRINTFN(10, ("uhci_check_intr: actlen=%d, status=0x%x\n",
+ actlen, status));
+ reqh->actlen = actlen;
+ if (status != 0) {
+ DPRINTFN(-1+((status&UHCI_TD_STALLED)!=0),
+ ("uhci_idone: error, addr=%d, endpt=0x%02x, "
+ "status 0x%b\n",
reqh->pipe->device->address,
reqh->pipe->endpoint->edesc->bEndpointAddress,
- (int)err,
+ (int)status,
"\20\22BITSTUFF\23CRCTO\24NAK\25BABBLE\26DBUFFER\27"
"STALLED\30ACTIVE"));
-
- if (err & ~UHCI_TD_STALLED) {
- /* more then STALLED, like +BABBLE or +CRC/TIMEOUT */
- reqh->status = USBD_IOERROR; /* more info XXX */
- } else {
+ if (status == UHCI_TD_STALLED)
reqh->status = USBD_STALLED;
- }
+ else
+ reqh->status = USBD_IOERROR; /* more info XXX */
} else {
reqh->status = USBD_NORMAL_COMPLETION;
}
-
- reqh->actlen = actlen;
-
- if (timedout) {
- s = splusb();
- /* We got a timeout. Make sure transaction is not active. */
- for (std = ii->stdstart; std != 0; std = std->td->link.std)
- std->td->td_status &= ~UHCI_TD_ACTIVE;
- splx(s);
-
- /* XXX should we wait 1 ms */
- reqh->status = USBD_TIMEOUT;
- }
-
- /* select the proper type termination of the transfer
- * based on the transfer type for the queue
- */
- switch (reqh->pipe->endpoint->edesc->bmAttributes & UE_XFERTYPE) {
- case UE_CONTROL:
- uhci_ctrl_done(ii);
- usb_start_next(reqh->pipe);
- break;
- case UE_BULK:
- uhci_bulk_done(ii);
- usb_start_next(reqh->pipe);
- break;
- case UE_INTERRUPT:
- uhci_intr_done(ii);
- break;
- case UE_ISOCHRONOUS:
- uhci_isoc_done(ii);
- usb_start_next(reqh->pipe);
- break;
- }
-
- /* And finally execute callback. */
- reqh->xfercb(reqh);
+ reqh->hcpriv = ii;
+ usb_transfer_complete(reqh);
}
-/* Deallocate request data structures */
+/*
+ * Called when a request does not complete.
+ */
void
-uhci_ctrl_done(ii)
- uhci_intr_info_t *ii;
+uhci_timeout(addr)
+ void *addr;
{
- uhci_softc_t *sc = ii->sc;
- usbd_request_handle reqh = ii->reqh;
- struct uhci_pipe *upipe = (struct uhci_pipe *)reqh->pipe;
- u_int datalen = upipe->u.ctl.length;
- usb_dma_t *dma;
-
-#ifdef DIAGNOSTIC
- if (!reqh->isreq)
- panic("uhci_ctrl_done: not a request\n");
-#endif
-
- LIST_REMOVE(ii, list); /* remove from active list */
-
- uhci_remove_ctrl(sc, upipe->u.ctl.sqh);
-
- if (datalen != 0) {
- /* there was a data stage */
- dma = &upipe->u.ctl.datadma;
- if (reqh->request.bmRequestType & UT_READ)
- memcpy(reqh->buffer, KERNADDR(dma), datalen);
-
- /*
- * when freeing the chain skip the first (setup) and last
- * (status) TD.
- */
- uhci_free_std_chain(sc, ii->stdstart->td->link.std, ii->stdend);
- usb_freemem(sc->sc_dmatag, dma);
- }
+ uhci_intr_info_t *ii = addr;
- DPRINTFN(5, ("uhci_ctrl_done: length=%d\n", reqh->actlen));
+ DPRINTF(("uhci_timeout: ii=%p\n", ii));
+ uhci_abort_req(ii->reqh, USBD_TIMEOUT);
}
-/* Deallocate request data structures */
+/*
+ * Wait here until controller claims to have an interrupt.
+ * Then call uhci_intr and return. Use timeout to avoid waiting
+ * too long.
+ * Only used during boot when interrupts are not enabled yet.
+ */
void
-uhci_bulk_done(ii)
- uhci_intr_info_t *ii;
+uhci_waitintr(sc, reqh)
+ uhci_softc_t *sc;
+ usbd_request_handle reqh;
{
- uhci_softc_t *sc = ii->sc;
- usbd_request_handle reqh = ii->reqh;
- struct uhci_pipe *upipe = (struct uhci_pipe *)reqh->pipe;
- uhci_soft_td_t *std;
- u_int datalen = upipe->u.bulk.length;
- usb_dma_t *dma;
-
- LIST_REMOVE(ii, list); /* remove from active list */
-
- uhci_remove_bulk(sc, upipe->u.bulk.sqh);
+ int timo = reqh->timeout;
+ uhci_intr_info_t *ii;
- /* find the toggle for the last transfer and invert it */
- for (std = ii->stdstart; std; std = std->td->link.std) {
- if (std->td->td_status & UHCI_TD_ACTIVE)
- break;
+ DPRINTFN(10,("uhci_waitintr: timeout = %dms\n", timo));
- upipe->nexttoggle = UHCI_TD_GET_DT(std->td->td_token);
+ reqh->status = USBD_IN_PROGRESS;
+ for (; timo >= 0; timo--) {
+ usb_delay_ms(&sc->sc_bus, 1);
+ DPRINTFN(20,("uhci_waitintr: 0x%04x\n", UREAD2(sc, UHCI_STS)));
+ if (UREAD2(sc, UHCI_STS) & UHCI_STS_USBINT) {
+ uhci_intr(sc);
+ if (reqh->status != USBD_IN_PROGRESS)
+ return;
+ }
}
- upipe->nexttoggle ^= 1;
- /* copy the data from dma memory to userland storage */
- dma = &upipe->u.bulk.datadma;
- if (upipe->u.bulk.isread)
- memcpy(reqh->buffer, KERNADDR(dma), datalen);
-
- /* free the whole chain of TDs */
- uhci_free_std_chain(sc, ii->stdstart, 0);
- usb_freemem(sc->sc_dmatag, dma);
+ /* Timeout */
+ DPRINTF(("uhci_waitintr: timeout\n"));
+ for (ii = LIST_FIRST(&sc->sc_intrhead);
+ ii && ii->reqh != reqh;
+ ii = LIST_NEXT(ii, list))
+ ;
+#ifdef DIAGNOSTIC
+ if (!ii)
+ panic("uhci_waitintr: lost intr_info\n");
+#endif
+ uhci_idone(ii);
}
void
-uhci_intr_done(ii)
- uhci_intr_info_t *ii;
+uhci_poll(bus)
+ struct usbd_bus *bus;
{
- uhci_softc_t *sc = ii->sc;
- usbd_request_handle reqh = ii->reqh;
- struct uhci_pipe *upipe = (struct uhci_pipe *)reqh->pipe;
- usb_dma_t *dma;
- uhci_soft_qh_t *sqh;
- int i, npoll;
-
- DPRINTFN(5, ("uhci_intr_done: length=%d\n", reqh->actlen));
-
- dma = &upipe->u.intr.datadma;
- memcpy(reqh->buffer, KERNADDR(dma), reqh->actlen);
- npoll = upipe->u.intr.npoll;
- for(i = 0; i < npoll; i++) {
- sqh = upipe->u.intr.qhs[i];
- sqh->qh->elink = 0;
- sqh->qh->qh_elink = UHCI_PTR_T;
- }
- uhci_free_std_chain(sc, ii->stdstart, NULL);
+ uhci_softc_t *sc = (uhci_softc_t *)bus;
- /* XXX Wasteful. */
- if (reqh->pipe->intrreqh == reqh
- && reqh->status == USBD_NORMAL_COMPLETION) {
- uhci_soft_td_t *std, *stdend;
+ if (UREAD2(sc, UHCI_STS) & UHCI_STS_USBINT)
+ uhci_intr(sc);
+}
- /* This alloc cannot fail since we freed the chain above. */
- upipe->pipe.endpoint->toggle = upipe->nexttoggle;
- uhci_alloc_std_chain(sc, upipe, reqh->length, 1,
- reqh->flags & USBD_SHORT_XFER_OK,
- dma, &std, &stdend);
- stdend->td->td_status |= UHCI_TD_IOC;
+#if 0
+void
+uhci_reset(p)
+ void *p;
+{
+ uhci_softc_t *sc = p;
+ int n;
-#ifdef UHCI_DEBUG
- if (uhcidebug > 10) {
- DPRINTF(("uhci_device_intr_done: xfer\n"));
- uhci_dump_tds(std);
- uhci_dump_qh(upipe->u.intr.qhs[0]);
- }
+ UHCICMD(sc, UHCI_CMD_HCRESET);
+ /* The reset bit goes low when the controller is done. */
+ for (n = 0; n < UHCI_RESET_TIMEOUT &&
+ (UREAD2(sc, UHCI_CMD) & UHCI_CMD_HCRESET); n++)
+ delay(100);
+ if (n >= UHCI_RESET_TIMEOUT)
+ printf("%s: controller did not reset\n",
+ USBDEVNAME(sc->sc_bus.bdev));
+}
#endif
- ii->stdstart = std;
- ii->stdend = stdend;
-#ifdef DIAGNOSTIC
- ii->isdone = 0;
-#endif
- for (i = 0; i < npoll; i++) {
- sqh = upipe->u.intr.qhs[i];
- sqh->qh->elink = std;
- sqh->qh->qh_elink = std->physaddr;
+usbd_status
+uhci_run(sc, run)
+ uhci_softc_t *sc;
+ int run;
+{
+ int s, n, running;
+
+ run = run != 0;
+ s = splusb();
+ DPRINTF(("uhci_run: setting run=%d\n", run));
+ UHCICMD(sc, run ? UHCI_CMD_RS : 0);
+ for(n = 0; n < 10; n++) {
+ running = !(UREAD2(sc, UHCI_STS) & UHCI_STS_HCH);
+ /* return when we've entered the state we want */
+ if (run == running) {
+ splx(s);
+ DPRINTF(("uhci_run: done cmd=0x%x sts=0x%x\n",
+ UREAD2(sc, UHCI_CMD), UREAD2(sc, UHCI_STS)));
+ return (USBD_NORMAL_COMPLETION);
}
- } else {
- usb_freemem(sc->sc_dmatag, dma);
- ii->stdstart = NULL; /* mark as inactive */
+ usb_delay_ms(&sc->sc_bus, 1);
}
-}
-
-void
-uhci_isoc_done(ii)
- uhci_intr_info_t *ii;
-{
+ splx(s);
+ printf("%s: cannot %s\n", USBDEVNAME(sc->sc_bus.bdev),
+ run ? "start" : "stop");
+ return (USBD_IOERROR);
}
/*
* Memory management routines.
* uhci_alloc_std allocates TDs
- * uhci_alloc_std_chain allocates a chain of TDs
* uhci_alloc_sqh allocates QHs
* These two routines do their own free list management,
* partly for speed, partly because allocating DMAable memory
@@ -942,33 +1128,27 @@ uhci_alloc_std(sc)
uhci_softc_t *sc;
{
uhci_soft_td_t *std;
- usbd_status err;
- int i;
+ usbd_status r;
+ int i, offs;
usb_dma_t dma;
if (!sc->sc_freetds) {
DPRINTFN(2,("uhci_alloc_std: allocating chunk\n"));
- std = malloc(sizeof(uhci_soft_td_t) * UHCI_TD_CHUNK,
- M_USBDEV, M_NOWAIT);
- if (!std)
- return(0);
- err = usb_allocmem(sc->sc_dmatag, UHCI_TD_SIZE * UHCI_TD_CHUNK,
+ r = usb_allocmem(sc->sc_dmatag, UHCI_STD_SIZE * UHCI_STD_CHUNK,
UHCI_TD_ALIGN, &dma);
- if (err != USBD_NORMAL_COMPLETION) {
- free(std, M_USBDEV);
- return(0);
- }
- for(i = 0; i < UHCI_TD_CHUNK; i++, std++) {
- std->physaddr = DMAADDR(&dma) + i * UHCI_TD_SIZE;
- std->td = (uhci_td_t *)
- ((char *)KERNADDR(&dma) + i * UHCI_TD_SIZE);
- std->td->link.std = sc->sc_freetds;
+ if (r != USBD_NORMAL_COMPLETION)
+ return (0);
+ for(i = 0; i < UHCI_STD_CHUNK; i++) {
+ offs = i * UHCI_STD_SIZE;
+ std = (uhci_soft_td_t *)((char *)KERNADDR(&dma) +offs);
+ std->physaddr = DMAADDR(&dma) + offs;
+ std->link.std = sc->sc_freetds;
sc->sc_freetds = std;
}
}
std = sc->sc_freetds;
- sc->sc_freetds = std->td->link.std;
- memset(std->td, 0, UHCI_TD_SIZE);
+ sc->sc_freetds = std->link.std;
+ memset(&std->td, 0, sizeof(uhci_td_t));
return std;
}
@@ -977,181 +1157,45 @@ uhci_free_std(sc, std)
uhci_softc_t *sc;
uhci_soft_td_t *std;
{
- if (!std)
-#ifdef UHCI_DEBUG
- panic("invalid TD to be freed, std=%p", std);
-#else
- return;
-#endif
-
#ifdef DIAGNOSTIC
#define TD_IS_FREE 0x12345678
- if (std->td->td_token == TD_IS_FREE) {
+ if (LE(std->td.td_token) == TD_IS_FREE) {
printf("uhci_free_std: freeing free TD %p\n", std);
return;
}
- std->td->td_token = TD_IS_FREE;
+ std->td.td_token = LE(TD_IS_FREE);
#endif
- std->td->link.std = sc->sc_freetds;
+ std->link.std = sc->sc_freetds;
sc->sc_freetds = std;
}
-/* allocates and prepares a chain of TDs */
-usbd_status
-uhci_alloc_std_chain(sc, upipe, datalen, isread, spd, dma, rstd, rstdend)
- uhci_softc_t *sc;
- struct uhci_pipe *upipe;
- int datalen;
- int isread, spd;
- usb_dma_t *dma;
- uhci_soft_td_t **rstd, **rstdend;
-{
- uhci_soft_td_t *std = NULL; /* soft TD we are working on */
- uhci_soft_td_t *stdprev = NULL; /* std from prev iteration */
- uhci_physaddr_t linkprev = UHCI_PTR_T; /* links real TDs together */
- int i; /* index over TDs */
- int ntd; /* number of TDs */
- int l; /* len of data in current std */
- int tog; /* current data toggle */
- int maxpacketsize;
- u_int32_t status; /* pre computed status for TD */
- int addr = upipe->pipe.device->address; /* shortcuts */
- int endpt = upipe->pipe.endpoint->edesc->bEndpointAddress;
-
- maxpacketsize = UGETW(upipe->pipe.endpoint->edesc->wMaxPacketSize);
- if (maxpacketsize == 0) {
- printf("uhci_alloc_std_chain: maxpacketsize = 0\n");
- return(USBD_INVAL);
- }
-
- ntd = (datalen + maxpacketsize - 1) / maxpacketsize - 1;
- tog = upipe->pipe.endpoint->toggle;
- if (ntd % 2 == 1)
- /* toggle for last TD, list of TDs is initialised backwards */
- tog ^= 1;
-
- /*
- * save the toggle for the first TD of the next transfer so we can
- * simply copy the value in transfers that transfer all the TDs. Bulk
- * with n out of m TDs transferrred have to recompute though.
- */
- upipe->nexttoggle = tog ^ 1;
-
- DPRINTFN(10, ("uhci_alloc_std_chain: addr=%d endpt=%d datalen=%d "
- "toggle=%d, nexttoggle=%d, %s%s%s\n",
- addr, endpt, datalen,
- upipe->pipe.endpoint->toggle, upipe->nexttoggle,
- isread? "read":"write",
- upipe->pipe.device->lowspeed? ", lowspeed":"",
- spd? ", short packet":""));
-
- if (datalen == 0) {
- *rstd = *rstdend = 0;
- return(USBD_NORMAL_COMPLETION);
- }
-
- status = UHCI_TD_SET_ERRCNT(3) | UHCI_TD_ACTIVE;
- if (upipe->pipe.device->lowspeed)
- status |= UHCI_TD_LOWSPEED;
- if (spd)
- status |= UHCI_TD_SPD;
-
- /*
- * create a list of std's, backwards. stdprev contains the std
- * from the previous iteration.
- */
- for (i = ntd; i >= 0; i--) {
- std = uhci_alloc_std(sc);
- if (!std) {
- uhci_free_std_chain(sc, stdprev, NULL);
- return(USBD_NOMEM);
- }
-
- std->td->link.std = stdprev;
- stdprev = std;
- std->td->td_link = linkprev;
- linkprev = std->physaddr;
- std->td->td_status = status;
- if (i == ntd) { /* compute length of TD */
- /* last TD is 0 > l >= maxPacketSize */
- l = datalen % maxpacketsize;
- if (l == 0)
- l = maxpacketsize;
-
- *rstdend = std; /* end of list of TDs */
- } else
- /* all other TDs should be max size */
- l = maxpacketsize;
-
- std->td->td_token =
- isread ? UHCI_TD_IN(l, endpt, addr, tog) :
- UHCI_TD_OUT(l, endpt, addr, tog);
- std->td->td_buffer = DMAADDR(dma) + i * maxpacketsize;
-
- tog ^= 1;
- }
- *rstd = stdprev;
-
- return(USBD_NORMAL_COMPLETION);
-}
-
-void
-uhci_free_std_chain(sc, std, stdend)
- uhci_softc_t *sc;
- uhci_soft_td_t *std;
- uhci_soft_td_t *stdend;
-{
- uhci_soft_td_t *std_link; /* temp store of next pointer */
-
- /* removes the chain up to (but excluding) the element stdend */
-
- if (!std)
-#ifdef UHCI_DEBUG
- panic("invalid TD chain to be freed, std=%p", std);
-#else
- return;
-#endif
-
- for (; std != stdend; std = std_link) {
- std_link = std->td->link.std;
- uhci_free_std(sc, std);
- }
-}
-
uhci_soft_qh_t *
uhci_alloc_sqh(sc)
uhci_softc_t *sc;
{
uhci_soft_qh_t *sqh;
- usbd_status err;
+ usbd_status r;
int i, offs;
usb_dma_t dma;
if (!sc->sc_freeqhs) {
DPRINTFN(2, ("uhci_alloc_sqh: allocating chunk\n"));
- sqh = malloc(sizeof(uhci_soft_qh_t) * UHCI_QH_CHUNK,
- M_USBDEV, M_NOWAIT);
- if (!sqh)
- return NULL;
- err = usb_allocmem(sc->sc_dmatag, UHCI_QH_SIZE * UHCI_QH_CHUNK,
+ r = usb_allocmem(sc->sc_dmatag, UHCI_SQH_SIZE * UHCI_SQH_CHUNK,
UHCI_QH_ALIGN, &dma);
- if (err != USBD_NORMAL_COMPLETION) {
- free(sqh, M_USBDEV);
- return NULL;
- }
- for(i = 0; i < UHCI_QH_CHUNK; i++, sqh++) {
- offs = i * UHCI_QH_SIZE;
+ if (r != USBD_NORMAL_COMPLETION)
+ return 0;
+ for(i = 0; i < UHCI_SQH_CHUNK; i++) {
+ offs = i * UHCI_SQH_SIZE;
+ sqh = (uhci_soft_qh_t *)((char *)KERNADDR(&dma) +offs);
sqh->physaddr = DMAADDR(&dma) + offs;
- sqh->qh = (uhci_qh_t *)
- ((char *)KERNADDR(&dma) + offs);
- sqh->qh->hlink = sc->sc_freeqhs;
+ sqh->hlink = sc->sc_freeqhs;
sc->sc_freeqhs = sqh;
}
}
sqh = sc->sc_freeqhs;
- sc->sc_freeqhs = sqh->qh->hlink;
- memset(sqh->qh, 0, UHCI_QH_SIZE);
- return(sqh);
+ sc->sc_freeqhs = sqh->hlink;
+ memset(&sqh->qh, 0, sizeof(uhci_qh_t));
+ return (sqh);
}
void
@@ -1159,414 +1203,137 @@ uhci_free_sqh(sc, sqh)
uhci_softc_t *sc;
uhci_soft_qh_t *sqh;
{
- if (!sqh) /* safety net */
-#ifdef UHCI_DEBUG
- panic("invalid QH to be freed, sqh=%p", sqh);
-#else
- return;
-#endif
-
- sqh->qh->hlink = sc->sc_freeqhs;
+ sqh->hlink = sc->sc_freeqhs;
sc->sc_freeqhs = sqh;
}
-
-/*
- * Allocate an interrupt information struct. A free list is kept
- * for fast allocation.
+#if 0
+/*
+ * Enter a list of transfers onto a control queue.
+ * Called at splusb()
*/
-uhci_intr_info_t *
-uhci_alloc_intr_info(sc)
- uhci_softc_t *sc;
-{
- uhci_intr_info_t *ii;
-
- ii = LIST_FIRST(&uhci_ii_free);
- if (ii)
- LIST_REMOVE(ii, list);
- else {
- ii = malloc(sizeof(uhci_intr_info_t), M_USBDEV, M_NOWAIT);
- }
- ii->sc = sc;
-#if defined(__FreeBSD__)
- callout_handle_init(&ii->timeout_handle);
-#endif
- return ii;
-}
-
void
-uhci_free_intr_info(ii)
+uhci_enter_ctl_q(sc, sqh, ii)
+ uhci_softc_t *sc;
+ uhci_soft_qh_t *sqh;
uhci_intr_info_t *ii;
{
- if (!ii)
-#ifdef UHCI_DEBUG
- panic("invalid intr info to be freed, ii=%p", ii);
-#else
- return;
-#endif
+ DPRINTFN(5, ("uhci_enter_ctl_q: sqh=%p\n", sqh));
- LIST_INSERT_HEAD(&uhci_ii_free, ii, list); /* and put on free list */
-}
-
-
-/*
- * request and release lock on the frames list
- */
-
-void
-uhci_lock_frames(sc)
- uhci_softc_t *sc;
-{
- int s = splusb();
- while (sc->sc_vflock) {
- sc->sc_vflock |= UHCI_WANT_LOCK;
- tsleep(&sc->sc_vflock, PRIBIO, "uhcqhl", 0);
- }
- sc->sc_vflock = UHCI_HAS_LOCK;
- splx(s);
}
+#endif
void
-uhci_unlock_frames(sc)
+uhci_free_std_chain(sc, std, stdend)
uhci_softc_t *sc;
+ uhci_soft_td_t *std;
+ uhci_soft_td_t *stdend;
{
- int s = splusb();
- sc->sc_vflock &= ~UHCI_HAS_LOCK;
- if (sc->sc_vflock & UHCI_WANT_LOCK)
- wakeup(&sc->sc_vflock);
- splx(s);
-}
-
-
-struct usbd_methods uhci_device_ctrl_methods = {
- uhci_device_ctrl_transfer,
- uhci_device_ctrl_start,
- uhci_device_ctrl_abort,
- uhci_device_ctrl_close,
- 0,
-};
-
-struct usbd_methods uhci_device_bulk_methods = {
- uhci_device_bulk_transfer,
- uhci_device_bulk_start,
- uhci_device_bulk_abort,
- uhci_device_bulk_close,
- 0,
-};
-
-struct usbd_methods uhci_device_intr_methods = {
- uhci_device_intr_transfer,
- uhci_device_intr_start,
- uhci_device_intr_abort,
- uhci_device_intr_close,
- 0,
-};
-
-struct usbd_methods uhci_device_isoc_methods = {
- uhci_device_isoc_transfer,
- uhci_device_isoc_start,
- uhci_device_isoc_abort,
- uhci_device_isoc_close,
- uhci_device_isoc_setbuf,
-};
-
-struct usbd_methods uhci_root_ctrl_methods = {
- uhci_root_ctrl_transfer,
- uhci_root_ctrl_start,
- uhci_root_ctrl_abort,
- uhci_root_ctrl_close,
- 0,
-};
-
-struct usbd_methods uhci_root_intr_methods = {
- uhci_root_intr_transfer,
- uhci_root_intr_start,
- uhci_root_intr_abort,
- uhci_root_intr_close,
- 0,
-};
-
-
-usbd_status
-uhci_open(pipe)
- usbd_pipe_handle pipe;
-{
- uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;
- struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
- usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc;
- usbd_status err;
-
- DPRINTFN(1, ("uhci_open: pipe=%p, addr=%d, endpt=%d (%d)\n",
- pipe, pipe->device->address,
- ed->bEndpointAddress, sc->sc_addr));
-
- if (pipe->device->address == sc->sc_addr) {
- /* root hub */
- switch (ed->bEndpointAddress) {
- case USB_CONTROL_ENDPOINT:
- pipe->methods = &uhci_root_ctrl_methods;
- break;
- case UE_IN | UHCI_INTR_ENDPT:
- pipe->methods = &uhci_root_intr_methods;
- break;
- default:
- return(USBD_INVAL);
- }
-
- } else {
- upipe->iinfo = uhci_alloc_intr_info(sc);
- if (upipe->iinfo == 0)
- return(USBD_NOMEM);
-
- upipe->nexttoggle = 0;
+ uhci_soft_td_t *p;
- switch (ed->bmAttributes & UE_XFERTYPE) {
- case UE_CONTROL:
- pipe->methods = &uhci_device_ctrl_methods;
- upipe->u.ctl.sqh = uhci_alloc_sqh(sc);
- if (upipe->u.ctl.sqh == 0)
- goto bad;
- upipe->u.ctl.setup = uhci_alloc_std(sc);
- if (upipe->u.ctl.setup == 0) {
- uhci_free_sqh(sc, upipe->u.ctl.sqh);
- goto bad;
- }
- upipe->u.ctl.stat = uhci_alloc_std(sc);
- if (upipe->u.ctl.stat == 0) {
- uhci_free_sqh(sc, upipe->u.ctl.sqh);
- uhci_free_std(sc, upipe->u.ctl.setup);
- goto bad;
- }
- err = usb_allocmem(sc->sc_dmatag,
- sizeof(usb_device_request_t),
- 0, &upipe->u.ctl.reqdma);
- if (err != USBD_NORMAL_COMPLETION) {
- uhci_free_sqh(sc, upipe->u.ctl.sqh);
- uhci_free_std(sc, upipe->u.ctl.setup);
- uhci_free_std(sc, upipe->u.ctl.stat);
- goto bad;
- }
- break;
- case UE_INTERRUPT:
- pipe->methods = &uhci_device_intr_methods;
- return(uhci_device_intr_interval(sc, upipe, ed->bInterval));
- case UE_ISOCHRONOUS:
- pipe->methods = &uhci_device_isoc_methods;
- upipe->u.iso.nbuf = 0;
- return(USBD_NORMAL_COMPLETION);
- case UE_BULK:
- pipe->methods = &uhci_device_bulk_methods;
- upipe->u.bulk.sqh = uhci_alloc_sqh(sc);
- if (upipe->u.bulk.sqh == 0)
- goto bad;
- break;
- }
+ for (; std != stdend; std = p) {
+ p = std->link.std;
+ uhci_free_std(sc, std);
}
- return(USBD_NORMAL_COMPLETION);
-
- bad:
- uhci_free_intr_info(upipe->iinfo);
- return(USBD_NOMEM);
}
-
-/* Control transfers are slightly more complicated as they consist of three
- * phases. This subroutine creates the three phases and schedules the chain
- */
-
usbd_status
-uhci_device_request(reqh)
- usbd_request_handle reqh;
+uhci_alloc_std_chain(upipe, sc, len, rd, shortok, dma, sp, ep)
+ struct uhci_pipe *upipe;
+ uhci_softc_t *sc;
+ int len, rd, shortok;
+ usb_dma_t *dma;
+ uhci_soft_td_t **sp, **ep;
{
- struct uhci_pipe *upipe = (struct uhci_pipe *)reqh->pipe;
- usb_device_request_t *req = &reqh->request;
- usbd_device_handle dev = upipe->pipe.device;
- uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
- int addr = dev->address;
+ uhci_soft_td_t *p, *lastp;
+ uhci_physaddr_t lastlink;
+ int i, ntd, l, tog, maxp;
+ u_int32_t status;
+ int addr = upipe->pipe.device->address;
int endpt = upipe->pipe.endpoint->edesc->bEndpointAddress;
- uhci_intr_info_t *ii = upipe->iinfo;
- uhci_soft_td_t *std, *stdend;
- uhci_soft_td_t *setup, *stat, *next;
- uhci_soft_qh_t *sqh;
- usb_dma_t *dmap;
- int datalen;
- u_int32_t ls;
- usbd_status err;
- int isread;
- int s;
-
- DPRINTFN(3,("uhci_device_request: bmRequestType=0x%02x, bRequest=0x%02x, "
- "wValue=0x%04x, wIndex=0x%04x, wLength=%d, addr=%d, endpt=%d\n",
- req->bmRequestType, req->bRequest, UGETW(req->wValue),
- UGETW(req->wIndex), UGETW(req->wLength),
- addr, endpt));
- ls = dev->lowspeed ? UHCI_TD_LOWSPEED : 0;
- isread = req->bmRequestType & UT_READ;
- datalen = UGETW(req->wLength);
-
- setup = upipe->u.ctl.setup;
- stat = upipe->u.ctl.stat;
- sqh = upipe->u.ctl.sqh;
- dmap = &upipe->u.ctl.datadma;
-
- if (datalen != 0) {
- /* initialise the data stage */
-
- err = usb_allocmem(sc->sc_dmatag, datalen, 0, dmap);
- if (err != USBD_NORMAL_COMPLETION)
- return(err);
-
- /*
- * data toggle starts at 0 with control requests, so first
- * data packet has toggle 1
- */
- upipe->pipe.endpoint->toggle = 1;
- err = uhci_alloc_std_chain(sc, upipe, datalen, isread,
- reqh->flags & USBD_SHORT_XFER_OK,
- dmap, &std, &stdend);
- if (err != USBD_NORMAL_COMPLETION) {
- usb_freemem(sc->sc_dmatag, dmap);
- return(err);
- }
-
- if (!isread)
- memcpy(KERNADDR(dmap), reqh->buffer, datalen);
-
- stdend->td->link.std = stat;
- stdend->td->td_link = stat->physaddr;
-
- next = std;
- } else {
- next = stat;
+ DPRINTFN(8, ("uhci_alloc_std_chain: addr=%d endpt=%d len=%d ls=%d "
+ "shortok=%d\n", addr, UE_GET_ADDR(endpt), len,
+ upipe->pipe.device->lowspeed, shortok));
+ if (len == 0) {
+ *sp = *ep = 0;
+ DPRINTFN(-1,("uhci_alloc_std_chain: len=0\n"));
+ return (USBD_NORMAL_COMPLETION);
}
-
- upipe->u.ctl.length = datalen;
-
-
- /*
- * initialise the setup stage and link it to either the data stage
- * or the status stage (in the case where there is no data stage)
- */
- setup->td->link.std = next;
- setup->td->td_link = next->physaddr;
- setup->td->td_status = UHCI_TD_SET_ERRCNT(3) | ls | UHCI_TD_ACTIVE;
- setup->td->td_token = UHCI_TD_SETUP(sizeof *req, endpt, addr);
- setup->td->td_buffer = DMAADDR(&upipe->u.ctl.reqdma);
- memcpy(KERNADDR(&upipe->u.ctl.reqdma), req, sizeof *req);
-
- /* initialise the status stage */
- stat->td->link.std = 0;
- stat->td->td_link = UHCI_PTR_T;
- stat->td->td_status = UHCI_TD_SET_ERRCNT(3) | ls |
- UHCI_TD_ACTIVE | UHCI_TD_IOC;
- stat->td->td_token =
- isread ? UHCI_TD_OUT(0, endpt, addr, 1) :
- UHCI_TD_IN (0, endpt, addr, 1);
- stat->td->td_buffer = 0;
-
- /* initialise interrupt info. */
- ii->reqh = reqh;
- ii->stdstart = setup;
- ii->stdend = stat;
-#if defined(__FreeBSD__)
- callout_handle_init(&ii->timeout_handle);
-#endif
-#ifdef DIAGNOSTIC
- ii->isdone = 0;
-#endif
-
-#ifdef UHCI_DEBUG
- if (uhcidebug > 10)
- uhci_dump_tds(setup);
-#endif
-
- sqh->qh->elink = setup;
- sqh->qh->qh_elink = setup->physaddr;
- sqh->intr_info = ii;
-
- s = splusb();
- uhci_add_ctrl(sc, sqh);
- LIST_INSERT_HEAD(&sc->sc_intrhead, ii, list);
- if (reqh->timeout && !sc->sc_bus.use_polling) {
- usb_timeout(uhci_timeout, ii,
- MS_TO_TICKS(reqh->timeout), ii->timeout_handle);
+ maxp = UGETW(upipe->pipe.endpoint->edesc->wMaxPacketSize);
+ if (maxp == 0) {
+ printf("uhci_alloc_std_chain: maxp=0\n");
+ return (USBD_INVAL);
}
- splx(s);
-
- return(USBD_NORMAL_COMPLETION);
-}
-
-
-usbd_status
-uhci_device_ctrl_transfer(reqh)
- usbd_request_handle reqh;
-{
- int s;
- usbd_status err;
-
- s = splusb();
- err = usb_insert_transfer(reqh);
- splx(s);
- if (err != USBD_NORMAL_COMPLETION)
- return(err);
- else
- return(uhci_device_ctrl_start(reqh));
-}
-
-usbd_status
-uhci_device_ctrl_start(reqh)
- usbd_request_handle reqh;
-{
- uhci_softc_t *sc = (uhci_softc_t *)reqh->pipe->device->bus;
- usbd_status err;
-
- if (!reqh->isreq)
- panic("uhci_device_ctrl_start: not a request\n");
-
- err = uhci_device_request(reqh);
- if (err != USBD_NORMAL_COMPLETION)
- return(err);
-
- if (sc->sc_bus.use_polling)
- uhci_waitintr(sc, reqh);
- return(USBD_IN_PROGRESS);
+ ntd = (len + maxp - 1) / maxp;
+ DPRINTFN(10, ("uhci_alloc_std_chain: maxp=%d ntd=%d\n", maxp, ntd));
+ tog = upipe->nexttoggle;
+ if (ntd % 2 == 0)
+ tog ^= 1;
+ upipe->nexttoggle = tog ^ 1;
+ lastp = 0;
+ lastlink = UHCI_PTR_T;
+ ntd--;
+ status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(3) | UHCI_TD_ACTIVE);
+ if (upipe->pipe.device->lowspeed)
+ status |= UHCI_TD_LS;
+ if (shortok)
+ status |= UHCI_TD_SPD;
+ for (i = ntd; i >= 0; i--) {
+ p = uhci_alloc_std(sc);
+ if (!p) {
+ uhci_free_std_chain(sc, lastp, 0);
+ return (USBD_NOMEM);
+ }
+ p->link.std = lastp;
+ p->td.td_link = LE(lastlink);
+ lastp = p;
+ lastlink = p->physaddr;
+ p->td.td_status = LE(status);
+ if (i == ntd) {
+ /* last TD */
+ l = len % maxp;
+ if (l == 0) l = maxp;
+ *ep = p;
+ } else
+ l = maxp;
+ p->td.td_token =
+ LE(rd ? UHCI_TD_IN (l, endpt, addr, tog) :
+ UHCI_TD_OUT(l, endpt, addr, tog));
+ p->td.td_buffer = LE(DMAADDR(dma) + i * maxp);
+ tog ^= 1;
+ }
+ *sp = lastp;
+ DPRINTFN(10, ("uhci_alloc_std_chain: nexttog=%d\n",
+ upipe->nexttoggle));
+ return (USBD_NORMAL_COMPLETION);
}
-
void
-uhci_device_ctrl_abort(reqh)
- usbd_request_handle reqh;
+uhci_device_clear_toggle(pipe)
+ usbd_pipe_handle pipe;
{
- /* XXX inactivate */
- usb_delay_ms(reqh->pipe->device->bus, 1); /* make sure it is done */
- /* XXX call done */
+ struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
+ upipe->nexttoggle = 0;
}
void
-uhci_device_ctrl_close(pipe)
+uhci_noop(pipe)
usbd_pipe_handle pipe;
{
- struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
-
- uhci_free_intr_info(upipe->iinfo);
- /* XXX free other resources */
}
usbd_status
uhci_device_bulk_transfer(reqh)
usbd_request_handle reqh;
{
- int s;
- usbd_status err;
+ usbd_status r;
- s = splusb();
- err = usb_insert_transfer(reqh);
- splx(s);
- if (err != USBD_NORMAL_COMPLETION)
- return(err);
+ r = usb_insert_transfer(reqh);
+ if (r != USBD_NORMAL_COMPLETION)
+ return (r);
else
- return(uhci_device_bulk_start(reqh));
+ return (uhci_device_bulk_start(reqh));
}
usbd_status
@@ -1577,60 +1344,46 @@ uhci_device_bulk_start(reqh)
usbd_device_handle dev = upipe->pipe.device;
uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
uhci_intr_info_t *ii = upipe->iinfo;
- uhci_soft_td_t *std, *stdend;
+ uhci_soft_td_t *xfer, *xferend;
uhci_soft_qh_t *sqh;
- usb_dma_t *dmap;
- usbd_status err;
- int datalen, isread;
+ usbd_status r;
+ int len, isread, endpt;
int s;
- DPRINTFN(3, ("uhci_device_bulk_start: reqh=%p buf=%p datalen=%d "
- "flags=%d\n",
- reqh, reqh->buffer, reqh->length, reqh->flags));
+ DPRINTFN(3, ("uhci_device_bulk_transfer: reqh=%p len=%d flags=%d\n",
+ reqh, reqh->length, reqh->flags));
- if (reqh->isreq)
- panic("uhci_device_bulk_start: a request\n");
-
- if (reqh->length == 0)
- return(USBD_INVAL);
+#ifdef DIAGNOSTIC
+ if (reqh->rqflags & URQ_REQUEST)
+ panic("uhci_device_bulk_transfer: a request\n");
+#endif
- datalen = reqh->length;
- dmap = &upipe->u.bulk.datadma;
- isread = reqh->pipe->endpoint->edesc->bEndpointAddress & UE_IN;
+ len = reqh->length;
+ endpt = reqh->pipe->endpoint->edesc->bEndpointAddress;
+ isread = UE_GET_DIR(endpt) == UE_DIR_IN;
sqh = upipe->u.bulk.sqh;
upipe->u.bulk.isread = isread;
- upipe->u.bulk.length = datalen;
+ upipe->u.bulk.length = len;
- err = usb_allocmem(sc->sc_dmatag, datalen, 0, dmap);
- if (err != USBD_NORMAL_COMPLETION)
- return(err);
-
- upipe->pipe.endpoint->toggle = upipe->nexttoggle;
- err = uhci_alloc_std_chain(sc, upipe, datalen, isread,
+ r = uhci_alloc_std_chain(upipe, sc, len, isread,
reqh->flags & USBD_SHORT_XFER_OK,
- dmap, &std, &stdend);
- if (err != USBD_NORMAL_COMPLETION) {
- usb_freemem(sc->sc_dmatag, dmap);
- return(err);
- }
-
- stdend->td->td_status |= UHCI_TD_IOC;
-
- if (!isread)
- memcpy(KERNADDR(dmap), reqh->buffer, datalen);
+ &reqh->dmabuf, &xfer, &xferend);
+ if (r != USBD_NORMAL_COMPLETION)
+ return (r);
+ xferend->td.td_status |= LE(UHCI_TD_IOC);
#ifdef UHCI_DEBUG
- if (uhcidebug > 10) {
- DPRINTF(("uhci_device_bulk_start: xfer\n"));
- uhci_dump_tds(std);
+ if (uhcidebug > 8) {
+ DPRINTF(("uhci_device_bulk_transfer: xfer(1)\n"));
+ uhci_dump_tds(xfer);
}
#endif
/* Set up interrupt info. */
ii->reqh = reqh;
- ii->stdstart = std;
- ii->stdend = stdend;
+ ii->stdstart = xfer;
+ ii->stdend = xferend;
#if defined(__FreeBSD__)
callout_handle_init(&ii->timeout_handle);
#endif
@@ -1638,8 +1391,8 @@ uhci_device_bulk_start(reqh)
ii->isdone = 0;
#endif
- sqh->qh->elink = std;
- sqh->qh->qh_elink = std->physaddr;
+ sqh->elink = xfer;
+ sqh->qh.qh_elink = LE(xfer->physaddr);
sqh->intr_info = ii;
s = splusb();
@@ -1647,24 +1400,79 @@ uhci_device_bulk_start(reqh)
LIST_INSERT_HEAD(&sc->sc_intrhead, ii, list);
if (reqh->timeout && !sc->sc_bus.use_polling) {
- usb_timeout(uhci_timeout, ii,
- MS_TO_TICKS(reqh->timeout), ii->timeout_handle);
+ usb_timeout(uhci_timeout, ii, MS_TO_TICKS(reqh->timeout),
+ ii->timeout_handle);
}
splx(s);
- return(USBD_IN_PROGRESS);
+#ifdef UHCI_DEBUG
+ if (uhcidebug > 10) {
+ DPRINTF(("uhci_device_bulk_transfer: xfer(2)\n"));
+ uhci_dump_tds(xfer);
+ }
+#endif
+
+ if (sc->sc_bus.use_polling)
+ uhci_waitintr(sc, reqh);
+
+ return (USBD_IN_PROGRESS);
}
+/* Abort a device bulk request. */
void
uhci_device_bulk_abort(reqh)
usbd_request_handle reqh;
{
- /* XXX inactivate */
- usb_delay_ms(reqh->pipe->device->bus, 1);/* make sure it is done */
- /* XXX call done */
+ DPRINTF(("uhci_device_bulk_abort:\n"));
+ uhci_abort_req(reqh, USBD_CANCELLED);
}
void
+uhci_abort_req(reqh, status)
+ usbd_request_handle reqh;
+ usbd_status status;
+{
+ struct uhci_pipe *upipe = (struct uhci_pipe *)reqh->pipe;
+ uhci_intr_info_t *ii = upipe->iinfo;
+ uhci_soft_td_t *std;
+
+ /* Make interrupt routine ignore it, */
+ reqh->status = status;
+
+ /* don't timeout, */
+ usb_untimeout(uhci_timeout, ii, ii->timeout_handle);
+
+ /* make hardware ignore it, */
+ for (std = ii->stdstart; std != 0; std = std->link.std)
+ std->td.td_status &= LE(~(UHCI_TD_ACTIVE | UHCI_TD_IOC));
+
+ reqh->hcpriv = ii;
+
+ /* make sure hardware has completed, */
+ if (curproc) {
+ usb_delay_ms(reqh->pipe->device->bus, 1);
+ /* and call final part of interrupt handler. */
+ uhci_abort_req_end(reqh);
+ } else {
+ /* We have no process context, so we can't use tsleep(). */
+ timeout(uhci_abort_req_end, reqh, hz / USB_FRAMES_PER_SECOND);
+ }
+}
+
+void
+uhci_abort_req_end(v)
+ void *v;
+{
+ usbd_request_handle reqh = v;
+ int s;
+
+ s = splusb();
+ usb_transfer_complete(reqh);
+ splx(s);
+}
+
+/* Close a device bulk pipe. */
+void
uhci_device_bulk_close(pipe)
usbd_pipe_handle pipe;
{
@@ -1678,19 +1486,50 @@ uhci_device_bulk_close(pipe)
}
usbd_status
+uhci_device_ctrl_transfer(reqh)
+ usbd_request_handle reqh;
+{
+ usbd_status r;
+
+ r = usb_insert_transfer(reqh);
+ if (r != USBD_NORMAL_COMPLETION)
+ return (r);
+ else
+ return (uhci_device_ctrl_start(reqh));
+}
+
+usbd_status
+uhci_device_ctrl_start(reqh)
+ usbd_request_handle reqh;
+{
+ uhci_softc_t *sc = (uhci_softc_t *)reqh->pipe->device->bus;
+ usbd_status r;
+
+#ifdef DIAGNOSTIC
+ if (!(reqh->rqflags & URQ_REQUEST))
+ panic("uhci_device_ctrl_transfer: not a request\n");
+#endif
+
+ r = uhci_device_request(reqh);
+ if (r != USBD_NORMAL_COMPLETION)
+ return (r);
+
+ if (sc->sc_bus.use_polling)
+ uhci_waitintr(sc, reqh);
+ return (USBD_IN_PROGRESS);
+}
+
+usbd_status
uhci_device_intr_transfer(reqh)
usbd_request_handle reqh;
{
- int s;
- usbd_status err;
+ usbd_status r;
- s = splusb();
- err = usb_insert_transfer(reqh);
- splx(s);
- if (err != USBD_NORMAL_COMPLETION)
- return(err);
+ r = usb_insert_transfer(reqh);
+ if (r != USBD_NORMAL_COMPLETION)
+ return (r);
else
- return(uhci_device_intr_start(reqh));
+ return (uhci_device_intr_start(reqh));
}
usbd_status
@@ -1701,45 +1540,30 @@ uhci_device_intr_start(reqh)
usbd_device_handle dev = upipe->pipe.device;
uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
uhci_intr_info_t *ii = upipe->iinfo;
- uhci_soft_td_t *std, *stdend;
+ uhci_soft_td_t *xfer, *xferend;
uhci_soft_qh_t *sqh;
- usb_dma_t *dmap;
- usbd_status err;
- int datalen, i;
- int s;
-
- DPRINTFN(3, ("uhci_device_intr_start: reqh=%p buf=%p datalen=%d "
- "flags=%d\n",
- reqh, reqh->buffer, reqh->length, reqh->flags));
+ usbd_status r;
+ int i, s;
- if (reqh->isreq)
- panic("uhci_device_intr_start: a request\n");
+ DPRINTFN(3,("uhci_device_intr_transfer: reqh=%p len=%d flags=%d\n",
+ reqh, reqh->length, reqh->flags));
- datalen = reqh->length;
- dmap = &upipe->u.intr.datadma;
- if (datalen == 0)
- return(USBD_INVAL); /* XXX should it be? */
-
- err = usb_allocmem(sc->sc_dmatag, datalen, 0, dmap);
- if (err != USBD_NORMAL_COMPLETION)
- return(err);
+#ifdef DIAGNOSTIC
+ if (reqh->rqflags & URQ_REQUEST)
+ panic("uhci_device_intr_transfer: a request\n");
+#endif
- upipe->pipe.endpoint->toggle = upipe->nexttoggle;
- err = uhci_alloc_std_chain(sc, upipe, datalen, 1,
+ r = uhci_alloc_std_chain(upipe, sc, reqh->length, 1,
reqh->flags & USBD_SHORT_XFER_OK,
- dmap, &std, &stdend);
- if (err != USBD_NORMAL_COMPLETION) {
- if (datalen != 0)
- usb_freemem(sc->sc_dmatag, dmap);
- return err;
- }
-
- stdend->td->td_status |= UHCI_TD_IOC;
+ &reqh->dmabuf, &xfer, &xferend);
+ if (r != USBD_NORMAL_COMPLETION)
+ return (r);
+ xferend->td.td_status |= LE(UHCI_TD_IOC);
#ifdef UHCI_DEBUG
if (uhcidebug > 10) {
- DPRINTF(("uhci_device_intr_start: xfer\n"));
- uhci_dump_tds(std);
+ DPRINTF(("uhci_device_intr_transfer: xfer(1)\n"));
+ uhci_dump_tds(xfer);
uhci_dump_qh(upipe->u.intr.qhs[0]);
}
#endif
@@ -1747,37 +1571,69 @@ uhci_device_intr_start(reqh)
s = splusb();
/* Set up interrupt info. */
ii->reqh = reqh;
- ii->stdstart = std;
- ii->stdend = stdend;
+ ii->stdstart = xfer;
+ ii->stdend = xferend;
+#if defined(__FreeBSD__)
+ callout_handle_init(&ii->timeout_handle);
+#endif
#ifdef DIAGNOSTIC
ii->isdone = 0;
#endif
- DPRINTFN(10,("uhci_device_intr_start: qhs[0]=%p\n",
+ DPRINTFN(10,("uhci_device_intr_transfer: qhs[0]=%p\n",
upipe->u.intr.qhs[0]));
for (i = 0; i < upipe->u.intr.npoll; i++) {
sqh = upipe->u.intr.qhs[i];
- sqh->qh->elink = std;
- sqh->qh->qh_elink = std->physaddr;
+ sqh->elink = xfer;
+ sqh->qh.qh_elink = LE(xfer->physaddr);
}
splx(s);
- return(USBD_IN_PROGRESS);
+#ifdef UHCI_DEBUG
+ if (uhcidebug > 10) {
+ DPRINTF(("uhci_device_intr_transfer: xfer(2)\n"));
+ uhci_dump_tds(xfer);
+ uhci_dump_qh(upipe->u.intr.qhs[0]);
+ }
+#endif
+
+ return (USBD_IN_PROGRESS);
}
+/* Abort a device control request. */
+void
+uhci_device_ctrl_abort(reqh)
+ usbd_request_handle reqh;
+{
+ DPRINTF(("uhci_device_ctrl_abort:\n"));
+ uhci_abort_req(reqh, USBD_CANCELLED);
+}
+
+/* Close a device control pipe. */
+void
+uhci_device_ctrl_close(pipe)
+ usbd_pipe_handle pipe;
+{
+ struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
+
+ uhci_free_intr_info(upipe->iinfo);
+ /* XXX free other resources */
+}
+
+/* Abort a device interrupt request. */
void
uhci_device_intr_abort(reqh)
usbd_request_handle reqh;
{
- DPRINTFN(1, ("uhci_device_intr_abort: reqh=%p\n", reqh));
+ DPRINTFN(1,("uhci_device_intr_abort: reqh=%p\n", reqh));
if (reqh->pipe->intrreqh == reqh) {
- DPRINTF(("uhci_device_intr_abort: remove\n"));
+ DPRINTFN(1,("uhci_device_intr_abort: remove\n"));
reqh->pipe->intrreqh = 0;
- /* make sure it is done */
- usb_delay_ms(reqh->pipe->device->bus, 2);
}
+ uhci_abort_req(reqh, USBD_CANCELLED);
}
+/* Close a device interrupt pipe. */
void
uhci_device_intr_close(pipe)
usbd_pipe_handle pipe;
@@ -1804,7 +1660,7 @@ uhci_device_intr_close(pipe)
for(i = 0; i < npoll; i++)
uhci_free_sqh(sc, upipe->u.intr.qhs[i]);
- free(upipe->u.intr.qhs, M_USB);
+ free(upipe->u.intr.qhs, M_USBHC);
s = splusb();
LIST_REMOVE(upipe->iinfo, list); /* remove from active list */
@@ -1815,35 +1671,292 @@ uhci_device_intr_close(pipe)
}
usbd_status
-uhci_device_isoc_transfer(reqh)
+uhci_device_request(reqh)
usbd_request_handle reqh;
{
struct uhci_pipe *upipe = (struct uhci_pipe *)reqh->pipe;
+ usb_device_request_t *req = &reqh->request;
+ usbd_device_handle dev = upipe->pipe.device;
+ uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
+ int addr = dev->address;
+ int endpt = upipe->pipe.endpoint->edesc->bEndpointAddress;
+ uhci_intr_info_t *ii = upipe->iinfo;
+ uhci_soft_td_t *setup, *xfer, *stat, *next, *xferend;
+ uhci_soft_qh_t *sqh;
+ int len;
+ u_int32_t ls;
+ usbd_status r;
+ int isread;
+ int s;
+
+ DPRINTFN(3,("uhci_device_control type=0x%02x, request=0x%02x, "
+ "wValue=0x%04x, wIndex=0x%04x len=%d, addr=%d, endpt=%d\n",
+ req->bmRequestType, req->bRequest, UGETW(req->wValue),
+ UGETW(req->wIndex), UGETW(req->wLength),
+ addr, endpt));
+
+ ls = dev->lowspeed ? UHCI_TD_LS : 0;
+ isread = req->bmRequestType & UT_READ;
+ len = UGETW(req->wLength);
+
+ setup = upipe->u.ctl.setup;
+ stat = upipe->u.ctl.stat;
+ sqh = upipe->u.ctl.sqh;
+
+ /* Set up data transaction */
+ if (len != 0) {
+ upipe->nexttoggle = 1;
+ r = uhci_alloc_std_chain(upipe, sc, len, isread,
+ reqh->flags & USBD_SHORT_XFER_OK,
+ &reqh->dmabuf, &xfer, &xferend);
+ if (r != USBD_NORMAL_COMPLETION)
+ return (r);
+ next = xfer;
+ xferend->link.std = stat;
+ xferend->td.td_link = LE(stat->physaddr);
+ } else {
+ next = stat;
+ }
+ upipe->u.ctl.length = len;
+
+ memcpy(KERNADDR(&upipe->u.ctl.reqdma), req, sizeof *req);
+
+ setup->link.std = next;
+ setup->td.td_link = LE(next->physaddr);
+ setup->td.td_status = LE(UHCI_TD_SET_ERRCNT(3) | ls | UHCI_TD_ACTIVE);
+ setup->td.td_token = LE(UHCI_TD_SETUP(sizeof *req, endpt, addr));
+ setup->td.td_buffer = LE(DMAADDR(&upipe->u.ctl.reqdma));
+
+ stat->link.std = 0;
+ stat->td.td_link = LE(UHCI_PTR_T);
+ stat->td.td_status = LE(UHCI_TD_SET_ERRCNT(3) | ls |
+ UHCI_TD_ACTIVE | UHCI_TD_IOC);
+ stat->td.td_token =
+ LE(isread ? UHCI_TD_OUT(0, endpt, addr, 1) :
+ UHCI_TD_IN (0, endpt, addr, 1));
+ stat->td.td_buffer = LE(0);
+
#ifdef UHCI_DEBUG
+ if (uhcidebug > 20) {
+ DPRINTF(("uhci_device_request: before transfer\n"));
+ uhci_dump_tds(setup);
+ }
+#endif
+
+ /* Set up interrupt info. */
+ ii->reqh = reqh;
+ ii->stdstart = setup;
+ ii->stdend = stat;
+#ifdef DIAGNOSTIC
+ ii->isdone = 0;
+#endif
+
+ sqh->elink = setup;
+ sqh->qh.qh_elink = LE(setup->physaddr);
+ sqh->intr_info = ii;
+
+ s = splusb();
+ uhci_add_ctrl(sc, sqh);
+ LIST_INSERT_HEAD(&sc->sc_intrhead, ii, list);
+#ifdef UHCI_DEBUG
+ if (uhcidebug > 12) {
+ uhci_soft_td_t *std;
+ uhci_soft_qh_t *xqh;
+ uhci_soft_qh_t *sxqh;
+ int maxqh = 0;
+ uhci_physaddr_t link;
+ DPRINTF(("uhci_enter_ctl_q: follow from [0]\n"));
+ for (std = sc->sc_vframes[0].htd, link = 0;
+ (link & UHCI_PTR_Q) == 0;
+ std = std->link.std) {
+ link = LE(std->td.td_link);
+ uhci_dump_td(std);
+ }
+ for (sxqh = xqh = (uhci_soft_qh_t *)std;
+ xqh;
+ xqh = (maxqh++ == 5 || xqh->hlink==sxqh ||
+ xqh->hlink==xqh ? NULL : xqh->hlink)) {
+ uhci_dump_qh(xqh);
+ uhci_dump_qh(sxqh);
+ }
+ DPRINTF(("Enqueued QH:\n"));
+ uhci_dump_qh(sqh);
+ uhci_dump_tds(sqh->elink);
+ }
+#endif
+ if (reqh->timeout && !sc->sc_bus.use_polling) {
+ usb_timeout(uhci_timeout, ii,
+ MS_TO_TICKS(reqh->timeout), ii->timeout_handle);
+ }
+ splx(s);
+
+ return (USBD_NORMAL_COMPLETION);
+}
+
+usbd_status
+uhci_device_isoc_transfer(reqh)
+ usbd_request_handle reqh;
+{
+ usbd_status r;
+
+ DPRINTFN(5,("uhci_device_isoc_transfer: reqh=%p\n", reqh));
+
+ /* Put it on our queue, */
+ r = usb_insert_transfer(reqh);
+
+ /* bail out on error, */
+ if (r != USBD_NORMAL_COMPLETION && r != USBD_IN_PROGRESS)
+ return (r);
+
+ /* XXX should check inuse here */
+
+ /* insert into schedule, */
+ uhci_device_isoc_enter(reqh);
+
+ /* and put on interrupt list if the pipe wasn't running */
+ if (r == USBD_NORMAL_COMPLETION)
+ uhci_device_isoc_start(reqh);
+
+ return (r);
+}
+
+void
+uhci_device_isoc_enter(reqh)
+ usbd_request_handle reqh;
+{
+ struct uhci_pipe *upipe = (struct uhci_pipe *)reqh->pipe;
usbd_device_handle dev = upipe->pipe.device;
uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
+ struct iso *iso = &upipe->u.iso;
+ uhci_soft_td_t *std;
+ u_int32_t buf, len, status;
+ int s, i, next, nframes;
+
+ DPRINTFN(5,("uhci_device_isoc_enter: used=%d next=%d reqh=%p "
+ "nframes=%d\n",
+ iso->inuse, iso->next, reqh, reqh->nframes));
+
+ if (reqh->status == USBD_IN_PROGRESS) {
+ /* This request has already been entered into the frame list */
+ }
+
+#ifdef DIAGNOSTIC
+ if (iso->inuse >= UHCI_VFRAMELIST_COUNT)
+ printf("uhci_device_isoc_enter: overflow!\n");
#endif
- DPRINTFN(1,("uhci_device_isoc_transfer: sc=%p\n", sc));
- if (upipe->u.iso.bufsize == 0)
- return(USBD_INVAL);
+ next = iso->next;
+ if (next == -1) {
+ /* Not in use yet, schedule it a few frames ahead. */
+ next = (UREAD2(sc, UHCI_FRNUM) + 3) % UHCI_VFRAMELIST_COUNT;
+ DPRINTFN(2,("uhci_device_isoc_enter: start next=%d\n", next));
+ }
- /* XXX copy data */
- return(USBD_XXX);
+ reqh->status = USBD_IN_PROGRESS;
+ reqh->hcprivint = next;
+
+ buf = DMAADDR(&reqh->dmabuf);
+ status = LE(UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(0) |
+ UHCI_TD_ACTIVE |
+ UHCI_TD_IOS));
+ nframes = reqh->nframes;
+ s = splusb();
+ for (i = 0; i < nframes; i++) {
+ std = iso->stds[next];
+ if (++next >= UHCI_VFRAMELIST_COUNT)
+ next = 0;
+ len = reqh->frlengths[i];
+ std->td.td_buffer = LE(buf);
+ if (i == nframes - 1)
+ status |= LE(UHCI_TD_IOC);
+ std->td.td_status = status;
+ std->td.td_token &= LE(~UHCI_TD_MAXLEN_MASK);
+ std->td.td_token |= LE(UHCI_TD_SET_MAXLEN(len));
+#ifdef UHCI_DEBUG
+ if (uhcidebug > 5) {
+ DPRINTFN(5,("uhci_device_isoc_enter: TD %d\n", i));
+ uhci_dump_td(std);
+ }
+#endif
+ buf += len;
+ }
+ iso->next = next;
+ iso->inuse += reqh->nframes;
+
+ splx(s);
}
usbd_status
uhci_device_isoc_start(reqh)
usbd_request_handle reqh;
{
- return(USBD_XXX);
+ struct uhci_pipe *upipe = (struct uhci_pipe *)reqh->pipe;
+ uhci_softc_t *sc = (uhci_softc_t *)upipe->pipe.device->bus;
+ uhci_intr_info_t *ii = upipe->iinfo;
+ uhci_soft_td_t *end;
+ int s, i;
+
+#ifdef DIAGNOSTIC
+ if (reqh->status != USBD_IN_PROGRESS)
+ printf("uhci_device_isoc_start: not in progress %p\n", reqh);
+#endif
+
+ /* Find the last TD */
+ i = reqh->hcprivint + reqh->nframes;
+ if (i >= UHCI_VFRAMELIST_COUNT)
+ i -= UHCI_VFRAMELIST_COUNT;
+ end = upipe->u.iso.stds[i];
+
+ s = splusb();
+
+ /* Set up interrupt info. */
+ ii->reqh = reqh;
+ ii->stdstart = end;
+ ii->stdend = end;
+#ifdef DIAGNOSTIC
+ ii->isdone = 0;
+#endif
+ LIST_INSERT_HEAD(&sc->sc_intrhead, ii, list);
+
+ splx(s);
+
+ return (USBD_IN_PROGRESS);
}
void
uhci_device_isoc_abort(reqh)
usbd_request_handle reqh;
{
- /* XXX Can't abort a single request. */
+ struct uhci_pipe *upipe = (struct uhci_pipe *)reqh->pipe;
+ uhci_intr_info_t *ii = upipe->iinfo;
+ uhci_soft_td_t **stds = upipe->u.iso.stds;
+ uhci_soft_td_t *std;
+ int i, n, nframes;
+
+ /* Make interrupt routine ignore it, */
+ reqh->status = USBD_CANCELLED;
+
+ /* make hardware ignore it, */
+ nframes = reqh->nframes;
+ n = reqh->hcprivint;
+ for (i = 0; i < nframes; i++) {
+ std = stds[n];
+ std->td.td_status &= LE(~(UHCI_TD_ACTIVE | UHCI_TD_IOC));
+ if (++n >= UHCI_VFRAMELIST_COUNT)
+ n = 0;
+ }
+
+ reqh->hcpriv = ii;
+
+ /* make sure hardware has completed, */
+ if (curproc) {
+ usb_delay_ms(reqh->pipe->device->bus, 1);
+ /* and call final part of interrupt handler. */
+ uhci_abort_req_end(reqh);
+ } else {
+ /* We have no process context, so we can't use tsleep(). */
+ timeout(uhci_abort_req_end, reqh, hz / USB_FRAMES_PER_SECOND);
+ }
}
void
@@ -1853,6 +1966,7 @@ uhci_device_isoc_close(pipe)
struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
usbd_device_handle dev = upipe->pipe.device;
uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
+ uhci_soft_td_t *std, *vstd;
struct iso *iso;
int i;
@@ -1865,480 +1979,388 @@ uhci_device_isoc_close(pipe)
iso = &upipe->u.iso;
for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++)
- iso->stds[i]->td->td_status &= ~UHCI_TD_ACTIVE;
+ iso->stds[i]->td.td_status &= LE(~UHCI_TD_ACTIVE);
usb_delay_ms(&sc->sc_bus, 2); /* wait for completion */
uhci_lock_frames(sc);
for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
- uhci_soft_td_t *std, *vstd;
-
std = iso->stds[i];
- for (vstd = sc->sc_vframes[i % UHCI_VFRAMELIST_COUNT].htd;
- vstd && vstd->td->link.std != std;
- vstd = vstd->td->link.std)
+ for (vstd = sc->sc_vframes[i].htd;
+ vstd && vstd->link.std != std;
+ vstd = vstd->link.std)
;
if (!vstd) {
/*panic*/
- DPRINTF(("uhci_device_isoc_close: %p not found\n",std));
+ printf("uhci_device_isoc_close: %p not found\n", std);
uhci_unlock_frames(sc);
return;
}
- vstd->td->link = std->td->link;
- vstd->td->td_link = std->td->td_link;
+ vstd->link = std->link;
+ vstd->td.td_link = std->td.td_link;
uhci_free_std(sc, std);
}
uhci_unlock_frames(sc);
- for (i = 0; i < iso->nbuf; i++)
- usb_freemem(sc->sc_dmatag, &iso->bufs[i]);
- free(iso->stds, M_USB);
- free(iso->bufs, M_USB);
-
- /* XXX what else? */
+ free(iso->stds, M_USBHC);
}
-
usbd_status
-uhci_device_isoc_setbuf(pipe, bufsize, nbuf)
+uhci_setup_isoc(pipe)
usbd_pipe_handle pipe;
- u_int bufsize;
- u_int nbuf;
{
struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
usbd_device_handle dev = upipe->pipe.device;
uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
int addr = upipe->pipe.device->address;
int endpt = upipe->pipe.endpoint->edesc->bEndpointAddress;
- int isread = upipe->pipe.endpoint->edesc->bEndpointAddress & UE_IN;
+ int rd = UE_GET_DIR(endpt) == UE_DIR_IN;
+ uhci_soft_td_t *std, *vstd;
+ u_int32_t token;
struct iso *iso;
int i;
- usbd_status err;
-
- /*
- * For simplicity the number of buffers must fit nicely in the frame
- * list.
- */
- if (UHCI_VFRAMELIST_COUNT % nbuf != 0)
- return(USBD_INVAL);
iso = &upipe->u.iso;
- iso->bufsize = bufsize;
- iso->nbuf = nbuf;
-
- /* Allocate memory for buffers. */
- iso->bufs = malloc(nbuf * sizeof(usb_dma_t), M_USB, M_WAITOK);
iso->stds = malloc(UHCI_VFRAMELIST_COUNT * sizeof (uhci_soft_td_t *),
- M_USB, M_WAITOK);
+ M_USBHC, M_WAITOK);
- for (i = 0; i < nbuf; i++) {
- err = usb_allocmem(sc->sc_dmatag, bufsize, 0, &iso->bufs[i]);
- if (err != USBD_NORMAL_COMPLETION) {
- nbuf = i;
- goto bad1;
- }
- }
+ token = LE(rd ? UHCI_TD_IN (0, endpt, addr, 0) :
+ UHCI_TD_OUT(0, endpt, addr, 0));
- /* Allocate the TDs. */
+ /* Allocate the TDs and mark as inactive; */
for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
- iso->stds[i] = uhci_alloc_std(sc);
- if (iso->stds[i] == 0)
- goto bad2;
+ std = uhci_alloc_std(sc);
+ if (std == 0)
+ goto bad;
+ std->td.td_status = LE(UHCI_TD_IOS); /* iso, inactive */
+ std->td.td_token = token;
+ iso->stds[i] = std;
}
- /* XXX check schedule */
-
- /* XXX interrupts */
-
- /* Insert TDs into schedule, all marked inactive. */
+ /* Insert TDs into schedule. */
uhci_lock_frames(sc);
for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
- uhci_soft_td_t *std, *vstd;
-
std = iso->stds[i];
- std->td->td_status = UHCI_TD_IOS; /* iso, inactive */
- std->td->td_token =
- isread ? UHCI_TD_IN (0, endpt, addr, 0) :
- UHCI_TD_OUT(0, endpt, addr, 0);
- std->td->td_buffer = DMAADDR(&iso->bufs[i % nbuf]);
-
- vstd = sc->sc_vframes[i % UHCI_VFRAMELIST_COUNT].htd;
- std->td->link = vstd->td->link;
- std->td->td_link = vstd->td->td_link;
- vstd->td->link.std = std;
- vstd->td->td_link = std->physaddr;
+ vstd = sc->sc_vframes[i].htd;
+ std->link = vstd->link;
+ std->td.td_link = vstd->td.td_link;
+ vstd->link.std = std;
+ vstd->td.td_link = LE(std->physaddr);
}
uhci_unlock_frames(sc);
- return(USBD_NORMAL_COMPLETION);
+ iso->next = -1;
+ iso->inuse = 0;
- bad2:
+ return (USBD_NORMAL_COMPLETION);
+
+ bad:
while (--i >= 0)
uhci_free_std(sc, iso->stds[i]);
- bad1:
- for (i = 0; i < nbuf; i++)
- usb_freemem(sc->sc_dmatag, &iso->bufs[i]);
- free(iso->stds, M_USB);
- free(iso->bufs, M_USB);
- return(USBD_NOMEM);
+ free(iso->stds, M_USBHC);
+ return (USBD_NOMEM);
}
-/* Set interval for interrupt transfer */
-usbd_status
-uhci_device_intr_interval(sc, upipe, ival)
- uhci_softc_t *sc;
- struct uhci_pipe *upipe;
- int ival;
+void
+uhci_device_isoc_done(reqh)
+ usbd_request_handle reqh;
{
- uhci_soft_qh_t *sqh;
- int i, npoll, s;
- u_int bestbw, bw, bestoffs, offs;
-
- DPRINTFN(2, ("uhci_setintr: pipe=%p\n", upipe));
- if (ival == 0) {
- DPRINTF(("uhci_setintr: 0 interval\n"));
- return(USBD_INVAL);
- }
-
- if (ival > UHCI_VFRAMELIST_COUNT)
- ival = UHCI_VFRAMELIST_COUNT;
- npoll = (UHCI_VFRAMELIST_COUNT + ival - 1) / ival;
- DPRINTFN(2, ("uhci_setintr: ival=%d npoll=%d\n", ival, npoll));
-
- upipe->u.intr.npoll = npoll;
- upipe->u.intr.qhs =
- malloc(npoll * sizeof(uhci_soft_qh_t *), M_USB, M_WAITOK);
-
- /*
- * Figure out which offset in the schedule that has most
- * bandwidth left over.
- */
-#define MOD(i) ((i) & (UHCI_VFRAMELIST_COUNT-1))
- for (bestoffs = offs = 0, bestbw = ~0; offs < ival; offs++) {
- for (bw = i = 0; i < npoll; i++)
- bw += sc->sc_vframes[MOD(i * ival + offs)].bandwidth;
- if (bw < bestbw) {
- bestbw = bw;
- bestoffs = offs;
- }
- }
- DPRINTFN(1, ("uhci_setintr: bw=%d offs=%d\n", bestbw, bestoffs));
-
- upipe->iinfo->stdstart = 0;
- for(i = 0; i < npoll; i++) {
- upipe->u.intr.qhs[i] = sqh = uhci_alloc_sqh(sc);
- sqh->qh->elink = 0;
- sqh->qh->qh_elink = UHCI_PTR_T;
- sqh->pos = MOD(i * ival + bestoffs);
- sqh->intr_info = upipe->iinfo;
- }
-#undef MOD
+ uhci_intr_info_t *ii = reqh->hcpriv;
- s = splusb();
- LIST_INSERT_HEAD(&sc->sc_intrhead, upipe->iinfo, list);
- splx(s);
+ DPRINTFN(4, ("uhci_isoc_done: length=%d\n", reqh->actlen));
- uhci_lock_frames(sc);
- /* Enter QHs into the controller data structures. */
- for(i = 0; i < npoll; i++)
- uhci_add_intr(sc, upipe->u.intr.qhs[i]->pos,
- upipe->u.intr.qhs[i]);
- uhci_unlock_frames(sc);
+ /* Turn off the interrupt since it is active even if the TD is not. */
+ ii->stdend->td.td_status &= LE(~UHCI_TD_IOC);
- DPRINTFN(5, ("uhci_setintr: returns %p\n", upipe));
- return(USBD_NORMAL_COMPLETION);
+ LIST_REMOVE(ii, list); /* remove from active list */
}
-
-usbd_status
-uhci_root_ctrl_transfer(reqh)
+void
+uhci_device_intr_done(reqh)
usbd_request_handle reqh;
{
- int s;
- usbd_status err;
-
- s = splusb();
- err = usb_insert_transfer(reqh);
- splx(s);
- if (err != USBD_NORMAL_COMPLETION)
- return(err);
- else
- return(uhci_root_ctrl_start(reqh));
-}
+ uhci_intr_info_t *ii = reqh->hcpriv;
+ uhci_softc_t *sc = ii->sc;
+ struct uhci_pipe *upipe = (struct uhci_pipe *)reqh->pipe;
+ uhci_soft_qh_t *sqh;
+ int i, npoll;
-usbd_status
-uhci_root_ctrl_start(usbd_request_handle reqh)
-{
- uhci_softc_t *sc = (uhci_softc_t *)reqh->pipe->device->bus;
+ DPRINTFN(5, ("uhci_intr_done: length=%d\n", reqh->actlen));
- if (!reqh->isreq)
- panic("uhci_root_ctrl_transfer: not a request\n");
+ npoll = upipe->u.intr.npoll;
+ for(i = 0; i < npoll; i++) {
+ sqh = upipe->u.intr.qhs[i];
+ sqh->elink = 0;
+ sqh->qh.qh_elink = LE(UHCI_PTR_T);
+ }
+ uhci_free_std_chain(sc, ii->stdstart, 0);
- reqh->status = uhci_roothub_ctrl_transfer(sc,
- &reqh->request, reqh->buffer, &reqh->actlen);
+ /* XXX Wasteful. */
+ if (reqh->pipe->repeat) {
+ uhci_soft_td_t *xfer, *xferend;
- reqh->xfercb(reqh);
- usb_start_next(reqh->pipe);
+ /* This alloc cannot fail since we freed the chain above. */
+ uhci_alloc_std_chain(upipe, sc, reqh->length, 1,
+ reqh->flags & USBD_SHORT_XFER_OK,
+ &reqh->dmabuf, &xfer, &xferend);
+ xferend->td.td_status |= LE(UHCI_TD_IOC);
- return(USBD_IN_PROGRESS);
-}
+#ifdef UHCI_DEBUG
+ if (uhcidebug > 10) {
+ DPRINTF(("uhci_device_intr_done: xfer(1)\n"));
+ uhci_dump_tds(xfer);
+ uhci_dump_qh(upipe->u.intr.qhs[0]);
+ }
+#endif
-void
-uhci_root_ctrl_abort(reqh)
- usbd_request_handle reqh;
-{
- /* Nothing to do, all transfers are syncronous. */
+ ii->stdstart = xfer;
+ ii->stdend = xferend;
+#ifdef DIAGNOSTIC
+ ii->isdone = 0;
+#endif
+ for (i = 0; i < npoll; i++) {
+ sqh = upipe->u.intr.qhs[i];
+ sqh->elink = xfer;
+ sqh->qh.qh_elink = LE(xfer->physaddr);
+ }
+ } else {
+ ii->stdstart = 0; /* mark as inactive */
+ }
}
+/* Deallocate request data structures */
void
-uhci_root_ctrl_close(pipe)
- usbd_pipe_handle pipe;
-{
- usb_untimeout(uhci_root_intr_sim, pipe->intrreqh, pipe->intrreqh->timeout_handle);
- DPRINTF(("uhci_root_ctrl_close\n"));
-}
-
-
-usbd_status
-uhci_root_intr_transfer(reqh)
+uhci_device_ctrl_done(reqh)
usbd_request_handle reqh;
{
- int s;
- usbd_status err;
-
- s = splusb();
- err = usb_insert_transfer(reqh);
- splx(s);
- if (err != USBD_NORMAL_COMPLETION)
- return(err);
- else
- return(uhci_root_intr_start(reqh));
-}
+ uhci_intr_info_t *ii = reqh->hcpriv;
+ uhci_softc_t *sc = ii->sc;
+ struct uhci_pipe *upipe = (struct uhci_pipe *)reqh->pipe;
-/* Start a transfer on the root interrupt pipe */
-usbd_status
-uhci_root_intr_start(reqh)
- usbd_request_handle reqh;
-{
- usbd_pipe_handle pipe = reqh->pipe;
- uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;
- struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
- usb_dma_t *dmap;
- usbd_status err;
- int datalen;
+#ifdef DIAGNOSTIC
+ if (!(reqh->rqflags & URQ_REQUEST))
+ panic("uhci_ctrl_done: not a request\n");
+#endif
- DPRINTFN(3, ("uhci_root_intr_transfer: reqh=%p buf=%p datalen=%d "
- "flags=%d\n",
- reqh, reqh->buffer, reqh->length, reqh->flags));
+ LIST_REMOVE(ii, list); /* remove from active list */
- datalen = reqh->length;
- dmap = &upipe->u.intr.datadma;
- if (datalen == 0)
- return(USBD_INVAL); /* XXX should it be? */
+ uhci_remove_ctrl(sc, upipe->u.ctl.sqh);
- err = usb_allocmem(sc->sc_dmatag, datalen, 0, dmap);
- if (err != USBD_NORMAL_COMPLETION)
- return(err);
+ if (upipe->u.ctl.length != 0)
+ uhci_free_std_chain(sc, ii->stdstart->link.std, ii->stdend);
- sc->sc_ival = MS_TO_TICKS(reqh->pipe->endpoint->edesc->bInterval);
- usb_timeout(uhci_root_intr_sim, reqh, sc->sc_ival, reqh->timeout_handle);
- return(USBD_IN_PROGRESS);
+ DPRINTFN(5, ("uhci_ctrl_done: length=%d\n", reqh->actlen));
}
-/* Abort a root interrupt request. */
+/* Deallocate request data structures */
void
-uhci_root_intr_abort(reqh)
+uhci_device_bulk_done(reqh)
usbd_request_handle reqh;
{
- usb_untimeout(uhci_root_intr_sim, reqh, reqh->timeout_handle);
-}
-
-/* Close the root interrupt pipe. */
-void
-uhci_root_intr_close(pipe)
- usbd_pipe_handle pipe;
-{
- usb_untimeout(uhci_root_intr_sim, pipe->intrreqh, pipe->intrreqh->timeout_handle);
-}
+ uhci_intr_info_t *ii = reqh->hcpriv;
+ uhci_softc_t *sc = ii->sc;
+ struct uhci_pipe *upipe = (struct uhci_pipe *)reqh->pipe;
-/*
- * This routine is executed periodically and simulates interrupts
- * from the root controller interrupt pipe for port status change.
- */
-void
-uhci_root_intr_sim(priv)
- void *priv;
-{
- usbd_request_handle reqh = priv;
- usbd_pipe_handle pipe = reqh->pipe;
- uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;
- struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
- int s;
- int actlen;
- u_int8_t *buf;
- int err;
+ LIST_REMOVE(ii, list); /* remove from active list */
- buf = KERNADDR(&upipe->u.intr.datadma);
+ uhci_remove_bulk(sc, upipe->u.bulk.sqh);
- err = uhci_roothub_intr_transfer(sc, buf, reqh->length, &actlen);
- s = splusb();
- if (err) {
- reqh->status = err;
- } else {
- reqh->actlen = actlen;
- reqh->status = USBD_NORMAL_COMPLETION;
- reqh->xfercb(reqh);
- }
+ uhci_free_std_chain(sc, ii->stdstart, 0);
- if (reqh->pipe->intrreqh == reqh) {
- usb_timeout(uhci_root_intr_sim, reqh, sc->sc_ival, reqh->timeout_handle);
- } else {
- usb_freemem(sc->sc_dmatag, &upipe->u.intr.datadma);
- usb_start_next(reqh->pipe);
- }
- splx(s);
+ DPRINTFN(5, ("uhci_bulk_done: length=%d\n", reqh->actlen));
}
-
-/* Add control QH, called at splusb(). */
+/* Add interrupt QH, called with vflock. */
void
-uhci_add_ctrl(sc, sqh)
+uhci_add_intr(sc, n, sqh)
uhci_softc_t *sc;
+ int n;
uhci_soft_qh_t *sqh;
{
- uhci_qh_t *eqh;
+ struct uhci_vframe *vf = &sc->sc_vframes[n];
+ uhci_soft_qh_t *eqh;
- DPRINTFN(10, ("uhci_add_ctrl: sqh=%p\n", sqh));
- eqh = sc->sc_ctl_end->qh;
- sqh->qh->hlink = eqh->hlink;
- sqh->qh->qh_hlink = eqh->qh_hlink;
- eqh->hlink = sqh;
- eqh->qh_hlink = sqh->physaddr | UHCI_PTR_Q;
- sc->sc_ctl_end = sqh;
+ DPRINTFN(4, ("uhci_add_intr: n=%d sqh=%p\n", n, sqh));
+ eqh = vf->eqh;
+ sqh->hlink = eqh->hlink;
+ sqh->qh.qh_hlink = eqh->qh.qh_hlink;
+ eqh->hlink = sqh;
+ eqh->qh.qh_hlink = LE(sqh->physaddr | UHCI_PTR_Q);
+ vf->eqh = sqh;
+ vf->bandwidth++;
}
-/* Remove control QH, called at splusb(). */
+/* Remove interrupt QH, called with vflock. */
void
-uhci_remove_ctrl(sc, sqh)
+uhci_remove_intr(sc, n, sqh)
uhci_softc_t *sc;
+ int n;
uhci_soft_qh_t *sqh;
{
+ struct uhci_vframe *vf = &sc->sc_vframes[n];
uhci_soft_qh_t *pqh;
- DPRINTFN(10, ("uhci_remove_ctrl: sqh=%p\n", sqh));
- for (pqh = sc->sc_ctl_start; pqh->qh->hlink != sqh; pqh=pqh->qh->hlink)
+ DPRINTFN(4, ("uhci_remove_intr: n=%d sqh=%p\n", n, sqh));
+
+ for (pqh = vf->hqh; pqh->hlink != sqh; pqh = pqh->hlink)
#if defined(DIAGNOSTIC) || defined(UHCI_DEBUG)
- if (pqh->qh->qh_hlink & UHCI_PTR_T) {
- DPRINTF(("uhci_remove_ctrl: QH not found\n"));
+ if (LE(pqh->qh.qh_hlink) & UHCI_PTR_T) {
+ DPRINTF(("uhci_remove_intr: QH not found\n"));
return;
}
#else
;
#endif
- pqh->qh->hlink = sqh->qh->hlink;
- pqh->qh->qh_hlink = sqh->qh->qh_hlink;
- if (sc->sc_ctl_end == sqh)
- sc->sc_ctl_end = pqh;
+ pqh->hlink = sqh->hlink;
+ pqh->qh.qh_hlink = sqh->qh.qh_hlink;
+ if (vf->eqh == sqh)
+ vf->eqh = pqh;
+ vf->bandwidth--;
}
-/* Add bulk QH, called at splusb(). */
-void
-uhci_add_bulk(sc, sqh)
+usbd_status
+uhci_device_setintr(sc, upipe, ival)
uhci_softc_t *sc;
- uhci_soft_qh_t *sqh;
+ struct uhci_pipe *upipe;
+ int ival;
{
- uhci_qh_t *eqh;
+ uhci_soft_qh_t *sqh;
+ int i, npoll, s;
+ u_int bestbw, bw, bestoffs, offs;
- DPRINTFN(10, ("uhci_add_bulk: sqh=%p\n", sqh));
- eqh = sc->sc_bulk_end->qh;
- sqh->qh->hlink = eqh->hlink;
- sqh->qh->qh_hlink = eqh->qh_hlink;
- eqh->hlink = sqh;
- eqh->qh_hlink = sqh->physaddr | UHCI_PTR_Q;
- sc->sc_bulk_end = sqh;
-}
+ DPRINTFN(2, ("uhci_setintr: pipe=%p\n", upipe));
+ if (ival == 0) {
+ printf("uhci_setintr: 0 interval\n");
+ return (USBD_INVAL);
+ }
-/* Remove bulk QH, called at splusb(). */
-void
-uhci_remove_bulk(sc, sqh)
- uhci_softc_t *sc;
- uhci_soft_qh_t *sqh;
-{
- uhci_soft_qh_t *pqh;
+ if (ival > UHCI_VFRAMELIST_COUNT)
+ ival = UHCI_VFRAMELIST_COUNT;
+ npoll = (UHCI_VFRAMELIST_COUNT + ival - 1) / ival;
+ DPRINTFN(2, ("uhci_setintr: ival=%d npoll=%d\n", ival, npoll));
- DPRINTFN(10, ("uhci_remove_bulk: sqh=%p\n", sqh));
- for (pqh = sc->sc_bulk_start;
- pqh->qh->hlink != sqh;
- pqh = pqh->qh->hlink)
-#if defined(DIAGNOSTIC)
- if (pqh->qh->qh_hlink & UHCI_PTR_T) {
- printf("uhci_remove_bulk: QH not found\n");
- return;
+ upipe->u.intr.npoll = npoll;
+ upipe->u.intr.qhs =
+ malloc(npoll * sizeof(uhci_soft_qh_t *), M_USBHC, M_WAITOK);
+
+ /*
+ * Figure out which offset in the schedule that has most
+ * bandwidth left over.
+ */
+#define MOD(i) ((i) & (UHCI_VFRAMELIST_COUNT-1))
+ for (bestoffs = offs = 0, bestbw = ~0; offs < ival; offs++) {
+ for (bw = i = 0; i < npoll; i++)
+ bw += sc->sc_vframes[MOD(i * ival + offs)].bandwidth;
+ if (bw < bestbw) {
+ bestbw = bw;
+ bestoffs = offs;
}
-#else
- ;
-#endif
- pqh->qh->hlink = sqh->qh->hlink;
- pqh->qh->qh_hlink = sqh->qh->qh_hlink;
- if (sc->sc_bulk_end == sqh)
- sc->sc_bulk_end = pqh;
-}
+ }
+ DPRINTFN(1, ("uhci_setintr: bw=%d offs=%d\n", bestbw, bestoffs));
+ upipe->iinfo->stdstart = 0;
+ for(i = 0; i < npoll; i++) {
+ upipe->u.intr.qhs[i] = sqh = uhci_alloc_sqh(sc);
+ sqh->elink = 0;
+ sqh->qh.qh_elink = LE(UHCI_PTR_T);
+ sqh->pos = MOD(i * ival + bestoffs);
+ sqh->intr_info = upipe->iinfo;
+ }
+#undef MOD
-/* Add interrupt QH, called with vflock. */
-void
-uhci_add_intr(sc, pos, sqh)
- uhci_softc_t *sc;
- int pos;
- uhci_soft_qh_t *sqh;
-{
- struct uhci_vframe *vf = &sc->sc_vframes[pos];
- uhci_qh_t *eqh;
+ s = splusb();
+ LIST_INSERT_HEAD(&sc->sc_intrhead, upipe->iinfo, list);
+ splx(s);
- DPRINTFN(4, ("uhci_add_intr: pos=%d sqh=%p\n", pos, sqh));
- eqh = vf->eqh->qh;
- sqh->qh->hlink = eqh->hlink;
- sqh->qh->qh_hlink = eqh->qh_hlink;
- eqh->hlink = sqh;
- eqh->qh_hlink = sqh->physaddr | UHCI_PTR_Q;
- vf->eqh = sqh;
- vf->bandwidth++;
+ uhci_lock_frames(sc);
+ /* Enter QHs into the controller data structures. */
+ for(i = 0; i < npoll; i++)
+ uhci_add_intr(sc, upipe->u.intr.qhs[i]->pos,
+ upipe->u.intr.qhs[i]);
+ uhci_unlock_frames(sc);
+
+ DPRINTFN(5, ("uhci_setintr: returns %p\n", upipe));
+ return (USBD_NORMAL_COMPLETION);
}
-/* Remove interrupt QH, called with vflock. */
-void
-uhci_remove_intr(sc, pos, sqh)
- uhci_softc_t *sc;
- int pos;
- uhci_soft_qh_t *sqh;
+/* Open a new pipe. */
+usbd_status
+uhci_open(pipe)
+ usbd_pipe_handle pipe;
{
- struct uhci_vframe *vf = &sc->sc_vframes[pos];
- uhci_soft_qh_t *pqh;
-
- DPRINTFN(4, ("uhci_remove_intr: pos=%d sqh=%p\n", pos, sqh));
+ uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;
+ struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
+ usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc;
+ usbd_status r;
- for (pqh = vf->hqh; pqh->qh->hlink != sqh; pqh = pqh->qh->hlink)
-#if defined(DIAGNOSTIC)
- if (pqh->qh->qh_hlink & UHCI_PTR_T) {
- printf("uhci_remove_intr: QH not found\n");
- return;
+ DPRINTFN(1, ("uhci_open: pipe=%p, addr=%d, endpt=%d (%d)\n",
+ pipe, pipe->device->address,
+ ed->bEndpointAddress, sc->sc_addr));
+ if (pipe->device->address == sc->sc_addr) {
+ switch (ed->bEndpointAddress) {
+ case USB_CONTROL_ENDPOINT:
+ pipe->methods = &uhci_root_ctrl_methods;
+ break;
+ case UE_DIR_IN | UHCI_INTR_ENDPT:
+ pipe->methods = &uhci_root_intr_methods;
+ break;
+ default:
+ return (USBD_INVAL);
}
-#else
- ;
-#endif
- pqh->qh->hlink = sqh->qh->hlink;
- pqh->qh->qh_hlink = sqh->qh->qh_hlink;
- if (vf->eqh == sqh)
- vf->eqh = pqh;
- vf->bandwidth--;
-}
+ } else {
+ upipe->iinfo = uhci_alloc_intr_info(sc);
+ if (upipe->iinfo == 0)
+ return (USBD_NOMEM);
+ switch (ed->bmAttributes & UE_XFERTYPE) {
+ case UE_CONTROL:
+ pipe->methods = &uhci_device_ctrl_methods;
+ upipe->u.ctl.sqh = uhci_alloc_sqh(sc);
+ if (upipe->u.ctl.sqh == 0)
+ goto bad;
+ upipe->u.ctl.setup = uhci_alloc_std(sc);
+ if (upipe->u.ctl.setup == 0) {
+ uhci_free_sqh(sc, upipe->u.ctl.sqh);
+ goto bad;
+ }
+ upipe->u.ctl.stat = uhci_alloc_std(sc);
+ if (upipe->u.ctl.stat == 0) {
+ uhci_free_sqh(sc, upipe->u.ctl.sqh);
+ uhci_free_std(sc, upipe->u.ctl.setup);
+ goto bad;
+ }
+ r = usb_allocmem(sc->sc_dmatag,
+ sizeof(usb_device_request_t),
+ 0, &upipe->u.ctl.reqdma);
+ if (r != USBD_NORMAL_COMPLETION) {
+ uhci_free_sqh(sc, upipe->u.ctl.sqh);
+ uhci_free_std(sc, upipe->u.ctl.setup);
+ uhci_free_std(sc, upipe->u.ctl.stat);
+ goto bad;
+ }
+ break;
+ case UE_INTERRUPT:
+ pipe->methods = &uhci_device_intr_methods;
+ return (uhci_device_setintr(sc, upipe, ed->bInterval));
+ case UE_ISOCHRONOUS:
+ pipe->methods = &uhci_device_isoc_methods;
+ return (uhci_setup_isoc(pipe));
+ case UE_BULK:
+ pipe->methods = &uhci_device_bulk_methods;
+ upipe->u.bulk.sqh = uhci_alloc_sqh(sc);
+ if (upipe->u.bulk.sqh == 0)
+ goto bad;
+ break;
+ }
+ }
+ return (USBD_NORMAL_COMPLETION);
+ bad:
+ uhci_free_intr_info(upipe->iinfo);
+ return (USBD_NOMEM);
+}
/*
- * The simulated root hub
+ * Data structures and routines to emulate the root hub.
*/
-
-/* Data structures */
-
usb_device_descriptor_t uhci_devd = {
USB_DEVICE_DESCRIPTOR_SIZE,
UDESC_DEVICE, /* type */
@@ -2380,7 +2402,7 @@ usb_interface_descriptor_t uhci_ifcd = {
usb_endpoint_descriptor_t uhci_endpd = {
USB_ENDPOINT_DESCRIPTOR_SIZE,
UDESC_ENDPOINT,
- UE_IN | UHCI_INTR_ENDPT,
+ UE_DIR_IN | UHCI_INTR_ENDPT,
UE_INTERRUPT,
{8},
255
@@ -2396,54 +2418,70 @@ usb_hub_descriptor_t uhci_hubd_piix = {
{ 0x00 }, /* both ports are removable */
};
-/*
- * creates the UNICODE-ified string descriptor for the root hub
- * returns the length copied
- */
-
int
-uhci_roothub_string_descriptor(sd, datalen, string)
- usb_string_descriptor_t *sd;
- int datalen;
- char *string;
+uhci_str(p, l, s)
+ usb_string_descriptor_t *p;
+ int l;
+ char *s;
{
int i;
- if (datalen == 0)
- return(0);
- sd->bLength = 2 * strlen(string) + 2;
- if (datalen == 1)
- return(1);
- sd->bDescriptorType = UDESC_STRING;
- datalen -= 2;
- for (i = 0; string[i] && datalen > 1; i++, datalen -= 2)
- USETW2(sd->bString[i], 0, string[i]);
- return(2*i+2);
+ if (l == 0)
+ return (0);
+ p->bLength = 2 * strlen(s) + 2;
+ if (l == 1)
+ return (1);
+ p->bDescriptorType = UDESC_STRING;
+ l -= 2;
+ for (i = 0; s[i] && l > 1; i++, l -= 2)
+ USETW2(p->bString[i], 0, s[i]);
+ return (2*i+2);
}
-/* function handling all requests for the root hub */
+/*
+ * Simulate a hardware hub by handling all the necessary requests.
+ */
+usbd_status
+uhci_root_ctrl_transfer(reqh)
+ usbd_request_handle reqh;
+{
+ usbd_status r;
+
+ r = usb_insert_transfer(reqh);
+ if (r != USBD_NORMAL_COMPLETION)
+ return (r);
+ else
+ return (uhci_root_ctrl_start(reqh));
+}
usbd_status
-uhci_roothub_ctrl_transfer(sc, req, buf, actlen)
- uhci_softc_t *sc;
- usb_device_request_t *req;
- void *buf;
- int *actlen;
+uhci_root_ctrl_start(reqh)
+ usbd_request_handle reqh;
{
- int port; /* port number */
- int x; /* temp storage for read register */
- int datalen, value, index; /* values in request */
- int l; /* temp storage for length to be copied */
+ uhci_softc_t *sc = (uhci_softc_t *)reqh->pipe->device->bus;
+ usb_device_request_t *req;
+ void *buf = NULL;
+ int port, x;
+ int len, value, index, status, change, l, totlen = 0;
+ usb_port_status_t ps;
+ usbd_status r;
- *actlen = 0;
+#ifdef DIAGNOSTIC
+ if (!(reqh->rqflags & URQ_REQUEST))
+ panic("uhci_root_ctrl_transfer: not a request\n");
+#endif
+ req = &reqh->request;
- DPRINTFN(12,("uhci_root_ctrl_control type=0x%02x request=%02x\n",
+ DPRINTFN(2,("uhci_root_ctrl_control type=0x%02x request=%02x\n",
req->bmRequestType, req->bRequest));
- datalen = UGETW(req->wLength);
+ len = UGETW(req->wLength);
value = UGETW(req->wValue);
index = UGETW(req->wIndex);
+ if (len != 0)
+ buf = KERNADDR(&reqh->dmabuf);
+
#define C(x,y) ((x) | ((y) << 8))
switch(C(req->bRequest, req->bmRequestType)) {
case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
@@ -2455,9 +2493,9 @@ uhci_roothub_ctrl_transfer(sc, req, buf, actlen)
*/
break;
case C(UR_GET_CONFIG, UT_READ_DEVICE):
- if (datalen > 0) {
+ if (len > 0) {
*(u_int8_t *)buf = sc->sc_conf;
- *actlen = 1;
+ totlen = 1;
}
break;
case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
@@ -2465,74 +2503,80 @@ uhci_roothub_ctrl_transfer(sc, req, buf, actlen)
switch(value >> 8) {
case UDESC_DEVICE:
if ((value & 0xff) != 0) {
- return USBD_IOERROR;
+ r = USBD_IOERROR;
+ goto ret;
}
- *actlen = l = min(datalen, USB_DEVICE_DESCRIPTOR_SIZE);
+ totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
+ USETW(uhci_devd.idVendor, sc->sc_id_vendor);
memcpy(buf, &uhci_devd, l);
break;
case UDESC_CONFIG:
if ((value & 0xff) != 0) {
- return USBD_IOERROR;
+ r = USBD_IOERROR;
+ goto ret;
}
- *actlen = l = min(datalen, USB_CONFIG_DESCRIPTOR_SIZE);
+ totlen = l = min(len, USB_CONFIG_DESCRIPTOR_SIZE);
memcpy(buf, &uhci_confd, l);
buf = (char *)buf + l;
- datalen -= l;
- l = min(datalen, USB_INTERFACE_DESCRIPTOR_SIZE);
- *actlen += l;
+ len -= l;
+ l = min(len, USB_INTERFACE_DESCRIPTOR_SIZE);
+ totlen += l;
memcpy(buf, &uhci_ifcd, l);
buf = (char *)buf + l;
- datalen -= l;
- l = min(datalen, USB_ENDPOINT_DESCRIPTOR_SIZE);
- *actlen += l;
+ len -= l;
+ l = min(len, USB_ENDPOINT_DESCRIPTOR_SIZE);
+ totlen += l;
memcpy(buf, &uhci_endpd, l);
break;
case UDESC_STRING:
- if (datalen == 0)
+ if (len == 0)
break;
*(u_int8_t *)buf = 0;
- *actlen = 1;
+ totlen = 1;
switch (value & 0xff) {
case 1: /* Vendor */
- *actlen = uhci_roothub_string_descriptor(buf, datalen, sc->sc_vendor);
+ totlen = uhci_str(buf, len, sc->sc_vendor);
break;
case 2: /* Product */
- *actlen = uhci_roothub_string_descriptor(buf, datalen, "UHCI root hub");
+ totlen = uhci_str(buf, len, "UHCI root hub");
break;
}
break;
default:
- return USBD_IOERROR;
+ r = USBD_IOERROR;
+ goto ret;
}
break;
case C(UR_GET_INTERFACE, UT_READ_INTERFACE):
- if (datalen > 0) {
+ if (len > 0) {
*(u_int8_t *)buf = 0;
- *actlen = 1;
+ totlen = 1;
}
break;
case C(UR_GET_STATUS, UT_READ_DEVICE):
- if (datalen > 1) {
+ if (len > 1) {
USETW(((usb_status_t *)buf)->wStatus,UDS_SELF_POWERED);
- *actlen = 2;
+ totlen = 2;
}
break;
case C(UR_GET_STATUS, UT_READ_INTERFACE):
case C(UR_GET_STATUS, UT_READ_ENDPOINT):
- if (datalen > 1) {
+ if (len > 1) {
USETW(((usb_status_t *)buf)->wStatus, 0);
- *actlen = 2;
+ totlen = 2;
}
break;
case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
if (value >= USB_MAX_DEVICES) {
- return USBD_IOERROR;
+ r = USBD_IOERROR;
+ goto ret;
}
sc->sc_addr = value;
break;
case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
if (value != 0 && value != 1) {
- return USBD_IOERROR;
+ r = USBD_IOERROR;
+ goto ret;
}
sc->sc_conf = value;
break;
@@ -2541,7 +2585,8 @@ uhci_roothub_ctrl_transfer(sc, req, buf, actlen)
case C(UR_SET_FEATURE, UT_WRITE_DEVICE):
case C(UR_SET_FEATURE, UT_WRITE_INTERFACE):
case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
- return USBD_IOERROR;
+ r = USBD_IOERROR;
+ goto ret;
case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
break;
case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
@@ -2558,7 +2603,8 @@ uhci_roothub_ctrl_transfer(sc, req, buf, actlen)
else if (index == 2)
port = UHCI_PORTSC2;
else {
- return USBD_IOERROR;
+ r = USBD_IOERROR;
+ goto ret;
}
switch(value) {
case UHF_PORT_ENABLE:
@@ -2587,14 +2633,16 @@ uhci_roothub_ctrl_transfer(sc, req, buf, actlen)
break;
case UHF_C_PORT_RESET:
sc->sc_isreset = 0;
- return USBD_NORMAL_COMPLETION;
+ r = USBD_NORMAL_COMPLETION;
+ goto ret;
case UHF_PORT_CONNECTION:
case UHF_PORT_OVER_CURRENT:
case UHF_PORT_POWER:
case UHF_PORT_LOW_SPEED:
case UHF_C_PORT_SUSPEND:
default:
- return USBD_IOERROR;
+ r = USBD_IOERROR;
+ goto ret;
}
break;
case C(UR_GET_BUS_STATE, UT_READ_CLASS_OTHER):
@@ -2603,44 +2651,45 @@ uhci_roothub_ctrl_transfer(sc, req, buf, actlen)
else if (index == 2)
port = UHCI_PORTSC2;
else {
- return USBD_IOERROR;
+ r = USBD_IOERROR;
+ goto ret;
}
- if (datalen > 0) {
+ if (len > 0) {
*(u_int8_t *)buf =
(UREAD2(sc, port) & UHCI_PORTSC_LS) >>
UHCI_PORTSC_LS_SHIFT;
- *actlen = 1;
+ totlen = 1;
}
break;
case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
if (value != 0) {
- return USBD_IOERROR;
+ r = USBD_IOERROR;
+ goto ret;
}
- l = min(datalen, USB_HUB_DESCRIPTOR_SIZE);
- *actlen = l;
+ l = min(len, USB_HUB_DESCRIPTOR_SIZE);
+ totlen = l;
memcpy(buf, &uhci_hubd_piix, l);
break;
case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
- if (datalen != 4) {
- return USBD_IOERROR;
+ if (len != 4) {
+ r = USBD_IOERROR;
+ goto ret;
}
- memset(buf, 0, datalen);
- *actlen = datalen;
+ memset(buf, 0, len);
+ totlen = len;
break;
case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):
- {
- int status, change;
- usb_port_status_t ps;
-
if (index == 1)
port = UHCI_PORTSC1;
else if (index == 2)
port = UHCI_PORTSC2;
else {
- return USBD_IOERROR;
+ r = USBD_IOERROR;
+ goto ret;
}
- if (datalen != 4) {
- return USBD_IOERROR;
+ if (len != 4) {
+ r = USBD_IOERROR;
+ goto ret;
}
x = UREAD2(sc, port);
status = change = 0;
@@ -2665,13 +2714,13 @@ uhci_roothub_ctrl_transfer(sc, req, buf, actlen)
change |= UPS_C_PORT_RESET;
USETW(ps.wPortStatus, status);
USETW(ps.wPortChange, change);
- l = min(datalen, sizeof ps);
+ l = min(len, sizeof ps);
memcpy(buf, &ps, l);
- *actlen = l;
+ totlen = l;
break;
- }
case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE):
- return USBD_IOERROR;
+ r = USBD_IOERROR;
+ goto ret;
case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE):
break;
case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):
@@ -2680,7 +2729,8 @@ uhci_roothub_ctrl_transfer(sc, req, buf, actlen)
else if (index == 2)
port = UHCI_PORTSC2;
else {
- return USBD_IOERROR;
+ r = USBD_IOERROR;
+ goto ret;
}
switch(value) {
case UHF_PORT_ENABLE:
@@ -2714,111 +2764,92 @@ uhci_roothub_ctrl_transfer(sc, req, buf, actlen)
case UHF_C_PORT_SUSPEND:
case UHF_C_PORT_RESET:
default:
- return USBD_IOERROR;
+ r = USBD_IOERROR;
+ goto ret;
}
break;
default:
- return USBD_IOERROR;
+ r = USBD_IOERROR;
+ goto ret;
}
-
- return USBD_NORMAL_COMPLETION;
+ reqh->actlen = totlen;
+ r = USBD_NORMAL_COMPLETION;
+ ret:
+ reqh->status = r;
+ reqh->hcpriv = 0;
+ usb_transfer_complete(reqh);
+ return (USBD_IN_PROGRESS);
}
-usbd_status
-uhci_roothub_intr_transfer(uhci_softc_t *sc,
- u_int8_t *buf, int buflen, int *actlen)
+/* Abort a root control request. */
+void
+uhci_root_ctrl_abort(reqh)
+ usbd_request_handle reqh;
{
- if (buflen < 1) {
- DPRINTF(("%s: buffer too small, %d < 1\n",
- USBDEVNAME(sc->sc_bus.bdev), buflen));
- return USBD_IOERROR;
- }
-
- buf[0] = 0;
- if (UREAD2(sc, UHCI_STS) & (UHCI_STS_RD))
- buf[0] |= 1<<0;
- if (UREAD2(sc, UHCI_PORTSC1) & (UHCI_PORTSC_CSC|UHCI_PORTSC_OCIC))
- buf[0] |= 1<<1;
- if (UREAD2(sc, UHCI_PORTSC2) & (UHCI_PORTSC_CSC|UHCI_PORTSC_OCIC))
- buf[0] |= 1<<2;
-
- if (buf[0] != 0)
- *actlen = 1;
- else
- actlen = 0;
-
- return USBD_NORMAL_COMPLETION;
+ /* Nothing to do, all transfers are syncronous. */
}
-
-/*
- * debugging functions
- */
-
-#ifdef UHCI_DEBUG
+/* Close the root pipe. */
void
-uhci_dumpregs(sc)
- uhci_softc_t *sc;
+uhci_root_ctrl_close(pipe)
+ usbd_pipe_handle pipe;
{
- DPRINTF(("%s: regs: cmd=%04x, sts=%04x, intr=%04x, frnum=%04x, "
- "flbase=%08x, sof=%02x, portsc1=%04x, portsc2=%04x\n",
- USBDEVNAME(sc->sc_bus.bdev),
- UREAD2(sc, UHCI_CMD),
- UREAD2(sc, UHCI_STS),
- UREAD2(sc, UHCI_INTR),
- UREAD2(sc, UHCI_FRNUM),
- UREAD4(sc, UHCI_FLBASEADDR),
- UREAD1(sc, UHCI_SOF),
- UREAD2(sc, UHCI_PORTSC1),
- UREAD2(sc, UHCI_PORTSC2)));
-}
+ uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;
-int uhci_longtd = 1;
+ sc->sc_has_timo = 0;
+ DPRINTF(("uhci_root_ctrl_close\n"));
+}
+/* Abort a root interrupt request. */
void
-uhci_dump_td(p)
- uhci_soft_td_t *p;
+uhci_root_intr_abort(reqh)
+ usbd_request_handle reqh;
{
- DPRINTF(("TD(%p) at %08lx link=0x%08lx st=0x%08lx tok=0x%08lx "
- "buf=0x%08lx\n",
- p, (long)p->physaddr,
- (long)p->td->td_link,
- (long)p->td->td_status,
- (long)p->td->td_token,
- (long)p->td->td_buffer));
- if (uhci_longtd)
- DPRINTF((" %b %b,errcnt=%d,actlen=%d pid=%02x,addr=%d,endpt=%d,"
- "D=%d,maxlen=%d\n",
- (int)p->td->td_link,
- "\20\1T\2Q\3VF",
- (int)p->td->td_status,
- "\20\22BITSTUFF\23CRCTO\24NAK\25BABBLE\26DBUFFER\27"
- "STALLED\30ACTIVE\31IOC\32ISO\33LS\36SPD",
- UHCI_TD_GET_ERRCNT(p->td->td_status),
- UHCI_TD_GET_ACTLEN(p->td->td_status),
- UHCI_TD_GET_PID(p->td->td_token),
- UHCI_TD_GET_DEVADDR(p->td->td_token),
- UHCI_TD_GET_ENDPT(p->td->td_token),
- UHCI_TD_GET_DT(p->td->td_token),
- UHCI_TD_GET_MAXLEN(p->td->td_token)));
+ uhci_softc_t *sc = (uhci_softc_t *)reqh->pipe->device->bus;
+
+ usb_untimeout(uhci_timo, reqh, reqh->timo_handle);
+ sc->sc_has_timo = 0;
}
-void
-uhci_dump_qh(p)
- uhci_soft_qh_t *p;
+usbd_status
+uhci_root_intr_transfer(reqh)
+ usbd_request_handle reqh;
{
- DPRINTF(("QH(%p) at %08x: hlink=%08x elink=%08x\n", p, (int)p->physaddr,
- p->qh->qh_hlink, p->qh->qh_elink));
+ usbd_status r;
+
+ r = usb_insert_transfer(reqh);
+ if (r != USBD_NORMAL_COMPLETION)
+ return (r);
+ else
+ return (uhci_root_intr_start(reqh));
}
+/* Start a transfer on the root interrupt pipe */
+usbd_status
+uhci_root_intr_start(reqh)
+ usbd_request_handle reqh;
+{
+ usbd_pipe_handle pipe = reqh->pipe;
+ uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;
+
+ DPRINTFN(3, ("uhci_root_intr_transfer: reqh=%p len=%d flags=%d\n",
+ reqh, reqh->length, reqh->flags));
+
+ sc->sc_ival = MS_TO_TICKS(reqh->pipe->endpoint->edesc->bInterval);
+ usb_timeout(uhci_timo, reqh, sc->sc_ival, reqh->timo_handle);
+ sc->sc_has_timo = reqh;
+ return (USBD_IN_PROGRESS);
+}
+/* Close the root interrupt pipe. */
void
-uhci_dump_tds(std)
- uhci_soft_td_t *std;
+uhci_root_intr_close(pipe)
+ usbd_pipe_handle pipe;
{
- uhci_soft_td_t *p;
+ uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;
- for(p = std; p; p = p->td->link.std)
- uhci_dump_td(p);
+ usb_untimeout(uhci_timo, pipe->intrreqh, pipe->intrreqh->timo_handle);
+ sc->sc_has_timo = 0;
+ DPRINTF(("uhci_root_intr_close\n"));
}
-#endif
+
diff --git a/sys/dev/usb/uhcireg.h b/sys/dev/usb/uhcireg.h
index 3dd9f02..dfdff27 100644
--- a/sys/dev/usb/uhcireg.h
+++ b/sys/dev/usb/uhcireg.h
@@ -1,5 +1,5 @@
-/* $NetBSD: uhcireg.h,v 1.5 1998/12/27 23:40:52 augustss Exp $ */
-/* $FreeBSD$ */
+/* $NetBSD: uhcireg.h,v 1.7 1999/08/22 23:19:57 augustss Exp $ */
+/* $FreeBSD$ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -116,11 +116,6 @@ typedef u_int32_t uhci_physaddr_t;
#define UHCI_PTR_Q 0x00000002
#define UHCI_PTR_VF 0x00000004
-typedef union {
- struct uhci_soft_qh *sqh;
- struct uhci_soft_td *std;
-} uhci_soft_td_qh_t;
-
/*
* The Queue Heads and Transfer Descriptors and accessed
* by both the CPU and the USB controller which runs
@@ -147,7 +142,7 @@ typedef struct {
#define UHCI_TD_ACTIVE 0x00800000
#define UHCI_TD_IOC 0x01000000
#define UHCI_TD_IOS 0x02000000
-#define UHCI_TD_LOWSPEED 0x04000000
+#define UHCI_TD_LS 0x04000000
#define UHCI_TD_GET_ERRCNT(s) (((s) >> 27) & 3)
#define UHCI_TD_SET_ERRCNT(n) ((n) << 27)
#define UHCI_TD_SPD 0x20000000
@@ -161,15 +156,12 @@ typedef struct {
#define UHCI_TD_SET_ENDPT(e) (((e)&0xf) << 15)
#define UHCI_TD_GET_ENDPT(s) (((s) >> 15) & 0xf)
#define UHCI_TD_SET_DT(t) ((t) << 19)
-#define UHCI_TD_GET_DT(t) (((t) >> 19) & 1)
+#define UHCI_TD_GET_DT(s) (((s) >> 19) & 1)
#define UHCI_TD_SET_MAXLEN(l) (((l)-1) << 21)
#define UHCI_TD_GET_MAXLEN(s) ((((s) >> 21) + 1) & 0x7ff)
#define UHCI_TD_MAXLEN_MASK 0xffe00000
u_int32_t td_buffer;
- uhci_soft_td_qh_t link; /* link to next TD (points to soft version of TD */
- /* padding to 32 bytes */
} uhci_td_t;
-#define UHCI_TD_SIZE 32
#define UHCI_TD_ERROR (UHCI_TD_BITSTUFF|UHCI_TD_CRCTO|UHCI_TD_BABBLE|UHCI_TD_DBUFFER|UHCI_TD_STALLED)
@@ -185,10 +177,6 @@ typedef struct {
typedef struct {
uhci_physaddr_t qh_hlink;
uhci_physaddr_t qh_elink;
- struct uhci_soft_qh *hlink; /* soft version of qh_hlink */
- struct uhci_soft_td *elink; /* soft version of qh_elink */
- /* padding to 32 bytes */
} uhci_qh_t;
-#define UHCI_QH_SIZE 32
#endif /* _DEV_PCI_UHCIREG_H_ */
diff --git a/sys/dev/usb/uhcivar.h b/sys/dev/usb/uhcivar.h
index 266bced..1c2ad1b 100644
--- a/sys/dev/usb/uhcivar.h
+++ b/sys/dev/usb/uhcivar.h
@@ -1,5 +1,5 @@
-/* $NetBSD: uhcivar.h,v 1.5 1998/12/26 12:53:02 augustss Exp $ */
-/* $FreeBSD$ */
+/* $NetBSD: uhcivar.h,v 1.12 1999/08/22 23:41:00 augustss Exp $ */
+/* $FreeBSD$ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -39,27 +39,28 @@
*/
/*
- * The framelist:
- *
* To avoid having 1024 TDs for each isochronous transfer we introduce
- * a virtual frame list. Every UHCI_VFRAMELIST_COUNT'th entry in the real
- * frame list points to a non-active TD. This TD is
- * UHCI_FRAMELIST_COUNT/UHCI_VFRAMELIST_COUNT times the start of the
- * virtual frame list for a queue of isochroneous transfers.
- *
- * The last isochroneous transfer in the list points to a QH for the
- * interrupt transfer in that timeslot. The QHs for interrupt transfers
- * all point to the single QH for control transfers, which in turn
- * points at the QH for control transfers.
+ * a virtual frame list. Every UHCI_VFRAMELIST_COUNT entries in the real
+ * frame list points to a non-active TD. These, in turn, which form the
+ * starts of the virtual frame list. This also has the advantage that it
+ * simplifies linking in/out TD/QH in the schedule.
+ * Furthermore, initially each of the inactive TDs point to an inactive
+ * QH that forms the start of the interrupt traffic for that slot.
+ * Each of these QHs point to the same QH that is the start of control
+ * traffic.
*
- * UHCI_VFRAMELIST_COUNT should be a power of 2 and UHCI_FRAMELIST_COUNT
- * should be a multiple of UHCI_VFRAMELIST_COUNT.
+ * UHCI_VFRAMELIST_COUNT should be a power of 2 and <= UHCI_FRAMELIST_COUNT.
*/
#define UHCI_VFRAMELIST_COUNT 128
typedef struct uhci_soft_qh uhci_soft_qh_t;
typedef struct uhci_soft_td uhci_soft_td_t;
+typedef union {
+ struct uhci_soft_qh *sqh;
+ struct uhci_soft_td *std;
+} uhci_soft_td_qh_t;
+
/*
* An interrupt info struct contains the information needed to
* execute a requested routine when the controller generates an
@@ -85,28 +86,34 @@ typedef struct uhci_intr_info {
* Extra information that we need for a TD.
*/
struct uhci_soft_td {
- uhci_td_t *td; /* The real TD */
- uhci_physaddr_t physaddr; /* and its physical address. */
+ uhci_td_t td; /* The real TD, must be first */
+ uhci_soft_td_qh_t link; /* soft version of the td_link field */
+ uhci_physaddr_t physaddr; /* TD's physical address. */
};
-#define UHCI_TD_CHUNK 128 /*(PAGE_SIZE / UHCI_TD_SIZE)*/
+/*
+ * Make the size such that it is a multiple of UHCI_TD_ALIGN. This way
+ * we can pack a number of soft TD together and have the real TS well
+ * aligned.
+ * NOTE: Minimum size is 32 bytes.
+ */
+#define UHCI_STD_SIZE ((sizeof (struct uhci_soft_td) + UHCI_TD_ALIGN - 1) / UHCI_TD_ALIGN * UHCI_TD_ALIGN)
+#define UHCI_STD_CHUNK 128 /*(PAGE_SIZE / UHCI_TD_SIZE)*/
/*
* Extra information that we need for a QH.
*/
struct uhci_soft_qh {
- uhci_qh_t *qh; /* The real QH */
- uhci_physaddr_t physaddr; /* and its physical address. */
+ uhci_qh_t qh; /* The real QH, must be first */
+ uhci_soft_qh_t *hlink; /* soft version of qh_hlink */
+ uhci_soft_td_t *elink; /* soft version of qh_elink */
+ uhci_physaddr_t physaddr; /* QH's physical address. */
int pos; /* Timeslot position */
uhci_intr_info_t *intr_info; /* Who to call on completion. */
+/* XXX should try to shrink with 4 bytes to fit into 32 bytes */
};
-#define UHCI_QH_CHUNK 128 /*(PAGE_SIZE / UHCI_QH_SIZE)*/
-
-/* Only used for buffer free list. */
-struct uhci_buffer {
- struct uhci_buffer *next;
-};
-#define UHCI_BUFFER_SIZE 64
-#define UHCI_BUFFER_CHUNK 64 /*(PAGE_SIZE / UHCI_BUFFER_SIZE)*/
+/* See comment about UHCI_STD_SIZE. */
+#define UHCI_SQH_SIZE ((sizeof (struct uhci_soft_qh) + UHCI_QH_ALIGN - 1) / UHCI_QH_ALIGN * UHCI_QH_ALIGN)
+#define UHCI_SQH_CHUNK 128 /*(PAGE_SIZE / UHCI_QH_SIZE)*/
/*
* Information about an entry in the virtial frame list.
@@ -121,19 +128,17 @@ struct uhci_vframe {
typedef struct uhci_softc {
struct usbd_bus sc_bus; /* base device */
-#if defined(__NetBSD__)
- void *sc_ih; /* interrupt vectoring */
-#endif
bus_space_tag_t iot;
bus_space_handle_t ioh;
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ void *sc_ih; /* interrupt vectoring */
-#if defined(__NetBSD__)
bus_dma_tag_t sc_dmatag; /* DMA tag */
/* XXX should keep track of all DMA memory */
-#endif
+#endif /* defined(__FreeBSD__) */
uhci_physaddr_t *sc_pframes;
- vm_offset_t sc_flbase;
+ usb_dma_t sc_dma;
struct uhci_vframe sc_vframes[UHCI_VFRAMELIST_COUNT];
uhci_soft_qh_t *sc_ctl_start; /* dummy QH for control */
@@ -143,13 +148,17 @@ typedef struct uhci_softc {
uhci_soft_td_t *sc_freetds;
uhci_soft_qh_t *sc_freeqhs;
- struct uhci_buffer *sc_freebuffers;
u_int8_t sc_addr; /* device address */
u_int8_t sc_conf; /* device configuration */
char sc_isreset;
+#if defined(__NetBSD__)
+ char sc_suspend;
+#endif
+ usbd_request_handle sc_has_timo;
+
int sc_intrs;
LIST_HEAD(, uhci_intr_info) sc_intrhead;
@@ -160,13 +169,13 @@ typedef struct uhci_softc {
#define UHCI_HAS_LOCK 1
#define UHCI_WANT_LOCK 2
-#if defined(__NetBSD__)
- usb_dma_t *sc_mallocs;
-#endif
-
char sc_vendor[16];
+ int sc_id_vendor;
} uhci_softc_t;
usbd_status uhci_init __P((uhci_softc_t *));
int uhci_intr __P((void *));
-usbd_status uhci_reset __P((uhci_softc_t *));
+#if 0
+void uhci_reset __P((void *));
+#endif
+
diff --git a/sys/dev/usb/uhid.c b/sys/dev/usb/uhid.c
index 9d1b28c..591f699 100644
--- a/sys/dev/usb/uhid.c
+++ b/sys/dev/usb/uhid.c
@@ -1,4 +1,4 @@
-/* $NetBSD: uhid.c,v 1.15 1999/01/10 11:13:36 augustss Exp $ */
+/* $NetBSD: uhid.c,v 1.24 1999/09/05 19:32:18 augustss Exp $ */
/* $FreeBSD$ */
/*
@@ -42,22 +42,21 @@
* HID spec: http://www.usb.org/developers/data/usbhid10.pdf
*/
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
-#if defined(__NetBSD__)
+#if defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/device.h>
#include <sys/ioctl.h>
#elif defined(__FreeBSD__)
#include <sys/ioccom.h>
-#include <sys/conf.h>
#include <sys/filio.h>
#include <sys/module.h>
#include <sys/bus.h>
#include <sys/ioccom.h>
#endif
+#include <sys/conf.h>
#include <sys/tty.h>
#include <sys/file.h>
#include <sys/select.h>
@@ -76,14 +75,14 @@
#ifdef UHID_DEBUG
#define DPRINTF(x) if (uhiddebug) logprintf x
#define DPRINTFN(n,x) if (uhiddebug>(n)) logprintf x
-int uhiddebug = 1;
+int uhiddebug = 0;
#else
#define DPRINTF(x)
#define DPRINTFN(n,x)
#endif
struct uhid_softc {
- bdevice sc_dev; /* base device */
+ USBBASEDEVICE sc_dev; /* base device */
usbd_interface_handle sc_iface; /* interface */
usbd_pipe_handle sc_intrpipe; /* interrupt pipe */
int sc_ep_addr;
@@ -108,20 +107,17 @@ struct uhid_softc {
#define UHID_ASLP 0x02 /* waiting for device data */
#define UHID_NEEDCLEAR 0x04 /* needs clearing endpoint stall */
#define UHID_IMMED 0x08 /* return read data immediately */
- int sc_disconnected; /* device is gone */
+
+ int sc_refcnt;
+ u_char sc_dying;
};
#define UHIDUNIT(dev) (minor(dev))
#define UHID_CHUNK 128 /* chunk size for read */
#define UHID_BSIZE 1020 /* buffer size */
-#if defined(__NetBSD__)
-int uhidopen __P((dev_t, int, int, struct proc *));
-int uhidclose __P((dev_t, int, int, struct proc *p));
-int uhidread __P((dev_t, struct uio *uio, int));
-int uhidwrite __P((dev_t, struct uio *uio, int));
-int uhidioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
-int uhidpoll __P((dev_t, int, struct proc *));
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+cdev_decl(uhid);
#elif defined(__FreeBSD__)
d_open_t uhidopen;
d_close_t uhidclose;
@@ -151,7 +147,10 @@ static struct cdevsw uhid_cdevsw = {
#endif
void uhid_intr __P((usbd_request_handle, usbd_private_handle, usbd_status));
-void uhid_disco __P((void *));
+
+int uhid_do_read __P((struct uhid_softc *, struct uio *uio, int));
+int uhid_do_write __P((struct uhid_softc *, struct uio *uio, int));
+int uhid_do_ioctl __P((struct uhid_softc *, u_long, caddr_t, int, struct proc *));
USB_DECLARE_DRIVER(uhid);
@@ -179,7 +178,6 @@ USB_ATTACH(uhid)
usbd_status r;
char devinfo[1024];
- sc->sc_disconnected = 1;
sc->sc_iface = iface;
id = usbd_get_interface_descriptor(iface);
usbd_devinfo(uaa->device, 0, devinfo);
@@ -191,6 +189,7 @@ USB_ATTACH(uhid)
if (!ed) {
printf("%s: could not read endpoint descriptor\n",
USBDEVNAME(sc->sc_dev));
+ sc->sc_dying = 1;
USB_ATTACH_ERROR_RETURN;
}
@@ -199,22 +198,26 @@ USB_ATTACH(uhid)
" bInterval=%d\n",
ed->bLength, ed->bDescriptorType,
ed->bEndpointAddress & UE_ADDR,
- ed->bEndpointAddress & UE_IN ? "in" : "out",
+ UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out",
ed->bmAttributes & UE_XFERTYPE,
UGETW(ed->wMaxPacketSize), ed->bInterval));
- if ((ed->bEndpointAddress & UE_IN) != UE_IN ||
+ if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN ||
(ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) {
printf("%s: unexpected endpoint\n", USBDEVNAME(sc->sc_dev));
+ sc->sc_dying = 1;
USB_ATTACH_ERROR_RETURN;
}
sc->sc_ep_addr = ed->bEndpointAddress;
- sc->sc_disconnected = 0;
- r = usbd_alloc_report_desc(uaa->iface, &desc, &size, M_USB);
+ desc = 0;
+ r = usbd_alloc_report_desc(uaa->iface, &desc, &size, M_USBDEV);
if (r != USBD_NORMAL_COMPLETION) {
printf("%s: no report descriptor\n", USBDEVNAME(sc->sc_dev));
+ sc->sc_dying = 1;
+ if (desc)
+ free(desc, M_USBDEV);
USB_ATTACH_ERROR_RETURN;
}
@@ -230,25 +233,70 @@ USB_ATTACH(uhid)
USB_ATTACH_SUCCESS_RETURN;
}
-#if defined(__FreeBSD__)
-static int
-uhid_detach(device_t self)
-{
- DPRINTF(("%s: disconnected\n", USBDEVNAME(self)));
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+int
+uhid_activate(self, act)
+ device_ptr_t self;
+ enum devact act;
+{
+ struct uhid_softc *sc = (struct uhid_softc *)self;
+
+ switch (act) {
+ case DVACT_ACTIVATE:
+ return (EOPNOTSUPP);
+ break;
- return 0;
+ case DVACT_DEACTIVATE:
+ sc->sc_dying = 1;
+ break;
+ }
+ return (0);
}
#endif
-void
-uhid_disco(p)
- void *p;
+USB_DETACH(uhid)
{
- struct uhid_softc *sc = p;
+ USB_DETACH_START(uhid, sc);
+ int s;
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ int maj, mn;
- DPRINTF(("ums_hid: sc=%p\n", sc));
- usbd_abort_pipe(sc->sc_intrpipe);
- sc->sc_disconnected = 1;
+ DPRINTF(("uhid_detach: sc=%p flags=%d\n", sc, flags));
+#elif defined(__FreeBSD__)
+ DPRINTF(("uhid_detach: sc=%p\n", sc));
+#endif
+
+ sc->sc_dying = 1;
+ if (sc->sc_intrpipe)
+ usbd_abort_pipe(sc->sc_intrpipe);
+
+ if (sc->sc_state & UHID_OPEN) {
+ s = splusb();
+ if (--sc->sc_refcnt >= 0) {
+ /* Wake everyone */
+ wakeup(&sc->sc_q);
+ /* Wait for processes to go away. */
+ usb_detach_wait(USBDEV(sc->sc_dev));
+ }
+ splx(s);
+ }
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ /* locate the major number */
+ for (maj = 0; maj < nchrdev; maj++)
+ if (cdevsw[maj].d_open == uhidopen)
+ break;
+
+ /* Nuke the vnodes for any open instances (calls close). */
+ mn = self->dv_unit;
+ vdevgone(maj, mn, mn, VCHR);
+#elif defined(__FreeBSD__)
+ /* XXX not implemented yet */
+#endif
+
+ free(sc->sc_repdesc, M_USBDEV);
+
+ return (0);
}
void
@@ -277,7 +325,7 @@ uhid_intr(reqh, addr, status)
if (sc->sc_state & UHID_ASLP) {
sc->sc_state &= ~UHID_ASLP;
DPRINTFN(5, ("uhid_intr: waking %p\n", sc));
- wakeup((caddr_t)sc);
+ wakeup(&sc->sc_q);
}
selwakeup(&sc->sc_rsel);
}
@@ -292,29 +340,26 @@ uhidopen(dev, flag, mode, p)
usbd_status r;
USB_GET_SC_OPEN(uhid, UHIDUNIT(dev), sc);
- if (!sc)
- return (ENXIO);
-
- DPRINTF(("uhidopen: sc=%p, disco=%d\n", sc, sc->sc_disconnected));
+ DPRINTF(("uhidopen: sc=%p\n", sc));
- if (sc->sc_disconnected)
- return (EIO);
+ if (sc->sc_dying)
+ return (ENXIO);
if (sc->sc_state & UHID_OPEN)
return (EBUSY);
+ sc->sc_state |= UHID_OPEN;
-#if defined(__NetBSD__)
- if (clalloc(&sc->sc_q, UHID_BSIZE, 0) == -1)
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ if (clalloc(&sc->sc_q, UHID_BSIZE, 0) == -1) {
+ sc->sc_state &= ~UHID_OPEN;
return (ENOMEM);
+ }
#elif defined(__FreeBSD__)
clist_alloc_cblocks(&sc->sc_q, UHID_BSIZE, 0);
#endif
- sc->sc_state |= UHID_OPEN;
- sc->sc_state &= ~UHID_IMMED;
-
- sc->sc_ibuf = malloc(sc->sc_isize, M_USB, M_WAITOK);
- sc->sc_obuf = malloc(sc->sc_osize, M_USB, M_WAITOK);
+ sc->sc_ibuf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
+ sc->sc_obuf = malloc(sc->sc_osize, M_USBDEV, M_WAITOK);
/* Set up interrupt pipe. */
r = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ep_addr,
@@ -324,10 +369,13 @@ uhidopen(dev, flag, mode, p)
if (r != USBD_NORMAL_COMPLETION) {
DPRINTF(("uhidopen: usbd_open_pipe_intr failed, "
"error=%d\n",r));
+ free(sc->sc_ibuf, M_USBDEV);
+ free(sc->sc_obuf, M_USBDEV);
sc->sc_state &= ~UHID_OPEN;
return (EIO);
}
- usbd_set_disco(sc->sc_intrpipe, uhid_disco, sc);
+
+ sc->sc_state &= ~UHID_IMMED;
return (0);
}
@@ -341,32 +389,30 @@ uhidclose(dev, flag, mode, p)
{
USB_GET_SC(uhid, UHIDUNIT(dev), sc);
- if (sc->sc_disconnected)
- return (EIO);
-
DPRINTF(("uhidclose: sc=%p\n", sc));
/* Disable interrupts. */
usbd_abort_pipe(sc->sc_intrpipe);
usbd_close_pipe(sc->sc_intrpipe);
+ sc->sc_intrpipe = 0;
- sc->sc_state &= ~UHID_OPEN;
-
-#if defined(__NetBSD__)
+#if defined(__NetBSD__) || defined(__OpenBSD__)
clfree(&sc->sc_q);
#elif defined(__FreeBSD__)
clist_free_cblocks(&sc->sc_q);
#endif
- free(sc->sc_ibuf, M_USB);
- free(sc->sc_obuf, M_USB);
+ free(sc->sc_ibuf, M_USBDEV);
+ free(sc->sc_obuf, M_USBDEV);
+
+ sc->sc_state &= ~UHID_OPEN;
return (0);
}
int
-uhidread(dev, uio, flag)
- dev_t dev;
+uhid_do_read(sc, uio, flag)
+ struct uhid_softc *sc;
struct uio *uio;
int flag;
{
@@ -375,17 +421,13 @@ uhidread(dev, uio, flag)
size_t length;
u_char buffer[UHID_CHUNK];
usbd_status r;
- USB_GET_SC(uhid, UHIDUNIT(dev), sc);
-
- if (sc->sc_disconnected)
- return (EIO);
DPRINTFN(1, ("uhidread\n"));
if (sc->sc_state & UHID_IMMED) {
DPRINTFN(1, ("uhidread immed\n"));
r = usbd_get_report(sc->sc_iface, UHID_INPUT_REPORT,
- sc->sc_iid, sc->sc_ibuf, sc->sc_isize);
+ sc->sc_iid, buffer, sc->sc_isize);
if (r != USBD_NORMAL_COMPLETION)
return (EIO);
return (uiomove(buffer, sc->sc_isize, uio));
@@ -395,16 +437,17 @@ uhidread(dev, uio, flag)
while (sc->sc_q.c_cc == 0) {
if (flag & IO_NDELAY) {
splx(s);
- return EWOULDBLOCK;
+ return (EWOULDBLOCK);
}
sc->sc_state |= UHID_ASLP;
DPRINTFN(5, ("uhidread: sleep on %p\n", sc));
- error = tsleep((caddr_t)sc, PZERO | PCATCH, "uhidrea", 0);
+ error = tsleep(&sc->sc_q, PZERO | PCATCH, "uhidrea", 0);
DPRINTFN(5, ("uhidread: woke, error=%d\n", error));
+ if (sc->sc_dying)
+ error = EIO;
if (error) {
sc->sc_state &= ~UHID_ASLP;
- splx(s);
- return (error);
+ break;
}
if (sc->sc_state & UHID_NEEDCLEAR) {
DPRINTFN(-1,("uhidread: clearing stall\n"));
@@ -415,7 +458,7 @@ uhidread(dev, uio, flag)
splx(s);
/* Transfer as many chunks as possible. */
- while (sc->sc_q.c_cc > 0 && uio->uio_resid > 0) {
+ while (sc->sc_q.c_cc > 0 && uio->uio_resid > 0 && !error) {
length = min(sc->sc_q.c_cc, uio->uio_resid);
if (length > sizeof(buffer))
length = sizeof(buffer);
@@ -433,28 +476,42 @@ uhidread(dev, uio, flag)
}
int
-uhidwrite(dev, uio, flag)
+uhidread(dev, uio, flag)
dev_t dev;
struct uio *uio;
int flag;
{
+ USB_GET_SC(uhid, UHIDUNIT(dev), sc);
+ int error;
+
+ sc->sc_refcnt++;
+ error = uhid_do_read(sc, uio, flag);
+ if (--sc->sc_refcnt < 0)
+ usb_detach_wakeup(USBDEV(sc->sc_dev));
+ return (error);
+}
+
+int
+uhid_do_write(sc, uio, flag)
+ struct uhid_softc *sc;
+ struct uio *uio;
+ int flag;
+{
int error;
int size;
usbd_status r;
- USB_GET_SC(uhid, UHIDUNIT(dev), sc);
-
- if (sc->sc_disconnected)
- return (EIO);
DPRINTFN(1, ("uhidwrite\n"));
+ if (sc->sc_dying)
+ return (EIO);
+
size = sc->sc_osize;
error = 0;
- while (uio->uio_resid > 0) {
- if (uio->uio_resid != size)
- return (0);
- if ((error = uiomove(sc->sc_obuf, size, uio)) != 0)
- break;
+ if (uio->uio_resid != size)
+ return (EINVAL);
+ error = uiomove(sc->sc_obuf, size, uio);
+ if (!error) {
if (sc->sc_oid)
r = usbd_set_report(sc->sc_iface, UHID_OUTPUT_REPORT,
sc->sc_obuf[0],
@@ -464,15 +521,31 @@ uhidwrite(dev, uio, flag)
0, sc->sc_obuf, size);
if (r != USBD_NORMAL_COMPLETION) {
error = EIO;
- break;
}
}
+
return (error);
}
int
-uhidioctl(dev, cmd, addr, flag, p)
+uhidwrite(dev, uio, flag)
dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ USB_GET_SC(uhid, UHIDUNIT(dev), sc);
+ int error;
+
+ sc->sc_refcnt++;
+ error = uhid_do_write(sc, uio, flag);
+ if (--sc->sc_refcnt < 0)
+ usb_detach_wakeup(USBDEV(sc->sc_dev));
+ return (error);
+}
+
+int
+uhid_do_ioctl(sc, cmd, addr, flag, p)
+ struct uhid_softc *sc;
u_long cmd;
caddr_t addr;
int flag;
@@ -482,12 +555,12 @@ uhidioctl(dev, cmd, addr, flag, p)
struct usb_ctl_report *re;
int size, id;
usbd_status r;
- USB_GET_SC(uhid, UHIDUNIT(dev), sc);
- if (sc->sc_disconnected)
+ DPRINTFN(2, ("uhidioctl: cmd=%lx\n", cmd));
+
+ if (sc->sc_dying)
return (EIO);
- DPRINTFN(2, ("uhidioctl: cmd=%lx\n", cmd));
switch (cmd) {
case FIONBIO:
/* All handled in the upper FS layer. */
@@ -545,6 +618,24 @@ uhidioctl(dev, cmd, addr, flag, p)
}
int
+uhidioctl(dev, cmd, addr, flag, p)
+ dev_t dev;
+ u_long cmd;
+ caddr_t addr;
+ int flag;
+ struct proc *p;
+{
+ USB_GET_SC(uhid, UHIDUNIT(dev), sc);
+ int error;
+
+ sc->sc_refcnt++;
+ error = uhid_do_ioctl(sc, cmd, addr, flag, p);
+ if (--sc->sc_refcnt < 0)
+ usb_detach_wakeup(USBDEV(sc->sc_dev));
+ return (error);
+}
+
+int
uhidpoll(dev, events, p)
dev_t dev;
int events;
@@ -554,7 +645,7 @@ uhidpoll(dev, events, p)
int s;
USB_GET_SC(uhid, UHIDUNIT(dev), sc);
- if (sc->sc_disconnected)
+ if (sc->sc_dying)
return (EIO);
s = splusb();
@@ -573,5 +664,5 @@ uhidpoll(dev, events, p)
#if defined(__FreeBSD__)
DEV_DRIVER_MODULE(uhid, uhub, uhid_driver, uhid_devclass,
- uhid_cdevsw, usbd_driver_load, 0);
+ uhid_cdevsw, usbd_driver_load, 0);
#endif
diff --git a/sys/dev/usb/uhub.c b/sys/dev/usb/uhub.c
index 4863a1e..5125f1d 100644
--- a/sys/dev/usb/uhub.c
+++ b/sys/dev/usb/uhub.c
@@ -1,4 +1,4 @@
-/* $NetBSD: uhub.c,v 1.16 1999/01/10 19:13:15 augustss Exp $ */
+/* $NetBSD: uhub.c,v 1.26 1999/09/05 19:32:18 augustss Exp $ */
/* $FreeBSD$ */
/*
@@ -46,7 +46,7 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
-#if defined(__NetBSD__)
+#if defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/device.h>
#elif defined(__FreeBSD__)
#include <sys/module.h>
@@ -54,8 +54,9 @@
#endif
#include <sys/proc.h>
-#include <dev/usb/usb.h>
+#include "bus_if.h"
+#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdi_util.h>
#include <dev/usb/usbdivar.h>
@@ -70,7 +71,7 @@ extern int usbdebug;
#endif
struct uhub_softc {
- bdevice sc_dev; /* base device */
+ USBBASEDEVICE sc_dev; /* base device */
usbd_device_handle sc_hub; /* USB device */
usbd_pipe_handle sc_ipipe; /* interrupt pipe */
u_int8_t sc_status[1]; /* XXX more ports */
@@ -82,32 +83,42 @@ void uhub_disconnect_port __P((struct usbd_port *up));
usbd_status uhub_explore __P((usbd_device_handle hub));
void uhub_intr __P((usbd_request_handle, usbd_private_handle, usbd_status));
-/* void uhub_disco __P((void *)); */
+#if defined(__FreeBSD__)
+static bus_child_detached_t uhub_child_detached;
+#endif
-USB_DECLARE_DRIVER(uhub);
+USB_DECLARE_DRIVER_INIT(uhub, DEVMETHOD(bus_child_detached, uhub_child_detached));
-#if defined(__FreeBSD__)
+/* We need two attachment points:
+ * hub to usb and hub to hub
+ * Every other driver only connects to hubs
+ */
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+/* Create the driver instance for the hub connected to hub case */
+struct cfattach uhub_uhub_ca = {
+ sizeof(struct uhub_softc), uhub_match, uhub_attach,
+ uhub_detach, uhub_activate
+};
+#elif defined(__FreeBSD__)
+/* Create the driver instance for the hub connected to usb case. */
devclass_t uhubroot_devclass;
static device_method_t uhubroot_methods[] = {
- DEVMETHOD(device_probe, uhub_match),
- DEVMETHOD(device_attach, uhub_attach),
+ DEVMETHOD(device_probe, uhub_match),
+ DEVMETHOD(device_attach, uhub_attach),
+
/* detach is not allowed for a root hub */
- {0,0}
+ {0,0}
};
-static driver_t uhubroot_driver = {
- "uhub",
- uhubroot_methods,
- sizeof(struct uhub_softc)
+static driver_t uhubroot_driver = {
+ "uhub",
+ uhubroot_methods,
+ sizeof(struct uhub_softc)
};
#endif
-#if defined(__NetBSD__)
-struct cfattach uhub_uhub_ca = {
- sizeof(struct uhub_softc), uhub_match, uhub_attach
-};
-#endif
USB_MATCH(uhub)
{
@@ -145,7 +156,7 @@ USB_ATTACH(uhub)
r = usbd_set_config_index(dev, 0, 1);
if (r != USBD_NORMAL_COMPLETION) {
- DPRINTF(("%s: configuration failed, %s\n",
+ DPRINTF(("%s: configuration failed, error=%s\n",
USBDEVNAME(sc->sc_dev), usbd_errstr(r)));
USB_ATTACH_ERROR_RETURN;
}
@@ -170,7 +181,7 @@ USB_ATTACH(uhub)
r = usbd_do_request(dev, &req, &hubdesc);
}
if (r != USBD_NORMAL_COMPLETION) {
- DPRINTF(("%s: getting hub descriptor failed, %s\n",
+ DPRINTF(("%s: getting hub descriptor failed, error=%s\n",
USBDEVNAME(sc->sc_dev), usbd_errstr(r)));
USB_ATTACH_ERROR_RETURN;
}
@@ -184,7 +195,7 @@ USB_ATTACH(uhub)
hub = malloc(sizeof(*hub) + (nports-1) * sizeof(struct usbd_port),
- M_USB, M_NOWAIT);
+ M_USBDEV, M_NOWAIT);
if (hub == 0)
USB_ATTACH_ERROR_RETURN;
dev->hub = hub;
@@ -197,28 +208,28 @@ USB_ATTACH(uhub)
dev->self_powered, dev->powersrc->parent,
dev->powersrc->parent ?
dev->powersrc->parent->self_powered : 0));
+
if (!dev->self_powered && dev->powersrc->parent &&
!dev->powersrc->parent->self_powered) {
printf("%s: bus powered hub connected to bus powered hub, "
- "ignored\n",
- USBDEVNAME(sc->sc_dev));
- USB_ATTACH_ERROR_RETURN;
+ "ignored\n", USBDEVNAME(sc->sc_dev));
+ goto bad;
}
/* Set up interrupt pipe. */
r = usbd_device2interface_handle(dev, 0, &iface);
if (r != USBD_NORMAL_COMPLETION) {
printf("%s: no interface handle\n", USBDEVNAME(sc->sc_dev));
- USB_ATTACH_ERROR_RETURN;
+ goto bad;
}
ed = usbd_interface2endpoint_descriptor(iface, 0);
if (ed == 0) {
printf("%s: no endpoint descriptor\n", USBDEVNAME(sc->sc_dev));
- USB_ATTACH_ERROR_RETURN;
+ goto bad;
}
if ((ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) {
printf("%s: bad interrupt endpoint\n", USBDEVNAME(sc->sc_dev));
- USB_ATTACH_ERROR_RETURN;
+ goto bad;
}
r = usbd_open_pipe_intr(iface, ed->bEndpointAddress,USBD_SHORT_XFER_OK,
@@ -228,7 +239,7 @@ USB_ATTACH(uhub)
if (r != USBD_NORMAL_COMPLETION) {
printf("%s: cannot open interrupt pipe\n",
USBDEVNAME(sc->sc_dev));
- USB_ATTACH_ERROR_RETURN;
+ goto bad;
}
/* Wait with power off for a while. */
@@ -247,18 +258,12 @@ USB_ATTACH(uhub)
sc->sc_running = 1;
USB_ATTACH_SUCCESS_RETURN;
-}
-#if defined(__FreeBSD__)
-static int
-uhub_detach(device_t self)
-{
- struct uhub_softc *sc = device_get_softc(self);
- DPRINTF(("%s: disconnected\n", USBDEVNAME(self)));
- free(sc->sc_hub->hub, M_USB);
- return 0;
+bad:
+ free(hub, M_USBDEV);
+ dev->hub = 0;
+ USB_ATTACH_ERROR_RETURN;
}
-#endif
usbd_status
uhub_init_port(up)
@@ -282,13 +287,15 @@ uhub_init_port(up)
/* First let the device go through a good power cycle, */
usbd_delay_ms(dev, USB_PORT_POWER_DOWN_TIME);
+#if 0
+usbd_clear_hub_feature(dev, UHF_C_HUB_OVER_CURRENT);
+usbd_clear_port_feature(dev, port, UHF_C_PORT_OVER_CURRENT);
+#endif
+
/* then turn the power on. */
r = usbd_set_port_feature(dev, port, UHF_PORT_POWER);
if (r != USBD_NORMAL_COMPLETION)
return (r);
- r = usbd_get_port_status(dev, port, &up->status);
- if (r != USBD_NORMAL_COMPLETION)
- return (r);
DPRINTF(("usb_init_port: turn on port %d power status=0x%04x "
"change=0x%04x\n",
port, UGETW(up->status.wPortStatus),
@@ -296,6 +303,26 @@ uhub_init_port(up)
/* Wait for stable power. */
usbd_delay_ms(dev, dev->hub->hubdesc.bPwrOn2PwrGood *
UHD_PWRON_FACTOR);
+ /* Get the port status again. */
+ r = usbd_get_port_status(dev, port, &up->status);
+ if (r != USBD_NORMAL_COMPLETION)
+ return (r);
+ DPRINTF(("usb_init_port: after power on status=0x%04x "
+ "change=0x%04x\n",
+ UGETW(up->status.wPortStatus),
+ UGETW(up->status.wPortChange)));
+
+#if 0
+usbd_clear_hub_feature(dev, UHF_C_HUB_OVER_CURRENT);
+usbd_clear_port_feature(dev, port, UHF_C_PORT_OVER_CURRENT);
+usbd_get_port_status(dev, port, &up->status);
+#endif
+
+ pstatus = UGETW(up->status.wPortStatus);
+ if ((pstatus & UPS_PORT_POWER) == 0)
+ printf("%s: port %d did not power up\n",
+ USBDEVNAME(((struct uhub_softc *)dev->hub->hubsoftc)->sc_dev), port);
+
}
if (dev->self_powered)
/* Self powered hub, give ports maximum current. */
@@ -329,8 +356,9 @@ uhub_explore(dev)
up = &dev->hub->ports[port-1];
r = usbd_get_port_status(dev, port, &up->status);
if (r != USBD_NORMAL_COMPLETION) {
- DPRINTF(("uhub_explore: get port %d status failed, %s\n",
- port, usbd_errstr(r)));
+ DPRINTF(("uhub_explore: get port status failed, "
+ "error=%s\n",
+ usbd_errstr(r)));
continue;
}
status = UGETW(up->status.wPortStatus);
@@ -340,16 +368,18 @@ uhub_explore(dev)
if (change & UPS_C_PORT_ENABLED) {
usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE);
if (status & UPS_PORT_ENABLED) {
- printf("%s: port %d illegal enable change\n",
+ printf("%s: illegal enable change, port %d\n",
USBDEVNAME(sc->sc_dev), port);
} else {
/* Port error condition. */
if (up->restartcnt++ < USBD_RESTART_MAX) {
- printf("%s: port %d error, restarting\n",
+ printf("%s: port error, restarting "
+ "port %d\n",
USBDEVNAME(sc->sc_dev), port);
goto disco;
} else {
- printf("%s: port %d error, giving up\n",
+ printf("%s: port error, giving up "
+ "port %d\n",
USBDEVNAME(sc->sc_dev), port);
}
}
@@ -378,6 +408,7 @@ uhub_explore(dev)
"on port %d\n",
up->device->address, port));
uhub_disconnect_port(up);
+
usbd_clear_port_feature(dev, port,
UHF_C_PORT_CONNECTION);
}
@@ -396,25 +427,23 @@ uhub_explore(dev)
continue;
/* Get device info and set its address. */
- r = usbd_new_device(&sc->sc_dev, dev->bus,
+ r = usbd_new_device(USBDEV(sc->sc_dev), dev->bus,
dev->depth + 1, status & UPS_LOW_SPEED,
port, up);
/* XXX retry a few times? */
if (r != USBD_NORMAL_COMPLETION) {
- DPRINTFN(-1,("uhub_explore: usb_new_device failed, %s\n",
- usbd_errstr(r)));
+ DPRINTFN(-1,("uhub_explore: usb_new_device failed, "
+ "error=%s\n", usbd_errstr(r)));
/* Avoid addressing problems by disabling. */
/* usbd_reset_port(dev, port, &up->status); */
/* XXX
* What should we do. The device may or may not be at its
* assigned address. In any case we'd like to ignore it.
- * Maybe the port should be disabled until the device is
- * disconnected.
*/
if (r == USBD_SET_ADDR_FAILED || 1) {/* XXX */
/* The unit refused to accept a new
* address, and since we cannot leave
- * it at 0 we have to disable the port
+ * at 0 we have to disable the port
* instead. */
printf("%s: device problem, disabling "
"port %d\n",
@@ -432,31 +461,35 @@ uhub_explore(dev)
return (USBD_NORMAL_COMPLETION);
}
+/*
+ * The general mechanism for detaching drivers works as follows: Each
+ * driver is responsible for maintaining a reference count on the
+ * number of outstanding references to its softc (e.g. from
+ * processing hanging in a read or write). The detach method of the
+ * driver decrements this counter and flags in the softc that the
+ * driver is dying and then wakes any sleepers. It then sleeps on the
+ * softc. Each place that can sleep must maintain the reference
+ * count. When the reference count drops to -1 (0 is the normal value
+ * of the reference count) the a wakeup on the softc is performed
+ * signaling to the detach waiter that all references are gone.
+ */
+
+/*
+ * Called from process context when we discover that a port has
+ * been disconnected.
+ */
void
uhub_disconnect_port(up)
struct usbd_port *up;
{
usbd_device_handle dev = up->device;
- usbd_pipe_handle p, n;
int i;
- struct softc { /* all softc begin like this */
- bdevice sc_dev;
- };
- struct softc *sc;
- struct softc *scp;
-
- if (!dev) /* no device driver attached at port */
- return;
-
- sc = (struct softc *)dev->softc;
- scp = (struct softc *)up->parent->softc;
- DPRINTFN(3,("uhub_disconnect_port: up=%p dev=%p port=%d\n",
+ DPRINTFN(3,("uhub_disconnect: up=%p dev=%p port=%d\n",
up, dev, up->portno));
- printf("%s: at %s port %d (addr %d) disconnected\n",
- USBDEVNAME(sc->sc_dev), USBDEVNAME(scp->sc_dev),
- up->portno, dev->address);
+ if (!dev) /* not even generic device was attached */
+ return;
if (!dev->cdesc) {
/* Partially attached device, just drop it. */
@@ -465,46 +498,126 @@ uhub_disconnect_port(up)
return;
}
- /* Remove the device */
- for (i = 0; i < dev->cdesc->bNumInterface; i++) {
- for (p = LIST_FIRST(&dev->ifaces[i].pipes); p; p = n) {
- n = LIST_NEXT(p, next);
- if (p->disco)
- p->disco(p->discoarg);
+ if (dev->subdevs) {
+ for (i = 0; dev->subdevs[i]; i++) {
+ if (!dev->subdevs[i]) /* skip empty elements */
+ continue;
+
+ printf("%s: at %s port %d (addr %d) disconnected\n",
+ USBDEVPTRNAME(dev->subdevs[i]),
+ USBDEVPTRNAME(up->parent->subdevs[0]),
+ up->portno, dev->address);
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ config_detach(dev->subdevs[i], DETACH_FORCE);
+#elif defined(__FreeBSD__)
+ device_delete_child(device_get_parent(dev->subdevs[i]),
+ dev->subdevs[i]);
+#endif
}
}
- /* XXX Free all data structures and disable further I/O. */
- if (dev->hub) {
- struct usbd_port *rup;
- int p, nports;
-
- DPRINTFN(3,("usb_disconnect: hub, recursing\n"));
- nports = dev->hub->hubdesc.bNbrPorts;
- for(p = 0; p < nports; p++) {
- rup = &dev->hub->ports[p];
- if (rup->device)
- uhub_disconnect_port(rup);
+ dev->bus->devices[dev->address] = 0;
+ up->device = 0;
+ usb_free_device(dev);
+}
+
+#if defined(__FreeBSD__)
+/* Called when a device has been detached from it */
+static void
+uhub_child_detached(self, child)
+ device_t self;
+ device_t child;
+{
+ struct uhub_softc *sc = device_get_softc(self);
+ usbd_device_handle dev = sc->sc_hub;
+ struct usbd_port *up;
+ int nports;
+ int port;
+ int i;
+
+ if (!dev->hub)
+ /* should never happen; children are only created after init */
+ panic("hub not fully initialised, but child deleted?");
+
+ for (port = 0; port < dev->hub->hubdesc.bNbrPorts; port++) {
+ up = &dev->hub->ports[port];
+ if (up->device && up->device->subdevs) {
+ for (i = 0; up->device->subdevs[i]; i++) {
+ if (up->device->subdevs[i] == child) {
+ up->device->subdevs[i] = NULL;
+ return;
+ }
+ }
}
}
-#if defined(__FreeBSD__)
- device_delete_child(scp->sc_dev, sc->sc_dev);
+}
#endif
- /* clean up the kitchen */
- for (i = 0; i < dev->cdesc->bNumInterface; i++) {
- for (p = LIST_FIRST(&dev->ifaces[i].pipes); p; p = n) {
- n = LIST_NEXT(p, next);
- usbd_abort_pipe(p);
- usbd_close_pipe(p);
+
+#if defined(__NetBSD__)
+int
+uhub_activate(self, act)
+ device_ptr_t self;
+ enum devact act;
+{
+ switch (act) {
+ case DVACT_ACTIVATE:
+ return (EOPNOTSUPP);
+ break;
+
+ case DVACT_DEACTIVATE:
+ break;
+ }
+ return (0);
+}
+#endif
+
+/*
+ * Called from process context when the hub is gone.
+ * Detach all devices on active ports.
+ */
+USB_DETACH(uhub)
+{
+ USB_DETACH_START(uhub, sc);
+ usbd_device_handle dev = sc->sc_hub;
+ struct usbd_port *up;
+ int port, nports;
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ DPRINTF(("uhub_detach: sc=%port flags=%d\n", sc, flags));
+#elif defined(__FreeBSD__)
+ DPRINTF(("uhub_detach: sc=%port\n", sc));
+#endif
+
+ if (!dev->hub) /* Must be partially working */
+ return (0);
+
+ usbd_abort_pipe(sc->sc_ipipe);
+ usbd_close_pipe(sc->sc_ipipe);
+
+ nports = dev->hub->hubdesc.bNbrPorts;
+ for(port = 0; port < nports; port++) {
+ up = &dev->hub->ports[port];
+ if (up->device) {
+ DPRINTF(("uhub_detach: device %d disappeared "
+ "on port %d\n",
+ up->device->address, port));
+ uhub_disconnect_port(up);
}
}
+
+ free(dev->hub, M_USBDEV);
+ dev->hub = 0;
- dev->bus->devices[dev->address] = 0;
- up->device = 0;
- /* XXX free */
+ return (0);
}
+/*
+ * Hub interrupt.
+ * This an indication that some port has changed status.
+ * Notify the bus event handler thread that we need
+ * to be explored again.
+ */
void
uhub_intr(reqh, addr, status)
usbd_request_handle reqh;
@@ -516,8 +629,8 @@ uhub_intr(reqh, addr, status)
DPRINTFN(5,("uhub_intr: sc=%p\n", sc));
if (status != USBD_NORMAL_COMPLETION)
usbd_clear_endpoint_stall_async(sc->sc_ipipe);
- else
- usb_needs_explore(sc->sc_hub->bus);
+
+ usb_needs_explore(sc->sc_hub->bus);
}
#if defined(__FreeBSD__)
diff --git a/sys/dev/usb/ulpt.c b/sys/dev/usb/ulpt.c
index da1ca4b..021e58f 100644
--- a/sys/dev/usb/ulpt.c
+++ b/sys/dev/usb/ulpt.c
@@ -1,4 +1,4 @@
-/* $NetBSD: ulpt.c,v 1.11 1999/01/10 11:13:36 augustss Exp $ */
+/* $NetBSD: ulpt.c,v 1.23 1999/09/11 10:40:07 augustss Exp $ */
/* $FreeBSD$ */
/*
@@ -42,10 +42,11 @@
* Printer Class spec: http://www.usb.org/developers/data/usbprn10.pdf
*/
+/* XXX Note in the manpage the ULPT_NOPRIME version of the printer */
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
-#include <sys/malloc.h>
#include <sys/kernel.h>
#if defined(__NetBSD__)
#include <sys/device.h>
@@ -57,6 +58,7 @@
#endif
#include <sys/uio.h>
#include <sys/conf.h>
+#include <sys/vnode.h>
#include <sys/syslog.h>
#include <dev/usb/usb.h>
@@ -74,7 +76,7 @@
#ifdef ULPT_DEBUG
#define DPRINTF(x) if (ulptdebug) logprintf x
#define DPRINTFN(n,x) if (ulptdebug>(n)) logprintf x
-int ulptdebug = 1;
+int ulptdebug = 0;
#else
#define DPRINTF(x)
#define DPRINTFN(n,x)
@@ -91,7 +93,7 @@ int ulptdebug = 1;
#define LPS_MASK (LPS_SELECT|LPS_NERR|LPS_NOPAPER)
struct ulpt_softc {
- bdevice sc_dev;
+ USBBASEDEVICE sc_dev;
usbd_device_handle sc_udev; /* device */
usbd_interface_handle sc_iface; /* interface */
int sc_ifaceno;
@@ -103,21 +105,19 @@ struct ulpt_softc {
#define ULPT_OBUSY 0x02 /* printer is busy doing output */
#define ULPT_INIT 0x04 /* waiting to initialize for open */
u_char sc_flags;
-#if defined(__NetBSD__)
#define ULPT_NOPRIME 0x40 /* don't prime on open */
-#elif defined(__FreeBSD__)
-/* values taken from i386/isa/lpt.c */
-#define ULPT_POS_INIT 0x04 /* if we are a postive init signal */
-#define ULPT_POS_ACK 0x08 /* if we are a positive going ack */
-#define ULPT_NOPRIME 0x10 /* don't prime the printer at all */
-#define ULPT_PRIMEOPEN 0x20 /* prime on every open */
-#define ULPT_AUTOLF 0x40 /* tell printer to do an automatic lf */
-#define ULPT_BYPASS 0x80 /* bypass printer ready checks */
-#endif
u_char sc_laststatus;
+
+ int sc_refcnt;
+ u_char sc_dying;
+
+#if defined(__FreeBSD__)
+ dev_t dev;
+ dev_t dev_noprime;
+#endif
};
-#if defined(__NetBSD__)
+#if defined(__NetBSD__) || defined(__OpenBSD__)
int ulptopen __P((dev_t, int, int, struct proc *));
int ulptclose __P((dev_t, int, int, struct proc *p));
int ulptwrite __P((dev_t, struct uio *uio, int));
@@ -148,18 +148,18 @@ static struct cdevsw ulpt_cdevsw = {
};
#endif
+void ulpt_disco __P((void *));
+
+int ulpt_do_write __P((struct ulpt_softc *, struct uio *uio, int));
int ulpt_status __P((struct ulpt_softc *));
void ulpt_reset __P((struct ulpt_softc *));
int ulpt_statusmsg __P((u_char, struct ulpt_softc *));
-#if defined(__NetBSD__)
+void ieee1284_print_id __P((char *));
+
#define ULPTUNIT(s) (minor(s) & 0x1f)
#define ULPTFLAGS(s) (minor(s) & 0xe0)
-#elif defined(__FreeBSD__)
-/* defines taken from i386/isa/lpt.c */
-#define ULPTUNIT(s) (minor(s) & 0x03)
-#define ULPTFLAGS(s) (minor(s) & 0xfc)
-#endif
+
USB_DECLARE_DRIVER(ulpt);
@@ -187,8 +187,6 @@ USB_ATTACH(ulpt)
usbd_device_handle dev = uaa->device;
usbd_interface_handle iface = uaa->iface;
usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface);
- usb_config_descriptor_t *cd = usbd_get_config_descriptor(dev);
- usb_device_request_t req;
char devinfo[1024];
usb_endpoint_descriptor_t *ed;
usbd_status r;
@@ -203,13 +201,13 @@ USB_ATTACH(ulpt)
ed = usbd_interface2endpoint_descriptor(iface, 0);
if (!ed)
goto nobulk;
- if ((ed->bEndpointAddress & UE_DIR) != UE_OUT ||
+ if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_OUT ||
(ed->bmAttributes & UE_XFERTYPE) != UE_BULK) {
/* In case we are using a bidir protocol... */
ed = usbd_interface2endpoint_descriptor(iface, 1);
if (!ed)
goto nobulk;
- if ((ed->bEndpointAddress & UE_IN) != UE_OUT ||
+ if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_OUT ||
(ed->bmAttributes & UE_XFERTYPE) != UE_BULK)
goto nobulk;
}
@@ -218,35 +216,127 @@ USB_ATTACH(ulpt)
sc->sc_iface = iface;
r = usbd_interface2device_handle(iface, &sc->sc_udev);
- if (r != USBD_NORMAL_COMPLETION)
+ if (r != USBD_NORMAL_COMPLETION) {
+ sc->sc_dying = 1;
USB_ATTACH_ERROR_RETURN;
+ }
sc->sc_ifaceno = id->bInterfaceNumber;
+#if 0
+/*
+ * This code is disabled because for some mysterious it causes
+ * printing not to work. But only sometimes, and mostly with
+ * UHCI and less often with OHCI. *sigh*
+ */
+ {
+ usb_config_descriptor_t *cd = usbd_get_config_descriptor(dev);
+ usb_device_request_t req;
+ int len, alen;
+
req.bmRequestType = UT_READ_CLASS_INTERFACE;
req.bRequest = UR_GET_DEVICE_ID;
USETW(req.wValue, cd->bConfigurationValue);
USETW2(req.wIndex, id->bInterfaceNumber, id->bAlternateSetting);
USETW(req.wLength, sizeof devinfo - 1);
- r = usbd_do_request_flags(dev, &req, devinfo, USBD_SHORT_XFER_OK, NULL);
- if (r == USBD_NORMAL_COMPLETION) {
- int len;
- char *idstr;
- len = (devinfo[0] << 8) | (devinfo[1] & 0xff);
- /* devinfo now contains an IEEE-1284 device ID */
- idstr = devinfo+2;
- idstr[len] = 0;
- printf("%s: device id <%s>\n", USBDEVNAME(sc->sc_dev), idstr);
- } else {
+ r = usbd_do_request_flags(dev, &req, devinfo,USBD_SHORT_XFER_OK,&alen);
+ if (r != USBD_NORMAL_COMPLETION) {
printf("%s: cannot get device id\n", USBDEVNAME(sc->sc_dev));
+ } else if (alen <= 2) {
+ printf("%s: empty device id, no printer connected?\n",
+ USBDEVNAME(sc->sc_dev));
+ } else {
+ /* devinfo now contains an IEEE-1284 device ID */
+ len = ((devinfo[0] & 0xff) << 8) | (devinfo[1] & 0xff);
+ if (len > sizeof devinfo - 3)
+ len = sizeof devinfo - 3;
+ devinfo[len] = 0;
+ printf("%s: device id <", USBDEVNAME(sc->sc_dev));
+ ieee1284_print_id(devinfo+2);
+ printf(">\n");
+ }
}
+#endif
+
+#if defined(__FreeBSD__)
+ sc->dev = make_dev(&ulpt_cdevsw, device_get_unit(self),
+ UID_ROOT, GID_OPERATOR, 0644, "ulpt%d", device_get_unit(self));
+ sc->dev_noprime = make_dev(&ulpt_cdevsw,
+ device_get_unit(self)|ULPT_NOPRIME,
+ UID_ROOT, GID_OPERATOR, 0644, "unlpt%d", device_get_unit(self));
+#endif
USB_ATTACH_SUCCESS_RETURN;
nobulk:
printf("%s: could not find bulk endpoint\n", USBDEVNAME(sc->sc_dev));
+ sc->sc_dying = 1;
USB_ATTACH_ERROR_RETURN;
}
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+int
+ulpt_activate(self, act)
+ device_ptr_t self;
+ enum devact act;
+{
+ struct ulpt_softc *sc = (struct ulpt_softc *)self;
+
+ switch (act) {
+ case DVACT_ACTIVATE:
+ return (EOPNOTSUPP);
+ break;
+
+ case DVACT_DEACTIVATE:
+ sc->sc_dying = 1;
+ break;
+ }
+ return (0);
+}
+#endif
+
+USB_DETACH(ulpt)
+{
+ USB_DETACH_START(ulpt, sc);
+ int s;
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ int maj, mn;
+
+ DPRINTF(("ulpt_detach: sc=%p flags=%d\n", sc, flags));
+#elif defined(__FreeBSD__)
+ DPRINTF(("ulpt_detach: sc=%p\n", sc));
+#endif
+
+ sc->sc_dying = 1;
+ if (sc->sc_bulkpipe)
+ usbd_abort_pipe(sc->sc_bulkpipe);
+
+ s = splusb();
+ if (--sc->sc_refcnt >= 0) {
+ /* There is noone to wake, aborting the pipe is enough */
+ /* Wait for processes to go away. */
+ usb_detach_wait(USBDEV(sc->sc_dev));
+ }
+ splx(s);
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ /* locate the major number */
+ for (maj = 0; maj < nchrdev; maj++)
+ if (cdevsw[maj].d_open == ulptopen)
+ break;
+
+ /* Nuke the vnodes for any open instances (calls close). */
+ mn = self->dv_unit;
+ vdevgone(maj, mn, mn, VCHR);
+#elif defined(__FreeBSD__)
+ /* XXX not implemented yet */
+
+ remove_dev(sc->dev);
+ remove_dev(sc->dev_noprime);
+#endif
+
+ return (0);
+}
+
int
ulpt_status(sc)
struct ulpt_softc *sc;
@@ -298,11 +388,11 @@ ulptopen(dev, flag, mode, p)
int spin, error;
USB_GET_SC_OPEN(ulpt, ULPTUNIT(dev), sc);
- if (!sc || !sc->sc_iface)
- return ENXIO;
+ if (!sc || !sc->sc_iface || sc->sc_dying)
+ return (ENXIO);
if (sc->sc_state)
- return EBUSY;
+ return (EBUSY);
sc->sc_state = ULPT_INIT;
sc->sc_flags = flags;
@@ -314,20 +404,22 @@ ulptopen(dev, flag, mode, p)
printf("ulptopen: flags ignored: %b\n", flags,
"\20\3POS_INIT\4POS_ACK\6PRIME_OPEN\7AUTOLF\10BYPASS");
#endif
+
+
if ((flags & ULPT_NOPRIME) == 0)
ulpt_reset(sc);
for (spin = 0; (ulpt_status(sc) & LPS_SELECT) == 0; spin += STEP) {
if (spin >= TIMEOUT) {
sc->sc_state = 0;
- return EBUSY;
+ return (EBUSY);
}
/* wait 1/4 second, give up if we get a signal */
error = tsleep((caddr_t)sc, LPTPRI | PCATCH, "ulptop", STEP);
if (error != EWOULDBLOCK) {
sc->sc_state = 0;
- return error;
+ return (error);
}
}
@@ -361,7 +453,7 @@ ulpt_statusmsg(status, sc)
else if (new & LPS_NERR)
log(LOG_NOTICE, "%s: output error\n", USBDEVNAME(sc->sc_dev));
- return status;
+ return (status);
}
int
@@ -373,51 +465,75 @@ ulptclose(dev, flag, mode, p)
{
USB_GET_SC(ulpt, ULPTUNIT(dev), sc);
+ if (sc->sc_state != ULPT_OPEN)
+ /* We are being forced to close before the open completed. */
+ return (0);
+
usbd_close_pipe(sc->sc_bulkpipe);
+ sc->sc_bulkpipe = 0;
sc->sc_state = 0;
+ DPRINTF(("ulptclose: closed\n"));
return (0);
}
int
-ulptwrite(dev, uio, flags)
- dev_t dev;
+ulpt_do_write(sc, uio, flags)
+ struct ulpt_softc *sc;
struct uio *uio;
int flags;
{
- size_t n;
+ u_int32_t n;
int error = 0;
- char buf[ULPT_BSIZE];
+ void *bufp;
usbd_request_handle reqh;
usbd_status r;
- USB_GET_SC(ulpt, ULPTUNIT(dev), sc);
- reqh = usbd_alloc_request();
+ DPRINTF(("ulptwrite\n"));
+ reqh = usbd_alloc_request(sc->sc_udev);
if (reqh == 0)
return (ENOMEM);
+ bufp = usbd_alloc_buffer(reqh, ULPT_BSIZE);
+ if (bufp == 0) {
+ usbd_free_request(reqh);
+ return (ENOMEM);
+ }
while ((n = min(ULPT_BSIZE, uio->uio_resid)) != 0) {
ulpt_statusmsg(ulpt_status(sc), sc);
- error = uiomove(buf, n, uio);
+ error = uiomove(bufp, n, uio);
if (error)
break;
- /* XXX use callback to enable interrupt? */
- r = usbd_setup_request(reqh, sc->sc_bulkpipe, 0, buf, n,
- 0, USBD_NO_TIMEOUT, 0);
- if (r != USBD_NORMAL_COMPLETION) {
- error = EIO;
- break;
- }
DPRINTFN(1, ("ulptwrite: transfer %d bytes\n", n));
- r = usbd_sync_transfer(reqh);
+ r = usbd_bulk_transfer(reqh, sc->sc_bulkpipe, 0,
+ USBD_NO_TIMEOUT, bufp, &n, "ulptwr");
if (r != USBD_NORMAL_COMPLETION) {
- DPRINTFN(1, ("ulptwrite: error=%d\n", r));
- usbd_clear_endpoint_stall(sc->sc_bulkpipe);
+ DPRINTF(("ulptwrite: error=%d\n", r));
error = EIO;
break;
}
}
usbd_free_request(reqh);
+
+ return (error);
+}
+
+int
+ulptwrite(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ USB_GET_SC(ulpt, ULPTUNIT(dev), sc);
+ int error;
+
+ if (sc->sc_dying)
+ return (EIO);
+
+ sc->sc_refcnt++;
+ error = ulpt_do_write(sc, uio, flags);
+ if (--sc->sc_refcnt < 0)
+ usb_detach_wakeup(USBDEV(sc->sc_dev));
return (error);
}
@@ -436,17 +552,35 @@ ulptioctl(dev, cmd, data, flag, p)
error = ENODEV;
}
- return error;
+ return (error);
}
-#if defined(__FreeBSD__)
-static int
-ulpt_detach(device_t self)
-{
- DPRINTF(("%s: disconnected\n", USBDEVNAME(self)));
-
- return 0;
+#if 0
+/* XXX This does not belong here. */
+/*
+ * Print select parts of a IEEE 1284 device ID.
+ */
+void
+ieee1284_print_id(str)
+ char *str;
+{
+ char *p, *q;
+
+ for (p = str-1; p; p = strchr(p, ';')) {
+ p++; /* skip ';' */
+ if (strncmp(p, "MFG:", 4) == 0 ||
+ strncmp(p, "MANUFACTURER:", 14) == 0 ||
+ strncmp(p, "MDL:", 4) == 0 ||
+ strncmp(p, "MODEL:", 6) == 0) {
+ q = strchr(p, ';');
+ if (q)
+ printf("%.*s", (int)(q - p + 1), p);
+ }
+ }
}
+#endif
-DEV_DRIVER_MODULE(ulpt, uhub, ulpt_driver, ulpt_devclass, ulpt_cdevsw, usbd_driver_load, 0);
+#if defined(__FreeBSD__)
+DEV_DRIVER_MODULE(ulpt, uhub, ulpt_driver, ulpt_devclass,
+ ulpt_cdevsw, usbd_driver_load, 0);
#endif
diff --git a/sys/dev/usb/umass.c b/sys/dev/usb/umass.c
index 6e943d7..42fb25b 100644
--- a/sys/dev/usb/umass.c
+++ b/sys/dev/usb/umass.c
@@ -76,7 +76,7 @@ int umassdebug = UDMASS_CAM|UDMASS_BULK|UDMASS_USB;
#endif
typedef struct umass_softc {
- bdevice sc_dev; /* base device */
+ USBBASEDEVICE sc_dev; /* base device */
usbd_interface_handle sc_iface; /* the interface we use */
u_int8_t sc_bulkout; /* bulk-out Endpoint Address */
@@ -213,10 +213,10 @@ USB_ATTACH(umass)
USBDEVNAME(sc->sc_dev));
USB_ATTACH_ERROR_RETURN;
}
- if (UE_GET_DIR(ed->bEndpointAddress) == UE_IN
+ if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN
&& (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) {
sc->sc_bulkin = ed->bEndpointAddress;
- } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_OUT
+ } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT
&& (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) {
sc->sc_bulkout = ed->bEndpointAddress;
}
@@ -287,6 +287,7 @@ usbd_status
umass_usb_transfer(usbd_interface_handle iface, usbd_pipe_handle pipe,
void *buf, int buflen, int flags, int *xfer_size)
{
+ usbd_device_handle dev;
usbd_request_handle reqh;
usbd_private_handle priv;
void *buffer;
@@ -297,7 +298,9 @@ umass_usb_transfer(usbd_interface_handle iface, usbd_pipe_handle pipe,
* transfer and then wait for it to complete
*/
- reqh = usbd_alloc_request();
+ usbd_interface2device_handle(iface, &dev);
+
+ reqh = usbd_alloc_request(dev);
if (!reqh) {
DPRINTF(UDMASS_USB, ("Not enough memory\n"));
return USBD_NOMEM;
diff --git a/sys/dev/usb/umodem.c b/sys/dev/usb/umodem.c
index 8041214..71ca9fc 100644
--- a/sys/dev/usb/umodem.c
+++ b/sys/dev/usb/umodem.c
@@ -1,4 +1,5 @@
/* $NetBSD: umodem.c,v 1.5 1999/01/08 11:58:25 augustss Exp $ */
+/* $FreeBSD$ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
diff --git a/sys/dev/usb/usb.c b/sys/dev/usb/usb.c
index 5713d62..344e6c5 100644
--- a/sys/dev/usb/usb.c
+++ b/sys/dev/usb/usb.c
@@ -1,4 +1,4 @@
-/* $NetBSD: usb.c,v 1.12 1999/01/10 19:13:16 augustss Exp $ */
+/* $NetBSD: usb.c,v 1.19 1999/09/05 19:32:19 augustss Exp $ */
/* $FreeBSD$ */
/*
@@ -48,8 +48,9 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
-#if defined(__NetBSD__)
+#if defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/device.h>
+#include <sys/kthread.h>
#elif defined(__FreeBSD__)
#include <sys/module.h>
#include <sys/bus.h>
@@ -62,31 +63,26 @@
#include <sys/select.h>
#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
#if defined(__FreeBSD__)
MALLOC_DEFINE(M_USB, "USB", "USB");
MALLOC_DEFINE(M_USBDEV, "USBdev", "USB device");
+MALLOC_DEFINE(M_USBHC, "USBHC", "USB host controller");
#include "usb_if.h"
-#include "uhci.h"
-#include "ohci.h"
#endif /* defined(__FreeBSD__) */
-#include <dev/usb/usbdi.h>
#include <dev/usb/usbdivar.h>
#include <dev/usb/usb_quirks.h>
#ifdef USB_DEBUG
#define DPRINTF(x) if (usbdebug) logprintf x
#define DPRINTFN(n,x) if (usbdebug>(n)) logprintf x
-int usbdebug = 1;
-
-#if NUHCI > 0
-extern int uhcidebug;
-#endif
-#if NOHCI > 0
-extern int ohcidebug;
-#endif
+int usbdebug = 0;
+extern int uhcidebug;
+extern int ohcidebug;
#else
#define DPRINTF(x)
#define DPRINTFN(n,x)
@@ -95,15 +91,17 @@ extern int ohcidebug;
#define USBUNIT(dev) (minor(dev))
struct usb_softc {
- bdevice sc_dev; /* base device */
+ USBBASEDEVICE sc_dev; /* base device */
usbd_bus_handle sc_bus; /* USB controller */
struct usbd_port sc_port; /* dummy port for root hub */
char sc_running;
char sc_exploring;
struct selinfo sc_consel; /* waiting for connect change */
+ int shutdown;
+ struct proc *event_thread;
};
-#if defined(__NetBSD__)
+#if defined(__NetBSD__) || defined(__OpenBSD__)
int usbopen __P((dev_t, int, int, struct proc *));
int usbclose __P((dev_t, int, int, struct proc *));
int usbioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
@@ -116,26 +114,28 @@ d_ioctl_t usbioctl;
int usbpoll __P((dev_t, int, struct proc *));
struct cdevsw usb_cdevsw = {
- /* open */ usbopen,
- /* close */ usbclose,
- /* read */ noread,
- /* write */ nowrite,
- /* ioctl */ usbioctl,
- /* poll */ usbpoll,
- /* mmap */ nommap,
- /* strategy */ nostrategy,
- /* name */ "usb",
- /* maj */ USB_CDEV_MAJOR,
- /* dump */ nodump,
- /* psize */ nopsize,
- /* flags */ 0,
- /* bmaj */ -1
+ /* open */ usbopen,
+ /* close */ usbclose,
+ /* read */ noread,
+ /* write */ nowrite,
+ /* ioctl */ usbioctl,
+ /* poll */ usbpoll,
+ /* mmap */ nommap,
+ /* strategy */ nostrategy,
+ /* name */ "usb",
+ /* maj */ USB_CDEV_MAJOR,
+ /* dump */ nodump,
+ /* psize */ nopsize,
+ /* flags */ 0,
+ /* bmaj */ -1
};
#endif
usbd_status usb_discover __P((struct usb_softc *));
+void usb_create_event_thread __P((void *));
+void usb_event_thread __P((void *));
-USB_DECLARE_DRIVER_INIT(usb, DEVMETHOD(bus_print_child, usbd_print_child));
+USB_DECLARE_DRIVER(usb);
USB_MATCH(usb)
{
@@ -145,7 +145,7 @@ USB_MATCH(usb)
USB_ATTACH(usb)
{
-#if defined(__NetBSD__)
+#if defined(__NetBSD__) || defined(__OpenBSD__)
struct usb_softc *sc = (struct usb_softc *)self;
#elif defined(__FreeBSD__)
struct usb_softc *sc = device_get_softc(self);
@@ -154,20 +154,20 @@ USB_ATTACH(usb)
usbd_device_handle dev;
usbd_status r;
-#if defined(__NetBSD__)
+#if defined(__NetBSD__) || defined(__OpenBSD__)
printf("\n");
#elif defined(__FreeBSD__)
sc->sc_dev = self;
#endif
DPRINTF(("usbd_attach\n"));
- usbd_init();
+
sc->sc_bus = aux;
sc->sc_bus->usbctl = sc;
sc->sc_running = 1;
sc->sc_bus->use_polling = 1;
sc->sc_port.power = USB_MAX_POWER;
- r = usbd_new_device(&sc->sc_dev, sc->sc_bus, 0, 0, 0, &sc->sc_port);
+ r = usbd_new_device(USBDEV(sc->sc_dev), sc->sc_bus, 0,0,0, &sc->sc_port);
if (r == USBD_NORMAL_COMPLETION) {
dev = sc->sc_port.device;
@@ -186,10 +186,55 @@ USB_ATTACH(usb)
}
sc->sc_bus->use_polling = 0;
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ kthread_create(usb_create_event_thread, sc);
+#endif
+
+#if defined(__FreeBSD__)
+ device_printf(self, "make_dev(usb_cdevsw, %d,_,_,_,'usb%%d',_)\n",
+ device_get_unit(self));
+ make_dev(&usb_cdevsw, device_get_unit(self), UID_ROOT, GID_OPERATOR,
+ 0644, "usb%d", device_get_unit(self));
+#endif
+
USB_ATTACH_SUCCESS_RETURN;
}
-#if defined(__NetBSD__)
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+void
+usb_create_event_thread(arg)
+ void *arg;
+{
+ struct usb_softc *sc = arg;
+
+ if (kthread_create1(usb_event_thread, sc, &sc->event_thread,
+ "%s", sc->sc_dev.dv_xname)) {
+ printf("%s: unable to create event thread for\n",
+ sc->sc_dev.dv_xname);
+ panic("usb_create_event_thread");
+ }
+}
+
+void
+usb_event_thread(arg)
+ void *arg;
+{
+ struct usb_softc *sc = arg;
+
+ while (!sc->shutdown) {
+ (void)tsleep(&sc->sc_bus->needs_explore,
+ PWAIT, "usbevt", hz*30);
+ DPRINTFN(2,("usb_event_thread: woke up\n"));
+ usb_discover(sc);
+ }
+ sc->event_thread = 0;
+
+ /* In case parent is waiting for us to exit. */
+ wakeup(sc);
+
+ kthread_exit(0);
+}
+
int
usbctlprint(aux, pnp)
void *aux;
@@ -201,7 +246,7 @@ usbctlprint(aux, pnp)
return (UNCONF);
}
-#endif
+#endif /* NetBSD && OpenBSD */
int
usbopen(dev, flag, mode, p)
@@ -227,33 +272,28 @@ usbclose(dev, flag, mode, p)
}
int
-usbioctl(dev, cmd, data, flag, p)
- dev_t dev;
+usbioctl(devt, cmd, data, flag, p)
+ dev_t devt;
u_long cmd;
caddr_t data;
int flag;
struct proc *p;
{
- USB_GET_SC(usb, USBUNIT(dev), sc);
+ USB_GET_SC(usb, USBUNIT(devt), sc);
if (sc == 0 || !sc->sc_running)
return (ENXIO);
-
switch (cmd) {
#ifdef USB_DEBUG
case USB_SETDEBUG:
- usbdebug = *(int *)data;
-#if NUHCI > 0
- uhcidebug = *(int *)data;
-#endif
-#if NOHCI > 0
- ohcidebug = *(int *)data;
-#endif
+ usbdebug = uhcidebug = ohcidebug = *(int *)data;
break;
#endif
+#if defined(__FreeBSD__)
case USB_DISCOVER:
usb_discover(sc);
break;
+#endif
case USB_REQUEST:
{
struct usb_ctl_request *ur = (void *)data;
@@ -291,9 +331,9 @@ usbioctl(dev, cmd, data, flag, p)
}
}
r = usbd_do_request_flags(sc->sc_bus->devices[addr],
- &ur->request, ptr,
+ &ur->request, ptr,
ur->flags, &ur->actlen);
- if (r) {
+ if (r != USBD_NORMAL_COMPLETION) {
error = EIO;
goto ret;
}
@@ -341,23 +381,23 @@ usbpoll(dev, events, p)
int events;
struct proc *p;
{
- int revents = 0;
- int s;
-
+ int revents, s;
USB_GET_SC(usb, USBUNIT(dev), sc);
+ DPRINTFN(15, ("usbpoll: sc=%p events=0x%x\n", sc, events));
s = splusb();
-
+ revents = 0;
if (events & (POLLOUT | POLLWRNORM))
if (sc->sc_bus->needs_explore)
revents |= events & (POLLOUT | POLLWRNORM);
-
- if (revents == 0)
- if (events & (POLLOUT | POLLWRNORM))
+ DPRINTFN(15, ("usbpoll: revents=0x%x\n", revents));
+ if (revents == 0) {
+ if (events & (POLLOUT | POLLWRNORM)) {
+ DPRINTFN(2, ("usbpoll: selrecord\n"));
selrecord(p, &sc->sc_consel);
-
+ }
+ }
splx(s);
-
return (revents);
}
@@ -399,21 +439,22 @@ usb_discover(sc)
/* Explore device tree from the root */
/* We need mutual exclusion while traversing the device tree. */
- s = splusb();
- while (sc->sc_exploring)
- tsleep(&sc->sc_exploring, PRIBIO, "usbdis", 0);
- sc->sc_exploring = 1;
- sc->sc_bus->needs_explore = 0;
- splx(s);
-
- sc->sc_bus->root_hub->hub->explore(sc->sc_bus->root_hub);
-
- s = splusb();
- sc->sc_exploring = 0;
- wakeup(&sc->sc_exploring);
- splx(s);
- /* XXX should we start over if sc_needsexplore is set again? */
- return (0);
+ do {
+ s = splusb();
+ while (sc->sc_exploring)
+ tsleep(&sc->sc_exploring, PRIBIO, "usbdis", 0);
+ sc->sc_exploring = 1;
+ sc->sc_bus->needs_explore = 0;
+ splx(s);
+
+ sc->sc_bus->root_hub->hub->explore(sc->sc_bus->root_hub);
+
+ s = splusb();
+ sc->sc_exploring = 0;
+ wakeup(&sc->sc_exploring);
+ splx(s);
+ } while (sc->sc_bus->needs_explore);
+ return (USBD_NORMAL_COMPLETION);
}
void
@@ -422,9 +463,28 @@ usb_needs_explore(bus)
{
bus->needs_explore = 1;
selwakeup(&bus->usbctl->sc_consel);
+ wakeup(&bus->needs_explore);
}
-#if defined(__FreeBSD__)
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+int
+usb_activate(self, act)
+ device_ptr_t self;
+ enum devact act;
+{
+ panic("usb_activate\n");
+ return (0);
+}
+
+int
+usb_detach(self, flags)
+ device_ptr_t self;
+ int flags;
+{
+ panic("usb_detach\n");
+ return (0);
+}
+#elif defined(__FreeBSD__)
int
usb_detach(device_t self)
{
@@ -432,7 +492,10 @@ usb_detach(device_t self)
return (EINVAL);
}
+#endif
-DRIVER_MODULE(usb, uhci, usb_driver, usb_devclass, 0, 0);
+
+#if defined(__FreeBSD__)
DRIVER_MODULE(usb, ohci, usb_driver, usb_devclass, 0, 0);
+DRIVER_MODULE(usb, uhci, usb_driver, usb_devclass, 0, 0);
#endif
diff --git a/sys/dev/usb/usb.h b/sys/dev/usb/usb.h
index ac0883f..4152b72 100644
--- a/sys/dev/usb/usb.h
+++ b/sys/dev/usb/usb.h
@@ -1,4 +1,4 @@
-/* $NetBSD: usb.h,v 1.17 1999/01/03 01:09:18 augustss Exp $ */
+/* $NetBSD: usb.h,v 1.33 1999/09/11 08:19:27 augustss Exp $ */
/* $FreeBSD$ */
/*
@@ -43,21 +43,21 @@
#define _USB_H_
#include <sys/types.h>
-#if defined(__NetBSD__)
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/ioctl.h>
-#endif
-#if defined(__NetBSD__)
#if defined(_KERNEL)
#include <dev/usb/usb_port.h>
#endif /* _KERNEL */
#elif defined(__FreeBSD__)
+#if defined(KERNEL)
#include <sys/malloc.h>
-#if defined(KERNEL)
MALLOC_DECLARE(M_USB);
MALLOC_DECLARE(M_USBDEV);
+MALLOC_DECLARE(M_USBHC);
#include <dev/usb/usb_port.h>
#endif /* KERNEL */
@@ -125,15 +125,19 @@ typedef struct {
#define UT_READ_CLASS_DEVICE (UT_READ | UT_CLASS | UT_DEVICE)
#define UT_READ_CLASS_INTERFACE (UT_READ | UT_CLASS | UT_INTERFACE)
#define UT_READ_CLASS_OTHER (UT_READ | UT_CLASS | UT_OTHER)
+#define UT_READ_CLASS_ENDPOINT (UT_READ | UT_CLASS | UT_ENDPOINT)
#define UT_WRITE_CLASS_DEVICE (UT_WRITE | UT_CLASS | UT_DEVICE)
#define UT_WRITE_CLASS_INTERFACE (UT_WRITE | UT_CLASS | UT_INTERFACE)
#define UT_WRITE_CLASS_OTHER (UT_WRITE | UT_CLASS | UT_OTHER)
+#define UT_WRITE_CLASS_ENDPOINT (UT_WRITE | UT_CLASS | UT_ENDPOINT)
#define UT_READ_VENDOR_DEVICE (UT_READ | UT_VENDOR | UT_DEVICE)
#define UT_READ_VENDOR_INTERFACE (UT_READ | UT_VENDOR | UT_INTERFACE)
#define UT_READ_VENDOR_OTHER (UT_READ | UT_VENDOR | UT_OTHER)
+#define UT_READ_VENDOR_ENDPOINT (UT_READ | UT_VENDOR | UT_ENDPOINT)
#define UT_WRITE_VENDOR_DEVICE (UT_WRITE | UT_VENDOR | UT_DEVICE)
#define UT_WRITE_VENDOR_INTERFACE (UT_WRITE | UT_VENDOR | UT_INTERFACE)
#define UT_WRITE_VENDOR_OTHER (UT_WRITE | UT_VENDOR | UT_OTHER)
+#define UT_WRITE_VENDOR_ENDPOINT (UT_WRITE | UT_VENDOR | UT_ENDPOINT)
/* Requests */
#define UR_GET_STATUS 0x00
@@ -141,12 +145,12 @@ typedef struct {
#define UR_SET_FEATURE 0x03
#define UR_SET_ADDRESS 0x05
#define UR_GET_DESCRIPTOR 0x06
-#define UDESC_DEVICE 0x01 /* descriptor types */
+#define UDESC_DEVICE 0x01
#define UDESC_CONFIG 0x02
#define UDESC_STRING 0x03
#define UDESC_INTERFACE 0x04
#define UDESC_ENDPOINT 0x05
-#define UDESC_CS_DEVICE 0x21 /* class specific */
+#define UDESC_CS_DEVICE 0x21 /* class specific */
#define UDESC_CS_CONFIG 0x22
#define UDESC_CS_STRING 0x23
#define UDESC_CS_INTERFACE 0x24
@@ -223,19 +227,19 @@ typedef struct {
uByte bLength;
uByte bDescriptorType;
uByte bEndpointAddress;
-#define UE_DIR 0x80 /* mask */
-#define UE_IN 0x80
-#define UE_OUT 0x00
+#define UE_GET_DIR(a) ((a) & 0x80)
+#define UE_SET_DIR(a,d) ((a) | (((d)&1) << 7))
+#define UE_DIR_IN 0x80
+#define UE_DIR_OUT 0x00
#define UE_ADDR 0x0f
#define UE_GET_ADDR(a) ((a) & UE_ADDR)
-#define UE_GET_IN(a) (((a) >> 7) & 1) /* XXX should be removed */
-#define UE_GET_DIR(a) ((a) & UE_DIR)
uByte bmAttributes;
#define UE_XFERTYPE 0x03
#define UE_CONTROL 0x00
#define UE_ISOCHRONOUS 0x01
#define UE_BULK 0x02
#define UE_INTERRUPT 0x03
+#define UE_GET_XFERTYPE(a) ((a) & UE_XFERTYPE)
#define UE_ISO_TYPE 0x0c
#define UE_ISO_ASYNC 0x04
#define UE_ISO_ADAPT 0x08
@@ -329,59 +333,55 @@ typedef struct {
#define UPS_C_PORT_RESET 0x0010
} usb_port_status_t;
-#define UCLASS_UNSPEC 0 /* Unspecified */
-#define UCLASS_AUDIO 1 /* Audio */
+#define UCLASS_UNSPEC 0
+#define UCLASS_AUDIO 1
#define USUBCLASS_AUDIOCONTROL 1
#define USUBCLASS_AUDIOSTREAM 2
-#define UCLASS_CDC 2 /* Communication */
+#define USUBCLASS_MIDISTREAM 3
+#define UCLASS_CDC 2 /* communication */
#define USUBCLASS_DIRECT_LINE_CONTROL_MODEL 1
#define USUBCLASS_ABSTRACT_CONTROL_MODEL 2
#define USUBCLASS_TELEPHONE_CONTROL_MODEL 3
-#define USUBCLASS_MULTICHANNEL_CONTROL_MODEL /*TBD*/
-#define USUBCLASS_CAPI_CONTROL_MODEL /*TBD*/
-#define USUBCLASS_ETHERNET_CONTROL_MODEL /*TBD*/
-#define USUBCLASS_ATM_CONTROL_MODEL /*TBD*/
-#define UPROTO_CDC_NONE 0 /* No class spec. protocol required */
-#define UPROTO_CDC_AT 1 /* V25.ter (AT commands) */
-#define UCLASS_HID 3 /* Human Interface Device */
+#define USUBCLASS_MULTICHANNEL_CONTROL_MODEL 4
+#define USUBCLASS_CAPI_CONTROLMODEL 5
+#define USUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL 6
+#define USUBCLASS_ATM_NETWORKING_CONTROL_MODEL 7
+#define UPROTO_CDC_AT 1
+#define UCLASS_HID 3
#define USUBCLASS_BOOT 1
-#define UCLASS_PRINTER 7 /* Printer/Parallel Port */
+#define UCLASS_PRINTER 7
#define USUBCLASS_PRINTER 1
-#define UPROTO_PRINTER_UNI 1 /* Unidirectional */
-#define UPROTO_PRINTER_BI 2 /* Bidirectional */
-#define UCLASS_MASS 8 /* Mass Storage */
-#define USUBCLASS_RBC 1 /* Reduced Block comm. (e.g. Flash ) */
-#define USUBCLASS_SFF8020I 2 /* (e.g. CD ROM) */
-#define USUBCLASS_QIC157 3 /* (e.g. tape drives) */
-#define USUBCLASS_UFI 4 /* (e.g. floppy drives) */
-#define USUBCLASS_SFF8070I 5 /* (e.g. floppy drives) */
-#define USUBCLASS_SCSI 6 /* SCSI transparent comman set */
-#define UPROTO_MASS_CBI_I 0 /* CBI protocol with comm. compl. int */
-#define UPROTO_MASS_CBI 1 /* CBI protocol */
-/*
- * XXX Pat LaVarre (Iomega): there are Bulk-Only devices using 0x02,
- * but recent versions of the Mass Storage spec. require it to be 0x50.
- */
-#define UPROTO_MASS_BULK 80 /* 'P' for prototype, used by ZIP 100 */
-#define UPROTO_MASS_BULK2 2 /* Bulk only transport */
-#define UCLASS_HUB 9 /* Hub */
+#define UPROTO_PRINTER_UNI 1
+#define UPROTO_PRINTER_BI 2
+#define UCLASS_MASS 8
+#define USUBCLASS_RBC 1
+#define USUBCLASS_SFF8020I 2
+#define USUBCLASS_QIC157 3
+#define USUBCLASS_UFI 4
+#define USUBCLASS_SFF8070I 5
+#define USUBCLASS_SCSI 6
+#define UPROTO_MASS_CBI_I 0
+#define UPROTO_MASS_CBI 1
+#define UPROTO_MASS_BULK 2
+#define UPROTO_MASS_BULK_P 80 /* 'P' for the Iomega Zip drive */
+#define UCLASS_HUB 9
#define USUBCLASS_HUB 0
-#define UCLASS_DATA 10 /* Data pipe for CDC */
+#define UCLASS_DATA 10
#define USUBCLASS_DATA 0
-#define UPROTO_DATA_NONE 0
-#define UPROTO_DATA_ISDNBRI 0x30 /* Physical iface ISDN BRI */
-#define UPROTO_DATA_HDLC 0x31 /* HDLC */
-#define UPROTO_DATA_TRANSPARENT 0x32 /* Transparent */
-#define UPROTO_DATA_Q921M 0x50 /* Management for Q921 */
-#define UPROTO_DATA_Q921 0x51 /* Data for Q921 */
-#define UPROTO_DATA_Q921TM 0x52 /* TEI multiplexer for Q921 */
-#define UPROTO_DATA_V42BIS 0x90 /* Data compression */
-#define UPROTO_DATA_Q931 0x91 /* Euro-ISDN */
-#define UPROTO_DATA_V120 0x92 /* V.24 rate adaption */
-#define UPROTO_DATA_CAPI 0x93 /* CAPI 2.0 commands */
-#define UPROTO_DATA_HOST_BASED 0xfd /* Host based driver */
-#define UPROTO_DATA_PUF 0xfe /* see Prot. Unit Func. Desc. */
-#define UPROTO_DATA_VENDOR 0xff /* Vendor specific */
+#define UPROTO_DATA_ISDNBRI 0x30 /* Physical iface */
+#define UPROTO_DATA_HDLC 0x31 /* HDLC */
+#define UPROTO_DATA_TRANSPARENT 0x32 /* Transparent */
+#define UPROTO_DATA_Q921M 0x50 /* Management for Q921 */
+#define UPROTO_DATA_Q921 0x51 /* Data for Q921 */
+#define UPROTO_DATA_Q921TM 0x52 /* TEI multiplexer for Q921 */
+#define UPROTO_DATA_V42BIS 0x90 /* Data compression */
+#define UPROTO_DATA_Q931 0x91 /* Euro-ISDN */
+#define UPROTO_DATA_V120 0x92 /* V.24 rate adaption */
+#define UPROTO_DATA_CAPI 0x93 /* CAPI 2.0 commands */
+#define UPROTO_DATA_HOST_BASED 0xfd /* Host based driver */
+#define UPROTO_DATA_PUF 0xfe /* see Prot. Unit Func. Desc. */
+#define UPROTO_DATA_VENDOR 0xff /* Vendor specific */
+
#define USB_HUB_MAX_DEPTH 5
@@ -398,20 +398,24 @@ typedef struct {
#define USB_PORT_RESET_SETTLE 10 /* ms */
#define USB_PORT_POWERUP_DELAY 100 /* ms */
#define USB_SET_ADDRESS_SETTLE 2 /* ms */
+#define USB_RESUME_TIME (20*5) /* ms */
+#define USB_RESUME_WAIT 10 /* ms */
+#define USB_RESUME_RECOVERY 10 /* ms */
#else
/* Allow for marginal (i.e. non-conforming) devices. */
#define USB_PORT_RESET_DELAY 50 /* ms */
#define USB_PORT_RESET_RECOVERY 50 /* ms */
#define USB_PORT_POWERUP_DELAY 200 /* ms */
#define USB_SET_ADDRESS_SETTLE 10 /* ms */
+#define USB_RESUME_DELAY (50*5) /* ms */
+#define USB_RESUME_WAIT 50 /* ms */
+#define USB_RESUME_RECOVERY 50 /* ms */
#endif
#define USB_MIN_POWER 100 /* mA */
#define USB_MAX_POWER 500 /* mA */
-
#define USB_BUS_RESET_DELAY 100 /* ms XXX?*/
-#define USB_RESUME_DELAY 10 /* ms XXX?*/
/*** ioctl() related stuff ***/
@@ -420,8 +424,7 @@ struct usb_ctl_request {
usb_device_request_t request;
void *data;
int flags;
-/* XXX must match flags in usbdi.h */
-#define USBD_SHORT_XFER_OK 0x04
+#define USBD_SHORT_XFER_OK 0x04 /* allow short reads */
int actlen; /* actual length transferred */
};
@@ -475,7 +478,7 @@ struct usb_device_info {
u_int8_t addr; /* device address */
char product[USB_MAX_STRING_LEN];
char vendor[USB_MAX_STRING_LEN];
- char revision[8];
+ char release[8];
u_int16_t productNo;
u_int16_t vendorNo;
u_int8_t class;
@@ -526,5 +529,10 @@ struct usb_device_stats {
#define USB_DO_REQUEST _IOWR('U', 111, struct usb_ctl_request)
#define USB_GET_DEVICEINFO _IOR ('U', 112, struct usb_device_info)
#define USB_SET_SHORT_XFER _IOW ('U', 113, int)
+#define USB_SET_TIMEOUT _IOW ('U', 114, int)
+
+/* Modem device */
+#define USB_GET_CM_OVER_DATA _IOR ('U', 130, int)
+#define USB_SET_CM_OVER_DATA _IOW ('U', 131, int)
#endif /* _USB_H_ */
diff --git a/sys/dev/usb/usb_mem.h b/sys/dev/usb/usb_mem.h
index 60abd5f..e254fb4 100644
--- a/sys/dev/usb/usb_mem.h
+++ b/sys/dev/usb/usb_mem.h
@@ -1,5 +1,5 @@
-/* $NetBSD: usb_mem.h,v 1.4 1999/01/09 12:16:54 augustss Exp $ */
-/* $FreeBSD$ */
+/* $NetBSD: usb_mem.h,v 1.7 1999/09/09 12:26:47 augustss Exp $ */
+/* $FreeBSD$ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -38,8 +38,8 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-#if defined(__NetBSD__)
-typedef struct usb_block_dma {
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+typedef struct usb_dma_block {
bus_dma_tag_t tag;
bus_dmamap_t map;
caddr_t kaddr;
@@ -48,14 +48,9 @@ typedef struct usb_block_dma {
size_t size;
size_t align;
int fullblock;
- LIST_ENTRY(usb_block_dma) next;
+ LIST_ENTRY(usb_dma_block) next;
} usb_dma_block_t;
-typedef struct {
- usb_dma_block_t *block;
- u_int offs;
-} usb_dma_t;
-
#define DMAADDR(dma) ((dma)->block->segs[0].ds_addr + (dma)->offs)
#define KERNADDR(dma) ((void *)((dma)->block->kaddr + (dma)->offs))
@@ -81,8 +76,6 @@ void usb_freemem __P((bus_dma_tag_t, usb_dma_t *));
#include <machine/pmap.h> /* for vtophys */
-typedef void * usb_dma_t;
-
#define usb_allocmem(t,s,a,p) (*(p) = malloc(s, M_USB, M_NOWAIT), (*(p) == NULL? USBD_NOMEM: USBD_NORMAL_COMPLETION))
#define usb_freemem(t,p) (free(*(p), M_USB))
diff --git a/sys/dev/usb/usb_port.h b/sys/dev/usb/usb_port.h
index 5ac8f9a..7c8d8c4 100644
--- a/sys/dev/usb/usb_port.h
+++ b/sys/dev/usb/usb_port.h
@@ -1,4 +1,4 @@
-/* $NetBSD: usb_port.h,v 1.5 1999/01/08 11:58:25 augustss Exp $ */
+/* $NetBSD: usb_port.h,v 1.11 1999/09/11 08:19:27 augustss Exp $ */
/* $FreeBSD$ */
/*
@@ -39,34 +39,49 @@
*/
-/*
+/*
* Macro's to cope with the differences between operating systems.
*/
+#if defined(__NetBSD__)
/*
* NetBSD
*/
-#if defined(__NetBSD__)
#include "opt_usbverbose.h"
+typedef struct device *device_ptr_t;
+#define USBBASEDEVICE struct device
+#define USBDEV(bdev) (&(bdev))
#define USBDEVNAME(bdev) ((bdev).dv_xname)
+#define USBDEVPTRNAME(bdevptr) ((bdevptr)->dv_xname)
-typedef struct device bdevice; /* base device */
+#define DECLARE_USB_DMA_T \
+ struct usb_dma_block; \
+ typedef struct { \
+ struct usb_dma_block *block; \
+ u_int offs; \
+ } usb_dma_t
#define usb_timeout(f, d, t, h) timeout((f), (d), (t))
#define usb_untimeout(f, d, h) untimeout((f), (d))
-#define USB_DECLARE_DRIVER_INIT(dname, _2) \
+#define logprintf printf
+
+#define USB_DECLARE_DRIVER_NAME_INIT(_1, dname, _2) \
int __CONCAT(dname,_match) __P((struct device *, struct cfdata *, void *)); \
void __CONCAT(dname,_attach) __P((struct device *, struct device *, void *)); \
+int __CONCAT(dname,_detach) __P((struct device *, int)); \
+int __CONCAT(dname,_activate) __P((struct device *, enum devact)); \
\
extern struct cfdriver __CONCAT(dname,_cd); \
\
struct cfattach __CONCAT(dname,_ca) = { \
sizeof(struct __CONCAT(dname,_softc)), \
__CONCAT(dname,_match), \
- __CONCAT(dname,_attach) \
+ __CONCAT(dname,_attach), \
+ __CONCAT(dname,_detach), \
+ __CONCAT(dname,_activate), \
}
#define USB_MATCH(dname) \
@@ -97,6 +112,16 @@ __CONCAT(dname,_attach)(parent, self, aux) \
#define USB_ATTACH_SETUP printf("\n")
+#define USB_DETACH(dname) \
+int \
+__CONCAT(dname,_detach)(self, flags) \
+ struct device *self; \
+ int flags;
+
+#define USB_DETACH_START(dname, sc) \
+ struct __CONCAT(dname,_softc) *sc = \
+ (struct __CONCAT(dname,_softc) *)self
+
#define USB_GET_SC_OPEN(dname, unit, sc) \
struct __CONCAT(dname,_softc) *sc; \
if (unit >= __CONCAT(dname,_cd).cd_ndevs) \
@@ -109,11 +134,107 @@ __CONCAT(dname,_attach)(parent, self, aux) \
struct __CONCAT(dname,_softc) *sc = __CONCAT(dname,_cd).cd_devs[unit]
#define USB_DO_ATTACH(dev, bdev, parent, args, print, sub) \
- ((dev)->softc = config_found_sm(parent, args, print, sub))
+ (config_found_sm(parent, args, print, sub))
+
+#elif defined(__OpenBSD__)
+/*
+ * OpenBSD
+ */
+#define memcpy(d, s, l) bcopy((s),(d),(l))
+#define memset(d, v, l) bzero((d),(l))
+#define bswap32(x) swap32(x)
+#define kthread_create1 kthread_create
+#define kthread_create kthread_create_deferred
+
+#define usbpoll usbselect
+#define uhidpoll uhidselect
+#define ugenpoll ugenselect
+
+typedef struct device device_ptr_t;
+#define USBBASEDEVICE struct device
+#define USBDEV(bdev) (&(bdev))
+#define USBDEVNAME(bdev) ((bdev).dv_xname)
+#define USBDEVPTRNAME(bdevptr) ((bdevptr)->dv_xname)
+
+#define DECLARE_USB_DMA_T \
+ struct usb_dma_block; \
+ typedef struct { \
+ struct usb_dma_block *block; \
+ u_int offs; \
+ } usb_dma_t
+
+#define usb_timeout(f, d, t, h) timeout((f), (d), (t))
+#define usb_untimeout(f, d, h) untimeout((f), (d))
+
+#define USB_DECLARE_DRIVER_NAME_INIT(_1, dname, _2) \
+int __CONCAT(dname,_match) __P((struct device *, void *, void *)); \
+void __CONCAT(dname,_attach) __P((struct device *, struct device *, void *)); \
+int __CONCAT(dname,_detach) __P((struct device *, int)); \
+int __CONCAT(dname,_activate) __P((struct device *, enum devact)); \
+\
+struct cfdriver __CONCAT(dname,_cd) = { \
+ NULL, #dname, DV_DULL \
+}; \
+\
+struct cfattach __CONCAT(dname,_ca) = { \
+ sizeof(struct __CONCAT(dname,_softc)), \
+ __CONCAT(dname,_match), \
+ __CONCAT(dname,_attach), \
+ __CONCAT(dname,_detach), \
+ __CONCAT(dname,_activate), \
+}
+
+#define USB_MATCH(dname) \
+int \
+__CONCAT(dname,_match)(parent, match, aux) \
+ struct device *parent; \
+ void *match; \
+ void *aux;
+
+#define USB_MATCH_START(dname, uaa) \
+ struct usb_attach_arg *uaa = aux
+
+#define USB_ATTACH(dname) \
+void \
+__CONCAT(dname,_attach)(parent, self, aux) \
+ struct device *parent; \
+ struct device *self; \
+ void *aux;
-#define logprintf printf
+#define USB_ATTACH_START(dname, sc, uaa) \
+ struct __CONCAT(dname,_softc) *sc = \
+ (struct __CONCAT(dname,_softc) *)self; \
+ struct usb_attach_arg *uaa = aux
+
+/* Returns from attach */
+#define USB_ATTACH_ERROR_RETURN return
+#define USB_ATTACH_SUCCESS_RETURN return
+
+#define USB_ATTACH_SETUP printf("\n")
+
+#define USB_DETACH(dname) \
+int \
+__CONCAT(dname,_detach)(self, flags) \
+ struct device *self; \
+ int flags;
+
+#define USB_DETACH_START(dname, sc) \
+ struct __CONCAT(dname,_softc) *sc = \
+ (struct __CONCAT(dname,_softc) *)self
+
+#define USB_GET_SC_OPEN(dname, unit, sc) \
+ struct __CONCAT(dname,_softc) *sc; \
+ if (unit >= __CONCAT(dname,_cd).cd_ndevs) \
+ return (ENXIO); \
+ sc = __CONCAT(dname,_cd).cd_devs[unit]; \
+ if (!sc) \
+ return (ENXIO)
+#define USB_GET_SC(dname, unit, sc) \
+ struct __CONCAT(dname,_softc) *sc = __CONCAT(dname,_cd).cd_devs[unit]
+#define USB_DO_ATTACH(dev, bdev, parent, args, print, sub) \
+ (config_found_sm(parent, args, print, sub))
#elif defined(__FreeBSD__)
/*
@@ -121,28 +242,30 @@ __CONCAT(dname,_attach)(parent, self, aux) \
*/
#include "opt_usb.h"
-/*
- * The following is not a type def to avoid error messages
- * because of includes in the wrong order.
- */
-#define bdevice device_t
-#define USBDEVNAME(bdev) (bdev? device_get_nameunit(bdev):"-")
+
+#define USBVERBOSE
+
+#define device_ptr_t device_t
+#define USBBASEDEVICE device_t
+#define USBDEV(bdev) (bdev)
+#define USBDEVNAME(bdev) device_get_nameunit(bdev)
+#define USBDEVPTRNAME(bdev) device_get_nameunit(bdev)
+
+#define DECLARE_USB_DMA_T typedef void * usb_dma_t
/* XXX Change this when FreeBSD has memset
*/
-#define memset(d, v, s) \
- do{ \
- if ((v) == 0) \
- bzero((d), (s));\
- else \
- panic("Non zero filler for memset, cannot handle!"); \
- } while (0)
+#define memcpy(d, s, l) bcopy((s),(d),(l))
+#define memset(d, v, l) bzero((d),(l))
+#define bswap32(x) swap32(x) /* XXX not available in FreeBSD */
+#define kthread_create1
+#define kthread_create
#define usb_timeout(f, d, t, h) ((h) = timeout((f), (d), (t)))
#define usb_untimeout(f, d, h) untimeout((f), (d), (h))
-#define USB_DECLARE_DRIVER_INIT(dname, init...) \
+#define USB_DECLARE_DRIVER_NAME_INIT(name, dname, init...) \
static device_probe_t __CONCAT(dname,_match); \
static device_attach_t __CONCAT(dname,_attach); \
static device_detach_t __CONCAT(dname,_detach); \
@@ -158,7 +281,7 @@ static device_method_t __CONCAT(dname,_methods)[] = { \
}; \
\
static driver_t __CONCAT(dname,_driver) = { \
- #dname, \
+ name, \
__CONCAT(dname,_methods), \
sizeof(struct __CONCAT(dname,_softc)) \
}
@@ -186,6 +309,13 @@ __CONCAT(dname,_attach)(device_t self)
sc->sc_dev = self; \
device_set_desc_copy(self, devinfo)
+#define USB_DETACH(dname) \
+static int \
+__CONCAT(dname,_detach)(device_t self)
+
+#define USB_DETACH_START(dname, sc) \
+ struct __CONCAT(dname,_softc) *sc = device_get_softc(self)
+
#define USB_GET_SC_OPEN(dname, unit, sc) \
struct __CONCAT(dname,_softc) *sc = \
devclass_get_softc(__CONCAT(dname,_devclass), unit); \
@@ -196,26 +326,43 @@ __CONCAT(dname,_attach)(device_t self)
struct __CONCAT(dname,_softc) *sc = \
devclass_get_softc(__CONCAT(dname,_devclass), unit)
-#define USB_DO_ATTACH(dev, bdev, parent, args, print, sub) \
- (device_probe_and_attach((bdev)) == 0 ? \
- ((dev)->softc = device_get_softc(bdev)) : 0)
+#define USB_DO_ATTACH(dev, bdev, parent, args, print, sub) \
+ (device_probe_and_attach((bdev)) == 0 ? (bdev) : 0)
/* conversion from one type of queue to the other */
-#define SIMPLEQ_REMOVE_HEAD STAILQ_REMOVE_HEAD
+/* XXX In FreeBSD SIMPLEQ_REMOVE_HEAD only removes the head element.
+ */
+#define SIMPLEQ_REMOVE_HEAD(h, e, f) do { \
+ if ( (e) != SIMPLEQ_FIRST((h)) ) \
+ panic("Removing other than first element"); \
+ STAILQ_REMOVE_HEAD(h, f); \
+} while (0)
#define SIMPLEQ_INSERT_HEAD STAILQ_INSERT_HEAD
#define SIMPLEQ_INSERT_TAIL STAILQ_INSERT_TAIL
#define SIMPLEQ_NEXT STAILQ_NEXT
#define SIMPLEQ_FIRST STAILQ_FIRST
#define SIMPLEQ_HEAD STAILQ_HEAD
#define SIMPLEQ_INIT STAILQ_INIT
+#define SIMPLEQ_HEAD_INITIALIZER STAILQ_HEAD_INITIALIZER
#define SIMPLEQ_ENTRY STAILQ_ENTRY
#include <sys/syslog.h>
-#define logprintf(args...) log(LOG_DEBUG, args);
+/*
+#define logprintf(args...) log(LOG_DEBUG, args)
+*/
+#define logprintf printf
#endif /* __FreeBSD__ */
+#define NONE {0,0}
-
+#define USB_DECLARE_DRIVER_NAME(name, dname) \
+ USB_DECLARE_DRIVER_NAME_INIT(#name, dname, NONE )
+#define USB_DECLARE_DRIVER_INIT(dname, init...) \
+ USB_DECLARE_DRIVER_NAME_INIT(#dname, dname, init)
#define USB_DECLARE_DRIVER(dname) \
- USB_DECLARE_DRIVER_INIT(dname, {0,0} )
+ USB_DECLARE_DRIVER_NAME_INIT(#dname, dname, NONE )
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+#elif defined(__FreeBSD__)
+#endif
diff --git a/sys/dev/usb/usb_quirks.c b/sys/dev/usb/usb_quirks.c
index 2b253d9..567f31d 100644
--- a/sys/dev/usb/usb_quirks.c
+++ b/sys/dev/usb/usb_quirks.c
@@ -1,4 +1,4 @@
-/* $NetBSD: usb_quirks.c,v 1.8 1999/01/08 11:58:25 augustss Exp $ */
+/* $NetBSD: usb_quirks.c,v 1.12 1999/09/05 21:22:39 augustss Exp $ */
/* $FreeBSD$ */
/*
@@ -43,7 +43,7 @@
#if defined(__FreeBSD__)
#include <sys/bus.h>
#endif
-
+
#include <dev/usb/usb.h>
#include <dev/usb/usbdevs.h>
@@ -62,11 +62,11 @@ struct usbd_quirk_entry {
{ USB_VENDOR_GENIUS, USB_PRODUCT_GENIUS_NICHE, 0x100, { UQ_NO_SET_PROTO}},
{ USB_VENDOR_INSIDEOUT,USB_PRODUCT_INSIDEOUT_EDGEPORT4,
0x094, { UQ_SWAP_UNICODE}},
- { USB_VENDOR_TI, USB_PRODUCT_TI_UTUSB41, 0x100, { UQ_HUB_POWER }},
{ USB_VENDOR_BTC, USB_PRODUCT_BTC_BTC7932, 0x100, { UQ_NO_STRINGS }},
{ USB_VENDOR_ADS, USB_PRODUCT_ADS_ENET, 0x002, { UQ_NO_STRINGS }},
{ USB_VENDOR_PERACOM, USB_PRODUCT_PERACOM_SERIAL1, 0x101, { UQ_NO_STRINGS }},
{ USB_VENDOR_JAZZ, USB_PRODUCT_JAZZ_J6502, 0x0a2, { UQ_BAD_ADC }},
+ { USB_VENDOR_LOGITECH, USB_PRODUCT_LOGITECH_USBPS2,0x110, { UQ_MS_REVZ }},
{ 0, 0, 0, { 0 } }
};
@@ -86,9 +86,9 @@ usbd_find_quirk(d)
}
#ifdef USB_DEBUG
if (usbdebug && t->quirks.uq_flags)
- printf("usbd_find_quirk 0x%04x/0x%04x/%x: %d\n",
- UGETW(d->idVendor), UGETW(d->idProduct),
- UGETW(d->bcdDevice), t->quirks.uq_flags);
+ logprintf("usbd_find_quirk 0x%04x/0x%04x/%x: %d\n",
+ UGETW(d->idVendor), UGETW(d->idProduct),
+ UGETW(d->bcdDevice), t->quirks.uq_flags);
#endif
return (&t->quirks);
}
diff --git a/sys/dev/usb/usb_quirks.h b/sys/dev/usb/usb_quirks.h
index 5518a5b..6fea94e 100644
--- a/sys/dev/usb/usb_quirks.h
+++ b/sys/dev/usb/usb_quirks.h
@@ -1,5 +1,5 @@
-/* $NetBSD: usb_quirks.h,v 1.5 1998/12/29 15:23:59 augustss Exp $ */
-/* $FreeBSD$ */
+/* $NetBSD: usb_quirks.h,v 1.7 1999/06/26 00:09:15 augustss Exp $ */
+/* $FreeBSD$ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -42,8 +42,7 @@ struct usbd_quirks {
u_int32_t uq_flags; /* Device problems: */
#define UQ_NO_SET_PROTO 0x01 /* cannot handle SET PROTOCOL. */
#define UQ_SWAP_UNICODE 0x02 /* has some Unicode strings swapped. */
-#define UQ_HUB_POWER 0x04 /* does not respond correctly to get
- device status; use get hub status. */
+#define UQ_MS_REVZ 0x04 /* mouse has Z-axis reversed */
#define UQ_NO_STRINGS 0x08 /* string descriptors are broken. */
#define UQ_BAD_ADC 0x10 /* bad audio spec version number. */
};
diff --git a/sys/dev/usb/usb_subr.c b/sys/dev/usb/usb_subr.c
index 5279c8b..9730939 100644
--- a/sys/dev/usb/usb_subr.c
+++ b/sys/dev/usb/usb_subr.c
@@ -1,4 +1,4 @@
-/* $NetBSD: usb_subr.c,v 1.29 1999/03/18 12:08:43 augustss Exp $ */
+/* $NetBSD: usb_subr.c,v 1.45 1999/09/09 12:26:47 augustss Exp $ */
/* $FreeBSD$ */
/*
@@ -42,7 +42,7 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
-#if defined(__NetBSD__)
+#if defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/device.h>
#elif defined(__FreeBSD__)
#include <sys/module.h>
@@ -73,6 +73,22 @@ extern int usbdebug;
#define DPRINTFN(n,x)
#endif
+static usbd_status usbd_set_config __P((usbd_device_handle, int));
+char *usbd_get_string __P((usbd_device_handle, int, char *));
+int usbd_getnewaddr __P((usbd_bus_handle bus));
+int usbd_print __P((void *aux, const char *pnp));
+#if defined(__NetBSD__)
+int usbd_submatch __P((device_ptr_t, struct cfdata *cf, void *));
+#elif defined(__OpenBSD__)
+int usbd_submatch __P((device_ptr_t, void *, void *));
+#endif
+void usbd_free_iface_data __P((usbd_device_handle dev, int ifcno));
+void usbd_kill_pipe __P((usbd_pipe_handle));
+usbd_status usbd_probe_and_attach
+ __P((device_ptr_t parent, usbd_device_handle dev, int port, int addr));
+
+
+#ifdef USBVERBOSE
typedef u_int16_t usb_vendor_id_t;
typedef u_int16_t usb_product_id_t;
@@ -80,28 +96,52 @@ typedef u_int16_t usb_product_id_t;
* Descriptions of of known vendors and devices ("products").
*/
struct usb_knowndev {
- usb_vendor_id_t vendor;
- usb_product_id_t product;
- int flags;
- char *vendorname, *productname;
+ usb_vendor_id_t vendor;
+ usb_product_id_t product;
+ int flags;
+ char *vendorname, *productname;
};
-#define USB_KNOWNDEV_NOPROD 0x01 /* match on vendor only */
+#define USB_KNOWNDEV_NOPROD 0x01 /* match on vendor only */
#include <dev/usb/usbdevs_data.h>
+#endif
+const char *usbd_error_strs[] = {
+ "NORMAL_COMPLETION",
+ "IN_PROGRESS",
+ "PENDING_REQUESTS",
+ "NOT_STARTED",
+ "INVAL",
+ "NOMEM",
+ "CANCELLED",
+ "BAD_ADDRESS",
+ "IN_USE",
+ "NO_ADDR",
+ "SET_ADDR_FAILED",
+ "NO_POWER",
+ "TOO_DEEP",
+ "IOERROR",
+ "NOT_CONFIGURED",
+ "TIMEOUT",
+ "SHORT_XFER",
+ "STALLED",
+ "INTERRUPTED",
+ "XXX",
+};
-static usbd_status usbd_set_config __P((usbd_device_handle, int));
-char *usbd_get_string __P((usbd_device_handle, int, char *));
-int usbd_getnewaddr __P((usbd_bus_handle bus));
-#if defined(__NetBSD__)
-int usbd_print __P((void *aux, const char *pnp));
-int usbd_submatch __P((bdevice *, struct cfdata *cf, void *));
-#endif
-void usbd_free_iface_data __P((usbd_device_handle dev, int ifcno));
-void usbd_kill_pipe __P((usbd_pipe_handle));
-usbd_status usbd_probe_and_attach
- __P((bdevice *parent, usbd_device_handle dev, int port, int addr));
+const char *
+usbd_errstr(err)
+ usbd_status err;
+{
+ static char buffer[5];
+ if (err < USBD_ERROR_MAX) {
+ return usbd_error_strs[err];
+ } else {
+ snprintf(buffer, sizeof buffer, "%d", err);
+ return buffer;
+ }
+}
usbd_status
usbd_get_string_desc(dev, sindex, langid, sdesc)
@@ -111,16 +151,16 @@ usbd_get_string_desc(dev, sindex, langid, sdesc)
usb_string_descriptor_t *sdesc;
{
usb_device_request_t req;
- usbd_status err;
+ usbd_status r;
req.bmRequestType = UT_READ_DEVICE;
req.bRequest = UR_GET_DESCRIPTOR;
USETW2(req.wValue, UDESC_STRING, sindex);
USETW(req.wIndex, langid);
USETW(req.wLength, 1); /* only size byte first */
- err = usbd_do_request(dev, &req, sdesc);
- if (err)
- return (err);
+ r = usbd_do_request(dev, &req, sdesc);
+ if (r != USBD_NORMAL_COMPLETION)
+ return (r);
USETW(req.wLength, sdesc->bLength); /* the whole string */
return (usbd_do_request(dev, &req, sdesc));
}
@@ -133,10 +173,10 @@ usbd_get_string(dev, si, buf)
{
int swap = dev->quirks->uq_flags & UQ_SWAP_UNICODE;
usb_string_descriptor_t us;
- char *string;
+ char *s;
int i, n;
u_int16_t c;
- usbd_status err;
+ usbd_status r;
if (si == 0)
return (0);
@@ -144,30 +184,30 @@ usbd_get_string(dev, si, buf)
return (0);
if (dev->langid == USBD_NOLANG) {
/* Set up default language */
- err = usbd_get_string_desc(dev, USB_LANGUAGE_TABLE, 0, &us);
- if (err) {
+ r = usbd_get_string_desc(dev, USB_LANGUAGE_TABLE, 0, &us);
+ if (r != USBD_NORMAL_COMPLETION || us.bLength < 4) {
dev->langid = 0; /* Well, just pick English then */
} else {
/* Pick the first language as the default. */
dev->langid = UGETW(us.bString[0]);
}
}
- err = usbd_get_string_desc(dev, si, dev->langid, &us);
- if (err)
+ r = usbd_get_string_desc(dev, si, dev->langid, &us);
+ if (r != USBD_NORMAL_COMPLETION)
return (0);
- string = buf;
+ s = buf;
n = us.bLength / 2 - 1;
for (i = 0; i < n; i++) {
c = UGETW(us.bString[i]);
/* Convert from Unicode, handle buggy strings. */
if ((c & 0xff00) == 0)
- *string++ = c;
+ *s++ = c;
else if ((c & 0x00ff) == 0 && swap)
- *string++ = c >> 8;
+ *s++ = c >> 8;
else
- *string++ = '?';
+ *s++ = '?';
}
- *string++ = 0;
+ *s++ = 0;
return buf;
}
@@ -177,30 +217,37 @@ usbd_devinfo_vp(dev, v, p)
char *v, *p;
{
usb_device_descriptor_t *udd = &dev->ddesc;
- char *vendor, *product;
+ char *vendor = 0, *product = 0;
+#ifdef USBVERBOSE
struct usb_knowndev *kdp;
+#endif
+
+ if (!dev) {
+ v[0] = p[0] = '\0';
+ return;
+ }
vendor = usbd_get_string(dev, udd->iManufacturer, v);
product = usbd_get_string(dev, udd->iProduct, p);
-
+#ifdef USBVERBOSE
if (!vendor) {
for(kdp = usb_knowndevs;
kdp->vendorname != NULL;
kdp++) {
if (kdp->vendor == UGETW(udd->idVendor) &&
(kdp->product == UGETW(udd->idProduct) ||
- (kdp->flags & USB_KNOWNDEV_NOPROD) != 0))
+ (kdp->flags & USB_KNOWNDEV_NOPROD) != 0))
break;
}
- if (kdp->vendorname == NULL) {
+ if (kdp->vendorname == NULL)
vendor = product = NULL;
- } else {
+ else {
vendor = kdp->vendorname;
product = (kdp->flags & USB_KNOWNDEV_NOPROD) == 0 ?
- kdp->productname : NULL;
+ kdp->productname : NULL;
}
}
-
+#endif
if (vendor)
strcpy(v, vendor);
@@ -275,7 +322,7 @@ usbd_reset_port(dev, port, ps)
usb_port_status_t *ps;
{
usb_device_request_t req;
- usbd_status err;
+ usbd_status r;
int n;
req.bmRequestType = UT_WRITE_CLASS_OTHER;
@@ -283,38 +330,34 @@ usbd_reset_port(dev, port, ps)
USETW(req.wValue, UHF_PORT_RESET);
USETW(req.wIndex, port);
USETW(req.wLength, 0);
- err = usbd_do_request(dev, &req, 0);
- DPRINTFN(1,("usbd_reset_port: port %d reset done, %s\n",
- port, usbd_errstr(err)));
- if (err)
- return(err);
-
+ r = usbd_do_request(dev, &req, 0);
+ DPRINTFN(1,("usbd_reset_port: port %d reset done, error=%s\n",
+ port, usbd_errstr(r)));
+ if (r != USBD_NORMAL_COMPLETION)
+ return (r);
n = 10;
do {
/* Wait for device to recover from reset. */
usbd_delay_ms(dev, USB_PORT_RESET_DELAY);
- err = usbd_get_port_status(dev, port, ps);
- if (err) {
- DPRINTF(("usbd_reset_port: get port %d status failed %s\n",
- port, usbd_errstr(err)));
- return (err);
+ r = usbd_get_port_status(dev, port, ps);
+ if (r != USBD_NORMAL_COMPLETION) {
+ DPRINTF(("usbd_reset_port: get status failed %d\n",r));
+ return (r);
}
} while ((UGETW(ps->wPortChange) & UPS_C_PORT_RESET) == 0 && --n > 0);
-
if (n == 0) {
printf("usbd_reset_port: timeout\n");
return (USBD_IOERROR);
}
- err = usbd_clear_port_feature(dev, port, UHF_C_PORT_RESET);
+ r = usbd_clear_port_feature(dev, port, UHF_C_PORT_RESET);
#ifdef USB_DEBUG
- if (err)
- DPRINTF(("usbd_reset_port: clear port %d feature failed %d\n",
- port, err));
+ if (r != USBD_NORMAL_COMPLETION)
+ DPRINTF(("usbd_reset_port: clear port feature failed %d\n",r));
#endif
/* Wait for the device to recover from reset. */
usbd_delay_ms(dev, USB_PORT_RESET_RECOVERY);
- return (err);
+ return (r);
}
usb_interface_descriptor_t *
@@ -436,14 +479,11 @@ usbd_fill_iface_data(dev, ifaceidx, altidx)
goto bad;
found:
ifc->endpoints[endpt].edesc = ed;
- ifc->endpoints[endpt].state = USBD_ENDPOINT_ACTIVE;
ifc->endpoints[endpt].refcnt = 0;
- ifc->endpoints[endpt].toggle = 0;
p += ed->bLength;
}
#undef ed
LIST_INIT(&ifc->pipes);
- ifc->state = USBD_INTERFACE_ACTIVE;
return (USBD_NORMAL_COMPLETION);
bad:
@@ -484,14 +524,14 @@ usbd_set_config_no(dev, no, msg)
{
int index;
usb_config_descriptor_t cd;
- usbd_status err;
+ usbd_status r;
DPRINTFN(5,("usbd_set_config_no: %d\n", no));
/* Figure out what config index to use. */
for (index = 0; index < dev->ddesc.bNumConfigurations; index++) {
- err = usbd_get_config_desc(dev, index, &cd);
- if (err)
- return (err);
+ r = usbd_get_config_desc(dev, index, &cd);
+ if (r != USBD_NORMAL_COMPLETION)
+ return (r);
if (cd.bConfigurationValue == no)
return (usbd_set_config_index(dev, index, msg));
}
@@ -505,9 +545,8 @@ usbd_set_config_index(dev, index, msg)
int msg;
{
usb_status_t ds;
- usb_hub_status_t hs;
usb_config_descriptor_t cd, *cdp;
- usbd_status err;
+ usbd_status r;
int ifcidx, nifc, len, selfpowered, power;
DPRINTFN(5,("usbd_set_config_index: dev=%p index=%d\n", dev, index));
@@ -524,24 +563,23 @@ usbd_set_config_index(dev, index, msg)
dev->ifaces = 0;
dev->cdesc = 0;
dev->config = 0;
- dev->state = USBD_DEVICE_ADDRESSED;
}
/* Figure out what config number to use. */
- err = usbd_get_config_desc(dev, index, &cd);
- if (err)
- return (err);
+ r = usbd_get_config_desc(dev, index, &cd);
+ if (r != USBD_NORMAL_COMPLETION)
+ return (r);
len = UGETW(cd.wTotalLength);
cdp = malloc(len, M_USB, M_NOWAIT);
if (cdp == 0)
return (USBD_NOMEM);
- err = usbd_get_desc(dev, UDESC_CONFIG, index, len, cdp);
- if (err)
+ r = usbd_get_desc(dev, UDESC_CONFIG, index, len, cdp);
+ if (r != USBD_NORMAL_COMPLETION)
goto bad;
if (cdp->bDescriptorType != UDESC_CONFIG) {
DPRINTFN(-1,("usbd_set_config_index: bad desc %d\n",
cdp->bDescriptorType));
- err = USBD_INVAL;
+ r = USBD_INVAL;
goto bad;
}
selfpowered = 0;
@@ -549,31 +587,23 @@ usbd_set_config_index(dev, index, msg)
/* May be self powered. */
if (cdp->bmAttributes & UC_BUS_POWERED) {
/* Must ask device. */
- if (dev->quirks->uq_flags & UQ_HUB_POWER) {
- /* Buggy hub, use hub descriptor. */
- err = usbd_get_hub_status(dev, &hs);
- if (err == USBD_NORMAL_COMPLETION &&
- !(UGETW(hs.wHubStatus) & UHS_LOCAL_POWER))
- selfpowered = 1;
- } else {
- err = usbd_get_device_status(dev, &ds);
- if (err == USBD_NORMAL_COMPLETION &&
- (UGETW(ds.wStatus) & UDS_SELF_POWERED))
- selfpowered = 1;
- }
- DPRINTF(("usbd_set_config_index: status=0x%04x, %s\n",
- UGETW(ds.wStatus), usbd_errstr(err)));
+ r = usbd_get_device_status(dev, &ds);
+ if (r == USBD_NORMAL_COMPLETION &&
+ (UGETW(ds.wStatus) & UDS_SELF_POWERED))
+ selfpowered = 1;
+ DPRINTF(("usbd_set_config_index: status=0x%04x, "
+ "error=%s\n",
+ UGETW(ds.wStatus), usbd_errstr(r)));
} else
selfpowered = 1;
}
DPRINTF(("usbd_set_config_index: (addr %d) attr=0x%02x, "
- "selfpowered=%d, power=%d, powerquirk=%x\n",
+ "selfpowered=%d, power=%d\n",
dev->address, cdp->bmAttributes,
- selfpowered, cdp->bMaxPower * 2,
- dev->quirks->uq_flags & UQ_HUB_POWER));
+ selfpowered, cdp->bMaxPower * 2));
#ifdef USB_DEBUG
if (!dev->powersrc) {
- printf("usbd_set_config_index: No power source?\n");
+ DPRINTF(("usbd_set_config_index: No power source?\n"));
return (USBD_IOERROR);
}
#endif
@@ -586,7 +616,7 @@ usbd_set_config_index(dev, index, msg)
USBDEVNAME(dev->bus->bdev), dev->address,
cdp->bConfigurationValue,
power, dev->powersrc->power);
- err = USBD_NO_POWER;
+ r = USBD_NO_POWER;
goto bad;
}
dev->power = power;
@@ -594,10 +624,11 @@ usbd_set_config_index(dev, index, msg)
DPRINTF(("usbd_set_config_index: set config %d\n",
cdp->bConfigurationValue));
- err = usbd_set_config(dev, cdp->bConfigurationValue);
- if (err) {
- DPRINTF(("usbd_set_config_index: setting config=%d failed, %s\n",
- cdp->bConfigurationValue, usbd_errstr(err)));
+ r = usbd_set_config(dev, cdp->bConfigurationValue);
+ if (r != USBD_NORMAL_COMPLETION) {
+ DPRINTF(("usbd_set_config_index: setting config=%d failed, "
+ "error=%s\n",
+ cdp->bConfigurationValue, usbd_errstr(r)));
goto bad;
}
DPRINTF(("usbd_set_config_index: setting new config %d\n",
@@ -606,16 +637,15 @@ usbd_set_config_index(dev, index, msg)
dev->ifaces = malloc(nifc * sizeof(struct usbd_interface),
M_USB, M_NOWAIT);
if (dev->ifaces == 0) {
- err = USBD_NOMEM;
+ r = USBD_NOMEM;
goto bad;
}
DPRINTFN(5,("usbd_set_config_index: dev=%p cdesc=%p\n", dev, cdp));
dev->cdesc = cdp;
dev->config = cdp->bConfigurationValue;
- dev->state = USBD_DEVICE_CONFIGURED;
for (ifcidx = 0; ifcidx < nifc; ifcidx++) {
- err = usbd_fill_iface_data(dev, ifcidx, 0);
- if (err) {
+ r = usbd_fill_iface_data(dev, ifcidx, 0);
+ if (r != USBD_NORMAL_COMPLETION) {
while (--ifcidx >= 0)
usbd_free_iface_data(dev, ifcidx);
goto bad;
@@ -626,48 +656,47 @@ usbd_set_config_index(dev, index, msg)
bad:
free(cdp, M_USB);
- return (err);
+ return (r);
}
/* XXX add function for alternate settings */
usbd_status
-usbd_setup_pipe(dev, iface, ep, rpipe)
+usbd_setup_pipe(dev, iface, ep, pipe)
usbd_device_handle dev;
usbd_interface_handle iface;
struct usbd_endpoint *ep;
- usbd_pipe_handle *rpipe;
+ usbd_pipe_handle *pipe;
{
- usbd_pipe_handle pipe;
- usbd_status err;
+ usbd_pipe_handle p;
+ usbd_status r;
DPRINTFN(1,("usbd_setup_pipe: dev=%p iface=%p ep=%p pipe=%p\n",
- dev, iface, ep, rpipe));
- pipe = malloc(dev->bus->pipe_size, M_USB, M_NOWAIT);
- if (!pipe)
+ dev, iface, ep, pipe));
+ p = malloc(dev->bus->pipe_size, M_USB, M_NOWAIT);
+ if (p == 0)
return (USBD_NOMEM);
-
- pipe->device = dev;
- pipe->iface = iface;
- pipe->state = USBD_PIPE_ACTIVE;
- pipe->endpoint = ep;
+ p->device = dev;
+ p->iface = iface;
+ p->endpoint = ep;
ep->refcnt++;
- pipe->refcnt = 1;
- pipe->intrreqh = 0;
- pipe->running = 0;
- pipe->disco = 0;
- pipe->discoarg = 0;
- SIMPLEQ_INIT(&pipe->queue);
-
- err = dev->bus->open_pipe(pipe);
- if (err) {
- DPRINTFN(-1,("usbd_setup_pipe: endpoint=0x%x failed, %s\n",
- ep->edesc->bEndpointAddress, usbd_errstr(err)));
- free(pipe, M_USB);
- return (err);
+ p->refcnt = 1;
+ p->intrreqh = 0;
+ p->running = 0;
+ p->repeat = 0;
+ SIMPLEQ_INIT(&p->queue);
+ r = dev->bus->methods->open_pipe(p);
+ if (r != USBD_NORMAL_COMPLETION) {
+ DPRINTFN(-1,("usbd_setup_pipe: endpoint=0x%x failed, error="
+ "%s\n",
+ ep->edesc->bEndpointAddress, usbd_errstr(r)));
+ free(p, M_USB);
+ return (r);
}
-
- *rpipe = pipe;
+ /* Clear any stall and make sure DATA0 toggle will be used next. */
+ if (UE_GET_ADDR(ep->edesc->bEndpointAddress) != USB_CONTROL_ENDPOINT)
+ usbd_clear_endpoint_stall(p);
+ *pipe = p;
return (USBD_NORMAL_COMPLETION);
}
@@ -690,29 +719,30 @@ usbd_getnewaddr(bus)
for (addr = 1; addr < USB_MAX_DEVICES; addr++)
if (bus->devices[addr] == 0)
return (addr);
-
return (-1);
}
+
usbd_status
usbd_probe_and_attach(parent, dev, port, addr)
- bdevice *parent;
+ device_ptr_t parent;
usbd_device_handle dev;
int port;
int addr;
{
struct usb_attach_arg uaa;
usb_device_descriptor_t *dd = &dev->ddesc;
- int found = 0;
- int err, i, confi, nifaces;
+ int r, found, i, confi, nifaces;
+ device_ptr_t dv;
usbd_interface_handle ifaces[256]; /* 256 is the absolute max */
#if defined(__FreeBSD__)
-/* XXX uaa is a static var. Not a problem as it _should_ be used only
- * during probe and attach. Should be changed however
- */
- bdevice bdev;
- bdev = device_add_child(*parent, NULL, -1, &uaa);
+ /*
+ * XXX uaa is a static var. Not a problem as it _should_ be used only
+ * during probe and attach. Should be changed however.
+ */
+ device_t bdev;
+ bdev = device_add_child(parent, NULL, -1, &uaa);
if (!bdev) {
printf("%s: Device creation failed\n", USBDEVNAME(dev->bus->bdev));
return (USBD_INVAL);
@@ -728,10 +758,20 @@ usbd_probe_and_attach(parent, dev, port, addr)
uaa.port = port;
uaa.configno = UHUB_UNK_CONFIGURATION;
uaa.ifaceno = UHUB_UNK_INTERFACE;
+ uaa.vendor = UGETW(dd->idVendor);
+ uaa.product = UGETW(dd->idProduct);
+ uaa.release = UGETW(dd->bcdDevice);
/* First try with device specific drivers. */
- if (USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print, usbd_submatch))
+ dv = USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print, usbd_submatch);
+ if (dv) {
+ dev->subdevs = malloc(2 * sizeof dv, M_USB, M_NOWAIT);
+ if (dev->subdevs == 0)
+ return (USBD_NOMEM);
+ dev->subdevs[0] = dv;
+ dev->subdevs[1] = 0;
return (USBD_NORMAL_COMPLETION);
+ }
DPRINTF(("usbd_probe_and_attach: no device specific driver found\n"));
@@ -739,11 +779,21 @@ usbd_probe_and_attach(parent, dev, port, addr)
for (confi = 0; confi < dd->bNumConfigurations; confi++) {
DPRINTFN(1,("usbd_probe_and_attach: trying config idx=%d\n",
confi));
- err = usbd_set_config_index(dev, confi, 1);
- if (err) {
- printf("%s: port %d, set config at addr %d failed, %s\n",
- USBDEVNAME(*parent), port, addr, usbd_errstr(err));
- return (err);
+ r = usbd_set_config_index(dev, confi, 1);
+ if (r != USBD_NORMAL_COMPLETION) {
+#ifdef USB_DEBUG
+ DPRINTF(("%s: port %d, set config at addr %d failed, "
+ "error=%s\n", USBDEVPTRNAME(parent), port,
+ addr, usbd_errstr(r)));
+#else
+ printf("%s: port %d, set config at addr %d failed\n",
+ USBDEVPTRNAME(parent), port, addr);
+#endif
+#if defined(__FreeBSD__)
+ device_delete_child(parent, bdev);
+#endif
+
+ return (r);
}
nifaces = dev->cdesc->bNumInterface;
uaa.configno = dev->cdesc->bConfigurationValue;
@@ -751,38 +801,56 @@ usbd_probe_and_attach(parent, dev, port, addr)
ifaces[i] = &dev->ifaces[i];
uaa.ifaces = ifaces;
uaa.nifaces = nifaces;
+
+ dev->subdevs = malloc((nifaces+1) * sizeof dv, M_USB,M_NOWAIT);
+ if (dev->subdevs == 0) {
+#if defined(__FreeBSD__)
+ device_delete_child(parent, bdev);
+#endif
+ return (USBD_NOMEM);
+ }
+
+ found = 0;
for (i = 0; i < nifaces; i++) {
if (!ifaces[i])
continue; /* interface already claimed */
+
uaa.iface = ifaces[i];
uaa.ifaceno = ifaces[i]->idesc->bInterfaceNumber;
- if (USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print,
- usbd_submatch)) {
- found++;
+ dv = USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print,
+ usbd_submatch);
+ if (dv) {
+ dev->subdevs[found++] = dv;
+ dev->subdevs[found] = 0;
ifaces[i] = 0; /* consumed */
#if defined(__FreeBSD__)
- /* create another device for the next iface */
- bdev = device_add_child(*parent, NULL, -1, &uaa);
+ /* create another child for the next iface */
+ bdev = device_add_child(parent, NULL, -1, &uaa);
if (!bdev) {
printf("%s: Device creation failed\n",
- USBDEVNAME(dev->bus->bdev));
+ USBDEVNAME(dev->bus->bdev));
return (USBD_NORMAL_COMPLETION);
}
device_quiet(bdev);
#endif
}
}
+
if (found != 0) {
#if defined(__FreeBSD__)
- /* remove the last created child again, it is unused */
- device_delete_child(*parent, bdev);
+ /* remove the last created child again; it is unused */
+ device_delete_child(parent, bdev);
#endif
return (USBD_NORMAL_COMPLETION);
}
+
+ free(dev->subdevs, M_USB);
+ dev->subdevs = 0;
}
/* No interfaces were attached in any of the configurations. */
- if (dd->bNumConfigurations > 1)/* don't change if only 1 config */
+
+ if (dd->bNumConfigurations > 1) /* don't change if only 1 config */
usbd_set_config_index(dev, 0, 0);
DPRINTF(("usbd_probe_and_attach: no interface drivers found\n"));
@@ -792,8 +860,18 @@ usbd_probe_and_attach(parent, dev, port, addr)
uaa.usegeneric = 1;
uaa.configno = UHUB_UNK_CONFIGURATION;
uaa.ifaceno = UHUB_UNK_INTERFACE;
- if (USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print, usbd_submatch))
+ uaa.vendor = UHUB_UNK_VENDOR;
+ uaa.product = UHUB_UNK_PRODUCT;
+ uaa.release = UHUB_UNK_RELEASE;
+ dv = USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print, usbd_submatch);
+ if (dv) {
+ dev->subdevs = malloc(2 * sizeof dv, M_USB, M_NOWAIT);
+ if (dev->subdevs == 0)
+ return (USBD_NOMEM);
+ dev->subdevs[0] = dv;
+ dev->subdevs[1] = 0;
return (USBD_NORMAL_COMPLETION);
+ }
/*
* The generic attach failed, but leave the device as it is.
@@ -802,13 +880,9 @@ usbd_probe_and_attach(parent, dev, port, addr)
*/
DPRINTF(("usbd_probe_and_attach: generic attach failed\n"));
#if defined(__FreeBSD__)
-/*
- * XXX should we delete the child again? Left for now to avoid dangling
- * references.
- device_delete_child(*parent, bdev);
-*/
+ device_delete_child(parent, bdev);
#endif
- return (USBD_NORMAL_COMPLETION);
+ return (USBD_NORMAL_COMPLETION);
}
@@ -821,7 +895,7 @@ usbd_probe_and_attach(parent, dev, port, addr)
*/
usbd_status
usbd_new_device(parent, bus, depth, lowspeed, port, up)
- bdevice *parent;
+ device_ptr_t parent;
usbd_bus_handle bus;
int depth;
int lowspeed;
@@ -830,7 +904,7 @@ usbd_new_device(parent, bus, depth, lowspeed, port, up)
{
usbd_device_handle dev;
usb_device_descriptor_t *dd;
- usbd_status err;
+ usbd_status r;
int addr;
int i;
@@ -852,7 +926,6 @@ usbd_new_device(parent, bus, depth, lowspeed, port, up)
/* Set up default endpoint handle. */
dev->def_ep.edesc = &dev->def_ep_desc;
- dev->def_ep.state = USBD_ENDPOINT_ACTIVE;
/* Set up default endpoint descriptor. */
dev->def_ep_desc.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE;
@@ -862,7 +935,6 @@ usbd_new_device(parent, bus, depth, lowspeed, port, up)
USETW(dev->def_ep_desc.wMaxPacketSize, USB_MAX_IPACKET);
dev->def_ep_desc.bInterval = 0;
- dev->state = USBD_DEVICE_DEFAULT;
dev->quirks = &usbd_no_quirk;
dev->address = USB_START_ADDR;
dev->ddesc.bMaxPacketSize = 0;
@@ -872,10 +944,10 @@ usbd_new_device(parent, bus, depth, lowspeed, port, up)
dev->langid = USBD_NOLANG;
/* Establish the the default pipe. */
- err = usbd_setup_pipe(dev, 0, &dev->def_ep, &dev->default_pipe);
- if (err) {
+ r = usbd_setup_pipe(dev, 0, &dev->def_ep, &dev->default_pipe);
+ if (r != USBD_NORMAL_COMPLETION) {
usbd_remove_device(dev, up);
- return (err);
+ return (r);
}
up->device = dev;
@@ -883,18 +955,25 @@ usbd_new_device(parent, bus, depth, lowspeed, port, up)
/* Try a few times in case the device is slow (i.e. outside specs.) */
for (i = 0; i < 5; i++) {
/* Get the first 8 bytes of the device descriptor. */
- err = usbd_get_desc(dev, UDESC_DEVICE, 0, USB_MAX_IPACKET, dd);
- if (err == USBD_NORMAL_COMPLETION)
+ r = usbd_get_desc(dev, UDESC_DEVICE, 0, USB_MAX_IPACKET, dd);
+ if (r == USBD_NORMAL_COMPLETION)
break;
usbd_delay_ms(dev, 200);
}
- if (err) {
+ if (r != USBD_NORMAL_COMPLETION) {
DPRINTFN(-1, ("usbd_new_device: addr=%d, getting first desc "
- "failed\n", addr));
+ "failed\n",
+ addr));
usbd_remove_device(dev, up);
- return (err);
+ return (r);
}
+ DPRINTF(("usbd_new_device: adding unit addr=%d, rev=%02x, class=%d, "
+ "subclass=%d, protocol=%d, maxpacket=%d, len=%d, ls=%d\n",
+ addr,UGETW(dd->bcdUSB), dd->bDeviceClass, dd->bDeviceSubClass,
+ dd->bDeviceProtocol, dd->bMaxPacketSize, dd->bLength,
+ dev->lowspeed));
+
if (dd->bDescriptorType != UDESC_DEVICE) {
/* Illegal device descriptor */
DPRINTFN(-1,("usbd_new_device: illegal descriptor %d\n",
@@ -903,38 +982,38 @@ usbd_new_device(parent, bus, depth, lowspeed, port, up)
return (USBD_INVAL);
}
- DPRINTF(("usbd_new_device: adding unit addr=%d, rev=%02x, class=%d, "
- "subclass=%d, protocol=%d, maxpacket=%d, ls=%d\n",
- addr,UGETW(dd->bcdUSB), dd->bDeviceClass, dd->bDeviceSubClass,
- dd->bDeviceProtocol, dd->bMaxPacketSize, dev->lowspeed));
+ if (dd->bLength < USB_DEVICE_DESCRIPTOR_SIZE) {
+ DPRINTFN(-1,("usbd_new_device: bad length %d\n", dd->bLength));
+ usbd_remove_device(dev, up);
+ return (USBD_INVAL);
+ }
USETW(dev->def_ep_desc.wMaxPacketSize, dd->bMaxPacketSize);
/* Get the full device descriptor. */
- err = usbd_get_device_desc(dev, dd);
- if (err) {
+ r = usbd_get_device_desc(dev, dd);
+ if (r != USBD_NORMAL_COMPLETION) {
DPRINTFN(-1, ("usbd_new_device: addr=%d, getting full desc "
"failed\n", addr));
usbd_remove_device(dev, up);
- return (err);
+ return (r);
}
/* Figure out what's wrong with this device. */
dev->quirks = usbd_find_quirk(dd);
/* Set the address */
- err = usbd_set_address(dev, addr);
- if (err) {
- DPRINTFN(-1,("usbd_new_device: set address %d failed\n",addr));
- err = USBD_SET_ADDR_FAILED;
+ r = usbd_set_address(dev, addr);
+ if (r != USBD_NORMAL_COMPLETION) {
+ DPRINTFN(-1,("usb_new_device: set address %d failed\n",addr));
+ r = USBD_SET_ADDR_FAILED;
usbd_remove_device(dev, up);
- return (err);
+ return (r);
}
/* Allow device time to set new address */
usbd_delay_ms(dev, USB_SET_ADDRESS_SETTLE);
dev->address = addr; /* New device address now */
- dev->state = USBD_DEVICE_ADDRESSED;
bus->devices[addr] = dev;
/* Assume 100mA bus powered for now. Changed when configured. */
@@ -944,12 +1023,12 @@ usbd_new_device(parent, bus, depth, lowspeed, port, up)
DPRINTF(("usbd_new_device: new dev (addr %d), dev=%p, parent=%p\n",
addr, dev, parent));
- err = usbd_probe_and_attach(parent, dev, port, addr);
- if (err) {
+ r = usbd_probe_and_attach(parent, dev, port, addr);
+ if (r != USBD_NORMAL_COMPLETION) {
usbd_remove_device(dev, up);
- return (err);
+ return (r);
}
-
+
return (USBD_NORMAL_COMPLETION);
}
@@ -962,14 +1041,13 @@ usbd_remove_device(dev, up)
if (dev->default_pipe)
usbd_kill_pipe(dev->default_pipe);
-
up->device = 0;
dev->bus->devices[dev->address] = 0;
free(dev, M_USB);
}
-#if defined(__NetBSD__)
+#if defined(__NetBSD__) || defined(__OpenBSD__)
int
usbd_print(aux, pnp)
void *aux;
@@ -991,15 +1069,38 @@ usbd_print(aux, pnp)
printf(" configuration %d", uaa->configno);
if (uaa->ifaceno != UHUB_UNK_INTERFACE)
printf(" interface %d", uaa->ifaceno);
+#if 0
+ /*
+ * It gets very crowded with these locators on the attach line.
+ * They are not really needed since they are printed in the clear
+ * by each driver.
+ */
+ if (uaa->vendor != UHUB_UNK_VENDOR)
+ printf(" vendor 0x%04x", uaa->vendor);
+ if (uaa->product != UHUB_UNK_PRODUCT)
+ printf(" product 0x%04x", uaa->product);
+ if (uaa->release != UHUB_UNK_RELEASE)
+ printf(" release 0x%04x", uaa->release);
+#endif
return (UNCONF);
}
+#if defined(__NetBSD__)
int
usbd_submatch(parent, cf, aux)
struct device *parent;
struct cfdata *cf;
void *aux;
{
+#elif defined(__OpenBSD__)
+int
+usbd_submatch(parent, match, aux)
+ struct device *parent;
+ void *match;
+ void *aux;
+{
+ struct cfdata *cf = match;
+#endif
struct usb_attach_arg *uaa = aux;
if ((uaa->port != 0 &&
@@ -1010,86 +1111,34 @@ usbd_submatch(parent, cf, aux)
cf->uhubcf_configuration != uaa->configno) ||
(uaa->ifaceno != UHUB_UNK_INTERFACE &&
cf->uhubcf_interface != UHUB_UNK_INTERFACE &&
- cf->uhubcf_interface != uaa->ifaceno))
+ cf->uhubcf_interface != uaa->ifaceno) ||
+ (uaa->vendor != UHUB_UNK_VENDOR &&
+ cf->uhubcf_vendor != UHUB_UNK_VENDOR &&
+ cf->uhubcf_vendor != uaa->vendor) ||
+ (uaa->product != UHUB_UNK_PRODUCT &&
+ cf->uhubcf_product != UHUB_UNK_PRODUCT &&
+ cf->uhubcf_product != uaa->product) ||
+ (uaa->release != UHUB_UNK_RELEASE &&
+ cf->uhubcf_release != UHUB_UNK_RELEASE &&
+ cf->uhubcf_release != uaa->release)
+ )
return 0;
return ((*cf->cf_attach->ca_match)(parent, cf, aux));
}
-#endif
-
-
-/*
- * Maintain a list of control transfers per pipe. As soon as the
- * previous one for the queue is done the next one is submitted
- */
-usbd_status
-usb_insert_transfer(reqh)
- usbd_request_handle reqh;
-{
- usbd_pipe_handle pipe = reqh->pipe;
- usbd_interface_handle iface = pipe->iface;
-
- if (pipe->state == USBD_PIPE_IDLE ||
- (iface && iface->state == USBD_INTERFACE_IDLE))
- return (USBD_IS_IDLE);
- SIMPLEQ_INSERT_TAIL(&pipe->queue, reqh, next);
- if (pipe->state != USBD_PIPE_ACTIVE ||
- (iface && iface->state != USBD_INTERFACE_ACTIVE))
- return (USBD_NOT_STARTED);
- if (pipe->running)
- return (USBD_IN_PROGRESS);
- pipe->running = 1;
- return (USBD_NORMAL_COMPLETION);
-}
-void
-usb_start_next(pipe)
- usbd_pipe_handle pipe;
-{
- usbd_request_handle reqh;
- usbd_status err;
-
-#ifdef DIAGNOSTIC
- if (SIMPLEQ_FIRST(&pipe->queue) == 0) {
- printf("usb_start_next: empty\n");
- return;
- }
#endif
- /* First remove finished transfer */
-#if defined(__NetBSD__)
- SIMPLEQ_REMOVE_HEAD(&pipe->queue, SIMPLEQ_FIRST(&pipe->queue), next);
-#elif defined(__FreeBSD__)
- SIMPLEQ_REMOVE_HEAD(&pipe->queue, next);
-#endif
- if (pipe->state != USBD_PIPE_ACTIVE) {
- pipe->running = 0;
- return;
- }
- reqh = SIMPLEQ_FIRST(&pipe->queue);
- DPRINTFN(5, ("usb_start_next: start reqh=%p\n", reqh));
- if (!reqh)
- pipe->running = 0;
- else {
- err = pipe->methods->start(reqh);
- if (err != USBD_IN_PROGRESS) {
- printf("usb_start_next: error=%d\n", err);
- pipe->running = 0;
- /* XXX do what? */
- }
- }
-}
-
void
usbd_fill_deviceinfo(dev, di)
usbd_device_handle dev;
struct usb_device_info *di;
{
- struct usbd_port *port;
- int i, err, s;
+ struct usbd_port *p;
+ int i, r, s;
di->config = dev->config;
usbd_devinfo_vp(dev, di->vendor, di->product);
- usbd_printBCD(di->revision, UGETW(dev->ddesc.bcdDevice));
+ usbd_printBCD(di->release, UGETW(dev->ddesc.bcdDevice));
di->vendorNo = UGETW(dev->ddesc.idVendor);
di->productNo = UGETW(dev->ddesc.idProduct);
di->class = dev->ddesc.bDeviceClass;
@@ -1101,24 +1150,44 @@ usbd_fill_deviceinfo(dev, di)
i < sizeof(di->ports) / sizeof(di->ports[0]) &&
i < dev->hub->hubdesc.bNbrPorts;
i++) {
- port = &dev->hub->ports[i];
- if (port->device)
- err = port->device->address;
+ p = &dev->hub->ports[i];
+ if (p->device)
+ r = p->device->address;
else {
- s = UGETW(port->status.wPortStatus);
+ s = UGETW(p->status.wPortStatus);
if (s & UPS_PORT_ENABLED)
- err = USB_PORT_ENABLED;
+ r = USB_PORT_ENABLED;
else if (s & UPS_SUSPEND)
- err = USB_PORT_SUSPENDED;
+ r = USB_PORT_SUSPENDED;
else if (s & UPS_PORT_POWER)
- err = USB_PORT_POWERED;
+ r = USB_PORT_POWERED;
else
- err = USB_PORT_DISABLED;
+ r = USB_PORT_DISABLED;
}
- di->ports[i] = err;
+ di->ports[i] = r;
}
di->nports = dev->hub->hubdesc.bNbrPorts;
} else
di->nports = 0;
}
+void
+usb_free_device(dev)
+ usbd_device_handle dev;
+{
+ int ifcidx, nifc;
+
+ if (dev->default_pipe)
+ usbd_kill_pipe(dev->default_pipe);
+ if (dev->ifaces) {
+ nifc = dev->cdesc->bNumInterface;
+ for (ifcidx = 0; ifcidx < nifc; ifcidx++)
+ usbd_free_iface_data(dev, ifcidx);
+ free(dev->ifaces, M_USB);
+ }
+ if (dev->cdesc)
+ free(dev->cdesc, M_USB);
+ if (dev->subdevs)
+ free(dev->subdevs, M_USB);
+ free(dev, M_USB);
+}
diff --git a/sys/dev/usb/usbcdc.h b/sys/dev/usb/usbcdc.h
index 58b0706..97bec79 100644
--- a/sys/dev/usb/usbcdc.h
+++ b/sys/dev/usb/usbcdc.h
@@ -1,4 +1,4 @@
-/* $NetBSD: usbcdc.h,v 1.3 1999/01/03 01:09:18 augustss Exp $ */
+/* $NetBSD: usbcdc.h,v 1.4 1999/08/16 20:20:19 augustss Exp $ */
/* $FreeBSD$ */
/*
@@ -41,24 +41,16 @@
#ifndef _USBCDC_H_
#define _USBCDC_H_
-#define UDESCSUB_CDC_HEADER 0x00 /* Header */
-#define UDESCSUB_CDC_CM 0x01 /* Call Management */
-#define UDESCSUB_CDC_ACM 0x02 /* Abstract Control Model */
-#define UDESCSUB_CDC_DLM 0x03 /* Direct Line Management */
-#define UDESCSUB_CDC_TRF 0x04 /* Telephone Ringer */
-#define UDESCSUB_CDC_TCLSR 0x05 /* Tel. Call and Line State Rep. Cap. */
-#define UDESCSUB_CDC_UNION 0x06 /* Union */
-#define UDESCSUB_CDC_CS 0x07 /* Country Selection */
-#define UDESCSUB_CDC_TOM 0x08 /* Telephone Operational Modes */
-#define UDESCSUB_CDC_USBT 0x09 /* USB Terminal */
-#define UDESCSUB_CDC_NCT 0x0a /* Network Channel Terminal */
-#define UDESCSUB_CDC_PU 0x0b /* Protocol Unit */
-#define UDESCSUB_CDC_EU 0x0c /* Extention Unit */
-#define UDESCSUB_CDC_MCM 0x0d /* Multi-Channel Management */
-#define UDESCSUB_CDC_CCM 0x0e /* CAPI Control Management */
-#define UDESCSUB_CDC_EN 0x0f /* Ethernet Networking */
-#define UDESCSUB_CDC_AN 0x10 /* ATM Networking */
-
+#define UDESCSUB_CDC_HEADER 0
+#define UDESCSUB_CDC_CM 1 /* Call Management */
+#define UDESCSUB_CDC_ACM 2 /* Abstract Control Model */
+#define UDESCSUB_CDC_DLM 3 /* Direct Line Management */
+#define UDESCSUB_CDC_TRF 4 /* Telephone Ringer */
+#define UDESCSUB_CDC_TCLSR 5 /* Telephone Call ... */
+#define UDESCSUB_CDC_UNION 6
+#define UDESCSUB_CDC_CS 7 /* Country Selection */
+#define UDESCSUB_CDC_TOM 8 /* Telephone Operational Modes */
+#define UDESCSUB_CDC_USBT 9 /* USB Terminal */
typedef struct {
uByte bLength;
@@ -100,17 +92,24 @@ typedef struct {
#define UCDC_GET_ENCAPSULATED_RESPONSE 0x01
#define UCDC_SET_COMM_FEATURE 0x02
#define UCDC_GET_COMM_FEATURE 0x03
-#define UCDC_CLEAR_COMM_FEATURE 0x04
#define UCDC_ABSTRACT_STATE 0x01
#define UCDC_COUNTRY_SETTING 0x02
+#define UCDC_CLEAR_COMM_FEATURE 0x04
#define UCDC_SET_LINE_CODING 0x20
#define UCDC_GET_LINE_CODING 0x21
+#define UCDC_SET_CONTROL_LINE_STATE 0x22
+#define UCDC_LINE_DTR 0x0001
+#define UCDC_LINE_RTS 0x0002
+#define UCDC_SEND_BREAK 0x23
+#define UCDC_BREAK_ON 0xffff
+#define UCDC_BREAK_OFF 0x0000
typedef struct {
uWord wState;
#define UCDC_IDLE_SETTING 0x0001
#define UCDC_DATA_MULTIPLEXED 0x0002
} usb_cdc_abstract_state_t;
+#define UCDC_ABSTRACT_STATE_LENGTH 2
typedef struct {
uDWord dwDTERate;
@@ -126,6 +125,7 @@ typedef struct {
#define UCDC_PARITY_SPACE 4
uByte bDataBits;
} usb_cdc_line_state_t;
+#define UCDC_LINE_STATE_LENGTH 7
typedef struct {
uByte bmRequestType;
diff --git a/sys/dev/usb/usbdevs.h b/sys/dev/usb/usbdevs.h
index 12e842a..acbef82 100644
--- a/sys/dev/usb/usbdevs.h
+++ b/sys/dev/usb/usbdevs.h
@@ -4,7 +4,7 @@
* THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
*
* generated from:
- * NetBSD: usbdevs,v 1.19 1999/01/08 11:18:38 augustss Exp
+ * NetBSD: usbdevs,v 1.35 1999/06/28 04:09:53 augustss Exp
*/
/*
@@ -73,6 +73,7 @@
#define USB_VENDOR_SHUTTLE 0x04e6 /* Shuttle Technology */
#define USB_VENDOR_BROTHER 0x04f9 /* Brother Industries Corp. */
#define USB_VENDOR_JAZZ 0x04fa /* Dallas Semiconductor */
+#define USB_VENDOR_KAWATSU 0x050f /* Kawatsu Semiconductor, Inc. */
#define USB_VENDOR_AKS 0x0529 /* Fast Security AG */
#define USB_VENDOR_VISION 0x0533 /* Alcatel Mobile Phones */
#define USB_VENDOR_ATEN 0x0557 /* ATEN International Corp. Ltd. */
@@ -86,10 +87,13 @@
#define USB_VENDOR_BELKIN 0x05ab /* In-System Design */
#define USB_VENDOR_APPLE 0x05ac /* Apple Computer */
#define USB_VENDOR_EIZONANAO 0x05e7 /* EIZO Nanao */
+#define USB_VENDOR_PIENGINEERING 0x05f3 /* P.I. Engineering */
#define USB_VENDOR_CHIC 0x05fe /* Chic Technology */
#define USB_VENDOR_MACALLY 0x0618 /* Macally */
#define USB_VENDOR_MULTITECH 0x06e0 /* MultiTech */
#define USB_VENDOR_ADS 0x06e1 /* ADS Technologies */
+#define USB_VENDOR_SIIG 0x07cc /* SIIG */
+#define USB_VENDOR_ACTIVEWIRE 0x0854 /* ActiveWire Inc. */
#define USB_VENDOR_PLX 0x10b5 /* PLX */
#define USB_VENDOR_INSIDEOUT 0x1608 /* Inside Out Networks */
#define USB_VENDOR_ENTREGA 0x1645 /* Entrega */
@@ -99,9 +103,6 @@
* List of known products. Grouped by vendor.
*/
-/* Thrustmaster products */
-#define USB_PRODUCT_THRUST_FUSION_PAD 0xa0a3 /* Fusion Digital Gamepad */
-
/* NEC products */
#define USB_PRODUCT_NEC_HUB 0x55aa /* hub */
#define USB_PRODUCT_NEC_HUB_B 0x55ab /* hub */
@@ -115,7 +116,10 @@
/* Gravis products */
#define USB_PRODUCT_GRAVIS_GAMEPADPRO 0x4001 /* GamePad Pro */
-/* Unixtar/Texas Instruments products */
+/* Thrustmaster products */
+#define USB_PRODUCT_THRUST_FUSION_PAD 0xa0a3 /* Fusion Digital Gamepad */
+
+/* Texas Intel products */
#define USB_PRODUCT_TI_UTUSB41 0x1446 /* UT-USB41 hub */
/* Genius products */
@@ -145,16 +149,16 @@
/* Connectix products */
#define USB_PRODUCT_CONNECTIX_QUICKCAM 0x0001 /* QuickCam */
-/* STMicroelectronics products */
-#define USB_PRODUCT_STMICRO_COMMUNICATOR 0x7554 /* USB Communicator */
-
/* Lucent products */
#define USB_PRODUCT_LUCENT_EVALKIT 0x1001 /* USS-720 evaluation kit */
+/* STMicroelectronics products */
+#define USB_PRODUCT_STMICRO_COMMUNICATOR 0x7554 /* USB Communicator */
+
/* Acer products */
#define USB_PRODUCT_ACER_ACERSCAN_C310U 0x12a6 /* Acerscan C310U */
-/* Cypress Semiconduuctor products */
+/* Cypress Semiconductor products */
#define USB_PRODUCT_CYPRESS_MOUSE 0x0001 /* mouse */
/* Epson products */
@@ -175,6 +179,9 @@
/* Jazz products */
#define USB_PRODUCT_JAZZ_J6502 0x4201 /* J-6502 speakers */
+/* Kawatsu products */
+#define USB_PRODUCT_KAWATSU_MH4000P 0x0003 /* MiniHub 4000P */
+
/* AKS products */
#define USB_PRODUCT_AKS_USBHASP 0x0001 /* USB-HASP 0.06 */
@@ -208,25 +215,43 @@
/* Belkin products */
#define USB_PRODUCT_BELKIN_F5U002 0x0002 /* Parallel printer adapter */
+#define USB_PRODUCT_BELKIN_1COM 0x8007 /* Serial port */
/* Logitech products */
#define USB_PRODUCT_LOGITECH_M2452 0x0203 /* M2452 keyboard */
#define USB_PRODUCT_LOGITECH_M4848 0x0301 /* M4848 mouse */
+#define USB_PRODUCT_LOGITECH_QUICKCAM 0x0801 /* QuickCam */
#define USB_PRODUCT_LOGITECH_USBPS2 0xc001 /* USB-PS/2 mouse */
+/* P.I. Engineering products */
+#define USB_PRODUCT_PIENGINEERING_PS2USB 0x020b /* PS2 to Mac USB Adapter */
+
/* Chic Technology products */
#define USB_PRODUCT_CHIC_MOUSE1 0x0001 /* mouse */
/* Macally products */
#define USB_PRODUCT_MACALLY_MOUSE1 0x0101 /* mouse */
-/* MultiTech Products */
+/* MultiTech products */
#define USB_PRODUCT_MULTITECH_ATLAS 0xf101 /* MT5634ZBA-USB modem */
+
/* ADS products */
#define USB_PRODUCT_ADS_ENET 0x0008 /* Ethernet adapter */
+/* SIIG products */
+#define USB_PRODUCT_SIIG_DIGIFILMREADER 0x0004 /* DigiFilm-Combo Reader */
+
+/* ActiveWire Inc. products */
+#define USB_PRODUCT_ACTIVEWIRE_IOBOARD 0x0100 /* I/O Board */
+#define USB_PRODUCT_ACTIVEWIRE_IOBOARD_FW 0x0101 /* I/O Board, rev. 1 firmware */
+
/* Entrega products */
+#define USB_PRODUCT_ENTREGA_1S 0x0001 /* 1S serial connector */
+#define USB_PRODUCT_ENTREGA_2S 0x0002 /* 2S serial connector */
+#define USB_PRODUCT_ENTREGA_1S25 0x0003 /* 1S25 serial connector */
+#define USB_PRODUCT_ENTREGA_4S 0x0004 /* 4S serial connector */
#define USB_PRODUCT_ENTREGA_CENTRONICS 0x0006 /* Centronics connector */
+#define USB_PRODUCT_ENTREGA_1S9 0x0093 /* 1S9 serial connector */
#define USB_PRODUCT_ENTREGA_SERIAL 0x8001 /* DB25 Serial connector */
/* PLX products */
diff --git a/sys/dev/usb/usbdevs_data.h b/sys/dev/usb/usbdevs_data.h
index c534729..192d18b 100644
--- a/sys/dev/usb/usbdevs_data.h
+++ b/sys/dev/usb/usbdevs_data.h
@@ -4,7 +4,7 @@
* THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
*
* generated from:
- * NetBSD: usbdevs,v 1.19 1999/01/08 11:18:38 augustss Exp
+ * NetBSD: usbdevs,v 1.35 1999/06/28 04:09:53 augustss Exp
*/
/*
@@ -46,12 +46,6 @@
struct usb_knowndev usb_knowndevs[] = {
{
- USB_VENDOR_THRUST, USB_PRODUCT_THRUST_FUSION_PAD,
- 0,
- "Thrustmaster",
- "Fusion Digital Gamepad",
- },
- {
USB_VENDOR_NEC, USB_PRODUCT_NEC_HUB,
0,
"NEC",
@@ -82,6 +76,12 @@ struct usb_knowndev usb_knowndevs[] = {
"GamePad Pro",
},
{
+ USB_VENDOR_THRUST, USB_PRODUCT_THRUST_FUSION_PAD,
+ 0,
+ "Thrustmaster",
+ "Fusion Digital Gamepad",
+ },
+ {
USB_VENDOR_TI, USB_PRODUCT_TI_UTUSB41,
0,
"Texas Instruments",
@@ -166,18 +166,18 @@ struct usb_knowndev usb_knowndevs[] = {
"QuickCam",
},
{
- USB_VENDOR_STMICRO, USB_PRODUCT_STMICRO_COMMUNICATOR,
- 0,
- "STMicroelectronics",
- "USB Communicator",
- },
- {
USB_VENDOR_LUCENT, USB_PRODUCT_LUCENT_EVALKIT,
0,
"Lucent",
"USS-720 evaluation kit",
},
{
+ USB_VENDOR_STMICRO, USB_PRODUCT_STMICRO_COMMUNICATOR,
+ 0,
+ "STMicroelectronics",
+ "USB Communicator",
+ },
+ {
USB_VENDOR_ACER, USB_PRODUCT_ACER_ACERSCAN_C310U,
0,
"Acer Peripheral Inc.",
@@ -226,6 +226,12 @@ struct usb_knowndev usb_knowndevs[] = {
"J-6502 speakers",
},
{
+ USB_VENDOR_KAWATSU, USB_PRODUCT_KAWATSU_MH4000P,
+ 0,
+ "Kawatsu Semiconductor, Inc.",
+ "MiniHub 4000P",
+ },
+ {
USB_VENDOR_AKS, USB_PRODUCT_AKS_USBHASP,
0,
"Fast Security AG",
@@ -298,6 +304,12 @@ struct usb_knowndev usb_knowndevs[] = {
"Parallel printer adapter",
},
{
+ USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_1COM,
+ 0,
+ "In-System Design",
+ "Serial port",
+ },
+ {
USB_VENDOR_LOGITECH, USB_PRODUCT_LOGITECH_M2452,
0,
"Logitech Inc.",
@@ -310,12 +322,24 @@ struct usb_knowndev usb_knowndevs[] = {
"M4848 mouse",
},
{
+ USB_VENDOR_LOGITECH, USB_PRODUCT_LOGITECH_QUICKCAM,
+ 0,
+ "Logitech Inc.",
+ "QuickCam",
+ },
+ {
USB_VENDOR_LOGITECH, USB_PRODUCT_LOGITECH_USBPS2,
0,
"Logitech Inc.",
"USB-PS/2 mouse",
},
{
+ USB_VENDOR_PIENGINEERING, USB_PRODUCT_PIENGINEERING_PS2USB,
+ 0,
+ "P.I. Engineering",
+ "PS2 to Mac USB Adapter",
+ },
+ {
USB_VENDOR_CHIC, USB_PRODUCT_CHIC_MOUSE1,
0,
"Chic Technology",
@@ -340,12 +364,60 @@ struct usb_knowndev usb_knowndevs[] = {
"Ethernet adapter",
},
{
+ USB_VENDOR_SIIG, USB_PRODUCT_SIIG_DIGIFILMREADER,
+ 0,
+ "SIIG",
+ "DigiFilm-Combo Reader",
+ },
+ {
+ USB_VENDOR_ACTIVEWIRE, USB_PRODUCT_ACTIVEWIRE_IOBOARD,
+ 0,
+ "ActiveWire Inc.",
+ "I/O Board",
+ },
+ {
+ USB_VENDOR_ACTIVEWIRE, USB_PRODUCT_ACTIVEWIRE_IOBOARD_FW,
+ 0,
+ "ActiveWire Inc.",
+ "I/O Board, rev. 1 firmware",
+ },
+ {
+ USB_VENDOR_ENTREGA, USB_PRODUCT_ENTREGA_1S,
+ 0,
+ "Entrega",
+ "1S serial connector",
+ },
+ {
+ USB_VENDOR_ENTREGA, USB_PRODUCT_ENTREGA_2S,
+ 0,
+ "Entrega",
+ "2S serial connector",
+ },
+ {
+ USB_VENDOR_ENTREGA, USB_PRODUCT_ENTREGA_1S25,
+ 0,
+ "Entrega",
+ "1S25 serial connector",
+ },
+ {
+ USB_VENDOR_ENTREGA, USB_PRODUCT_ENTREGA_4S,
+ 0,
+ "Entrega",
+ "4S serial connector",
+ },
+ {
USB_VENDOR_ENTREGA, USB_PRODUCT_ENTREGA_CENTRONICS,
0,
"Entrega",
"Centronics connector",
},
{
+ USB_VENDOR_ENTREGA, USB_PRODUCT_ENTREGA_1S9,
+ 0,
+ "Entrega",
+ "1S9 serial connector",
+ },
+ {
USB_VENDOR_ENTREGA, USB_PRODUCT_ENTREGA_SERIAL,
0,
"Entrega",
@@ -520,6 +592,12 @@ struct usb_knowndev usb_knowndevs[] = {
NULL,
},
{
+ USB_VENDOR_KAWATSU, 0,
+ USB_KNOWNDEV_NOPROD,
+ "Kawatsu Semiconductor, Inc.",
+ NULL,
+ },
+ {
USB_VENDOR_AKS, 0,
USB_KNOWNDEV_NOPROD,
"Fast Security AG",
@@ -598,6 +676,12 @@ struct usb_knowndev usb_knowndevs[] = {
NULL,
},
{
+ USB_VENDOR_PIENGINEERING, 0,
+ USB_KNOWNDEV_NOPROD,
+ "P.I. Engineering",
+ NULL,
+ },
+ {
USB_VENDOR_CHIC, 0,
USB_KNOWNDEV_NOPROD,
"Chic Technology",
@@ -622,6 +706,18 @@ struct usb_knowndev usb_knowndevs[] = {
NULL,
},
{
+ USB_VENDOR_SIIG, 0,
+ USB_KNOWNDEV_NOPROD,
+ "SIIG",
+ NULL,
+ },
+ {
+ USB_VENDOR_ACTIVEWIRE, 0,
+ USB_KNOWNDEV_NOPROD,
+ "ActiveWire Inc.",
+ NULL,
+ },
+ {
USB_VENDOR_PLX, 0,
USB_KNOWNDEV_NOPROD,
"PLX",
diff --git a/sys/dev/usb/usbdi.c b/sys/dev/usb/usbdi.c
index 56afce1..f07d00f 100644
--- a/sys/dev/usb/usbdi.c
+++ b/sys/dev/usb/usbdi.c
@@ -1,4 +1,4 @@
-/* $NetBSD: usbdi.c,v 1.20 1999/01/08 11:58:26 augustss Exp $ */
+/* $NetBSD: usbdi.c,v 1.37 1999/09/11 08:19:27 augustss Exp $ */
/* $FreeBSD$ */
/*
@@ -41,9 +41,9 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
-#if defined(__NetBSD__)
+#if defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/device.h>
-#else
+#elif defined(__FreeBSD__)
#include <sys/module.h>
#include <sys/bus.h>
#include <sys/conf.h>
@@ -51,16 +51,18 @@
#include <sys/malloc.h>
#include <sys/proc.h>
-#include <dev/usb/usb.h>
+#include <machine/bus.h>
+#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdi_util.h>
#include <dev/usb/usbdivar.h>
+#include <dev/usb/usb_mem.h>
#if defined(__FreeBSD__)
#include "usb_if.h"
#endif
-
+
#ifdef USB_DEBUG
#define DPRINTF(x) if (usbdebug) logprintf x
#define DPRINTFN(n,x) if (usbdebug>(n)) logprintf x
@@ -71,41 +73,42 @@ extern int usbdebug;
#endif
static usbd_status usbd_ar_pipe __P((usbd_pipe_handle pipe));
-static usbd_status usbd_ar_iface __P((usbd_interface_handle iface));
-static void usbd_transfer_cb __P((usbd_request_handle reqh));
-static void usbd_sync_transfer_cb __P((usbd_request_handle reqh));
-static usbd_status usbd_do_transfer __P((usbd_request_handle reqh));
void usbd_do_request_async_cb
__P((usbd_request_handle, usbd_private_handle, usbd_status));
+void usbd_start_next __P((usbd_pipe_handle pipe));
-static SIMPLEQ_HEAD(, usbd_request) usbd_free_requests;
+static SIMPLEQ_HEAD(, usbd_request) usbd_free_requests
+ = SIMPLEQ_HEAD_INITIALIZER(usbd_free_requests);
+
+static __inline int usbd_reqh_isread __P((usbd_request_handle reqh));
+static __inline int
+usbd_reqh_isread(reqh)
+ usbd_request_handle reqh;
+{
+ if (reqh->rqflags & URQ_REQUEST)
+ return (reqh->request.bmRequestType & UT_READ);
+ else
+ return (reqh->pipe->endpoint->edesc->bEndpointAddress &
+ UE_DIR_IN);
+}
#ifdef USB_DEBUG
-char *usbd_error_strs[USBD_ERROR_MAX] = {
- "NORMAL_COMPLETION",
- "IN_PROGRESS",
- "PENDING_REQUESTS",
- "NOT_STARTED",
- "INVAL",
- "IS_IDLE",
- "NOMEM",
- "CANCELLED",
- "BAD_ADDRESS",
- "IN_USE",
- "INTERFACE_NOT_ACTIVE",
- "NO_ADDR",
- "SET_ADDR_FAILED",
- "NO_POWER",
- "TOO_DEEP",
- "IOERROR",
- "NOT_CONFIGURED",
- "TIMEOUT",
- "SHORT_XFER",
- "STALLED",
- "XXX",
-};
-#endif
+void usbd_dump_queue __P((usbd_pipe_handle));
+void
+usbd_dump_queue(pipe)
+ usbd_pipe_handle pipe;
+{
+ usbd_request_handle reqh;
+
+ printf("usbd_dump_queue: pipe=%p\n", pipe);
+ for (reqh = SIMPLEQ_FIRST(&pipe->queue);
+ reqh;
+ reqh = SIMPLEQ_NEXT(reqh, next)) {
+ printf(" reqh=%p\n", reqh);
+ }
+}
+#endif
usbd_status
usbd_open_pipe(iface, address, flags, pipe)
@@ -119,8 +122,6 @@ usbd_open_pipe(iface, address, flags, pipe)
usbd_status r;
int i;
- if (iface->state != USBD_INTERFACE_ACTIVE)
- return (USBD_INTERFACE_NOT_ACTIVE);
for (i = 0; i < iface->idesc->bNumEndpoints; i++) {
ep = &iface->endpoints[i];
if (ep->edesc->bEndpointAddress == address)
@@ -154,59 +155,30 @@ usbd_open_pipe_intr(iface, address, flags, pipe, priv, buffer, length, cb)
usbd_request_handle reqh;
usbd_pipe_handle ipipe;
- reqh = usbd_alloc_request();
- if (reqh == 0)
- return (USBD_NOMEM);
r = usbd_open_pipe(iface, address, USBD_EXCLUSIVE_USE, &ipipe);
if (r != USBD_NORMAL_COMPLETION)
+ return (r);
+ reqh = usbd_alloc_request(iface->device);
+ if (reqh == 0) {
+ r = USBD_NOMEM;
goto bad1;
- r = usbd_setup_request(reqh, ipipe, priv, buffer, length,
- USBD_XFER_IN | flags, USBD_NO_TIMEOUT, cb);
- if (r != USBD_NORMAL_COMPLETION)
- goto bad2;
+ }
+ usbd_setup_request(reqh, ipipe, priv, buffer, length, flags,
+ USBD_NO_TIMEOUT, cb);
ipipe->intrreqh = reqh;
+ ipipe->repeat = 1;
r = usbd_transfer(reqh);
*pipe = ipipe;
if (r != USBD_IN_PROGRESS)
- goto bad3;
+ goto bad2;
return (USBD_NORMAL_COMPLETION);
- bad3:
- ipipe->intrreqh = 0;
bad2:
- usbd_close_pipe(ipipe);
- bad1:
+ ipipe->intrreqh = 0;
+ ipipe->repeat = 0;
usbd_free_request(reqh);
- return r;
-}
-
-usbd_status
-usbd_open_pipe_iso(iface, address, flags, pipe, priv, bufsize, nbuf, cb)
- usbd_interface_handle iface;
- u_int8_t address;
- u_int8_t flags;
- usbd_pipe_handle *pipe;
- usbd_private_handle priv;
- u_int32_t bufsize;
- u_int32_t nbuf;
- usbd_callback cb;
-{
- usbd_status r;
- usbd_pipe_handle p;
-
- r = usbd_open_pipe(iface, address, USBD_EXCLUSIVE_USE, &p);
- if (r != USBD_NORMAL_COMPLETION)
- return (r);
- if (!p->methods->isobuf) {
- usbd_close_pipe(p);
- return (USBD_INVAL);
- }
- r = p->methods->isobuf(p, bufsize, nbuf);
- if (r != USBD_NORMAL_COMPLETION) {
- usbd_close_pipe(p);
- return (r);
- }
- *pipe = p;
+ bad1:
+ usbd_close_pipe(ipipe);
return r;
}
@@ -214,8 +186,13 @@ usbd_status
usbd_close_pipe(pipe)
usbd_pipe_handle pipe;
{
- if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
- return (USBD_INTERFACE_NOT_ACTIVE);
+#ifdef DIAGNOSTIC
+ if (pipe == 0) {
+ printf("usbd_close_pipe: pipe==NULL\n");
+ return (USBD_NORMAL_COMPLETION);
+ }
+#endif
+
if (--pipe->refcnt != 0)
return (USBD_NORMAL_COMPLETION);
if (SIMPLEQ_FIRST(&pipe->queue) != 0)
@@ -229,42 +206,125 @@ usbd_close_pipe(pipe)
return (USBD_NORMAL_COMPLETION);
}
-usbd_status
+usbd_status
usbd_transfer(reqh)
usbd_request_handle reqh;
{
- reqh->xfercb = usbd_transfer_cb;
- return (usbd_do_transfer(reqh));
+ usbd_pipe_handle pipe = reqh->pipe;
+ usbd_status r;
+ u_int size;
+ int s;
+
+ DPRINTFN(5,("usbd_transfer: reqh=%p, flags=%d, pipe=%p, running=%d\n",
+ reqh, reqh->flags, pipe, pipe->running));
+#ifdef USB_DEBUG
+ if (usbdebug > 5)
+ usbd_dump_queue(pipe);
+#endif
+ reqh->done = 0;
+
+ size = reqh->length;
+ /* If there is no buffer, allocate one and copy data. */
+ if (!(reqh->rqflags & URQ_DEV_DMABUF) && size != 0) {
+ usb_dma_t *dmap = &reqh->dmabuf;
+ struct usbd_bus *bus = pipe->device->bus;
+
+#ifdef DIAGNOSTIC
+ if (reqh->rqflags & URQ_AUTO_DMABUF)
+ printf("usbd_transfer: has old buffer!\n");
+#endif
+ r = bus->methods->allocm(bus, dmap, size);
+ if (r != USBD_NORMAL_COMPLETION)
+ return (r);
+ reqh->rqflags |= URQ_AUTO_DMABUF;
+
+ /* finally copy data if going out */
+ if (!usbd_reqh_isread(reqh))
+ memcpy(KERNADDR(dmap), reqh->buffer, size);
+ }
+
+ r = pipe->methods->transfer(reqh);
+
+ if (r != USBD_IN_PROGRESS && r != USBD_NORMAL_COMPLETION) {
+ /* The transfer has not been queued, so free buffer. */
+ if (reqh->rqflags & URQ_AUTO_DMABUF) {
+ struct usbd_bus *bus = pipe->device->bus;
+
+ bus->methods->freem(bus, &reqh->dmabuf);
+ reqh->rqflags &= ~URQ_AUTO_DMABUF;
+ }
+ }
+
+ if (!(reqh->flags & USBD_SYNCHRONOUS))
+ return (r);
+
+ /* Sync transfer, wait for completion. */
+ if (r != USBD_IN_PROGRESS)
+ return (r);
+ s = splusb();
+ if (!reqh->done) {
+ if (pipe->device->bus->use_polling)
+ panic("usbd_transfer: not done\n");
+ tsleep(reqh, PRIBIO, "usbsyn", 0);
+ }
+ splx(s);
+ return (reqh->status);
+}
+
+/* Like usbd_transfer(), but waits for completion. */
+usbd_status
+usbd_sync_transfer(reqh)
+ usbd_request_handle reqh;
+{
+ reqh->flags |= USBD_SYNCHRONOUS;
+ return (usbd_transfer(reqh));
}
-static usbd_status
-usbd_do_transfer(reqh)
+void *
+usbd_alloc_buffer(reqh, size)
usbd_request_handle reqh;
+ u_int32_t size;
{
- usbd_pipe_handle pipe = reqh->pipe;
+ struct usbd_bus *bus = reqh->device->bus;
+ usbd_status r;
- DPRINTFN(10,("usbd_do_transfer: reqh=%p\n", reqh));
- reqh->done = 0;
- return (pipe->methods->transfer(reqh));
+ r = bus->methods->allocm(bus, &reqh->dmabuf, size);
+ if (r != USBD_NORMAL_COMPLETION)
+ return (0);
+ reqh->rqflags |= URQ_DEV_DMABUF;
+ return (KERNADDR(&reqh->dmabuf));
+}
+
+void
+usbd_free_buffer(reqh)
+ usbd_request_handle reqh;
+{
+#ifdef DIAGNOSTIC
+ if (!(reqh->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF))) {
+ printf("usbd_free_buffer: no buffer\n");
+ return;
+ }
+#endif
+ reqh->rqflags &= ~(URQ_DEV_DMABUF | URQ_AUTO_DMABUF);
+ reqh->device->bus->methods->freem(reqh->device->bus, &reqh->dmabuf);
}
usbd_request_handle
-usbd_alloc_request()
+usbd_alloc_request(dev)
+ usbd_device_handle dev;
{
usbd_request_handle reqh;
reqh = SIMPLEQ_FIRST(&usbd_free_requests);
if (reqh)
-#if defined(__NetBSD__)
SIMPLEQ_REMOVE_HEAD(&usbd_free_requests, reqh, next);
-#elif defined(__FreeBSD__)
- SIMPLEQ_REMOVE_HEAD(&usbd_free_requests, next);
-#endif
else
reqh = malloc(sizeof(*reqh), M_USB, M_NOWAIT);
if (!reqh)
return (0);
memset(reqh, 0, sizeof *reqh);
+ reqh->device = dev;
+ DPRINTFN(5,("usbd_alloc_request() = %p\n", reqh));
return (reqh);
}
@@ -272,11 +332,14 @@ usbd_status
usbd_free_request(reqh)
usbd_request_handle reqh;
{
+ DPRINTFN(5,("usbd_free_request: %p\n", reqh));
+ if (reqh->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF))
+ usbd_free_buffer(reqh);
SIMPLEQ_INSERT_HEAD(&usbd_free_requests, reqh, next);
return (USBD_NORMAL_COMPLETION);
}
-usbd_status
+void
usbd_setup_request(reqh, pipe, priv, buffer, length, flags, timeout, callback)
usbd_request_handle reqh;
usbd_pipe_handle pipe;
@@ -298,22 +361,11 @@ usbd_setup_request(reqh, pipe, priv, buffer, length, flags, timeout, callback)
reqh->timeout = timeout;
reqh->status = USBD_NOT_STARTED;
reqh->callback = callback;
- reqh->retries = 1;
- reqh->isreq = 0;
- return (USBD_NORMAL_COMPLETION);
+ reqh->rqflags &= ~URQ_REQUEST;
+ reqh->nframes = 0;
}
-usbd_status
-usbd_setup_device_request(reqh, req)
- usbd_request_handle reqh;
- usb_device_request_t *req;
-{
- reqh->isreq = 1;
- reqh->request = *req;
- return (USBD_NORMAL_COMPLETION);
-}
-
-usbd_status
+void
usbd_setup_default_request(reqh, dev, priv, timeout, req, buffer,
length, flags, callback)
usbd_request_handle reqh;
@@ -338,21 +390,34 @@ usbd_setup_default_request(reqh, dev, priv, timeout, req, buffer,
reqh->status = USBD_NOT_STARTED;
reqh->callback = callback;
reqh->request = *req;
- reqh->retries = 1;
- reqh->isreq = 1;
- return (USBD_NORMAL_COMPLETION);
+ reqh->rqflags |= URQ_REQUEST;
+ reqh->nframes = 0;
}
-usbd_status
-usbd_set_request_timeout(reqh, timeout)
+void
+usbd_setup_isoc_request(reqh, pipe, priv, frlengths, nframes, callback)
usbd_request_handle reqh;
- u_int32_t timeout;
+ usbd_pipe_handle pipe;
+ usbd_private_handle priv;
+ u_int16_t *frlengths;
+ u_int32_t nframes;
+ usbd_callback callback;
{
- reqh->timeout = timeout;
- return (USBD_NORMAL_COMPLETION);
+ reqh->pipe = pipe;
+ reqh->priv = priv;
+ reqh->buffer = 0;
+ reqh->length = 0;
+ reqh->actlen = 0;
+ reqh->flags = 0;
+ reqh->timeout = USBD_NO_TIMEOUT;
+ reqh->status = USBD_NOT_STARTED;
+ reqh->callback = callback;
+ reqh->rqflags &= ~URQ_REQUEST;
+ reqh->frlengths = frlengths;
+ reqh->nframes = nframes;
}
-usbd_status
+void
usbd_get_request_status(reqh, priv, buffer, count, status)
usbd_request_handle reqh;
usbd_private_handle *priv;
@@ -368,29 +433,8 @@ usbd_get_request_status(reqh, priv, buffer, count, status)
*count = reqh->actlen;
if (status)
*status = reqh->status;
-
- return (USBD_NORMAL_COMPLETION);
-}
-
-usbd_status
-usbd_request_device_data(reqh, req)
- usbd_request_handle reqh;
- usb_device_request_t *req;
-{
- if (!reqh->isreq)
- return (USBD_INVAL);
- *req = reqh->request;
- return (USBD_NORMAL_COMPLETION);
}
-#if 0
-usb_descriptor_t *
-usbd_get_descriptor(iface, desc_type)
- usbd_interface_handle *iface;
- u_int8_t desc_type;
-XX
-#endif
-
usb_config_descriptor_t *
usbd_get_config_descriptor(dev)
usbd_device_handle dev;
@@ -423,91 +467,24 @@ usbd_interface2endpoint_descriptor(iface, index)
}
usbd_status
-usbd_set_configuration(dev, conf)
- usbd_device_handle dev;
- u_int8_t conf;
-{
- return usbd_set_config_no(dev, conf, 0);
-}
-
-usbd_status
-usbd_retry_request(reqh, retry_count)
- usbd_request_handle reqh;
- u_int32_t retry_count;
-{
- usbd_status r;
-
- r = usbd_set_pipe_state(reqh->pipe, USBD_PIPE_ACTIVE);
- if (r != USBD_NORMAL_COMPLETION)
- return (r);
- reqh->retries = retry_count;
- return (usbd_transfer(reqh));
-}
-
-usbd_status
usbd_abort_pipe(pipe)
usbd_pipe_handle pipe;
{
usbd_status r;
- int s, state;
-
- if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
- return (USBD_INTERFACE_NOT_ACTIVE);
- s = splusb();
- state = pipe->state;
- r = usbd_ar_pipe(pipe);
- pipe->state = state;
- splx(s);
- return (r);
-}
-
-usbd_status
-usbd_abort_interface(iface)
- usbd_interface_handle iface;
-{
- usbd_status r;
- int s, st;
-
- s = splusb();
- st = iface->state;
- r = usbd_ar_iface(iface);
- iface->state = st;
- splx(s);
- return (r);
-}
-
-usbd_status
-usbd_reset_pipe(pipe)
- usbd_pipe_handle pipe;
-{
- usbd_status r;
int s;
- if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
- return (USBD_INTERFACE_NOT_ACTIVE);
+#ifdef DIAGNOSTIC
+ if (pipe == 0) {
+ printf("usbd_close_pipe: pipe==NULL\n");
+ return (USBD_NORMAL_COMPLETION);
+ }
+#endif
s = splusb();
r = usbd_ar_pipe(pipe);
- /* XXX anything else */
- pipe->state = USBD_PIPE_ACTIVE;
- splx(s);
- return (r);
-}
-
-usbd_status
-usbd_reset_interface(iface)
- usbd_interface_handle iface;
-{
- usbd_status r;
- int s;
-
- s = splusb();
- r = usbd_ar_iface(iface);
- /* XXX anything else */
- iface->state = USBD_INTERFACE_ACTIVE;
splx(s);
return (r);
}
-
+
usbd_status
usbd_clear_endpoint_stall(pipe)
usbd_pipe_handle pipe;
@@ -516,6 +493,14 @@ usbd_clear_endpoint_stall(pipe)
usb_device_request_t req;
usbd_status r;
+ DPRINTFN(8, ("usbd_clear_endpoint_stall\n"));
+
+ /*
+ * Clearing en endpoint stall resets the enpoint toggle, so
+ * do the same to the HC toggle.
+ */
+ pipe->methods->cleartoggle(pipe);
+
req.bmRequestType = UT_WRITE_ENDPOINT;
req.bRequest = UR_CLEAR_FEATURE;
USETW(req.wValue, UF_ENDPOINT_HALT);
@@ -540,6 +525,8 @@ usbd_clear_endpoint_stall_async(pipe)
usb_device_request_t req;
usbd_status r;
+ pipe->methods->cleartoggle(pipe);
+
req.bmRequestType = UT_WRITE_ENDPOINT;
req.bRequest = UR_CLEAR_FEATURE;
USETW(req.wValue, UF_ENDPOINT_HALT);
@@ -550,126 +537,6 @@ usbd_clear_endpoint_stall_async(pipe)
}
usbd_status
-usbd_set_pipe_state(pipe, state)
- usbd_pipe_handle pipe;
- usbd_pipe_state state;
-{
- int s;
- usbd_status r;
- usbd_request_handle reqh;
-
- if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
- return (USBD_INTERFACE_NOT_ACTIVE);
- if (state != USBD_PIPE_ACTIVE &&
- state != USBD_PIPE_STALLED &&
- state != USBD_PIPE_IDLE)
- return (USBD_INVAL);
- pipe->state = state;
- r = USBD_NORMAL_COMPLETION;
- if (state == USBD_PIPE_ACTIVE) {
- s = splusb();
- if (!pipe->running) {
- reqh = SIMPLEQ_FIRST(&pipe->queue);
- if (reqh != 0) {
- pipe->running = 1;
- splx(s);
- r = pipe->methods->start(reqh);
- } else
- splx(s);
- } else
- splx(s);
- }
- return (r);
-}
-
-usbd_status
-usbd_get_pipe_state(pipe, state, endpoint_state, request_count)
- usbd_pipe_handle pipe;
- usbd_pipe_state *state;
- u_int32_t *endpoint_state;
- u_int32_t *request_count;
-{
- int n;
- usbd_request_handle r;
-
- *state = pipe->state;
- *endpoint_state = pipe->endpoint->state;
- for (r = SIMPLEQ_FIRST(&pipe->queue), n = 0;
- r != 0;
- r = SIMPLEQ_NEXT(r, next), n++)
- ;
- *request_count = n;
- return (USBD_NORMAL_COMPLETION);
-}
-
-usbd_status
-usbd_set_interface_state(iface, state)
- usbd_interface_handle iface;
- usbd_interface_state state;
-{
- int ps;
- usbd_pipe_handle p;
-
- if (state == USBD_INTERFACE_ACTIVE)
- ps = USBD_PIPE_ACTIVE;
- else if (state == USBD_INTERFACE_STALLED)
- ps = USBD_PIPE_STALLED;
- else if (state == USBD_INTERFACE_IDLE)
- ps = USBD_PIPE_IDLE;
- else
- return (USBD_INVAL);
- iface->state = USBD_INTERFACE_ACTIVE; /* to allow setting the pipe */
- for (p = LIST_FIRST(&iface->pipes); p != 0; p = LIST_NEXT(p, next))
- usbd_set_pipe_state(p, ps);
- iface->state = state;
- return (USBD_NORMAL_COMPLETION);
-}
-
-usbd_status
-usbd_get_interface_state(iface, state)
- usbd_interface_handle iface;
- usbd_interface_state *state;
-{
- *state = iface->state;
- return (USBD_NORMAL_COMPLETION);
-}
-
-usbd_status
-usbd_get_device_state(dev, state)
- usbd_device_handle dev;
- usbd_device_state *state;
-{
- *state = dev->state;
- return (USBD_NORMAL_COMPLETION);
-}
-
-#if 0
-usbd_status
-usbd_set_device_state(dev, state)
- usbd_device_handle dev;
- usbd_device_state state;
-X
-#endif
-
-usbd_status
-usbd_device_address(dev, address)
- usbd_device_handle dev;
- u_int8_t *address;
-{
- *address = dev->address;
- return (USBD_NORMAL_COMPLETION);
-}
-
-usbd_status
-usbd_endpoint_address(pipe, address)
- usbd_pipe_handle pipe;
- u_int8_t *address;
-{
- *address = pipe->endpoint->edesc->bEndpointAddress;
- return (USBD_NORMAL_COMPLETION);
-}
-
-usbd_status
usbd_endpoint_count(iface, count)
usbd_interface_handle iface;
u_int8_t *count;
@@ -689,73 +556,6 @@ usbd_interface_count(dev, count)
return (USBD_NORMAL_COMPLETION);
}
-#if 0
-u_int8_t
-usbd_bus_count()
-{
- return (usb_bus_count());
-}
-
-usbd_status
-usbd_get_bus_handle(index, bus)
- u_int8_t index;
- usbd_bus_handle *bus;
-{
- return (usb_get_bus_handle(index, bus));
-}
-
-usbd_status
-usbd_get_root_hub(bus, dev)
- usbd_bus_handle bus;
- usbd_device_handle *dev;
-{
- *dev = bus->root_hub;
- return (USBD_NORMAL_COMPLETION);
-}
-
-usbd_status
-usbd_port_count(dev, nports)
- usbd_device_handle dev;
- u_int8_t *nports;
-{
- if (dev->hub == 0)
- return (USBD_INVAL);
- *nports = dev->hub->hubdesc.bNbrPorts;
- return (USBD_NORMAL_COMPLETION);
-}
-
-usbd_status
-usbd_hub2device_handle(dev, port, devp)
- usbd_device_handle dev;
- u_int8_t port;
- usbd_device_handle *devp;
-{
- if (dev->hub == 0 || port >= dev->hub->hubdesc.bNbrPorts ||
- dev->hub->ports[port].device == 0)
- return (USBD_INVAL);
- *devp = dev->hub->ports[port].device;
- return (USBD_NORMAL_COMPLETION);
-}
-#endif
-
-usbd_status
-usbd_request2pipe_handle(reqh, pipe)
- usbd_request_handle reqh;
- usbd_pipe_handle *pipe;
-{
- *pipe = reqh->pipe;
- return (USBD_NORMAL_COMPLETION);
-}
-
-usbd_status
-usbd_pipe2interface_handle(pipe, iface)
- usbd_pipe_handle pipe;
- usbd_interface_handle *iface;
-{
- *iface = pipe->iface;
- return (USBD_NORMAL_COMPLETION);
-}
-
usbd_status
usbd_interface2device_handle(iface, dev)
usbd_interface_handle iface;
@@ -766,15 +566,6 @@ usbd_interface2device_handle(iface, dev)
}
usbd_status
-usbd_device2bus_handle(dev, bus)
- usbd_device_handle dev;
- usbd_bus_handle *bus;
-{
- *bus = dev->bus;
- return (USBD_NORMAL_COMPLETION);
-}
-
-usbd_status
usbd_device2interface_handle(dev, ifaceno, iface)
usbd_device_handle dev;
u_int8_t ifaceno;
@@ -788,51 +579,11 @@ usbd_device2interface_handle(dev, ifaceno, iface)
return (USBD_NORMAL_COMPLETION);
}
-usbd_status
-usbd_set_interface_private_handle(iface, priv)
- usbd_interface_handle iface;
- usbd_private_handle priv;
-{
- iface->priv = priv;
- return (USBD_NORMAL_COMPLETION);
-}
-
-usbd_status
-usbd_get_interface_private_handle(iface, priv)
- usbd_interface_handle iface;
- usbd_private_handle *priv;
-{
- *priv = iface->priv;
- return (USBD_NORMAL_COMPLETION);
-}
-
-usbd_status
-usbd_reference_pipe(pipe)
- usbd_pipe_handle pipe;
-{
- pipe->refcnt++;
- return (USBD_NORMAL_COMPLETION);
-}
-
-usbd_status
-usbd_dereference_pipe(pipe)
+usbd_device_handle
+usbd_pipe2device_handle(pipe)
usbd_pipe_handle pipe;
{
- pipe->refcnt--;
- return (USBD_NORMAL_COMPLETION);
-}
-
-usbd_lock_token
-usbd_lock()
-{
- return (splusb());
-}
-
-void
-usbd_unlock(tok)
- usbd_lock_token tok;
-{
- splx(tok);
+ return (pipe->device);
}
/* XXXX use altno */
@@ -851,7 +602,6 @@ usbd_set_interface(iface, altidx)
free(iface->endpoints, M_USB);
iface->endpoints = 0;
iface->idesc = 0;
- iface->state = USBD_INTERFACE_IDLE;
r = usbd_fill_iface_data(iface->device, iface->index, altidx);
if (r != USBD_NORMAL_COMPLETION)
@@ -916,66 +666,70 @@ usbd_ar_pipe(pipe)
{
usbd_request_handle reqh;
+ DPRINTFN(2,("usbd_ar_pipe: pipe=%p\n", pipe));
+#ifdef USB_DEBUG
+ if (usbdebug > 5)
+ usbd_dump_queue(pipe);
+#endif
while ((reqh = SIMPLEQ_FIRST(&pipe->queue))) {
+ DPRINTFN(2,("usbd_ar_pipe: pipe=%p reqh=%p (methods=%p)\n",
+ pipe, reqh, pipe->methods));
+ /* Make the HC abort it (and invoke the callback). */
pipe->methods->abort(reqh);
-#if defined(__NetBSD__)
- SIMPLEQ_REMOVE_HEAD(&pipe->queue, reqh, next);
-#elif defined(__FreeBSD__)
- SIMPLEQ_REMOVE_HEAD(&pipe->queue, next);
-#endif
- /* XXX should the callback not be called something
- * else than splusb? Create a new list of reqh and
- * execute them after the while for example?
- */
- reqh->status = USBD_CANCELLED;
- if (reqh->callback)
- reqh->callback(reqh, reqh->priv, reqh->status);
+ /* XXX only for non-0 usbd_clear_endpoint_stall(pipe); */
}
-
return (USBD_NORMAL_COMPLETION);
}
-/* Dequeue all interface operations, called at splusb(). */
-static usbd_status
-usbd_ar_iface(iface)
- usbd_interface_handle iface;
+void
+usb_transfer_complete(reqh)
+ usbd_request_handle reqh;
{
- usbd_pipe_handle p;
- usbd_status r, ret = USBD_NORMAL_COMPLETION;
+ usbd_pipe_handle pipe = reqh->pipe;
+ int polling;
- for (p = LIST_FIRST(&iface->pipes); p != 0; p = LIST_NEXT(p, next)) {
- r = usbd_ar_pipe(p);
- if (r != USBD_NORMAL_COMPLETION)
- ret = r;
+ DPRINTFN(5, ("usb_transfer_complete: pipe=%p reqh=%p actlen=%d\n",
+ pipe, reqh, reqh->actlen));
+
+#ifdef DIAGNOSTIC
+ if (!pipe) {
+ printf("usbd_transfer_cb: pipe==0, reqh=%p\n", reqh);
+ return;
}
- return (ret);
-}
+#endif
-static int usbd_global_init_done = 0;
+ polling = pipe->device->bus->use_polling;
+ /* XXXX */
+ if (polling)
+ pipe->running = 0;
+
+ /* if we allocated the buffer in usbd_transfer() we free it here. */
+ if (reqh->rqflags & URQ_AUTO_DMABUF) {
+ usb_dma_t *dmap = &reqh->dmabuf;
+
+ if (usbd_reqh_isread(reqh))
+ memcpy(reqh->buffer, KERNADDR(dmap), reqh->actlen);
+ if (!pipe->repeat) {
+ struct usbd_bus *bus = pipe->device->bus;
+ bus->methods->freem(bus, dmap);
+ reqh->rqflags &= ~URQ_AUTO_DMABUF;
+ }
+ }
-void
-usbd_init()
-{
- if (!usbd_global_init_done) {
- usbd_global_init_done = 1;
- SIMPLEQ_INIT(&usbd_free_requests);
+ if (pipe->methods->done)
+ pipe->methods->done(reqh);
-#if defined(__FreeBSD__)
- cdevsw_add(&usb_cdevsw);
-#endif
- }
-}
+ /* Remove request from queue. */
+ if ( reqh == SIMPLEQ_FIRST(&pipe->queue) )
+ SIMPLEQ_REMOVE_HEAD(&pipe->queue, reqh, next);
+ else
+ DPRINTF(("XXX duplicated call to usb_transfer_complete\n"));
-static void
-usbd_transfer_cb(reqh)
- usbd_request_handle reqh;
-{
- usbd_pipe_handle pipe = reqh->pipe;
/* Count completed transfers. */
- ++pipe->device->bus->stats.requests[pipe->endpoint->edesc->bmAttributes & UE_XFERTYPE];
+ ++pipe->device->bus->stats.requests
+ [pipe->endpoint->edesc->bmAttributes & UE_XFERTYPE];
- /* XXX check retry count */
reqh->done = 1;
if (reqh->status == USBD_NORMAL_COMPLETION &&
reqh->actlen < reqh->length &&
@@ -984,40 +738,73 @@ usbd_transfer_cb(reqh)
reqh->actlen, reqh->length));
reqh->status = USBD_SHORT_XFER;
}
-
+
if (reqh->callback)
reqh->callback(reqh, reqh->priv, reqh->status);
-}
-static void
-usbd_sync_transfer_cb(reqh)
- usbd_request_handle reqh;
-{
- usbd_transfer_cb(reqh);
- if (!reqh->pipe->device->bus->use_polling)
+ if ((reqh->flags & USBD_SYNCHRONOUS) && !polling)
wakeup(reqh);
+
+ if (!pipe->repeat &&
+ reqh->status != USBD_CANCELLED && reqh->status != USBD_TIMEOUT)
+ usbd_start_next(pipe);
}
-/* Like usbd_transfer(), but waits for completion. */
usbd_status
-usbd_sync_transfer(reqh)
+usb_insert_transfer(reqh)
usbd_request_handle reqh;
{
+ usbd_pipe_handle pipe = reqh->pipe;
usbd_status r;
int s;
- reqh->xfercb = usbd_sync_transfer_cb;
- r = usbd_do_transfer(reqh);
- if (r != USBD_IN_PROGRESS)
- return (r);
+ DPRINTFN(5,("usb_insert_transfer: pipe=%p running=%d\n", pipe,
+ pipe->running));
s = splusb();
- if (!reqh->done) {
- if (reqh->pipe->device->bus->use_polling)
- panic("usbd_sync_transfer: not done\n");
- tsleep(reqh, PRIBIO, "usbsyn", 0);
+ SIMPLEQ_INSERT_TAIL(&pipe->queue, reqh, next);
+ if (pipe->running)
+ r = USBD_IN_PROGRESS;
+ else {
+ pipe->running = 1;
+ r = USBD_NORMAL_COMPLETION;
}
splx(s);
- return (reqh->status);
+ return (r);
+}
+
+void
+usbd_start_next(pipe)
+ usbd_pipe_handle pipe;
+{
+ usbd_request_handle reqh;
+ usbd_status r;
+
+ DPRINTFN(10, ("usbd_start_next: pipe=%p\n", pipe));
+
+#ifdef DIAGNOSTIC
+ if (!pipe) {
+ printf("usbd_start_next: pipe == 0\n");
+ return;
+ }
+ if (!pipe->methods || !pipe->methods->start) {
+ printf("usbd_start_next: no start method\n");
+ return;
+ }
+#endif
+
+ /* Get next request in queue. */
+ reqh = SIMPLEQ_FIRST(&pipe->queue);
+ DPRINTFN(5, ("usbd_start_next: pipe=%p start reqh=%p\n", pipe, reqh));
+ if (!reqh)
+ pipe->running = 0;
+ else {
+ r = pipe->methods->start(reqh);
+ if (r != USBD_IN_PROGRESS) {
+ printf("usbd_start_next: error=%d\n", r);
+ pipe->running = 0;
+ /* XXX do what? */
+ }
+ }
}
usbd_status
@@ -1043,34 +830,28 @@ usbd_do_request_flags(dev, req, data, flags, actlen)
#ifdef DIAGNOSTIC
if (!curproc) {
printf("usbd_do_request: not in process context\n");
- return (USBD_XXX);
+ return (USBD_INVAL);
}
#endif
- reqh = usbd_alloc_request();
+ reqh = usbd_alloc_request(dev);
if (reqh == 0)
return (USBD_NOMEM);
- r = usbd_setup_default_request(
- reqh, dev, 0, USBD_DEFAULT_TIMEOUT, req, data,
- UGETW(req->wLength), flags, 0);
- if (r != USBD_NORMAL_COMPLETION)
- goto bad;
+ usbd_setup_default_request(reqh, dev, 0, USBD_DEFAULT_TIMEOUT, req,
+ data, UGETW(req->wLength), flags, 0);
r = usbd_sync_transfer(reqh);
-
#if defined(USB_DEBUG) || defined(DIAGNOSTIC)
if (reqh->actlen > reqh->length)
- printf("usbd_do_request: overrun addr=%d type=0x%02x req=0x"
- "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
- dev->address, reqh->request.bmRequestType,
- reqh->request.bRequest, UGETW(reqh->request.wValue),
- UGETW(reqh->request.wIndex),
- UGETW(reqh->request.wLength),
- reqh->length, reqh->actlen);
+ DPRINTF(("usbd_do_request: overrun addr=%d type=0x%02x req=0x"
+ "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
+ dev->address, reqh->request.bmRequestType,
+ reqh->request.bRequest, UGETW(reqh->request.wValue),
+ UGETW(reqh->request.wIndex),
+ UGETW(reqh->request.wLength),
+ reqh->length, reqh->actlen));
#endif
-
if (actlen)
*actlen = reqh->actlen;
-
if (r == USBD_STALLED) {
/*
* The control endpoint has stalled. Control endpoints
@@ -1087,11 +868,9 @@ usbd_do_request_flags(dev, req, data, flags, actlen)
USETW(treq.wValue, 0);
USETW(treq.wIndex, 0);
USETW(treq.wLength, sizeof(usb_status_t));
- nr = usbd_setup_default_request(
- reqh, dev, 0, USBD_DEFAULT_TIMEOUT, &treq, &status,
- sizeof(usb_status_t), 0, 0);
- if (nr != USBD_NORMAL_COMPLETION)
- goto bad;
+ usbd_setup_default_request(reqh, dev, 0, USBD_DEFAULT_TIMEOUT,
+ &treq, &status,sizeof(usb_status_t),
+ 0, 0);
nr = usbd_sync_transfer(reqh);
if (nr != USBD_NORMAL_COMPLETION)
goto bad;
@@ -1104,11 +883,8 @@ usbd_do_request_flags(dev, req, data, flags, actlen)
USETW(treq.wValue, UF_ENDPOINT_HALT);
USETW(treq.wIndex, 0);
USETW(treq.wLength, 0);
- nr = usbd_setup_default_request(
- reqh, dev, 0, USBD_DEFAULT_TIMEOUT, &treq, &status,
- 0, 0, 0);
- if (nr != USBD_NORMAL_COMPLETION)
- goto bad;
+ usbd_setup_default_request(reqh, dev, 0, USBD_DEFAULT_TIMEOUT,
+ &treq, &status, 0, 0, 0);
nr = usbd_sync_transfer(reqh);
if (nr != USBD_NORMAL_COMPLETION)
goto bad;
@@ -1127,14 +903,14 @@ usbd_do_request_async_cb(reqh, priv, status)
{
#if defined(USB_DEBUG) || defined(DIAGNOSTIC)
if (reqh->actlen > reqh->length)
- printf("usbd_do_request: overrun addr=%d type=0x%02x req=0x"
- "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
- reqh->pipe->device->address,
- reqh->request.bmRequestType,
- reqh->request.bRequest, UGETW(reqh->request.wValue),
- UGETW(reqh->request.wIndex),
- UGETW(reqh->request.wLength),
- reqh->length, reqh->actlen);
+ DPRINTF(("usbd_do_request: overrun addr=%d type=0x%02x req=0x"
+ "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
+ reqh->pipe->device->address,
+ reqh->request.bmRequestType,
+ reqh->request.bRequest, UGETW(reqh->request.wValue),
+ UGETW(reqh->request.wIndex),
+ UGETW(reqh->request.wLength),
+ reqh->length, reqh->actlen));
#endif
usbd_free_request(reqh);
}
@@ -1152,19 +928,17 @@ usbd_do_request_async(dev, req, data)
usbd_request_handle reqh;
usbd_status r;
- reqh = usbd_alloc_request();
+ reqh = usbd_alloc_request(dev);
if (reqh == 0)
return (USBD_NOMEM);
- r = usbd_setup_default_request(
- reqh, dev, 0, USBD_DEFAULT_TIMEOUT, req, data,
- UGETW(req->wLength), 0, usbd_do_request_async_cb);
- if (r != USBD_NORMAL_COMPLETION) {
+ usbd_setup_default_request(reqh, dev, 0, USBD_DEFAULT_TIMEOUT, req, data,
+ UGETW(req->wLength), 0,
+ usbd_do_request_async_cb);
+ r = usbd_transfer(reqh);
+ if (r != USBD_IN_PROGRESS) {
usbd_free_request(reqh);
return (r);
}
- r = usbd_transfer(reqh);
- if (r != USBD_IN_PROGRESS)
- return (r);
return (USBD_NORMAL_COMPLETION);
}
@@ -1175,16 +949,6 @@ usbd_get_quirks(dev)
return (dev->quirks);
}
-void
-usbd_set_disco(p, hdl, data)
- usbd_pipe_handle p;
- void (*hdl) __P((void *));
- void *data;
-{
- p->disco = hdl;
- p->discoarg = data;
-}
-
/* XXX do periodic free() of free list */
/*
@@ -1194,7 +958,7 @@ void
usbd_dopoll(iface)
usbd_interface_handle iface;
{
- iface->device->bus->do_poll(iface->device->bus);
+ iface->device->bus->methods->do_poll(iface->device->bus);
}
void
@@ -1224,100 +988,10 @@ usbd_get_endpoint_descriptor(iface, address)
#if defined(__FreeBSD__)
int
-usbd_print_child(device_t parent, device_t child)
-{
- /*
- struct usb_softc *sc = device_get_softc(child);
- */
- int retval = 0;
-
- retval += bus_print_child_header(parent, child);
- retval += bus_print_child_footer(parent, child);
-
- /* XXX How do we get to the usbd_device_handle???
- usbd_device_handle dev = invalidadosch;
-
- retval += printf(" addr %d\n", dev->addr);
-
- if (bootverbose) {
- if (dev->lowspeed)
- retval += printf(", lowspeed");
- if (dev->self_powered)
- retval += printf(", self powered");
- else
- retval += printf(", %dmA", dev->power);
- retval += printf(", config %d", dev->config);
- }
- */
-
- return (retval);
-}
-
-/* Reconfigure all the USB busses in the system. */
-int
usbd_driver_load(module_t mod, int what, void *arg)
{
-#if 1
- return 0;
-#else
- devclass_t usb_devclass = devclass_find("usb");
- devclass_t ugen_devclass = devclass_find("ugen");
- device_t *devlist;
- int devcount;
- int error;
-
- if ( what == MOD_LOAD || what == MOD_UNLOAD ) {
- if (!usb_devclass)
- return 0; /* just ignore call */
-
- /* Detach all the generic devices and do a reconfigure
- * of the bus. This should attach the new driver to anything
- * that is already connected and it can handle.
- * XXX For the moment disabled. The detach does not remove
- * the device from the list of devices attached to the hub.
- * Legacy of converting from NetBSD to FreeBSD.
- */
- if (ugen_devclass) {
- /* detach devices from generic driver if possible */
- error = devclass_get_devices(ugen_devclass, &devlist,
- &devcount);
- if (!error)
- for (devcount--; devcount >= 0; devcount--)
- (void)DEVICE_DETACH(devlist[devcount]);
- free(devlist, M_TEMP);
- }
-
- /* Reconfigure the busses, possibly attaching something to the
- * new driver */
- error = devclass_get_devices(usb_devclass, &devlist, &devcount);
- if (error)
- return 0; /* XXX maybe transient, or error? */
-
- for (devcount--; devcount >= 0; devcount--)
- USB_RECONFIGURE(devlist[devcount]);
-
- free(devlist, M_TEMP);
- }
+ /* XXX should implement something like a function that removes all generic devices */
- return 0; /* nothing to do */
-#endif
+ return 0; /* nothing to do by us */
}
#endif
-
-char *
-usbd_errstr(usbd_status err)
-{
- static char buffer[5]; /* XXX static buffer */
-
-#ifdef USB_DEBUG
- if ( err < USBD_ERROR_MAX ) {
- return usbd_error_strs[err];
- } else {
- snprintf(buffer, 4, "%d", err);
- return buffer;
- }
-#else
- snprintf(buffer, 4, "%d", err);
- return buffer;
-#endif
-}
diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h
index 19450dc..15780be 100644
--- a/sys/dev/usb/usbdi.h
+++ b/sys/dev/usb/usbdi.h
@@ -1,4 +1,4 @@
-/* $NetBSD: usbdi.h,v 1.16 1999/01/08 11:58:26 augustss Exp $ */
+/* $NetBSD: usbdi.h,v 1.28 1999/09/11 08:19:27 augustss Exp $ */
/* $FreeBSD$ */
/*
@@ -45,45 +45,17 @@ typedef struct usbd_pipe *usbd_pipe_handle;
typedef struct usbd_request *usbd_request_handle;
typedef void *usbd_private_handle;
-typedef enum {
- USBD_ENDPOINT_ACTIVE,
- USBD_ENDPOINT_STALLED,
-} usbd_endpoint_state;
-
-typedef enum {
- USBD_PIPE_ACTIVE,
- USBD_PIPE_STALLED,
- USBD_PIPE_IDLE,
-} usbd_pipe_state;
-
-typedef enum {
- USBD_INTERFACE_ACTIVE,
- USBD_INTERFACE_STALLED,
- USBD_INTERFACE_IDLE,
-} usbd_interface_state;
-
-typedef enum {
- USBD_DEVICE_ATTACHED,
- USBD_DEVICE_POWERED,
- USBD_DEVICE_DEFAULT,
- USBD_DEVICE_ADDRESSED,
- USBD_DEVICE_CONFIGURED,
- USBD_DEVICE_SUSPENDED,
-} usbd_device_state;
-
-typedef enum {
- USBD_NORMAL_COMPLETION = 0,
+typedef enum { /* keep in sync with usbd_status_msgs */
+ USBD_NORMAL_COMPLETION = 0, /* must be 0 */
USBD_IN_PROGRESS,
/* errors */
USBD_PENDING_REQUESTS,
USBD_NOT_STARTED,
USBD_INVAL,
- USBD_IS_IDLE,
USBD_NOMEM,
USBD_CANCELLED,
USBD_BAD_ADDRESS,
USBD_IN_USE,
- USBD_INTERFACE_NOT_ACTIVE,
USBD_NO_ADDR,
USBD_SET_ADDR_FAILED,
USBD_NO_POWER,
@@ -95,8 +67,7 @@ typedef enum {
USBD_STALLED,
USBD_INTERRUPTED,
- USBD_XXX,
-#define USBD_ERROR_MAX 21 /* used for usbd_error_strs */
+ USBD_ERROR_MAX, /* must be last */
} usbd_status;
typedef int usbd_lock_token;
@@ -107,19 +78,15 @@ typedef void (*usbd_callback) __P((usbd_request_handle, usbd_private_handle,
/* Open flags */
#define USBD_EXCLUSIVE_USE 0x01
-/* XXX broken, should not use the same value */
/* Request flags */
-#define USBD_XFER_OUT 0x01
-#define USBD_XFER_IN 0x02
-#define USBD_SHORT_XFER_OK 0x04
+/* in usb.h #define USBD_SHORT_XFER_OK 0x04*/ /* allow short reads */
+#define USBD_SYNCHRONOUS 0x08 /* wait for completion */
#define USBD_NO_TIMEOUT 0
#define USBD_DEFAULT_TIMEOUT 5000 /* ms = 5 s */
#if defined(__FreeBSD__)
#define USB_CDEV_MAJOR 108
-
-extern struct cdevsw usb_cdevsw;
#endif
usbd_status usbd_open_pipe
@@ -127,109 +94,54 @@ usbd_status usbd_open_pipe
u_int8_t flags, usbd_pipe_handle *pipe));
usbd_status usbd_close_pipe __P((usbd_pipe_handle pipe));
usbd_status usbd_transfer __P((usbd_request_handle req));
-usbd_request_handle usbd_alloc_request __P((void));
+usbd_request_handle usbd_alloc_request __P((usbd_device_handle));
usbd_status usbd_free_request __P((usbd_request_handle reqh));
-usbd_status usbd_setup_request
+void usbd_setup_request
__P((usbd_request_handle reqh, usbd_pipe_handle pipe,
usbd_private_handle priv, void *buffer,
u_int32_t length, u_int16_t flags, u_int32_t timeout,
usbd_callback));
-usbd_status usbd_setup_device_request
- __P((usbd_request_handle reqh, usb_device_request_t *req));
-usbd_status usbd_setup_default_request
+void usbd_setup_default_request
__P((usbd_request_handle reqh, usbd_device_handle dev,
usbd_private_handle priv, u_int32_t timeout,
usb_device_request_t *req, void *buffer,
u_int32_t length, u_int16_t flags, usbd_callback));
-usbd_status usbd_set_request_timeout
- __P((usbd_request_handle reqh, u_int32_t timeout));
-usbd_status usbd_get_request_status
+void usbd_setup_isoc_request
+ __P((usbd_request_handle reqh, usbd_pipe_handle pipe,
+ usbd_private_handle priv, u_int16_t *frlengths,
+ u_int32_t nframes, usbd_callback));
+void usbd_get_request_status
__P((usbd_request_handle reqh, usbd_private_handle *priv,
void **buffer, u_int32_t *count, usbd_status *status));
-usbd_status usbd_request_device_data
- __P((usbd_request_handle reqh, usb_device_request_t *req));
-usb_descriptor_t *usbd_get_descriptor
- __P((usbd_interface_handle *iface, u_int8_t desc_type));
usb_endpoint_descriptor_t *usbd_interface2endpoint_descriptor
__P((usbd_interface_handle iface, u_int8_t address));
-usbd_status usbd_set_configuration
- __P((usbd_device_handle dev, u_int8_t conf));
-usbd_status usbd_retry_request
- __P((usbd_request_handle reqh, u_int32_t retry_count));
usbd_status usbd_abort_pipe __P((usbd_pipe_handle pipe));
-usbd_status usbd_abort_interface __P((usbd_interface_handle iface));
-usbd_status usbd_reset_pipe __P((usbd_pipe_handle pipe));
-usbd_status usbd_reset_interface __P((usbd_interface_handle iface));
usbd_status usbd_clear_endpoint_stall __P((usbd_pipe_handle pipe));
usbd_status usbd_clear_endpoint_stall_async __P((usbd_pipe_handle pipe));
-usbd_status usbd_set_pipe_state
- __P((usbd_pipe_handle pipe, usbd_pipe_state state));
-usbd_status usbd_get_pipe_state
- __P((usbd_pipe_handle pipe, usbd_pipe_state *state,
- u_int32_t *endpoint_state, u_int32_t *request_count));
-usbd_status usbd_set_interface_state
- __P((usbd_interface_handle iface, usbd_interface_state state));
-usbd_status usbd_get_interface_state
- __P((usbd_interface_handle iface, usbd_interface_state *state));
-usbd_status usbd_get_device_state
- __P((usbd_device_handle dev, usbd_device_state *state));
-usbd_status usbd_set_device_state
- __P((usbd_device_handle dev, usbd_device_state state));
-usbd_status usbd_device_address
- __P((usbd_device_handle dev, u_int8_t *address));
-usbd_status usbd_endpoint_address
- __P((usbd_pipe_handle dev, u_int8_t *address));
usbd_status usbd_endpoint_count
__P((usbd_interface_handle dev, u_int8_t *count));
usbd_status usbd_interface_count
__P((usbd_device_handle dev, u_int8_t *count));
-#if 0
-u_int8_t usbd_bus_count __P((void));
-usbd_status usbd_get_bus_handle __P((u_int8_t index, usbd_bus_handle *bus));
-usbd_status usbd_get_root_hub
- __P((usbd_bus_handle bus, usbd_device_handle *dev));
-usbd_status usbd_port_count __P((usbd_device_handle hub, u_int8_t *nports));
-usbd_status usbd_hub2device_handle
- __P((usbd_device_handle hub, u_int8_t port, usbd_device_handle *dev));
-#endif
-usbd_status usbd_request2pipe_handle
- __P((usbd_request_handle reqh, usbd_pipe_handle *pipe));
-usbd_status usbd_pipe2interface_handle
- __P((usbd_pipe_handle pipe, usbd_interface_handle *iface));
usbd_status usbd_interface2device_handle
__P((usbd_interface_handle iface, usbd_device_handle *dev));
-usbd_status usbd_device2bus_handle
- __P((usbd_device_handle dev, usbd_bus_handle *bus));
usbd_status usbd_device2interface_handle
- __P((usbd_device_handle dev, u_int8_t ifaceno,
- usbd_interface_handle *iface));
-usbd_status usbd_set_interface_private_handle
- __P((usbd_interface_handle iface, usbd_private_handle priv));
-usbd_status usbd_get_interface_private_handle
- __P((usbd_interface_handle iface, usbd_private_handle *priv));
-usbd_status usbd_reference_pipe __P((usbd_pipe_handle pipe));
-usbd_status usbd_dereference_pipe __P((usbd_pipe_handle pipe));
-usbd_lock_token usbd_lock __P((void));
-void usbd_unlock __P((usbd_lock_token tok));
+ __P((usbd_device_handle dev, u_int8_t ifaceno, usbd_interface_handle *iface));
-/* Non-standard */
+usbd_device_handle usbd_pipe2device_handle __P((usbd_pipe_handle));
+void *usbd_alloc_buffer __P((usbd_request_handle req, u_int32_t size));
+void usbd_free_buffer __P((usbd_request_handle req));
usbd_status usbd_sync_transfer __P((usbd_request_handle req));
usbd_status usbd_open_pipe_intr
__P((usbd_interface_handle iface, u_int8_t address,
u_int8_t flags, usbd_pipe_handle *pipe,
usbd_private_handle priv, void *buffer,
u_int32_t length, usbd_callback));
-usbd_status usbd_open_pipe_iso
- __P((usbd_interface_handle iface, u_int8_t address,
- u_int8_t flags, usbd_pipe_handle *pipe,
- usbd_private_handle priv, u_int32_t bufsize, u_int32_t nbuf,
- usbd_callback));
usbd_status usbd_do_request
- __P((usbd_device_handle dev, usb_device_request_t *req, void *data));
+ __P((usbd_device_handle pipe, usb_device_request_t *req, void *data));
usbd_status usbd_do_request_async
- __P((usbd_device_handle dev, usb_device_request_t *req, void *data));
+ __P((usbd_device_handle pipe, usb_device_request_t *req, void *data));
usbd_status usbd_do_request_flags
- __P((usbd_device_handle dev, usb_device_request_t *req,
+ __P((usbd_device_handle pipe, usb_device_request_t *req,
void *data, u_int16_t flags, int *));
usb_interface_descriptor_t *usbd_get_interface_descriptor
__P((usbd_interface_handle iface));
@@ -251,9 +163,6 @@ usb_endpoint_descriptor_t *usbd_find_edesc
__P((usb_config_descriptor_t *cd, int ifaceidx, int altidx,
int endptidx));
-char * usbd_errstr(usbd_status err);
-
-
void usbd_dopoll __P((usbd_interface_handle));
void usbd_set_polling __P((usbd_interface_handle iface, int on));
@@ -264,6 +173,9 @@ struct usb_attach_arg {
int port;
int configno;
int ifaceno;
+ int vendor;
+ int product;
+ int release;
usbd_device_handle device; /* current device */
usbd_interface_handle iface; /* current interface */
int usegeneric;
@@ -271,7 +183,7 @@ struct usb_attach_arg {
int nifaces; /* number of interfaces */
};
-#if defined(__NetBSD__)
+#if defined(__NetBSD__) || defined(__OpenBSD__)
/* Match codes. */
/* First five codes is for a whole device. */
#define UMATCH_VENDOR_PRODUCT_REV 14
@@ -295,33 +207,54 @@ struct usb_attach_arg {
#elif defined(__FreeBSD__)
/* FreeBSD needs values less than zero */
-#define UMATCH_VENDOR_PRODUCT_REV (-10)
-#define UMATCH_VENDOR_PRODUCT (-20)
-#define UMATCH_VENDOR_DEVCLASS_DEVPROTO (-30)
-#define UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO (-40)
-#define UMATCH_DEVCLASS_DEVSUBCLASS (-50)
-#define UMATCH_VENDOR_PRODUCT_REV_CONF_IFACE (-60)
-#define UMATCH_VENDOR_PRODUCT_CONF_IFACE (-70)
-#define UMATCH_VENDOR_IFACESUBCLASS_IFACEPROTO (-80)
-#define UMATCH_VENDOR_IFACESUBCLASS (-90)
-#define UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO (-100)
-#define UMATCH_IFACECLASS_IFACESUBCLASS (-110)
-#define UMATCH_IFACECLASS (-120)
-#define UMATCH_IFACECLASS_GENERIC (-130)
-#define UMATCH_GENERIC (-140)
-#define UMATCH_NONE (ENXIO)
-#endif
+/* for the moment disabled
+#define UMATCH_VENDOR_PRODUCT_REV -14
+#define UMATCH_VENDOR_PRODUCT -13
+#define UMATCH_VENDOR_DEVCLASS_DEVPROTO -12
+#define UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO -11
+#define UMATCH_DEVCLASS_DEVSUBCLASS -10
+#define UMATCH_VENDOR_PRODUCT_REV_CONF_IFACE -9
+#define UMATCH_VENDOR_PRODUCT_CONF_IFACE -8
+#define UMATCH_VENDOR_IFACESUBCLASS_IFACEPROTO -7
+#define UMATCH_VENDOR_IFACESUBCLASS -6
+#define UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO -5
+#define UMATCH_IFACECLASS_IFACESUBCLASS -4
+#define UMATCH_IFACECLASS -3
+#define UMATCH_IFACECLASS_GENERIC -2
+#define UMATCH_GENERIC -1
+#define UMATCH_NONE ENXIO
+* For the moment we use Yes/No answers with appropriate
+* sorting in the config file
+*/
+#define UMATCH_VENDOR_PRODUCT_REV 0
+#define UMATCH_VENDOR_PRODUCT 0
+#define UMATCH_VENDOR_DEVCLASS_DEVPROTO 0
+#define UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO 0
+#define UMATCH_DEVCLASS_DEVSUBCLASS 0
+#define UMATCH_VENDOR_PRODUCT_REV_CONF_IFACE 0
+#define UMATCH_VENDOR_PRODUCT_CONF_IFACE 0
+#define UMATCH_VENDOR_IFACESUBCLASS_IFACEPROTO 0
+#define UMATCH_VENDOR_IFACESUBCLASS 0
+#define UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO 0
+#define UMATCH_IFACECLASS_IFACESUBCLASS 0
+#define UMATCH_IFACECLASS 0
+#define UMATCH_IFACECLASS_GENERIC 0
+#define UMATCH_GENERIC 0
+#define UMATCH_NONE ENXIO
+
+
+#endif
void usbd_devinfo __P((usbd_device_handle, int, char *));
struct usbd_quirks *usbd_get_quirks __P((usbd_device_handle));
-void usbd_set_disco __P((usbd_pipe_handle, void (*)(void *), void *));
usb_endpoint_descriptor_t *usbd_get_endpoint_descriptor
__P((usbd_interface_handle iface, u_int8_t address));
+const char *usbd_errstr __P((usbd_status));
+
#if defined(__FreeBSD__)
int usbd_driver_load __P((module_t mod, int what, void *arg));
-bus_print_child_t usbd_print_child;
#endif
/* XXX */
diff --git a/sys/dev/usb/usbdi_util.c b/sys/dev/usb/usbdi_util.c
index 4dd849b..cc64284 100644
--- a/sys/dev/usb/usbdi_util.c
+++ b/sys/dev/usb/usbdi_util.c
@@ -1,4 +1,4 @@
-/* $NetBSD: usbdi_util.c,v 1.19 1999/08/22 20:12:40 augustss Exp $ */
+/* $NetBSD: usbdi_util.c,v 1.21 1999/09/09 12:26:48 augustss Exp $ */
/* $FreeBSD$ */
/*
@@ -43,7 +43,7 @@
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/proc.h>
-#if defined(__NetBSD__)
+#if defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/device.h>
#elif defined(__FreeBSD__)
#include <sys/bus.h>
@@ -514,10 +514,8 @@ usbd_bulk_transfer(reqh, pipe, flags, timeout, buf, size, lbl)
usbd_status r;
int s, error;
- r = usbd_setup_request(reqh, pipe, 0, buf, *size,
- flags, timeout, usbd_bulk_transfer_cb);
- if (r != USBD_NORMAL_COMPLETION)
- return (r);
+ usbd_setup_request(reqh, pipe, 0, buf, *size,
+ flags, timeout, usbd_bulk_transfer_cb);
DPRINTFN(1, ("usbd_bulk_transfer: start transfer %d bytes\n", *size));
s = splusb(); /* don't want callback until tsleep() */
r = usbd_transfer(reqh);
@@ -543,19 +541,19 @@ usbd_bulk_transfer(reqh, pipe, flags, timeout, buf, size, lbl)
void
usb_detach_wait(dv)
- bdevice *dv;
+ device_ptr_t dv;
{
- DPRINTF(("usb_detach_wait: waiting for %s\n", USBDEVNAME(*dv)));
+ DPRINTF(("usb_detach_wait: waiting for %s\n", USBDEVPTRNAME(dv)));
if (tsleep(dv, PZERO, "usbdet", hz * 60))
printf("usb_detach_wait: %s didn't detach\n",
- USBDEVNAME(*dv));
- DPRINTF(("usb_detach_wait: %s done\n", USBDEVNAME(*dv)));
+ USBDEVPTRNAME(dv));
+ DPRINTF(("usb_detach_wait: %s done\n", USBDEVPTRNAME(dv)));
}
void
usb_detach_wakeup(dv)
- bdevice *dv;
+ device_ptr_t dv;
{
- DPRINTF(("usb_detach_wakeup: for %s\n", USBDEVNAME(*dv)));
+ DPRINTF(("usb_detach_wakeup: for %s\n", USBDEVPTRNAME(dv)));
wakeup(dv);
}
diff --git a/sys/dev/usb/usbdi_util.h b/sys/dev/usb/usbdi_util.h
index 6a07520..17d6d5b 100644
--- a/sys/dev/usb/usbdi_util.h
+++ b/sys/dev/usb/usbdi_util.h
@@ -1,4 +1,4 @@
-/* $NetBSD: usbdi_util.h,v 1.16 1999/08/22 20:12:40 augustss Exp $ */
+/* $NetBSD: usbdi_util.h,v 1.17 1999/09/05 19:32:19 augustss Exp $ */
/* $FreeBSD$ */
/*
@@ -93,6 +93,6 @@ usbd_status usbd_bulk_transfer
__P((usbd_request_handle reqh, usbd_pipe_handle pipe, u_int16_t flags,
u_int32_t timeout, void *buf, u_int32_t *size, char *lbl));
-void usb_detach_wait __P((bdevice *));
-void usb_detach_wakeup __P((bdevice *));
+void usb_detach_wait __P((device_ptr_t));
+void usb_detach_wakeup __P((device_ptr_t));
diff --git a/sys/dev/usb/usbdivar.h b/sys/dev/usb/usbdivar.h
index 96354d1..d2a1544 100644
--- a/sys/dev/usb/usbdivar.h
+++ b/sys/dev/usb/usbdivar.h
@@ -1,5 +1,5 @@
-/* $NetBSD: usbdivar.h,v 1.16 1999/01/08 11:58:26 augustss Exp $ */
-/* $FreeBSD$ */
+/* $NetBSD: usbdivar.h,v 1.30 1999/09/11 08:19:27 augustss Exp $ */
+/* $FreeBSD$ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -38,25 +38,32 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+/* From usb_mem.h */
+DECLARE_USB_DMA_T;
+
struct usbd_request;
struct usbd_pipe;
struct usbd_endpoint {
usb_endpoint_descriptor_t *edesc;
- usbd_endpoint_state state;
int refcnt;
- int toggle; /* XXX */
};
-typedef void (*usbd_xfercb)__P((usbd_request_handle req));
+struct usbd_bus_methods {
+ usbd_status (*open_pipe)__P((struct usbd_pipe *pipe));
+ void (*do_poll)__P((struct usbd_bus *));
+ usbd_status (*allocm)__P((struct usbd_bus *, usb_dma_t *,
+ u_int32_t bufsize));
+ void (*freem)__P((struct usbd_bus *, usb_dma_t *));
+};
-struct usbd_methods {
+struct usbd_pipe_methods {
usbd_status (*transfer)__P((usbd_request_handle reqh));
usbd_status (*start)__P((usbd_request_handle reqh));
void (*abort)__P((usbd_request_handle reqh));
- void (*close)__P((usbd_pipe_handle pipe));
- usbd_status (*isobuf)__P((usbd_pipe_handle pipe,
- u_int32_t bufsize,u_int32_t nbuf));
+ void (*close)__P((usbd_pipe_handle pipe));
+ void (*cleartoggle)__P((usbd_pipe_handle pipe));
+ void (*done)__P((usbd_request_handle reqh));
};
struct usbd_port {
@@ -82,10 +89,9 @@ struct usb_softc;
struct usbd_bus {
/* Filled by HC driver */
- bdevice bdev; /* base device, host adapter */
- usbd_status (*open_pipe)__P((struct usbd_pipe *pipe));
+ USBBASEDEVICE bdev; /* base device, host adapter */
+ struct usbd_bus_methods *methods;
u_int32_t pipe_size; /* size of a pipe struct */
- void (*do_poll)__P((struct usbd_bus *));
/* Filled by usb driver */
struct usbd_device *root_hub;
usbd_device_handle devices[USB_MAX_DEVICES];
@@ -97,7 +103,6 @@ struct usbd_bus {
struct usbd_device {
struct usbd_bus *bus;
- usbd_device_state state;
struct usbd_pipe *default_pipe;
u_int8_t address;
u_int8_t depth;
@@ -115,12 +120,11 @@ struct usbd_device {
usb_config_descriptor_t *cdesc; /* full config descr */
struct usbd_quirks *quirks;
struct usbd_hub *hub; /* only if this is a hub */
- void *softc; /* device softc if attached */
+ device_ptr_t *subdevs; /* sub-devices, 0 terminated */
};
struct usbd_interface {
struct usbd_device *device;
- usbd_interface_state state;
usb_interface_descriptor_t *idesc;
int index;
int altindex;
@@ -133,19 +137,16 @@ struct usbd_pipe {
struct usbd_interface *iface;
struct usbd_device *device;
struct usbd_endpoint *endpoint;
- usbd_pipe_state state;
- int32_t refcnt;
+ int refcnt;
char running;
SIMPLEQ_HEAD(, usbd_request) queue;
LIST_ENTRY(usbd_pipe) next;
- void (*disco) __P((void *));
- void *discoarg;
-
usbd_request_handle intrreqh; /* used for repeating requests */
+ char repeat;
/* Filled by HC driver. */
- struct usbd_methods *methods;
+ struct usbd_pipe_methods *methods;
};
struct usbd_request {
@@ -158,24 +159,34 @@ struct usbd_request {
u_int32_t timeout;
usbd_status status;
usbd_callback callback;
- usbd_xfercb xfercb;
- u_int32_t retries;
- char done;
+ __volatile char done;
+ /* For control pipe */
usb_device_request_t request;
- u_int8_t isreq;
+
+ /* For isoc */
+ u_int16_t *frlengths;
+ int nframes;
+
+ /* For memory allocation */
+ struct usbd_device *device;
+ usb_dma_t dmabuf;
+
+ int rqflags;
+#define URQ_REQUEST 0x01
+#define URQ_AUTO_DMABUF 0x10
+#define URQ_DEV_DMABUF 0x20
SIMPLEQ_ENTRY(usbd_request) next;
- void *hcpriv; /* XXX private use by the HC driver */
+ void *hcpriv; /* private use by the HC driver */
+ int hcprivint; /* ditto */
#if defined(__FreeBSD__)
- struct callout_handle timeout_handle;
+ struct callout_handle timo_handle;
#endif
};
-void usbd_init __P((void));
-
/* Routines from usb_subr.c */
int usbctlprint __P((void *, const char *));
void usb_delay_ms __P((usbd_bus_handle, u_int));
@@ -186,30 +197,29 @@ usbd_status usbd_setup_pipe __P((usbd_device_handle dev,
usbd_interface_handle iface,
struct usbd_endpoint *,
usbd_pipe_handle *pipe));
-usbd_status usbd_new_device __P((bdevice *parent,
+usbd_status usbd_new_device __P((device_ptr_t parent,
usbd_bus_handle bus, int depth,
int lowspeed, int port,
struct usbd_port *));
void usbd_remove_device __P((usbd_device_handle,
struct usbd_port *));
int usbd_printBCD __P((char *cp, int bcd));
-usbd_status usb_insert_transfer __P((usbd_request_handle reqh));
-void usb_start_next __P((usbd_pipe_handle pipe));
usbd_status usbd_fill_iface_data __P((usbd_device_handle dev,
int i, int a));
+void usb_free_device __P((usbd_device_handle));
+
+usbd_status usb_insert_transfer __P((usbd_request_handle reqh));
+void usb_transfer_complete __P((usbd_request_handle reqh));
/* Routines from usb.c */
int usb_bus_count __P((void));
void usb_needs_explore __P((usbd_bus_handle));
-#if 0
-usbd_status usb_get_bus_handle __P((int, usbd_bus_handle *));
-#endif
/* Locator stuff. */
#if defined(__NetBSD__)
#include "locators.h"
-#elif defined(__FreeBSD__)
+#elif defined(__FreeBSD__) || defined(__OpenBSD__)
/* XXX these values are used to statically bind some elements in the USB tree
* to specific driver instances. This should be somehow emulated in FreeBSD
* but can be done later on.
@@ -218,12 +228,30 @@ usbd_status usb_get_bus_handle __P((int, usbd_bus_handle *));
#define UHUBCF_PORT_DEFAULT -1
#define UHUBCF_CONFIGURATION_DEFAULT -1
#define UHUBCF_INTERFACE_DEFAULT -1
+#define UHUBCF_VENDOR_DEFAULT -1
+#define UHUBCF_PRODUCT_DEFAULT -1
+#define UHUBCF_RELEASE_DEFAULT -1
+#endif
+
+#if defined (__OpenBSD__)
+#define UHUBCF_PORT 0
+#define UHUBCF_CONFIGURATION 1
+#define UHUBCF_INTERFACE 2
+#define UHUBCF_VENDOR 3
+#define UHUBCF_PRODUCT 4
+#define UHUBCF_RELEASE 5
#endif
#define uhubcf_port cf_loc[UHUBCF_PORT]
#define uhubcf_configuration cf_loc[UHUBCF_CONFIGURATION]
#define uhubcf_interface cf_loc[UHUBCF_INTERFACE]
+#define uhubcf_vendor cf_loc[UHUBCF_VENDOR]
+#define uhubcf_product cf_loc[UHUBCF_PRODUCT]
+#define uhubcf_release cf_loc[UHUBCF_RELEASE]
#define UHUB_UNK_PORT UHUBCF_PORT_DEFAULT /* wildcarded 'port' */
#define UHUB_UNK_CONFIGURATION UHUBCF_CONFIGURATION_DEFAULT /* wildcarded 'configuration' */
#define UHUB_UNK_INTERFACE UHUBCF_INTERFACE_DEFAULT /* wildcarded 'interface' */
+#define UHUB_UNK_VENDOR UHUBCF_VENDOR_DEFAULT /* wildcarded 'vendor' */
+#define UHUB_UNK_PRODUCT UHUBCF_PRODUCT_DEFAULT /* wildcarded 'product' */
+#define UHUB_UNK_RELEASE UHUBCF_RELEASE_DEFAULT /* wildcarded 'release' */
diff --git a/sys/dev/usb/usbhid.h b/sys/dev/usb/usbhid.h
index bffca68..5858b42 100644
--- a/sys/dev/usb/usbhid.h
+++ b/sys/dev/usb/usbhid.h
@@ -1,5 +1,5 @@
-/* $NetBSD: usbhid.h,v 1.3 1998/12/26 12:53:04 augustss Exp $ */
-/* $FreeBSD$ */
+/* $NetBSD: usbhid.h,v 1.5 1999/05/13 23:29:11 augustss Exp $ */
+/* $FreeBSD$ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -72,6 +72,7 @@ typedef struct usb_hid_descriptor {
#define HUP_SIMULATION 0x0002
#define HUP_LEDS 0x0008
#define HUP_BUTTON 0x0009
+#define HUP_DIGITIZERS 0x000d
/* Usages, generic desktop */
#define HUG_POINTER 0x0001
@@ -115,6 +116,26 @@ typedef struct usb_hid_descriptor {
#define HUG_SYSTEM_MENU_UP 0x008c
#define HUG_SYSTEM_MENU_DOWN 0x008d
+/* Usages Digitizers */
+#define HUD_TIP_PRESSURE 0x0030
+#define HUD_BARREL_PRESSURE 0x0031
+#define HUD_IN_RANGE 0x0032
+#define HUD_TOUCH 0x0033
+#define HUD_UNTOUCH 0x0034
+#define HUD_TAP 0x0035
+#define HUD_QUALITY 0x0036
+#define HUD_INVERT 0x003c
+#define HUD_X_TILT 0x003d
+#define HUD_Y_TILT 0x003e
+#define HUD_AZIMUTH 0x003f
+#define HUD_ALTITUDE 0x0040
+#define HUD_TWIST 0x0041
+#define HUD_TIP_SWITCH 0x0042
+#define HUD_SEC_TIP_SWITCH 0x0043
+#define HUD_BARREL_SWITCH 0x0044
+#define HUD_ERASER 0x0045
+#define HUD_TABLET_PICK 0x0046
+
#define HID_USAGE2(p,u) (((p) << 16) | u)
#define UHID_INPUT_REPORT 0x01
OpenPOWER on IntegriCloud