diff options
Diffstat (limited to 'sys/dev/usb')
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 |