Index: sys/conf/files =================================================================== RCS file: /home/ncvs/src/sys/conf/files,v retrieving revision 1.340.2.142 diff -u -r1.340.2.142 files --- sys/conf/files 22 Aug 2003 20:52:47 -0000 1.340.2.142 +++ sys/conf/files 4 Oct 2003 18:54:40 -0000 @@ -1335,7 +1335,7 @@ dev/usb/usb.c optional usb dev/usb/usbdi.c optional usb dev/usb/usbdi_util.c optional usb -#dev/usb/usb_mem.c optional usb +dev/usb/usb_mem.c optional usb dev/usb/usb_ethersubr.c optional usb dev/usb/usb_subr.c optional usb dev/usb/usb_quirks.c optional usb Index: sys/dev/usb/FILES =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/FILES,v retrieving revision 1.2.2.1 diff -u -r1.2.2.1 FILES --- sys/dev/usb/FILES 4 Mar 2002 04:01:35 -0000 1.2.2.1 +++ sys/dev/usb/FILES 4 Oct 2003 18:54:40 -0000 @@ -1,4 +1,4 @@ -$FreeBSD: src/sys/dev/usb/FILES,v 1.2.2.1 2002/03/04 04:01:35 alfred Exp $ +$FreeBSD: src/sys/dev/usb/FILES,v 1.6 2003/04/14 14:04:07 ticso Exp $ A small roadmap of the USB files: @@ -8,16 +8,26 @@ TODO just a list of things to do devlist2h.awk script to generate usbdevs*.h dsbr100io.h API for ufm.c +ehci.c Host controller driver for EHCI +ehcireg.h Hardware definitions for EHCI +ehcivar.h API for ehci.c files.usb config include file hid.c subroutines to parse and access HID data hid.h API for hid.c +if_aue.c USB Pegasus Ethernet driver +if_auereg.h and definitions for it +if_cue.c USB CATC Ethernet driver +if_cuereg.h and definitions for it +if_kue.c USB Kawasaki Ethernet driver +if_kuereg.h and definitions for it +if_upl.c USB Prolofic host-to-host driver 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 ufm.c USB fm radio driver -ugen.c generic driver that can handle access to any USB device +[Merged] 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 @@ -27,9 +37,10 @@ ukbdmap.c wscons key mapping for ukbd ukbdvar.h API for ukbd.c ulpt.c USB printer class driver -umass.c USB mass storage driver (bulk only for now) +umass.c USB mass storage driver umodem.c USB modem (CDC ACM) driver ums.c USB mouse driver +urio.c USB Diamond Rio500 driver usb.c usb (bus) device driver usb.h general USB defines usb_mem.c memory allocation for DMAable memory @@ -47,4 +58,5 @@ 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 +uscanner.c minimal USB scanner driver usbhid.h USB HID class definitions Index: sys/dev/usb/Makefile.usbdevs =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/Makefile.usbdevs,v retrieving revision 1.1.2.2 diff -u -r1.1.2.2 Makefile.usbdevs --- sys/dev/usb/Makefile.usbdevs 7 May 2000 14:36:41 -0000 1.1.2.2 +++ sys/dev/usb/Makefile.usbdevs 4 Oct 2003 18:54:40 -0000 @@ -1,6 +1,6 @@ # The files usbdevs.h and usbdevs_data.h are generated from usbdevs # -# $FreeBSD: src/sys/dev/usb/Makefile.usbdevs,v 1.1.2.2 2000/05/07 14:36:41 n_hibma Exp $ +# $FreeBSD: src/sys/dev/usb/Makefile.usbdevs,v 1.2 2000/03/15 22:13:50 n_hibma Exp $ AWK= awk UNAME= uname Index: sys/dev/usb/devlist2h.awk =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/devlist2h.awk,v retrieving revision 1.1 diff -u -r1.1 devlist2h.awk --- sys/dev/usb/devlist2h.awk 18 Nov 1999 18:02:44 -0000 1.1 +++ sys/dev/usb/devlist2h.awk 4 Oct 2003 18:54:40 -0000 @@ -1,6 +1,6 @@ #! /usr/bin/awk -f -# $NetBSD: devlist2h.awk,v 1.6 1999/08/17 16:06:20 augustss Exp $ -# $FreeBSD: src/sys/dev/usb/devlist2h.awk,v 1.1 1999/11/18 18:02:44 n_hibma Exp $ +# $NetBSD: usb/devlist2h.awk,v 1.9 2001/01/18 20:28:22 jdolecek Exp $ +# $FreeBSD: src/sys/dev/usb/devlist2h.awk,v 1.2 2002/04/01 19:22:04 joe Exp $ # # Copyright (c) 1995, 1996 Christopher G. Demetriou # All rights reserved. @@ -175,7 +175,7 @@ printf("\n") > dfile - printf("struct usb_knowndev usb_knowndevs[] = {\n") > dfile + printf("const struct usb_knowndev usb_knowndevs[] = {\n") > dfile for (i = 1; i <= nproducts; i++) { printf("\t{\n") > dfile printf("\t USB_VENDOR_%s, USB_PRODUCT_%s_%s,\n", Index: sys/dev/usb/dsbr100io.h =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/dsbr100io.h,v retrieving revision 1.1.2.1 diff -u -r1.1.2.1 dsbr100io.h --- sys/dev/usb/dsbr100io.h 4 Mar 2002 04:01:35 -0000 1.1.2.1 +++ sys/dev/usb/dsbr100io.h 4 Oct 2003 18:54:40 -0000 @@ -28,7 +28,7 @@ * its contributors. */ -/* $FreeBSD: src/sys/dev/usb/dsbr100io.h,v 1.1.2.1 2002/03/04 04:01:35 alfred Exp $ */ +/* $FreeBSD: src/sys/dev/usb/dsbr100io.h,v 1.1 2002/03/04 03:51:19 alfred Exp $ */ #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) #include Index: sys/dev/usb/hid.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/hid.c,v retrieving revision 1.11.2.6 diff -u -r1.11.2.6 hid.c --- sys/dev/usb/hid.c 6 Nov 2002 14:03:37 -0000 1.11.2.6 +++ sys/dev/usb/hid.c 4 Oct 2003 18:54:40 -0000 @@ -1,6 +1,8 @@ -/* $NetBSD: hid.c,v 1.15 2000/04/27 15:26:46 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/hid.c,v 1.11.2.6 2002/11/06 14:03:37 joe Exp $ */ +/* $NetBSD: hid.c,v 1.17 2001/11/13 06:24:53 lukem Exp $ */ + +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/hid.c,v 1.23 2003/08/24 17:55:54 obrien Exp $"); /* * Copyright (c) 1998 The NetBSD Foundation, Inc. * All rights reserved. @@ -44,7 +46,7 @@ #include #endif #include - + #include #include @@ -78,6 +80,7 @@ Static void hid_clear_local(struct hid_item *c) { + c->usage = 0; c->usage_minimum = 0; c->usage_maximum = 0; @@ -95,8 +98,7 @@ { struct hid_data *s; - s = malloc(sizeof *s, M_TEMP, M_WAITOK); - memset(s, 0, sizeof *s); + s = malloc(sizeof *s, M_TEMP, M_WAITOK|M_ZERO); s->start = s->p = d; s->end = (char *)d + len; s->kindset = kindset; @@ -106,6 +108,7 @@ void hid_end_parse(struct hid_data *s) { + while (s->cur.next != NULL) { struct hid_item *hi = s->cur.next->next; free(s->cur.next, M_TEMP); @@ -188,7 +191,7 @@ printf("BAD LENGTH %d\n", bSize); continue; } - + switch (bType) { case 0: /* Main */ switch (bTag) { @@ -203,8 +206,8 @@ s->multi = 0; c->loc.count = 1; if (s->minset) { - for (i = c->usage_minimum; - i <= c->usage_maximum; + for (i = c->usage_minimum; + i <= c->usage_maximum; i++) { s->usages[s->nu] = i; if (s->nu < MAXUSAGE-1) @@ -216,7 +219,7 @@ } else { *h = *c; h->next = 0; - c->loc.pos += + c->loc.pos += c->loc.size * c->loc.count; hid_clear_local(c); s->minset = 0; @@ -306,9 +309,9 @@ case 2: /* Local */ switch (bTag) { case 0: - if (bSize == 1) + if (bSize == 1) dval = c->_usage_page | (dval&0xff); - else if (bSize == 2) + else if (bSize == 2) dval = c->_usage_page | (dval&0xffff); c->usage = dval; if (s->nu < MAXUSAGE) @@ -317,16 +320,16 @@ break; case 1: s->minset = 1; - if (bSize == 1) + if (bSize == 1) dval = c->_usage_page | (dval&0xff); - else if (bSize == 2) + else if (bSize == 2) dval = c->_usage_page | (dval&0xffff); c->usage_minimum = dval; break; case 2: - if (bSize == 1) + if (bSize == 1) dval = c->_usage_page | (dval&0xff); - else if (bSize == 2) + else if (bSize == 2) dval = c->_usage_page | (dval&0xffff); c->usage_maximum = dval; break; @@ -420,7 +423,7 @@ return (0); data = 0; - s = hpos / 8; + s = hpos / 8; for (i = hpos; i < hpos+hsize; i += 8) data |= buf[i / 8] << ((i / 8 - s) * 8); data >>= hpos % 8; @@ -428,7 +431,7 @@ hsize = 32 - hsize; /* Sign extend */ data = ((int32_t)data << hsize) >> hsize; - DPRINTFN(10,("hid_get_data: loc %d/%d = %lu\n", + DPRINTFN(10,("hid_get_data: loc %d/%d = %lu\n", loc->pos, loc->size, (long)data)); return (data); } Index: sys/dev/usb/hid.h =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/hid.h,v retrieving revision 1.7.2.3 diff -u -r1.7.2.3 hid.h --- sys/dev/usb/hid.h 31 Oct 2000 23:23:29 -0000 1.7.2.3 +++ sys/dev/usb/hid.h 4 Oct 2003 18:54:40 -0000 @@ -1,5 +1,5 @@ -/* $NetBSD: hid.h,v 1.5 2000/04/27 15:26:46 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/hid.h,v 1.7.2.3 2000/10/31 23:23:29 n_hibma Exp $ */ +/* $NetBSD: hid.h,v 1.6 2000/06/01 14:28:57 augustss Exp $ */ +/* $FreeBSD: src/sys/dev/usb/hid.h,v 1.12 2003/07/04 01:50:38 jmg Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -38,7 +38,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -enum hid_kind { +enum hid_kind { hid_input, hid_output, hid_feature, hid_collection, hid_endcollection }; @@ -84,8 +84,8 @@ void hid_end_parse(struct hid_data *s); int hid_get_item(struct hid_data *s, struct hid_item *h); int hid_report_size(void *buf, int len, enum hid_kind k, u_int8_t *id); -int hid_locate(void *desc, int size, u_int32_t usage, - enum hid_kind kind, struct hid_location *loc, +int hid_locate(void *desc, int size, u_int32_t usage, + enum hid_kind kind, struct hid_location *loc, u_int32_t *flags); u_long hid_get_data(u_char *buf, struct hid_location *loc); int hid_is_collection(void *desc, int size, u_int32_t usage); Index: sys/dev/usb/if_aue.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/if_aue.c,v retrieving revision 1.19.2.18 diff -u -r1.19.2.18 if_aue.c --- sys/dev/usb/if_aue.c 14 Jun 2003 15:56:48 -0000 1.19.2.18 +++ sys/dev/usb/if_aue.c 4 Oct 2003 22:38:20 -0000 @@ -28,13 +28,14 @@ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD: src/sys/dev/usb/if_aue.c,v 1.19.2.18 2003/06/14 15:56:48 trhodes Exp $ */ +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/if_aue.c,v 1.73 2003/10/04 21:41:01 joe Exp $"); + /* - * ADMtek AN986 Pegasus USB to ethernet driver. Datasheet is available - * from http://www.admtek.com.tw. + * ADMtek AN986 Pegasus and AN8511 Pegasus II USB to ethernet driver. + * Datasheet is available from http://www.admtek.com.tw. * * Written by Bill Paul * Electrical Engineering Department @@ -61,6 +62,9 @@ * done using usbd_transfer() and friends. */ +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/if_aue.c,v 1.73 2003/10/04 21:41:01 joe Exp $"); + #include #include #include @@ -77,8 +81,11 @@ #include -#include /* for DELAY */ #include +#include +#if __FreeBSD_version < 500000 +#include +#endif #include #include @@ -92,80 +99,90 @@ #include +MODULE_DEPEND(aue, usb, 1, 1, 1); +MODULE_DEPEND(aue, ether, 1, 1, 1); +MODULE_DEPEND(aue, miibus, 1, 1, 1); + /* "controller miibus0" required. See GENERIC if you get errors here. */ #include "miibus_if.h" -#ifndef lint -static const char rcsid[] = - "$FreeBSD: src/sys/dev/usb/if_aue.c,v 1.19.2.18 2003/06/14 15:56:48 trhodes Exp $"; -#endif - /* * Various supported device vendors/products. */ -Static struct aue_type aue_devs[] = { - { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX1, PNA|PII }, - { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX2, PII }, - { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_UFE1000, LSYS }, - { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX4, PNA }, - { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX5, PNA }, - { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX6, PII }, - { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX7, PII }, - { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX8, PII }, - { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX9, PNA }, - { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX10, 0 }, - { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_DSB650TX_PNA, 0 }, - { USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_USB320_EC, 0 }, - { USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_SS1001, PII }, - { USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUS, PNA }, - { USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUSII, PII }, - { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_USB2LAN, PII }, - { USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USB100, 0 }, - { USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBLP100, PNA }, - { USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBEL100, 0 }, - { USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBE100, PII }, - { USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TX, 0 }, - { USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TXS,PII }, - { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX4, LSYS|PII }, - { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX1, LSYS }, - { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX, LSYS }, - { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX_PNA, PNA }, - { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX3, LSYS|PII }, - { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX2, LSYS|PII }, - { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650, LSYS }, - { USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX0, 0 }, - { USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX1, LSYS }, - { USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX2, 0 }, - { USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX3, LSYS }, - { USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBLTX, PII }, - { USB_VENDOR_ELSA, USB_PRODUCT_ELSA_USB2ETHERNET, 0 }, - { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBETTX, 0 }, - { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBETTXS, PII }, - { USB_VENDOR_KINGSTON, USB_PRODUCT_KINGSTON_KNU101TX, 0 }, - { USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TX1, LSYS|PII }, - { USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10T, LSYS }, - { USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB100TX, LSYS }, - { USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB100H1, LSYS|PNA }, - { USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TA, LSYS }, - { USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TX2, LSYS|PII }, - { USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUATX1, 0 }, - { USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUATX5, 0 }, - { USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUA2TX5, PII }, - { USB_VENDOR_SIEMENS, USB_PRODUCT_SIEMENS_SPEEDSTREAM, PII }, - { USB_VENDOR_SMARTBRIDGES, USB_PRODUCT_SMARTBRIDGES_SMARTNIC,PII }, - { USB_VENDOR_SMC, USB_PRODUCT_SMC_2202USB, 0 }, - { USB_VENDOR_SMC, USB_PRODUCT_SMC_2206USB, PII }, - { USB_VENDOR_SOHOWARE, USB_PRODUCT_SOHOWARE_NUB100, 0 }, - { 0, 0, 0 } +struct aue_type { + struct usb_devno aue_dev; + u_int16_t aue_flags; +#define LSYS 0x0001 /* use Linksys reset */ +#define PNA 0x0002 /* has Home PNA */ +#define PII 0x0004 /* Pegasus II chip */ +}; + +Static const struct aue_type aue_devs[] = { + {{ USB_VENDOR_3COM, USB_PRODUCT_3COM_3C460B}, PII }, + {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX1}, PNA|PII }, + {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX2}, PII }, + {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_UFE1000}, LSYS }, + {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX4}, PNA }, + {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX5}, PNA }, + {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX6}, PII }, + {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX7}, PII }, + {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX8}, PII }, + {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX9}, PNA }, + {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX10}, 0 }, + {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_DSB650TX_PNA}, 0 }, + {{ USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_USB320_EC}, 0 }, + {{ USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_SS1001}, PII }, + {{ USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUS}, PNA }, + {{ USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUSII}, PII }, + {{ USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_USB2LAN}, PII }, + {{ USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USB100}, 0 }, + {{ USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBLP100}, PNA }, + {{ USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBEL100}, 0 }, + {{ USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBE100}, PII }, + {{ USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TX}, 0 }, + {{ USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TXS},PII }, + {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX4}, LSYS|PII }, + {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX1}, LSYS }, + {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX}, LSYS }, + {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX_PNA}, PNA }, + {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX3}, LSYS|PII }, + {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX2}, LSYS|PII }, + {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650}, LSYS }, + {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX0}, 0 }, + {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX1}, LSYS }, + {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX2}, 0 }, + {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX3}, LSYS }, + {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBLTX}, PII }, + {{ USB_VENDOR_ELSA, USB_PRODUCT_ELSA_USB2ETHERNET}, 0 }, + {{ USB_VENDOR_HAWKING, USB_PRODUCT_HAWKING_UF100}, PII }, + {{ USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBETTX}, 0 }, + {{ USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBETTXS}, PII }, + {{ USB_VENDOR_KINGSTON, USB_PRODUCT_KINGSTON_KNU101TX}, 0 }, + {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TX1}, LSYS|PII }, + {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10T}, LSYS }, + {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB100TX}, LSYS }, + {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB100H1}, LSYS|PNA }, + {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TA}, LSYS }, + {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TX2}, LSYS|PII }, + {{ USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_MN110}, PII }, + {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUATX1}, 0 }, + {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUATX5}, 0 }, + {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUA2TX5}, PII }, + {{ USB_VENDOR_SIEMENS, USB_PRODUCT_SIEMENS_SPEEDSTREAM}, PII }, + {{ USB_VENDOR_SMARTBRIDGES, USB_PRODUCT_SMARTBRIDGES_SMARTNIC},PII }, + {{ USB_VENDOR_SMC, USB_PRODUCT_SMC_2202USB}, 0 }, + {{ USB_VENDOR_SMC, USB_PRODUCT_SMC_2206USB}, PII }, + {{ USB_VENDOR_SOHOWARE, USB_PRODUCT_SOHOWARE_NUB100}, 0 }, }; +#define aue_lookup(v, p) ((const struct aue_type *)usb_lookup(aue_devs, v, p)) Static struct usb_qdat aue_qdat; -Static int aue_match(device_t); -Static int aue_attach(device_t); -Static int aue_detach(device_t); +Static int aue_match(device_ptr_t); +Static int aue_attach(device_ptr_t); +Static int aue_detach(device_ptr_t); -Static void aue_reset_pegasus_II(struct aue_softc *); +Static void aue_reset_pegasus_II(struct aue_softc *sc); Static int aue_tx_list_init(struct aue_softc *); Static int aue_rx_list_init(struct aue_softc *); Static int aue_newbuf(struct aue_softc *, struct aue_chain *, struct mbuf *); @@ -182,24 +199,24 @@ Static void aue_init(void *); Static void aue_stop(struct aue_softc *); Static void aue_watchdog(struct ifnet *); -Static void aue_shutdown(device_t); +Static void aue_shutdown(device_ptr_t); Static int aue_ifmedia_upd(struct ifnet *); Static void aue_ifmedia_sts(struct ifnet *, struct ifmediareq *); Static void aue_eeprom_getword(struct aue_softc *, int, u_int16_t *); Static void aue_read_eeprom(struct aue_softc *, caddr_t, int, int, int); -Static int aue_miibus_readreg(device_t, int, int); -Static int aue_miibus_writereg(device_t, int, int, int); -Static void aue_miibus_statchg(device_t); +Static int aue_miibus_readreg(device_ptr_t, int, int); +Static int aue_miibus_writereg(device_ptr_t, int, int, int); +Static void aue_miibus_statchg(device_ptr_t); Static void aue_setmulti(struct aue_softc *); Static u_int32_t aue_crc(caddr_t); Static void aue_reset(struct aue_softc *); -Static int csr_read_1(struct aue_softc *, int); -Static int csr_write_1(struct aue_softc *, int, int); -Static int csr_read_2(struct aue_softc *, int); -Static int csr_write_2(struct aue_softc *, int, int); +Static int aue_csr_read_1(struct aue_softc *, int); +Static int aue_csr_write_1(struct aue_softc *, int, int); +Static int aue_csr_read_2(struct aue_softc *, int); +Static int aue_csr_write_2(struct aue_softc *, int, int); Static device_method_t aue_methods[] = { /* Device interface */ @@ -228,27 +245,26 @@ Static devclass_t aue_devclass; -DRIVER_MODULE(if_aue, uhub, aue_driver, aue_devclass, usbd_driver_load, 0); +DRIVER_MODULE(aue, uhub, aue_driver, aue_devclass, usbd_driver_load, 0); DRIVER_MODULE(miibus, aue, miibus_driver, miibus_devclass, 0, 0); #define AUE_SETBIT(sc, reg, x) \ - csr_write_1(sc, reg, csr_read_1(sc, reg) | (x)) + aue_csr_write_1(sc, reg, aue_csr_read_1(sc, reg) | (x)) #define AUE_CLRBIT(sc, reg, x) \ - csr_write_1(sc, reg, csr_read_1(sc, reg) & ~(x)) + aue_csr_write_1(sc, reg, aue_csr_read_1(sc, reg) & ~(x)) Static int -csr_read_1(struct aue_softc *sc, int reg) +aue_csr_read_1(struct aue_softc *sc, int reg) { usb_device_request_t req; usbd_status err; u_int8_t val = 0; - int s; - if (sc->aue_gone) - return(0); + if (sc->aue_dying) + return (0); - s = splusb(); + AUE_LOCK(sc); req.bmRequestType = UT_READ_VENDOR_DEVICE; req.bRequest = AUE_UR_READREG; @@ -256,29 +272,28 @@ USETW(req.wIndex, reg); USETW(req.wLength, 1); - err = usbd_do_request_flags(sc->aue_udev, &req, - &val, USBD_NO_TSLEEP, NULL); + err = usbd_do_request(sc->aue_udev, &req, &val); - splx(s); + AUE_UNLOCK(sc); - if (err) - return(0); + if (err) { + return (0); + } - return(val); + return (val); } Static int -csr_read_2(struct aue_softc *sc, int reg) +aue_csr_read_2(struct aue_softc *sc, int reg) { usb_device_request_t req; usbd_status err; u_int16_t val = 0; - int s; - if (sc->aue_gone) - return(0); + if (sc->aue_dying) + return (0); - s = splusb(); + AUE_LOCK(sc); req.bmRequestType = UT_READ_VENDOR_DEVICE; req.bRequest = AUE_UR_READREG; @@ -286,28 +301,27 @@ USETW(req.wIndex, reg); USETW(req.wLength, 2); - err = usbd_do_request_flags(sc->aue_udev, &req, - &val, USBD_NO_TSLEEP, NULL); + err = usbd_do_request(sc->aue_udev, &req, &val); - splx(s); + AUE_UNLOCK(sc); - if (err) - return(0); + if (err) { + return (0); + } - return(val); + return (val); } Static int -csr_write_1(struct aue_softc *sc, int reg, int val) +aue_csr_write_1(struct aue_softc *sc, int reg, int val) { usb_device_request_t req; usbd_status err; - int s; - if (sc->aue_gone) - return(0); + if (sc->aue_dying) + return (0); - s = splusb(); + AUE_LOCK(sc); req.bmRequestType = UT_WRITE_VENDOR_DEVICE; req.bRequest = AUE_UR_WRITEREG; @@ -315,28 +329,27 @@ USETW(req.wIndex, reg); USETW(req.wLength, 1); - err = usbd_do_request_flags(sc->aue_udev, &req, - &val, USBD_NO_TSLEEP, NULL); + err = usbd_do_request(sc->aue_udev, &req, &val); - splx(s); + AUE_UNLOCK(sc); - if (err) - return(-1); + if (err) { + return (-1); + } - return(0); + return (0); } Static int -csr_write_2(struct aue_softc *sc, int reg, int val) +aue_csr_write_2(struct aue_softc *sc, int reg, int val) { usb_device_request_t req; usbd_status err; - int s; - if (sc->aue_gone) - return(0); + if (sc->aue_dying) + return (0); - s = splusb(); + AUE_LOCK(sc); req.bmRequestType = UT_WRITE_VENDOR_DEVICE; req.bRequest = AUE_UR_WRITEREG; @@ -344,15 +357,15 @@ USETW(req.wIndex, reg); USETW(req.wLength, 2); - err = usbd_do_request_flags(sc->aue_udev, &req, - &val, USBD_NO_TSLEEP, NULL); + err = usbd_do_request(sc->aue_udev, &req, &val); - splx(s); + AUE_UNLOCK(sc); - if (err) - return(-1); + if (err) { + return (-1); + } - return(0); + return (0); } /* @@ -361,15 +374,14 @@ Static void aue_eeprom_getword(struct aue_softc *sc, int addr, u_int16_t *dest) { - register int i; - u_int16_t word = 0; + int i; + u_int16_t word = 0; - csr_write_1(sc, AUE_EE_REG, addr); - csr_write_1(sc, AUE_EE_CTL, AUE_EECTL_READ); + aue_csr_write_1(sc, AUE_EE_REG, addr); + aue_csr_write_1(sc, AUE_EE_CTL, AUE_EECTL_READ); for (i = 0; i < AUE_TIMEOUT; i++) { - if (csr_read_1(sc, AUE_EE_CTL) & - AUE_EECTL_DONE) + if (aue_csr_read_1(sc, AUE_EE_CTL) & AUE_EECTL_DONE) break; } @@ -378,7 +390,7 @@ sc->aue_unit); } - word = csr_read_2(sc, AUE_EE_DATA); + word = aue_csr_read_2(sc, AUE_EE_DATA); *dest = word; return; @@ -406,14 +418,12 @@ } Static int -aue_miibus_readreg(device_t dev, int phy, int reg) +aue_miibus_readreg(device_ptr_t dev, int phy, int reg) { - struct aue_softc *sc; + struct aue_softc *sc = USBGETSOFTC(dev); int i; u_int16_t val = 0; - sc = device_get_softc(dev); - /* * The Am79C901 HomePNA PHY actually contains * two transceivers: a 1Mbps HomePNA PHY and a @@ -424,53 +434,48 @@ * happens to be configured for MII address 3, * so we filter that out. */ - if (sc->aue_info->aue_vid == USB_VENDOR_ADMTEK && - sc->aue_info->aue_did == USB_PRODUCT_ADMTEK_PEGASUS) { + if (sc->aue_vendor == USB_VENDOR_ADMTEK && + sc->aue_product == USB_PRODUCT_ADMTEK_PEGASUS) { if (phy == 3) - return(0); + return (0); #ifdef notdef if (phy != 1) - return(0); + return (0); #endif } - csr_write_1(sc, AUE_PHY_ADDR, phy); - csr_write_1(sc, AUE_PHY_CTL, reg|AUE_PHYCTL_READ); + aue_csr_write_1(sc, AUE_PHY_ADDR, phy); + aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_READ); for (i = 0; i < AUE_TIMEOUT; i++) { - if (csr_read_1(sc, AUE_PHY_CTL) & - AUE_PHYCTL_DONE) + if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE) break; } if (i == AUE_TIMEOUT) { - printf("aue%d: MII read timed out\n", - sc->aue_unit); + printf("aue%d: MII read timed out\n", sc->aue_unit); } - val = csr_read_2(sc, AUE_PHY_DATA); + val = aue_csr_read_2(sc, AUE_PHY_DATA); - return(val); + return (val); } Static int -aue_miibus_writereg(device_t dev, int phy, int reg, int data) +aue_miibus_writereg(device_ptr_t dev, int phy, int reg, int data) { - struct aue_softc *sc; + struct aue_softc *sc = USBGETSOFTC(dev); int i; if (phy == 3) - return(0); + return (0); - sc = device_get_softc(dev); - - csr_write_2(sc, AUE_PHY_DATA, data); - csr_write_1(sc, AUE_PHY_ADDR, phy); - csr_write_1(sc, AUE_PHY_CTL, reg|AUE_PHYCTL_WRITE); + aue_csr_write_2(sc, AUE_PHY_DATA, data); + aue_csr_write_1(sc, AUE_PHY_ADDR, phy); + aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_WRITE); for (i = 0; i < AUE_TIMEOUT; i++) { - if (csr_read_1(sc, AUE_PHY_CTL) & - AUE_PHYCTL_DONE) + if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE) break; } @@ -483,35 +488,32 @@ } Static void -aue_miibus_statchg(device_t dev) +aue_miibus_statchg(device_ptr_t dev) { - struct aue_softc *sc; - struct mii_data *mii; + struct aue_softc *sc = USBGETSOFTC(dev); + struct mii_data *mii = GET_MII(sc); - sc = device_get_softc(dev); - mii = device_get_softc(sc->aue_miibus); - - AUE_CLRBIT(sc, AUE_CTL0, AUE_CTL0_RX_ENB|AUE_CTL0_TX_ENB); + AUE_CLRBIT(sc, AUE_CTL0, AUE_CTL0_RX_ENB | AUE_CTL0_TX_ENB); if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) { AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_SPEEDSEL); } else { AUE_CLRBIT(sc, AUE_CTL1, AUE_CTL1_SPEEDSEL); } - if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) { + if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_DUPLEX); - } else { + else AUE_CLRBIT(sc, AUE_CTL1, AUE_CTL1_DUPLEX); - } - AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_RX_ENB|AUE_CTL0_TX_ENB); + + AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_RX_ENB | AUE_CTL0_TX_ENB); /* * Set the LED modes on the LinkSys adapter. * This turns on the 'dual link LED' bin in the auxmode * register of the Broadcom PHY. */ - if (sc->aue_info->aue_flags & LSYS) { - u_int16_t auxmode; + if (sc->aue_flags & LSYS) { + u_int16_t auxmode; auxmode = aue_miibus_readreg(dev, 0, 0x1b); aue_miibus_writereg(dev, 0, 0x1b, auxmode | 0x04); } @@ -556,11 +558,15 @@ /* first, zot all the existing hash bits */ for (i = 0; i < 8; i++) - csr_write_1(sc, AUE_MAR0 + i, 0); + aue_csr_write_1(sc, AUE_MAR0 + i, 0); /* now program new ones */ - for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; - ifma = ifma->ifma_link.le_next) { +#if __FreeBSD_version >= 500000 + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) +#else + LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) +#endif + { if (ifma->ifma_addr->sa_family != AF_LINK) continue; h = aue_crc(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); @@ -574,25 +580,25 @@ aue_reset_pegasus_II(struct aue_softc *sc) { /* Magic constants taken from Linux driver. */ - csr_write_1(sc, AUE_REG_1D, 0); - csr_write_1(sc, AUE_REG_7B, 2); + aue_csr_write_1(sc, AUE_REG_1D, 0); + aue_csr_write_1(sc, AUE_REG_7B, 2); #if 0 if ((sc->aue_flags & HAS_HOME_PNA) && mii_mode) - csr_write_1(sc, AUE_REG_81, 6); + aue_csr_write_1(sc, AUE_REG_81, 6); else #endif - csr_write_1(sc, AUE_REG_81, 2); + aue_csr_write_1(sc, AUE_REG_81, 2); } Static void aue_reset(struct aue_softc *sc) { - register int i; + int i; AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_RESETMAC); for (i = 0; i < AUE_TIMEOUT; i++) { - if (!(csr_read_1(sc, AUE_CTL1) & AUE_CTL1_RESETMAC)) + if (!(aue_csr_read_1(sc, AUE_CTL1) & AUE_CTL1_RESETMAC)) break; } @@ -608,23 +614,24 @@ * Note: We force all of the GPIO pins low first, *then* * enable the ones we want. */ - csr_write_1(sc, AUE_GPIO0, AUE_GPIO_OUT0|AUE_GPIO_SEL0); - csr_write_1(sc, AUE_GPIO0, AUE_GPIO_OUT0|AUE_GPIO_SEL0|AUE_GPIO_SEL1); + aue_csr_write_1(sc, AUE_GPIO0, AUE_GPIO_OUT0|AUE_GPIO_SEL0); + aue_csr_write_1(sc, AUE_GPIO0, AUE_GPIO_OUT0|AUE_GPIO_SEL0|AUE_GPIO_SEL1); - /* Grrr. LinkSys has to be different from everyone else. */ - if (sc->aue_info->aue_flags & LSYS) { - csr_write_1(sc, AUE_GPIO0, AUE_GPIO_SEL0|AUE_GPIO_SEL1); - csr_write_1(sc, AUE_GPIO0, AUE_GPIO_SEL0|AUE_GPIO_SEL1| - AUE_GPIO_OUT0); + if (sc->aue_flags & LSYS) { + /* Grrr. LinkSys has to be different from everyone else. */ + aue_csr_write_1(sc, AUE_GPIO0, + AUE_GPIO_SEL0 | AUE_GPIO_SEL1); + aue_csr_write_1(sc, AUE_GPIO0, + AUE_GPIO_SEL0 | AUE_GPIO_SEL1 | AUE_GPIO_OUT0); } - if (sc->aue_info->aue_flags & PII) + if (sc->aue_flags & PII) aue_reset_pegasus_II(sc); /* Wait a little while for the chip to get its brains in order. */ DELAY(10000); - return; + return; } /* @@ -633,21 +640,12 @@ USB_MATCH(aue) { USB_MATCH_START(aue, uaa); - struct aue_type *t; - if (!uaa->iface) - return(UMATCH_NONE); + if (uaa->iface != NULL) + return (UMATCH_NONE); - t = aue_devs; - while(t->aue_vid) { - if (uaa->vendor == t->aue_vid && - uaa->product == t->aue_did) { - return(UMATCH_VENDOR_PRODUCT); - } - t++; - } - - return(UMATCH_NONE); + return (aue_lookup(uaa->vendor, uaa->product) != NULL ? + UMATCH_VENDOR_PRODUCT : UMATCH_NONE); } /* @@ -658,39 +656,41 @@ { USB_ATTACH_START(aue, sc, uaa); char devinfo[1024]; - int s; u_char eaddr[ETHER_ADDR_LEN]; struct ifnet *ifp; + usbd_interface_handle iface; + usbd_status err; usb_interface_descriptor_t *id; usb_endpoint_descriptor_t *ed; int i; - struct aue_type *t; - - s = splimp(); bzero(sc, sizeof(struct aue_softc)); - sc->aue_iface = uaa->iface; + + usbd_devinfo(uaa->device, 0, devinfo); + sc->aue_udev = uaa->device; sc->aue_unit = device_get_unit(self); if (usbd_set_config_no(sc->aue_udev, AUE_CONFIG_NO, 0)) { printf("aue%d: getting interface handle failed\n", sc->aue_unit); - splx(s); USB_ATTACH_ERROR_RETURN; } - t = aue_devs; - while(t->aue_vid) { - if (uaa->vendor == t->aue_vid && - uaa->product == t->aue_did) { - sc->aue_info = t; - break; - } - t++; + err = usbd_device2interface_handle(uaa->device, AUE_IFACE_IDX, &iface); + if (err) { + printf("aue%d: getting interface handle failed\n", + sc->aue_unit); + USB_ATTACH_ERROR_RETURN; } - id = usbd_get_interface_descriptor(uaa->iface); + sc->aue_iface = iface; + sc->aue_flags = aue_lookup(uaa->vendor, uaa->product)->aue_flags; + + sc->aue_product = uaa->product; + sc->aue_vendor = uaa->vendor; + + id = usbd_get_interface_descriptor(sc->aue_iface); usbd_devinfo(uaa->device, 0, devinfo); device_set_desc_copy(self, devinfo); @@ -698,25 +698,30 @@ /* Find endpoints. */ for (i = 0; i < id->bNumEndpoints; i++) { - ed = usbd_interface2endpoint_descriptor(uaa->iface, i); - if (!ed) { + ed = usbd_interface2endpoint_descriptor(iface, i); + if (ed == NULL) { printf("aue%d: couldn't get ep %d\n", sc->aue_unit, i); - splx(s); USB_ATTACH_ERROR_RETURN; } if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && - (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) { + UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { sc->aue_ed[AUE_ENDPT_RX] = ed->bEndpointAddress; } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && - (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) { + UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { sc->aue_ed[AUE_ENDPT_TX] = ed->bEndpointAddress; } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && - (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) { + UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { sc->aue_ed[AUE_ENDPT_INTR] = ed->bEndpointAddress; } } +#if __FreeBSD_version >= 500000 + mtx_init(&sc->aue_mtx, device_get_nameunit(self), MTX_NETWORK_LOCK, + MTX_DEF | MTX_RECURSE); +#endif + AUE_LOCK(sc); + /* Reset the adapter. */ aue_reset(sc); @@ -762,7 +767,10 @@ if (mii_phy_probe(self, &sc->aue_miibus, aue_ifmedia_upd, aue_ifmedia_sts)) { printf("aue%d: MII without any PHY!\n", sc->aue_unit); - splx(s); + AUE_UNLOCK(sc); +#if __FreeBSD_version >= 500000 + mtx_destroy(&sc->aue_mtx); +#endif USB_ATTACH_ERROR_RETURN; } @@ -772,12 +780,16 @@ /* * Call MI attach routine. */ +#if __FreeBSD_version >= 500000 + ether_ifattach(ifp, eaddr); +#else ether_ifattach(ifp, ETHER_BPF_SUPPORTED); +#endif callout_handle_init(&sc->aue_stat_ch); usb_register_netisr(); - sc->aue_gone = 0; + sc->aue_dying = 0; - splx(s); + AUE_UNLOCK(sc); USB_ATTACH_SUCCESS_RETURN; } @@ -786,16 +798,18 @@ { struct aue_softc *sc; struct ifnet *ifp; - int s; - - s = splusb(); sc = device_get_softc(dev); + AUE_LOCK(sc); ifp = &sc->arpcom.ac_if; - sc->aue_gone = 1; + sc->aue_dying = 1; untimeout(aue_tick, sc, sc->aue_stat_ch); +#if __FreeBSD_version >= 500000 + ether_ifdetach(ifp); +#else ether_ifdetach(ifp, ETHER_BPF_SUPPORTED); +#endif if (sc->aue_ep[AUE_ENDPT_TX] != NULL) usbd_abort_pipe(sc->aue_ep[AUE_ENDPT_TX]); @@ -805,9 +819,13 @@ if (sc->aue_ep[AUE_ENDPT_INTR] != NULL) usbd_abort_pipe(sc->aue_ep[AUE_ENDPT_INTR]); #endif - splx(s); - return(0); + AUE_UNLOCK(sc); +#if __FreeBSD_version >= 500000 + mtx_destroy(&sc->aue_mtx); +#endif + + return (0); } /* @@ -823,7 +841,7 @@ if (m_new == NULL) { printf("aue%d: no memory for rx list " "-- packet dropped!\n", sc->aue_unit); - return(ENOBUFS); + return (ENOBUFS); } MCLGET(m_new, M_DONTWAIT); @@ -831,7 +849,7 @@ printf("aue%d: no memory for rx list " "-- packet dropped!\n", sc->aue_unit); m_freem(m_new); - return(ENOBUFS); + return (ENOBUFS); } m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; } else { @@ -843,7 +861,7 @@ m_adj(m_new, ETHER_ALIGN); c->aue_mbuf = m_new; - return(0); + return (0); } Static int @@ -859,15 +877,15 @@ c->aue_sc = sc; c->aue_idx = i; if (aue_newbuf(sc, c, NULL) == ENOBUFS) - return(ENOBUFS); + return (ENOBUFS); if (c->aue_xfer == NULL) { c->aue_xfer = usbd_alloc_xfer(sc->aue_udev); if (c->aue_xfer == NULL) - return(ENOBUFS); + return (ENOBUFS); } } - return(0); + return (0); } Static int @@ -886,45 +904,42 @@ if (c->aue_xfer == NULL) { c->aue_xfer = usbd_alloc_xfer(sc->aue_udev); if (c->aue_xfer == NULL) - return(ENOBUFS); + return (ENOBUFS); } c->aue_buf = malloc(AUE_BUFSZ, M_USBDEV, M_NOWAIT); if (c->aue_buf == NULL) - return(ENOBUFS); + return (ENOBUFS); } - return(0); + return (0); } #ifdef AUE_INTR_PIPE Static void aue_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) { - struct aue_softc *sc; + struct aue_softc *sc = priv; struct ifnet *ifp; struct aue_intrpkt *p; - int s; - - s = splimp(); - sc = priv; + AUE_LOCK(sc); ifp = &sc->arpcom.ac_if; if (!(ifp->if_flags & IFF_RUNNING)) { - splx(s); + AUE_UNLOCK(sc); return; } if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) { - splx(s); + AUE_UNLOCK(sc); return; } printf("aue%d: usb error on intr: %s\n", sc->aue_unit, usbd_errstr(status)); if (status == USBD_STALLED) usbd_clear_endpoint_stall(sc->aue_ep[AUE_ENDPT_RX]); - splx(s); + AUE_UNLOCK(sc); return; } @@ -936,7 +951,7 @@ if (p->aue_txstat0 & (AUE_TXSTAT0_LATECOLL & AUE_TXSTAT0_EXCESSCOLL)) ifp->if_collisions++; - splx(s); + AUE_UNLOCK(sc); return; } #endif @@ -948,10 +963,12 @@ struct aue_chain *c; sc = ifp->if_softc; + AUE_LOCK(sc); c = &sc->aue_cdata.aue_rx_chain[sc->aue_cdata.aue_rx_prod]; if (aue_newbuf(sc, c, NULL) == ENOBUFS) { ifp->if_ierrors++; + AUE_UNLOCK(sc); return; } @@ -961,6 +978,7 @@ USBD_NO_TIMEOUT, aue_rxeof); usbd_transfer(c->aue_xfer); + AUE_UNLOCK(sc); return; } @@ -978,18 +996,24 @@ int total_len = 0; struct aue_rxpkt r; - c = priv; - sc = c->aue_sc; + if (sc->aue_dying) + return; + AUE_LOCK(sc); ifp = &sc->arpcom.ac_if; - if (!(ifp->if_flags & IFF_RUNNING)) + if (!(ifp->if_flags & IFF_RUNNING)) { + AUE_UNLOCK(sc); return; + } if (status != USBD_NORMAL_COMPLETION) { - if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) + if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) { + AUE_UNLOCK(sc); return; - printf("aue%d: usb error on rx: %s\n", sc->aue_unit, - usbd_errstr(status)); + } + if (usbd_ratecheck(&sc->aue_rx_notice)) + printf("aue%d: usb error on rx: %s\n", sc->aue_unit, + usbd_errstr(status)); if (status == USBD_STALLED) usbd_clear_endpoint_stall(sc->aue_ep[AUE_ENDPT_RX]); goto done; @@ -1022,7 +1046,7 @@ /* Put the packet on the special USB input queue. */ usb_ether_input(m); - + AUE_UNLOCK(sc); return; done: @@ -1032,6 +1056,7 @@ USBD_NO_TIMEOUT, aue_rxeof); usbd_transfer(xfer); + AUE_UNLOCK(sc); return; } @@ -1043,28 +1068,24 @@ Static void aue_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) { - struct aue_softc *sc; - struct aue_chain *c; + struct aue_chain *c = priv; + struct aue_softc *sc = c->aue_sc; struct ifnet *ifp; usbd_status err; - int s; - - s = splimp(); - c = priv; - sc = c->aue_sc; + AUE_LOCK(sc); ifp = &sc->arpcom.ac_if; if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) { - splx(s); + AUE_UNLOCK(sc); return; } printf("aue%d: usb error on tx: %s\n", sc->aue_unit, usbd_errstr(status)); if (status == USBD_STALLED) usbd_clear_endpoint_stall(sc->aue_ep[AUE_ENDPT_TX]); - splx(s); + AUE_UNLOCK(sc); return; } @@ -1083,7 +1104,7 @@ else ifp->if_opackets++; - splx(s); + AUE_UNLOCK(sc); return; } @@ -1091,40 +1112,33 @@ Static void aue_tick(void *xsc) { - struct aue_softc *sc; + struct aue_softc *sc = xsc; struct ifnet *ifp; struct mii_data *mii; - int s; - s = splimp(); - - sc = xsc; - - if (sc == NULL) { - splx(s); + if (sc == NULL) return; - } + + AUE_LOCK(sc); ifp = &sc->arpcom.ac_if; - mii = device_get_softc(sc->aue_miibus); + mii = GET_MII(sc); if (mii == NULL) { - splx(s); + AUE_UNLOCK(sc); return; } mii_tick(mii); - if (!sc->aue_link) { - mii_pollstat(mii); - if (mii->mii_media_status & IFM_ACTIVE && - IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) - sc->aue_link++; - if (ifp->if_snd.ifq_head != NULL) - aue_start(ifp); + if (!sc->aue_link && mii->mii_media_status & IFM_ACTIVE && + IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { + sc->aue_link++; + if (ifp->if_snd.ifq_head != NULL) + aue_start(ifp); } sc->aue_stat_ch = timeout(aue_tick, sc, hz); - splx(s); + AUE_UNLOCK(sc); return; } @@ -1164,35 +1178,42 @@ err = usbd_transfer(c->aue_xfer); if (err != USBD_IN_PROGRESS) { aue_stop(sc); - return(EIO); + return (EIO); } sc->aue_cdata.aue_tx_cnt++; - return(0); + return (0); } Static void aue_start(struct ifnet *ifp) { - struct aue_softc *sc; + struct aue_softc *sc = ifp->if_softc; struct mbuf *m_head = NULL; - sc = ifp->if_softc; + AUE_LOCK(sc); - if (!sc->aue_link) + if (!sc->aue_link) { + AUE_UNLOCK(sc); return; + } - if (ifp->if_flags & IFF_OACTIVE) + if (ifp->if_flags & IFF_OACTIVE) { + AUE_UNLOCK(sc); return; + } IF_DEQUEUE(&ifp->if_snd, m_head); - if (m_head == NULL) + if (m_head == NULL) { + AUE_UNLOCK(sc); return; + } if (aue_encap(sc, m_head, 0)) { IF_PREPEND(&ifp->if_snd, m_head); ifp->if_flags |= IFF_OACTIVE; + AUE_UNLOCK(sc); return; } @@ -1200,8 +1221,7 @@ * If there's a BPF listener, bounce a copy of this frame * to him. */ - if (ifp->if_bpf) - bpf_mtap(ifp, m_head); + BPF_MTAP(ifp, m_head); ifp->if_flags |= IFF_OACTIVE; @@ -1209,6 +1229,7 @@ * Set a timeout in case the chip goes out to lunch. */ ifp->if_timer = 5; + AUE_UNLOCK(sc); return; } @@ -1218,45 +1239,44 @@ { struct aue_softc *sc = xsc; struct ifnet *ifp = &sc->arpcom.ac_if; - struct mii_data *mii; + struct mii_data *mii = GET_MII(sc); struct aue_chain *c; usbd_status err; - int i, s; + int i; - if (ifp->if_flags & IFF_RUNNING) - return; + AUE_LOCK(sc); - s = splimp(); + if (ifp->if_flags & IFF_RUNNING) { + AUE_UNLOCK(sc); + return; + } /* * Cancel pending I/O and free all RX/TX buffers. */ aue_reset(sc); - mii = device_get_softc(sc->aue_miibus); - /* Set MAC address */ for (i = 0; i < ETHER_ADDR_LEN; i++) - csr_write_1(sc, AUE_PAR0 + i, sc->arpcom.ac_enaddr[i]); + aue_csr_write_1(sc, AUE_PAR0 + i, sc->arpcom.ac_enaddr[i]); /* If we want promiscuous mode, set the allframes bit. */ - if (ifp->if_flags & IFF_PROMISC) { + if (ifp->if_flags & IFF_PROMISC) AUE_SETBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC); - } else { + else AUE_CLRBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC); - } /* Init TX ring. */ if (aue_tx_list_init(sc) == ENOBUFS) { printf("aue%d: tx list init failed\n", sc->aue_unit); - splx(s); + AUE_UNLOCK(sc); return; } /* Init RX ring. */ if (aue_rx_list_init(sc) == ENOBUFS) { printf("aue%d: rx list init failed\n", sc->aue_unit); - splx(s); + AUE_UNLOCK(sc); return; } @@ -1268,9 +1288,10 @@ aue_setmulti(sc); /* Enable RX and TX */ - csr_write_1(sc, AUE_CTL0, AUE_CTL0_RXSTAT_APPEND|AUE_CTL0_RX_ENB); + aue_csr_write_1(sc, AUE_CTL0, AUE_CTL0_RXSTAT_APPEND | AUE_CTL0_RX_ENB); AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_TX_ENB); AUE_SETBIT(sc, AUE_CTL2, AUE_CTL2_EP3_CLR); + mii_mediachg(mii); /* Open RX and TX pipes. */ @@ -1279,7 +1300,7 @@ if (err) { printf("aue%d: open rx pipe failed: %s\n", sc->aue_unit, usbd_errstr(err)); - splx(s); + AUE_UNLOCK(sc); return; } err = usbd_open_pipe(sc->aue_iface, sc->aue_ed[AUE_ENDPT_TX], @@ -1287,7 +1308,7 @@ if (err) { printf("aue%d: open tx pipe failed: %s\n", sc->aue_unit, usbd_errstr(err)); - splx(s); + AUE_UNLOCK(sc); return; } @@ -1299,7 +1320,7 @@ if (err) { printf("aue%d: open intr pipe failed: %s\n", sc->aue_unit, usbd_errstr(err)); - splx(s); + AUE_UNLOCK(sc); return; } #endif @@ -1316,10 +1337,10 @@ ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; - (void)splx(s); - sc->aue_stat_ch = timeout(aue_tick, sc, hz); + AUE_UNLOCK(sc); + return; } @@ -1329,22 +1350,18 @@ Static int aue_ifmedia_upd(struct ifnet *ifp) { - struct aue_softc *sc; - struct mii_data *mii; - - sc = ifp->if_softc; + struct aue_softc *sc = ifp->if_softc; + struct mii_data *mii = GET_MII(sc); - mii = device_get_softc(sc->aue_miibus); sc->aue_link = 0; if (mii->mii_instance) { struct mii_softc *miisc; - for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL; - miisc = LIST_NEXT(miisc, mii_list)) + LIST_FOREACH(miisc, &mii->mii_phys, mii_list) mii_phy_reset(miisc); } mii_mediachg(mii); - return(0); + return (0); } /* @@ -1353,12 +1370,9 @@ Static void aue_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) { - struct aue_softc *sc; - struct mii_data *mii; - - sc = ifp->if_softc; + struct aue_softc *sc = ifp->if_softc; + struct mii_data *mii = GET_MII(sc); - mii = device_get_softc(sc->aue_miibus); mii_pollstat(mii); ifmr->ifm_active = mii->mii_media_active; ifmr->ifm_status = mii->mii_media_status; @@ -1370,18 +1384,13 @@ aue_ioctl(struct ifnet *ifp, u_long command, caddr_t data) { struct aue_softc *sc = ifp->if_softc; - struct ifreq *ifr = (struct ifreq *) data; + struct ifreq *ifr = (struct ifreq *)data; struct mii_data *mii; - int s, error = 0; + int error = 0; - s = splimp(); + AUE_LOCK(sc); switch(command) { - case SIOCSIFADDR: - case SIOCGIFADDR: - case SIOCSIFMTU: - error = ether_ioctl(ifp, command, data); - break; case SIOCSIFFLAGS: if (ifp->if_flags & IFF_UP) { if (ifp->if_flags & IFF_RUNNING && @@ -1408,27 +1417,27 @@ break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: - mii = device_get_softc(sc->aue_miibus); + mii = GET_MII(sc); error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); break; default: - error = EINVAL; + error = ether_ioctl(ifp, command, data); break; } - (void)splx(s); + AUE_UNLOCK(sc); - return(error); + return (error); } Static void aue_watchdog(struct ifnet *ifp) { - struct aue_softc *sc; + struct aue_softc *sc = ifp->if_softc; struct aue_chain *c; usbd_status stat; - sc = ifp->if_softc; + AUE_LOCK(sc); ifp->if_oerrors++; printf("aue%d: watchdog timeout\n", sc->aue_unit); @@ -1439,7 +1448,7 @@ if (ifp->if_snd.ifq_head != NULL) aue_start(ifp); - + AUE_UNLOCK(sc); return; } @@ -1454,11 +1463,12 @@ struct ifnet *ifp; int i; + AUE_LOCK(sc); ifp = &sc->arpcom.ac_if; ifp->if_timer = 0; - csr_write_1(sc, AUE_CTL0, 0); - csr_write_1(sc, AUE_CTL1, 0); + aue_csr_write_1(sc, AUE_CTL0, 0); + aue_csr_write_1(sc, AUE_CTL1, 0); aue_reset(sc); untimeout(aue_tick, sc, sc->aue_stat_ch); @@ -1547,6 +1557,7 @@ sc->aue_link = 0; ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); + AUE_UNLOCK(sc); return; } @@ -1561,9 +1572,11 @@ struct aue_softc *sc; sc = device_get_softc(dev); - + sc->aue_dying++; + AUE_LOCK(sc); aue_reset(sc); aue_stop(sc); + AUE_UNLOCK(sc); return; } Index: sys/dev/usb/if_auereg.h =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/if_auereg.h,v retrieving revision 1.5.2.1 diff -u -r1.5.2.1 if_auereg.h --- sys/dev/usb/if_auereg.h 11 Dec 2001 14:57:04 -0000 1.5.2.1 +++ sys/dev/usb/if_auereg.h 4 Oct 2003 21:27:25 -0000 @@ -29,7 +29,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/usb/if_auereg.h,v 1.5.2.1 2001/12/11 14:57:04 sumikawa Exp $ + * $FreeBSD: src/sys/dev/usb/if_auereg.h,v 1.17 2003/10/04 21:41:01 joe Exp $ */ /* @@ -46,20 +46,11 @@ * the RX case, the data includes an optional RX status word. */ -#define AUE_VENDORID_ADMTEK 0x07A6 -#define AUE_DEVICEID_PEGASUS 0x0986 - -#define AUE_VENDORID_BILLIONTON 0x08DD -#define AUE_DEVICEID_USB100 0x0986 - -#define AUE_VENDORID_MELCO 0x0411 -#define AUE_DEVICEID_LUATX 0x0001 - - #define AUE_UR_READREG 0xF0 #define AUE_UR_WRITEREG 0xF1 #define AUE_CONFIG_NO 1 +#define AUE_IFACE_IDX 0 /* * Note that while the ADMtek technically has four @@ -205,15 +196,6 @@ #define AUE_RXSTAT_DRIBBLE 0x10 #define AUE_RXSTAT_MASK 0x1E -struct aue_type { - u_int16_t aue_vid; - u_int16_t aue_did; - u_int16_t aue_flags; -#define LSYS 0x0001 /* use Linksys reset */ -#define PNA 0x0002 /* has Home PNA */ -#define PII 0x0004 /* Pegasus II chip */ -}; - #define AUE_TX_LIST_CNT 1 #define AUE_RX_LIST_CNT 1 @@ -240,23 +222,43 @@ #define AUE_INC(x, y) (x) = (x + 1) % y struct aue_softc { +#if defined(__FreeBSD__) +#define GET_MII(sc) (device_get_softc((sc)->aue_miibus)) +#elif defined(__NetBSD__) +#define GET_MII(sc) (&(sc)->aue_mii) +#elif defined(__OpenBSD__) +#define GET_MII(sc) (&(sc)->aue_mii) +#endif struct arpcom arpcom; device_t aue_miibus; usbd_device_handle aue_udev; usbd_interface_handle aue_iface; - struct aue_type *aue_info; + u_int16_t aue_vendor; + u_int16_t aue_product; int aue_ed[AUE_ENDPT_MAX]; usbd_pipe_handle aue_ep[AUE_ENDPT_MAX]; int aue_unit; u_int8_t aue_link; - u_int8_t aue_gone; int aue_if_flags; struct aue_cdata aue_cdata; struct callout_handle aue_stat_ch; +#if __FreeBSD_version >= 500000 + struct mtx aue_mtx; +#endif + u_int16_t aue_flags; + char aue_dying; + struct timeval aue_rx_notice; }; +#if 0 +#define AUE_LOCK(_sc) mtx_lock(&(_sc)->aue_mtx) +#define AUE_UNLOCK(_sc) mtx_unlock(&(_sc)->aue_mtx) +#else +#define AUE_LOCK(_sc) +#define AUE_UNLOCK(_sc) +#endif + #define AUE_TIMEOUT 1000 -#define ETHER_ALIGN 2 #define AUE_BUFSZ 1536 #define AUE_MIN_FRAMELEN 60 #define AUE_INTR_INTERVAL 100 /* ms */ Index: sys/dev/usb/if_cue.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/if_cue.c,v retrieving revision 1.7.2.6 diff -u -r1.7.2.6 if_cue.c --- sys/dev/usb/if_cue.c 6 Nov 2002 14:23:20 -0000 1.7.2.6 +++ sys/dev/usb/if_cue.c 4 Oct 2003 21:27:25 -0000 @@ -28,10 +28,11 @@ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD: src/sys/dev/usb/if_cue.c,v 1.7.2.6 2002/11/06 14:23:20 joe Exp $ */ +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/if_cue.c,v 1.39 2003/10/04 21:41:01 joe Exp $"); + /* * CATC USB-EL1210A USB to ethernet driver. Used in the CATC Netmate * adapters and others. @@ -50,6 +51,9 @@ * transaction, which helps performance a great deal. */ +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/if_cue.c,v 1.39 2003/10/04 21:41:01 joe Exp $"); + #include #include #include @@ -65,8 +69,11 @@ #include -#include /* for DELAY */ #include +#include +#if __FreeBSD_version < 500000 +#include +#endif #include #include @@ -77,11 +84,6 @@ #include -#ifndef lint -static const char rcsid[] = - "$FreeBSD: src/sys/dev/usb/if_cue.c,v 1.7.2.6 2002/11/06 14:23:20 joe Exp $"; -#endif - /* * Various supported device vendors/products. */ @@ -94,9 +96,9 @@ Static struct usb_qdat cue_qdat; -Static int cue_match(device_t); -Static int cue_attach(device_t); -Static int cue_detach(device_t); +Static int cue_match(device_ptr_t); +Static int cue_attach(device_ptr_t); +Static int cue_detach(device_ptr_t); Static int cue_tx_list_init(struct cue_softc *); Static int cue_rx_list_init(struct cue_softc *); @@ -111,17 +113,17 @@ Static void cue_init(void *); Static void cue_stop(struct cue_softc *); Static void cue_watchdog(struct ifnet *); -Static void cue_shutdown(device_t); +Static void cue_shutdown(device_ptr_t); Static void cue_setmulti(struct cue_softc *); Static u_int32_t cue_crc(caddr_t); Static void cue_reset(struct cue_softc *); -Static int csr_read_1(struct cue_softc *, int); -Static int csr_write_1(struct cue_softc *, int, int); -Static int csr_read_2(struct cue_softc *, int); +Static int cue_csr_read_1(struct cue_softc *, int); +Static int cue_csr_write_1(struct cue_softc *, int, int); +Static int cue_csr_read_2(struct cue_softc *, int); #ifdef notdef -Static int csr_write_2(struct cue_softc *, int, int); +Static int cue_csr_write_2(struct cue_softc *, int, int); #endif Static int cue_mem(struct cue_softc *, int, int, void *, int); Static int cue_getmac(struct cue_softc *, void *); @@ -144,26 +146,27 @@ Static devclass_t cue_devclass; -DRIVER_MODULE(if_cue, uhub, cue_driver, cue_devclass, usbd_driver_load, 0); +DRIVER_MODULE(cue, uhub, cue_driver, cue_devclass, usbd_driver_load, 0); +MODULE_DEPEND(cue, usb, 1, 1, 1); +MODULE_DEPEND(cue, ether, 1, 1, 1); #define CUE_SETBIT(sc, reg, x) \ - csr_write_1(sc, reg, csr_read_1(sc, reg) | (x)) + cue_csr_write_1(sc, reg, cue_csr_read_1(sc, reg) | (x)) #define CUE_CLRBIT(sc, reg, x) \ - csr_write_1(sc, reg, csr_read_1(sc, reg) & ~(x)) + cue_csr_write_1(sc, reg, cue_csr_read_1(sc, reg) & ~(x)) Static int -csr_read_1(struct cue_softc *sc, int reg) +cue_csr_read_1(struct cue_softc *sc, int reg) { usb_device_request_t req; usbd_status err; u_int8_t val = 0; - int s; - if (sc->cue_gone) + if (sc->cue_dying) return(0); - s = splusb(); + CUE_LOCK(sc); req.bmRequestType = UT_READ_VENDOR_DEVICE; req.bRequest = CUE_CMD_READREG; @@ -171,10 +174,9 @@ USETW(req.wIndex, reg); USETW(req.wLength, 1); - err = usbd_do_request_flags(sc->cue_udev, - &req, &val, USBD_NO_TSLEEP, NULL); + err = usbd_do_request(sc->cue_udev, &req, &val); - splx(s); + CUE_UNLOCK(sc); if (err) return(0); @@ -183,17 +185,16 @@ } Static int -csr_read_2(struct cue_softc *sc, int reg) +cue_csr_read_2(struct cue_softc *sc, int reg) { usb_device_request_t req; usbd_status err; u_int16_t val = 0; - int s; - if (sc->cue_gone) + if (sc->cue_dying) return(0); - s = splusb(); + CUE_LOCK(sc); req.bmRequestType = UT_READ_VENDOR_DEVICE; req.bRequest = CUE_CMD_READREG; @@ -201,10 +202,9 @@ USETW(req.wIndex, reg); USETW(req.wLength, 2); - err = usbd_do_request_flags(sc->cue_udev, - &req, &val, USBD_NO_TSLEEP, NULL); + err = usbd_do_request(sc->cue_udev, &req, &val); - splx(s); + CUE_UNLOCK(sc); if (err) return(0); @@ -213,16 +213,15 @@ } Static int -csr_write_1(struct cue_softc *sc, int reg, int val) +cue_csr_write_1(struct cue_softc *sc, int reg, int val) { usb_device_request_t req; usbd_status err; - int s; - if (sc->cue_gone) + if (sc->cue_dying) return(0); - s = splusb(); + CUE_LOCK(sc); req.bmRequestType = UT_WRITE_VENDOR_DEVICE; req.bRequest = CUE_CMD_WRITEREG; @@ -230,10 +229,9 @@ USETW(req.wIndex, reg); USETW(req.wLength, 0); - err = usbd_do_request_flags(sc->cue_udev, - &req, &val, USBD_NO_TSLEEP, NULL); + err = usbd_do_request(sc->cue_udev, &req, NULL); - splx(s); + CUE_UNLOCK(sc); if (err) return(-1); @@ -243,16 +241,15 @@ #ifdef notdef Static int -csr_write_2(struct cue_softc *sc, int reg, int val) +cue_csr_write_2(struct cue_softc *sc, int reg, int val) { usb_device_request_t req; usbd_status err; - int s; - if (sc->cue_gone) + if (sc->cue_dying) return(0); - s = splusb(); + CUE_LOCK(sc); req.bmRequestType = UT_WRITE_VENDOR_DEVICE; req.bRequest = CUE_CMD_WRITEREG; @@ -260,10 +257,9 @@ USETW(req.wIndex, reg); USETW(req.wLength, 0); - err = usbd_do_request_flags(sc->cue_udev, - &req, &val, USBD_NO_TSLEEP, NULL); + err = usbd_do_request(sc->cue_udev, &req, NULL); - splx(s); + CUE_UNLOCK(sc); if (err) return(-1); @@ -277,12 +273,11 @@ { usb_device_request_t req; usbd_status err; - int s; - if (sc->cue_gone) + if (sc->cue_dying) return(0); - s = splusb(); + CUE_LOCK(sc); if (cmd == CUE_CMD_READSRAM) req.bmRequestType = UT_READ_VENDOR_DEVICE; @@ -293,10 +288,9 @@ USETW(req.wIndex, addr); USETW(req.wLength, len); - err = usbd_do_request_flags(sc->cue_udev, - &req, &buf, USBD_NO_TSLEEP, NULL); + err = usbd_do_request(sc->cue_udev, &req, buf); - splx(s); + CUE_UNLOCK(sc); if (err) return(-1); @@ -309,12 +303,11 @@ { usb_device_request_t req; usbd_status err; - int s; - if (sc->cue_gone) + if (sc->cue_dying) return(0); - s = splusb(); + CUE_LOCK(sc); req.bmRequestType = UT_READ_VENDOR_DEVICE; req.bRequest = CUE_CMD_GET_MACADDR; @@ -322,10 +315,9 @@ USETW(req.wIndex, 0); USETW(req.wLength, ETHER_ADDR_LEN); - err = usbd_do_request_flags(sc->cue_udev, - &req, buf, USBD_NO_TSLEEP, NULL); + err = usbd_do_request(sc->cue_udev, &req, buf); - splx(s); + CUE_UNLOCK(sc); if (err) { printf("cue%d: read MAC address failed\n", sc->cue_unit); @@ -366,8 +358,8 @@ if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { for (i = 0; i < CUE_MCAST_TABLE_LEN; i++) sc->cue_mctab[i] = 0xFF; - cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR, - &sc->cue_mctab, CUE_MCAST_TABLE_LEN); + cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR, + &sc->cue_mctab, CUE_MCAST_TABLE_LEN); return; } @@ -376,12 +368,16 @@ sc->cue_mctab[i] = 0; /* now program new ones */ - for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; - ifma = ifma->ifma_link.le_next) { +#if __FreeBSD_version >= 500000 + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) +#else + LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) +#endif + { if (ifma->ifma_addr->sa_family != AF_LINK) continue; h = cue_crc(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); - sc->cue_mctab[h >> 3] |= 1 << (h & 0x7); + sc->cue_mctab[h >> 3] |= 1 << (h & 0x7); } /* @@ -389,8 +385,12 @@ * so we can receive broadcast frames. */ if (ifp->if_flags & IFF_BROADCAST) { +#if __FreeBSD_version >= 500000 + h = cue_crc(ifp->if_broadcastaddr); +#else h = cue_crc(etherbroadcastaddr); - sc->cue_mctab[h >> 3] |= 1 << (h & 0x7); +#endif + sc->cue_mctab[h >> 3] |= 1 << (h & 0x7); } cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR, @@ -404,23 +404,16 @@ { usb_device_request_t req; usbd_status err; - int s; - if (sc->cue_gone) + if (sc->cue_dying) return; - s = splusb(); - req.bmRequestType = UT_WRITE_VENDOR_DEVICE; req.bRequest = CUE_CMD_RESET; USETW(req.wValue, 0); USETW(req.wIndex, 0); USETW(req.wLength, 0); - err = usbd_do_request_flags(sc->cue_udev, - &req, NULL, USBD_NO_TSLEEP, NULL); - - splx(s); - + err = usbd_do_request(sc->cue_udev, &req, NULL); if (err) printf("cue%d: reset failed\n", sc->cue_unit); @@ -460,15 +453,12 @@ { USB_ATTACH_START(cue, sc, uaa); char devinfo[1024]; - int s; u_char eaddr[ETHER_ADDR_LEN]; struct ifnet *ifp; usb_interface_descriptor_t *id; usb_endpoint_descriptor_t *ed; int i; - s = splimp(); - bzero(sc, sizeof(struct cue_softc)); sc->cue_iface = uaa->iface; sc->cue_udev = uaa->device; @@ -477,7 +467,6 @@ if (usbd_set_config_no(sc->cue_udev, CUE_CONFIG_NO, 0)) { printf("cue%d: getting interface handle failed\n", sc->cue_unit); - splx(s); USB_ATTACH_ERROR_RETURN; } @@ -493,21 +482,26 @@ if (!ed) { printf("cue%d: couldn't get ep %d\n", sc->cue_unit, i); - splx(s); USB_ATTACH_ERROR_RETURN; } if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && - (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) { + UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { sc->cue_ed[CUE_ENDPT_RX] = ed->bEndpointAddress; } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && - (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) { + UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { sc->cue_ed[CUE_ENDPT_TX] = ed->bEndpointAddress; } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && - (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) { + UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { sc->cue_ed[CUE_ENDPT_INTR] = ed->bEndpointAddress; } } +#if __FreeBSD_version >= 500000 + mtx_init(&sc->cue_mtx, device_get_nameunit(self), MTX_NETWORK_LOCK, + MTX_DEF | MTX_RECURSE); +#endif + CUE_LOCK(sc); + #ifdef notdef /* Reset the adapter. */ cue_reset(sc); @@ -544,12 +538,16 @@ /* * Call MI attach routine. */ +#if __FreeBSD_version >= 500000 + ether_ifattach(ifp, eaddr); +#else ether_ifattach(ifp, ETHER_BPF_SUPPORTED); +#endif callout_handle_init(&sc->cue_stat_ch); usb_register_netisr(); - sc->cue_gone = 0; + sc->cue_dying = 0; - splx(s); + CUE_UNLOCK(sc); USB_ATTACH_SUCCESS_RETURN; } @@ -558,16 +556,18 @@ { struct cue_softc *sc; struct ifnet *ifp; - int s; - - s = splusb(); sc = device_get_softc(dev); + CUE_LOCK(sc); ifp = &sc->arpcom.ac_if; - sc->cue_gone = 1; + sc->cue_dying = 1; untimeout(cue_tick, sc, sc->cue_stat_ch); +#if __FreeBSD_version >= 500000 + ether_ifdetach(ifp); +#else ether_ifdetach(ifp, ETHER_BPF_SUPPORTED); +#endif if (sc->cue_ep[CUE_ENDPT_TX] != NULL) usbd_abort_pipe(sc->cue_ep[CUE_ENDPT_TX]); @@ -576,7 +576,10 @@ if (sc->cue_ep[CUE_ENDPT_INTR] != NULL) usbd_abort_pipe(sc->cue_ep[CUE_ENDPT_INTR]); - splx(s); + CUE_UNLOCK(sc); +#if __FreeBSD_version >= 500000 + mtx_destroy(&sc->cue_mtx); +#endif return(0); } @@ -674,10 +677,12 @@ struct cue_chain *c; sc = ifp->if_softc; + CUE_LOCK(sc); c = &sc->cue_cdata.cue_rx_chain[sc->cue_cdata.cue_rx_prod]; if (cue_newbuf(sc, c, NULL) == ENOBUFS) { ifp->if_ierrors++; + CUE_UNLOCK(sc); return; } @@ -686,6 +691,7 @@ c, mtod(c->cue_mbuf, char *), CUE_BUFSZ, USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, cue_rxeof); usbd_transfer(c->cue_xfer); + CUE_UNLOCK(sc); return; } @@ -706,16 +712,22 @@ c = priv; sc = c->cue_sc; + CUE_LOCK(sc); ifp = &sc->arpcom.ac_if; - if (!(ifp->if_flags & IFF_RUNNING)) + if (!(ifp->if_flags & IFF_RUNNING)) { + CUE_UNLOCK(sc); return; + } if (status != USBD_NORMAL_COMPLETION) { - if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) + if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) { + CUE_UNLOCK(sc); return; - printf("cue%d: usb error on rx: %s\n", sc->cue_unit, - usbd_errstr(status)); + } + if (usbd_ratecheck(&sc->cue_rx_notice)) + printf("cue%d: usb error on rx: %s\n", sc->cue_unit, + usbd_errstr(status)); if (status == USBD_STALLED) usbd_clear_endpoint_stall(sc->cue_ep[CUE_ENDPT_RX]); goto done; @@ -741,6 +753,7 @@ /* Put the packet on the special USB input queue. */ usb_ether_input(m); + CUE_UNLOCK(sc); return; done: @@ -749,6 +762,7 @@ c, mtod(c->cue_mbuf, char *), CUE_BUFSZ, USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, cue_rxeof); usbd_transfer(c->cue_xfer); + CUE_UNLOCK(sc); return; } @@ -765,24 +779,22 @@ struct cue_chain *c; struct ifnet *ifp; usbd_status err; - int s; - - s = splimp(); c = priv; sc = c->cue_sc; + CUE_LOCK(sc); ifp = &sc->arpcom.ac_if; if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) { - splx(s); + CUE_UNLOCK(sc); return; } printf("cue%d: usb error on tx: %s\n", sc->cue_unit, usbd_errstr(status)); if (status == USBD_STALLED) usbd_clear_endpoint_stall(sc->cue_ep[CUE_ENDPT_TX]); - splx(s); + CUE_UNLOCK(sc); return; } @@ -801,7 +813,7 @@ else ifp->if_opackets++; - splx(s); + CUE_UNLOCK(sc); return; } @@ -811,29 +823,26 @@ { struct cue_softc *sc; struct ifnet *ifp; - int s; - - s = splimp(); sc = xsc; - if (sc == NULL) { - splx(s); + if (sc == NULL) return; - } + + CUE_LOCK(sc); ifp = &sc->arpcom.ac_if; - ifp->if_collisions += csr_read_2(sc, CUE_TX_SINGLECOLL); - ifp->if_collisions += csr_read_2(sc, CUE_TX_MULTICOLL); - ifp->if_collisions += csr_read_2(sc, CUE_TX_EXCESSCOLL); + ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_SINGLECOLL); + ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_MULTICOLL); + ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_EXCESSCOLL); - if (csr_read_2(sc, CUE_RX_FRAMEERR)) + if (cue_csr_read_2(sc, CUE_RX_FRAMEERR)) ifp->if_ierrors++; sc->cue_stat_ch = timeout(cue_tick, sc, hz); - splx(s); + CUE_UNLOCK(sc); return; } @@ -882,17 +891,23 @@ struct mbuf *m_head = NULL; sc = ifp->if_softc; + CUE_LOCK(sc); - if (ifp->if_flags & IFF_OACTIVE) + if (ifp->if_flags & IFF_OACTIVE) { + CUE_UNLOCK(sc); return; + } IF_DEQUEUE(&ifp->if_snd, m_head); - if (m_head == NULL) + if (m_head == NULL) { + CUE_UNLOCK(sc); return; + } if (cue_encap(sc, m_head, 0)) { IF_PREPEND(&ifp->if_snd, m_head); ifp->if_flags |= IFF_OACTIVE; + CUE_UNLOCK(sc); return; } @@ -900,8 +915,7 @@ * If there's a BPF listener, bounce a copy of this frame * to him. */ - if (ifp->if_bpf) - bpf_mtap(ifp, m_head); + BPF_MTAP(ifp, m_head); ifp->if_flags |= IFF_OACTIVE; @@ -909,6 +923,7 @@ * Set a timeout in case the chip goes out to lunch. */ ifp->if_timer = 5; + CUE_UNLOCK(sc); return; } @@ -920,12 +935,12 @@ struct ifnet *ifp = &sc->arpcom.ac_if; struct cue_chain *c; usbd_status err; - int i, s; + int i; if (ifp->if_flags & IFF_RUNNING) return; - s = splimp(); + CUE_LOCK(sc); /* * Cancel pending I/O and free all RX/TX buffers. @@ -936,10 +951,10 @@ /* Set MAC address */ for (i = 0; i < ETHER_ADDR_LEN; i++) - csr_write_1(sc, CUE_PAR0 - i, sc->arpcom.ac_enaddr[i]); + cue_csr_write_1(sc, CUE_PAR0 - i, sc->arpcom.ac_enaddr[i]); /* Enable RX logic. */ - csr_write_1(sc, CUE_ETHCTL, CUE_ETHCTL_RX_ON|CUE_ETHCTL_MCAST_ON); + cue_csr_write_1(sc, CUE_ETHCTL, CUE_ETHCTL_RX_ON|CUE_ETHCTL_MCAST_ON); /* If we want promiscuous mode, set the allframes bit. */ if (ifp->if_flags & IFF_PROMISC) { @@ -951,14 +966,14 @@ /* Init TX ring. */ if (cue_tx_list_init(sc) == ENOBUFS) { printf("cue%d: tx list init failed\n", sc->cue_unit); - splx(s); + CUE_UNLOCK(sc); return; } /* Init RX ring. */ if (cue_rx_list_init(sc) == ENOBUFS) { printf("cue%d: rx list init failed\n", sc->cue_unit); - splx(s); + CUE_UNLOCK(sc); return; } @@ -969,15 +984,15 @@ * Set the number of RX and TX buffers that we want * to reserve inside the ASIC. */ - csr_write_1(sc, CUE_RX_BUFPKTS, CUE_RX_FRAMES); - csr_write_1(sc, CUE_TX_BUFPKTS, CUE_TX_FRAMES); + cue_csr_write_1(sc, CUE_RX_BUFPKTS, CUE_RX_FRAMES); + cue_csr_write_1(sc, CUE_TX_BUFPKTS, CUE_TX_FRAMES); /* Set advanced operation modes. */ - csr_write_1(sc, CUE_ADVANCED_OPMODES, + cue_csr_write_1(sc, CUE_ADVANCED_OPMODES, CUE_AOP_EMBED_RXLEN|0x01); /* 1 wait state */ /* Program the LED operation. */ - csr_write_1(sc, CUE_LEDCTL, CUE_LEDCTL_FOLLOW_LINK); + cue_csr_write_1(sc, CUE_LEDCTL, CUE_LEDCTL_FOLLOW_LINK); /* Open RX and TX pipes. */ err = usbd_open_pipe(sc->cue_iface, sc->cue_ed[CUE_ENDPT_RX], @@ -985,7 +1000,7 @@ if (err) { printf("cue%d: open rx pipe failed: %s\n", sc->cue_unit, usbd_errstr(err)); - splx(s); + CUE_UNLOCK(sc); return; } err = usbd_open_pipe(sc->cue_iface, sc->cue_ed[CUE_ENDPT_TX], @@ -993,7 +1008,7 @@ if (err) { printf("cue%d: open tx pipe failed: %s\n", sc->cue_unit, usbd_errstr(err)); - splx(s); + CUE_UNLOCK(sc); return; } @@ -1009,7 +1024,7 @@ ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; - (void)splx(s); + CUE_UNLOCK(sc); sc->cue_stat_ch = timeout(cue_tick, sc, hz); @@ -1020,16 +1035,11 @@ cue_ioctl(struct ifnet *ifp, u_long command, caddr_t data) { struct cue_softc *sc = ifp->if_softc; - int s, error = 0; + int error = 0; - s = splimp(); + CUE_LOCK(sc); switch(command) { - case SIOCSIFADDR: - case SIOCGIFADDR: - case SIOCSIFMTU: - error = ether_ioctl(ifp, command, data); - break; case SIOCSIFFLAGS: if (ifp->if_flags & IFF_UP) { if (ifp->if_flags & IFF_RUNNING && @@ -1057,11 +1067,11 @@ error = 0; break; default: - error = EINVAL; + error = ether_ioctl(ifp, command, data); break; } - (void)splx(s); + CUE_UNLOCK(sc); return(error); } @@ -1071,9 +1081,10 @@ { struct cue_softc *sc; struct cue_chain *c; - usbd_status stat; + sc = ifp->if_softc; + CUE_LOCK(sc); ifp->if_oerrors++; printf("cue%d: watchdog timeout\n", sc->cue_unit); @@ -1084,6 +1095,7 @@ if (ifp->if_snd.ifq_head != NULL) cue_start(ifp); + CUE_UNLOCK(sc); return; } @@ -1099,10 +1111,12 @@ struct ifnet *ifp; int i; + CUE_LOCK(sc); + ifp = &sc->arpcom.ac_if; ifp->if_timer = 0; - csr_write_1(sc, CUE_ETHCTL, 0); + cue_csr_write_1(sc, CUE_ETHCTL, 0); cue_reset(sc); untimeout(cue_tick, sc, sc->cue_stat_ch); @@ -1182,6 +1196,7 @@ } ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); + CUE_UNLOCK(sc); return; } @@ -1197,8 +1212,10 @@ sc = device_get_softc(dev); + CUE_LOCK(sc); cue_reset(sc); cue_stop(sc); + CUE_UNLOCK(sc); return; } Index: sys/dev/usb/if_cuereg.h =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/if_cuereg.h,v retrieving revision 1.5 diff -u -r1.5 if_cuereg.h --- sys/dev/usb/if_cuereg.h 28 Jan 2000 02:15:30 -0000 1.5 +++ sys/dev/usb/if_cuereg.h 4 Oct 2003 21:27:25 -0000 @@ -29,7 +29,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/usb/if_cuereg.h,v 1.5 2000/01/28 02:15:30 wpaul Exp $ + * $FreeBSD: src/sys/dev/usb/if_cuereg.h,v 1.12 2003/10/04 21:41:01 joe Exp $ */ /* @@ -116,7 +116,6 @@ #define CUE_MCAST_TABLE_LEN 64 #define CUE_TIMEOUT 1000 -#define ETHER_ALIGN 2 #define CUE_BUFSZ 1536 #define CUE_MIN_FRAMELEN 60 #define CUE_RX_FRAMES 1 @@ -175,8 +174,20 @@ int cue_unit; u_int8_t cue_mctab[CUE_MCAST_TABLE_LEN]; int cue_if_flags; - u_int8_t cue_gone; u_int16_t cue_rxfilt; struct cue_cdata cue_cdata; struct callout_handle cue_stat_ch; +#if __FreeBSD_version >= 500000 + struct mtx cue_mtx; +#endif + char cue_dying; + struct timeval cue_rx_notice; }; + +#if 0 +#define CUE_LOCK(_sc) mtx_lock(&(_sc)->cue_mtx) +#define CUE_UNLOCK(_sc) mtx_unlock(&(_sc)->cue_mtx) +#else +#define CUE_LOCK(_sc) +#define CUE_UNLOCK(_sc) +#endif Index: sys/dev/usb/if_kue.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/if_kue.c,v retrieving revision 1.17.2.9 diff -u -r1.17.2.9 if_kue.c --- sys/dev/usb/if_kue.c 13 Apr 2003 02:39:25 -0000 1.17.2.9 +++ sys/dev/usb/if_kue.c 4 Oct 2003 21:27:26 -0000 @@ -28,10 +28,11 @@ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD: src/sys/dev/usb/if_kue.c,v 1.17.2.9 2003/04/13 02:39:25 murray Exp $ */ +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/if_kue.c,v 1.50 2003/10/04 21:41:01 joe Exp $"); + /* * Kawasaki LSI KL5KUSB101B USB to ethernet adapter driver. * @@ -64,6 +65,9 @@ * the development of this driver. */ +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/if_kue.c,v 1.50 2003/10/04 21:41:01 joe Exp $"); + #include #include #include @@ -80,8 +84,11 @@ #include -#include /* for DELAY */ #include +#include +#if __FreeBSD_version < 500000 +#include +#endif #include #include @@ -93,10 +100,8 @@ #include #include -#ifndef lint -static const char rcsid[] = - "$FreeBSD: src/sys/dev/usb/if_kue.c,v 1.17.2.9 2003/04/13 02:39:25 murray Exp $"; -#endif +MODULE_DEPEND(kue, usb, 1, 1, 1); +MODULE_DEPEND(kue, ether, 1, 1, 1); /* * Various supported device vendors/products. @@ -118,15 +123,17 @@ { USB_VENDOR_KLSI, USB_PRODUCT_KLSI_DUH3E10BT }, { USB_VENDOR_KLSI, USB_PRODUCT_KLSI_DUH3E10BTN }, { USB_VENDOR_PERACOM, USB_PRODUCT_PERACOM_ENET3 }, + { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBETT }, + { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_URE450 }, { 0, 0 } }; Static struct usb_qdat kue_qdat; -Static int kue_match(device_t); -Static int kue_attach(device_t); -Static int kue_detach(device_t); -Static void kue_shutdown(device_t); +Static int kue_match(device_ptr_t); +Static int kue_attach(device_ptr_t); +Static int kue_detach(device_ptr_t); +Static void kue_shutdown(device_ptr_t); Static int kue_tx_list_init(struct kue_softc *); Static int kue_rx_list_init(struct kue_softc *); Static int kue_newbuf(struct kue_softc *, struct kue_chain *, struct mbuf *); @@ -168,7 +175,7 @@ Static devclass_t kue_devclass; -DRIVER_MODULE(if_kue, uhub, kue_driver, kue_devclass, usbd_driver_load, 0); +DRIVER_MODULE(kue, uhub, kue_driver, kue_devclass, usbd_driver_load, 0); /* * We have a custom do_request function which is almost like the @@ -185,7 +192,7 @@ xfer = usbd_alloc_xfer(dev); usbd_setup_default_xfer(xfer, dev, 0, 500000, req, - data, UGETW(req->wLength), USBD_SHORT_XFER_OK|USBD_NO_TSLEEP, 0); + data, UGETW(req->wLength), USBD_SHORT_XFER_OK, 0); err = usbd_sync_transfer(xfer); usbd_free_xfer(xfer); return(err); @@ -197,14 +204,13 @@ usbd_device_handle dev; usb_device_request_t req; usbd_status err; - int s; - if (sc->kue_gone) + if (sc->kue_dying) return(USBD_NORMAL_COMPLETION); dev = sc->kue_udev; - s = splusb(); + KUE_LOCK(sc); req.bmRequestType = UT_WRITE_VENDOR_DEVICE; @@ -215,7 +221,7 @@ err = kue_do_request(dev, &req, NULL); - splx(s); + KUE_UNLOCK(sc); return(err); } @@ -227,14 +233,13 @@ usbd_device_handle dev; usb_device_request_t req; usbd_status err; - int s; dev = sc->kue_udev; - if (sc->kue_gone) + if (sc->kue_dying) return(USBD_NORMAL_COMPLETION); - s = splusb(); + KUE_LOCK(sc); if (rw == KUE_CTL_WRITE) req.bmRequestType = UT_WRITE_VENDOR_DEVICE; @@ -248,7 +253,7 @@ err = kue_do_request(dev, &req, data); - splx(s); + KUE_UNLOCK(sc); return(err); } @@ -328,8 +333,12 @@ sc->kue_rxfilt &= ~KUE_RXFILT_ALLMULTI; - for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; - ifma = ifma->ifma_link.le_next) { +#if __FreeBSD_version >= 500000 + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) +#else + LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) +#endif + { if (ifma->ifma_addr->sa_family != AF_LINK) continue; /* @@ -364,7 +373,9 @@ Static void kue_reset(struct kue_softc *sc) { - if (usbd_set_config_no(sc->kue_udev, KUE_CONFIG_NO, 0)) { + if (usbd_set_config_no(sc->kue_udev, KUE_CONFIG_NO, 0) || + usbd_device2interface_handle(sc->kue_udev, KUE_IFACE_IDX, + &sc->kue_iface)) { printf("kue%d: getting interface handle failed\n", sc->kue_unit); } @@ -405,15 +416,12 @@ { USB_ATTACH_START(kue, sc, uaa); char devinfo[1024]; - int s; struct ifnet *ifp; usbd_status err; usb_interface_descriptor_t *id; usb_endpoint_descriptor_t *ed; int i; - s = splimp(); - bzero(sc, sizeof(struct kue_softc)); sc->kue_iface = uaa->iface; sc->kue_udev = uaa->device; @@ -431,24 +439,32 @@ if (!ed) { printf("kue%d: couldn't get ep %d\n", sc->kue_unit, i); - splx(s); USB_ATTACH_ERROR_RETURN; } if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && - (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) { + UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { sc->kue_ed[KUE_ENDPT_RX] = ed->bEndpointAddress; } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && - (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) { + UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { sc->kue_ed[KUE_ENDPT_TX] = ed->bEndpointAddress; } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && - (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) { + UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { sc->kue_ed[KUE_ENDPT_INTR] = ed->bEndpointAddress; } } +#if __FreeBSD_version >= 500000 + mtx_init(&sc->kue_mtx, device_get_nameunit(self), MTX_NETWORK_LOCK, + MTX_DEF | MTX_RECURSE); +#endif + KUE_LOCK(sc); + /* Load the firmware into the NIC. */ if (kue_load_fw(sc)) { - splx(s); + KUE_UNLOCK(sc); +#if __FreeBSD_version >= 500000 + mtx_destroy(&sc->kue_mtx); +#endif USB_ATTACH_ERROR_RETURN; } @@ -491,11 +507,16 @@ /* * Call MI attach routine. */ +#if __FreeBSD_version >= 500000 + ether_ifattach(ifp, sc->kue_desc.kue_macaddr); +#else ether_ifattach(ifp, ETHER_BPF_SUPPORTED); +#endif usb_register_netisr(); - sc->kue_gone = 0; + sc->kue_dying = 0; + + KUE_UNLOCK(sc); - splx(s); USB_ATTACH_SUCCESS_RETURN; } @@ -504,17 +525,19 @@ { struct kue_softc *sc; struct ifnet *ifp; - int s; - - s = splusb(); sc = device_get_softc(dev); + KUE_LOCK(sc); ifp = &sc->arpcom.ac_if; - sc->kue_gone = 1; + sc->kue_dying = 1; if (ifp != NULL) +#if __FreeBSD_version >= 500000 + ether_ifdetach(ifp); +#else ether_ifdetach(ifp, ETHER_BPF_SUPPORTED); +#endif if (sc->kue_ep[KUE_ENDPT_TX] != NULL) usbd_abort_pipe(sc->kue_ep[KUE_ENDPT_TX]); @@ -526,7 +549,10 @@ if (sc->kue_mcfilters != NULL) free(sc->kue_mcfilters, M_USBDEV); - splx(s); + KUE_UNLOCK(sc); +#if __FreeBSD_version >= 500000 + mtx_destroy(&sc->kue_mtx); +#endif return(0); } @@ -623,6 +649,7 @@ struct kue_chain *c; sc = ifp->if_softc; + KUE_LOCK(sc); c = &sc->kue_cdata.kue_rx_chain[sc->kue_cdata.kue_rx_prod]; if (kue_newbuf(sc, c, NULL) == ENOBUFS) { @@ -636,6 +663,8 @@ USBD_NO_TIMEOUT, kue_rxeof); usbd_transfer(c->kue_xfer); + KUE_UNLOCK(sc); + return; } @@ -655,16 +684,22 @@ c = priv; sc = c->kue_sc; + KUE_LOCK(sc); ifp = &sc->arpcom.ac_if; - if (!(ifp->if_flags & IFF_RUNNING)) + if (!(ifp->if_flags & IFF_RUNNING)) { + KUE_UNLOCK(sc); return; + } if (status != USBD_NORMAL_COMPLETION) { - if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) + if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) { + KUE_UNLOCK(sc); return; - printf("kue%d: usb error on rx: %s\n", sc->kue_unit, - usbd_errstr(status)); + } + if (usbd_ratecheck(&sc->kue_rx_notice)) + printf("kue%d: usb error on rx: %s\n", sc->kue_unit, + usbd_errstr(status)); if (status == USBD_STALLED) usbd_clear_endpoint_stall(sc->kue_ep[KUE_ENDPT_RX]); goto done; @@ -692,6 +727,7 @@ /* Put the packet on the special USB input queue. */ usb_ether_input(m); + KUE_UNLOCK(sc); return; done: @@ -701,6 +737,7 @@ c, mtod(c->kue_mbuf, char *), KUE_BUFSZ, USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, kue_rxeof); usbd_transfer(c->kue_xfer); + KUE_UNLOCK(sc); return; } @@ -717,26 +754,25 @@ struct kue_chain *c; struct ifnet *ifp; usbd_status err; - int s; - - s = splimp(); c = priv; sc = c->kue_sc; + KUE_LOCK(sc); + ifp = &sc->arpcom.ac_if; ifp->if_timer = 0; ifp->if_flags &= ~IFF_OACTIVE; if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) { - splx(s); + KUE_UNLOCK(sc); return; } printf("kue%d: usb error on tx: %s\n", sc->kue_unit, usbd_errstr(status)); if (status == USBD_STALLED) usbd_clear_endpoint_stall(sc->kue_ep[KUE_ENDPT_TX]); - splx(s); + KUE_UNLOCK(sc); return; } @@ -753,7 +789,7 @@ else ifp->if_opackets++; - splx(s); + KUE_UNLOCK(sc); return; } @@ -803,17 +839,23 @@ struct mbuf *m_head = NULL; sc = ifp->if_softc; + KUE_LOCK(sc); - if (ifp->if_flags & IFF_OACTIVE) + if (ifp->if_flags & IFF_OACTIVE) { + KUE_UNLOCK(sc); return; + } IF_DEQUEUE(&ifp->if_snd, m_head); - if (m_head == NULL) + if (m_head == NULL) { + KUE_UNLOCK(sc); return; + } if (kue_encap(sc, m_head, 0)) { IF_PREPEND(&ifp->if_snd, m_head); ifp->if_flags |= IFF_OACTIVE; + KUE_UNLOCK(sc); return; } @@ -821,8 +863,7 @@ * If there's a BPF listener, bounce a copy of this frame * to him. */ - if (ifp->if_bpf) - bpf_mtap(ifp, m_head); + BPF_MTAP(ifp, m_head); ifp->if_flags |= IFF_OACTIVE; @@ -830,6 +871,7 @@ * Set a timeout in case the chip goes out to lunch. */ ifp->if_timer = 5; + KUE_UNLOCK(sc); return; } @@ -841,12 +883,14 @@ struct ifnet *ifp = &sc->arpcom.ac_if; struct kue_chain *c; usbd_status err; - int i, s; + int i; - if (ifp->if_flags & IFF_RUNNING) - return; + KUE_LOCK(sc); - s = splimp(); + if (ifp->if_flags & IFF_RUNNING) { + KUE_UNLOCK(sc); + return; + } /* Set MAC address */ kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SET_MAC, @@ -873,14 +917,14 @@ /* Init TX ring. */ if (kue_tx_list_init(sc) == ENOBUFS) { printf("kue%d: tx list init failed\n", sc->kue_unit); - splx(s); + KUE_UNLOCK(sc); return; } /* Init RX ring. */ if (kue_rx_list_init(sc) == ENOBUFS) { printf("kue%d: rx list init failed\n", sc->kue_unit); - splx(s); + KUE_UNLOCK(sc); return; } @@ -893,7 +937,7 @@ if (err) { printf("kue%d: open rx pipe failed: %s\n", sc->kue_unit, usbd_errstr(err)); - splx(s); + KUE_UNLOCK(sc); return; } @@ -902,7 +946,7 @@ if (err) { printf("kue%d: open tx pipe failed: %s\n", sc->kue_unit, usbd_errstr(err)); - splx(s); + KUE_UNLOCK(sc); return; } @@ -918,7 +962,7 @@ ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; - (void)splx(s); + KUE_UNLOCK(sc); return; } @@ -927,16 +971,11 @@ kue_ioctl(struct ifnet *ifp, u_long command, caddr_t data) { struct kue_softc *sc = ifp->if_softc; - int s, error = 0; + int error = 0; - s = splimp(); + KUE_LOCK(sc); switch(command) { - case SIOCSIFADDR: - case SIOCGIFADDR: - case SIOCSIFMTU: - error = ether_ioctl(ifp, command, data); - break; case SIOCSIFFLAGS: if (ifp->if_flags & IFF_UP) { if (ifp->if_flags & IFF_RUNNING && @@ -966,11 +1005,11 @@ error = 0; break; default: - error = EINVAL; + error = ether_ioctl(ifp, command, data); break; } - (void)splx(s); + KUE_UNLOCK(sc); return(error); } @@ -983,7 +1022,7 @@ usbd_status stat; sc = ifp->if_softc; - + KUE_LOCK(sc); ifp->if_oerrors++; printf("kue%d: watchdog timeout\n", sc->kue_unit); @@ -993,6 +1032,7 @@ if (ifp->if_snd.ifq_head != NULL) kue_start(ifp); + KUE_UNLOCK(sc); return; } @@ -1008,6 +1048,7 @@ struct ifnet *ifp; int i; + KUE_LOCK(sc); ifp = &sc->arpcom.ac_if; ifp->if_timer = 0; @@ -1087,6 +1128,7 @@ } ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); + KUE_UNLOCK(sc); return; } Index: sys/dev/usb/if_kuereg.h =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/if_kuereg.h,v retrieving revision 1.5 diff -u -r1.5 if_kuereg.h --- sys/dev/usb/if_kuereg.h 28 Jan 2000 02:15:31 -0000 1.5 +++ sys/dev/usb/if_kuereg.h 4 Oct 2003 21:27:26 -0000 @@ -29,7 +29,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/usb/if_kuereg.h,v 1.5 2000/01/28 02:15:31 wpaul Exp $ + * $FreeBSD: src/sys/dev/usb/if_kuereg.h,v 1.13 2003/10/04 21:41:01 joe Exp $ */ /* @@ -110,7 +110,6 @@ #define KUE_RXFILT_MULTICAST 0x0010 #define KUE_TIMEOUT 1000 -#define ETHER_ALIGN 2 #define KUE_BUFSZ 1536 #define KUE_MIN_FRAMELEN 60 @@ -121,6 +120,7 @@ #define KUE_CTL_WRITE 0x02 #define KUE_CONFIG_NO 1 +#define KUE_IFACE_IDX 0 /* * The interrupt endpoint is currently unused @@ -166,8 +166,20 @@ usbd_pipe_handle kue_ep[KUE_ENDPT_MAX]; int kue_unit; int kue_if_flags; - u_int8_t kue_gone; u_int16_t kue_rxfilt; u_int8_t *kue_mcfilters; struct kue_cdata kue_cdata; +#if __FreeBSD_version >= 500000 + struct mtx kue_mtx; +#endif + char kue_dying; + struct timeval kue_rx_notice; }; + +#if 0 +#define KUE_LOCK(_sc) mtx_lock(&(_sc)->kue_mtx) +#define KUE_UNLOCK(_sc) mtx_unlock(&(_sc)->kue_mtx) +#else +#define KUE_LOCK(_sc) +#define KUE_UNLOCK(_sc) +#endif Index: sys/dev/usb/if_rue.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/if_rue.c,v retrieving revision 1.2.2.1 diff -u -r1.2.2.1 if_rue.c --- sys/dev/usb/if_rue.c 30 Jul 2003 13:57:35 -0000 1.2.2.1 +++ sys/dev/usb/if_rue.c 4 Oct 2003 21:27:26 -0000 @@ -23,9 +23,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/usb/if_rue.c,v 1.2.2.1 2003/07/30 13:57:35 akiyama Exp $ */ +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/if_rue.c,v 1.4 2003/10/04 21:41:01 joe Exp $"); + /* * RealTek RTL8150 USB to fast ethernet controller driver. * Datasheet is available from @@ -49,8 +51,11 @@ #include -#include /* for DELAY */ #include +#include +#if __FreeBSD_version < 500000 +#include +#endif #include #include @@ -164,6 +169,7 @@ DRIVER_MODULE(rue, uhub, rue_driver, rue_devclass, usbd_driver_load, 0); DRIVER_MODULE(miibus, rue, miibus_driver, miibus_devclass, 0, 0); MODULE_DEPEND(rue, usb, 1, 1, 1); +MODULE_DEPEND(rue, ether, 1, 1, 1); MODULE_DEPEND(rue, miibus, 1, 1, 1); #define RUE_SETBIT(sc, reg, x) \ @@ -183,12 +189,11 @@ { usb_device_request_t req; usbd_status err; - int s; if (sc->rue_dying) return (0); - s = splusb(); + RUE_LOCK(sc); req.bmRequestType = UT_READ_VENDOR_DEVICE; req.bRequest = UR_SET_ADDRESS; @@ -196,10 +201,9 @@ USETW(req.wIndex, 0); USETW(req.wLength, len); - err = usbd_do_request_flags(sc->rue_udev, &req, buf, - USBD_NO_TSLEEP, NULL); + err = usbd_do_request(sc->rue_udev, &req, buf); - splx(s); + RUE_UNLOCK(sc); if (err) { printf("rue%d: control pipe read failed: %s\n", @@ -215,12 +219,11 @@ { usb_device_request_t req; usbd_status err; - int s; if (sc->rue_dying) return (0); - s = splusb(); + RUE_LOCK(sc); req.bmRequestType = UT_WRITE_VENDOR_DEVICE; req.bRequest = UR_SET_ADDRESS; @@ -228,10 +231,9 @@ USETW(req.wIndex, 0); USETW(req.wLength, len); - err = usbd_do_request_flags(sc->rue_udev, &req, buf, - USBD_NO_TSLEEP, NULL); + err = usbd_do_request(sc->rue_udev, &req, buf); - splx(s); + RUE_UNLOCK(sc); if (err) { printf("rue%d: control pipe write failed: %s\n", @@ -319,12 +321,10 @@ Static int rue_miibus_readreg(device_ptr_t dev, int phy, int reg) { - struct rue_softc *sc; + struct rue_softc *sc = USBGETSOFTC(dev); int rval; int ruereg; - sc = device_get_softc(dev); - if (phy != 0) /* RTL8150 supports PHY == 0, only */ return (0); @@ -365,11 +365,9 @@ Static int rue_miibus_writereg(device_ptr_t dev, int phy, int reg, int data) { - struct rue_softc *sc; + struct rue_softc *sc = USBGETSOFTC(dev); int ruereg; - sc = device_get_softc(dev); - if (phy != 0) /* RTL8150 supports PHY == 0, only */ return (0); @@ -409,13 +407,10 @@ Static void rue_miibus_statchg(device_ptr_t dev) { - struct rue_softc *sc; - struct mii_data *mii; + struct rue_softc *sc = USBGETSOFTC(dev); + struct mii_data *mii = GET_MII(sc); int bmcr; - sc = device_get_softc(dev); - mii = device_get_softc(sc->rue_miibus); - RUE_CLRBIT(sc, RUE_CR, (RUE_CR_RE | RUE_CR_TE)); bmcr = rue_csr_read_2(sc, RUE_BMCR); @@ -496,7 +491,12 @@ rue_csr_write_4(sc, RUE_MAR4, 0); /* now program new ones */ - LIST_FOREACH (ifma, &ifp->if_multiaddrs, ifma_link) { +#if __FreeBSD_version >= 500000 + TAILQ_FOREACH (ifma, &ifp->if_multiaddrs, ifma_link) +#else + LIST_FOREACH (ifma, &ifp->if_multiaddrs, ifma_link) +#endif + { if (ifma->ifma_addr->sa_family != AF_LINK) continue; h = rue_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); @@ -570,21 +570,20 @@ { USB_ATTACH_START(rue, sc, uaa); char *devinfo; - int s; u_char eaddr[ETHER_ADDR_LEN]; struct ifnet *ifp; + usbd_interface_handle iface; + usbd_status err; usb_interface_descriptor_t *id; usb_endpoint_descriptor_t *ed; int i; struct rue_type *t; - int err; devinfo = malloc(1024, M_USBDEV, M_WAITOK); - s = splimp(); - bzero(sc, sizeof (struct rue_softc)); - sc->rue_iface = uaa->iface; + usbd_devinfo(uaa->device, 0, devinfo); + sc->rue_udev = uaa->device; sc->rue_unit = device_get_unit(self); @@ -594,6 +593,15 @@ goto error; } + err = usbd_device2interface_handle(uaa->device, RUE_IFACE_IDX, &iface); + if (err) { + printf("rue%d: getting interface handle failed\n", + sc->rue_unit); + goto error; + } + + sc->rue_iface = iface; + t = rue_devs; while (t->rue_vid) { if (uaa->vendor == t->rue_vid && @@ -612,7 +620,7 @@ /* Find endpoints */ for (i = 0; i < id->bNumEndpoints; i++) { - ed = usbd_interface2endpoint_descriptor(uaa->iface, i); + ed = usbd_interface2endpoint_descriptor(iface, i); if (ed == NULL) { printf("rue%d: couldn't get ep %d\n", sc->rue_unit, i); goto error; @@ -629,6 +637,12 @@ } } +#if __FreeBSD_version >= 500000 + mtx_init(&sc->rue_mtx, device_get_nameunit(self), MTX_NETWORK_LOCK, + MTX_DEF | MTX_RECURSE); +#endif + RUE_LOCK(sc); + /* Reset the adapter */ rue_reset(sc); @@ -637,7 +651,7 @@ (caddr_t)&eaddr, ETHER_ADDR_LEN); if (err) { printf("rue%d: couldn't get station address\n", sc->rue_unit); - goto error; + goto error1; } /* RealTek RTL8150 was detected */ @@ -663,24 +677,32 @@ if (mii_phy_probe(self, &sc->rue_miibus, rue_ifmedia_upd, rue_ifmedia_sts)) { printf("rue%d: MII without any PHY!\n", sc->rue_unit); - goto error; + goto error1; } rue_qdat.ifp = ifp; rue_qdat.if_rxstart = rue_rxstart; /* Call MI attach routine */ +#if __FreeBSD_version >= 500000 + ether_ifattach(ifp, eaddr); +#else ether_ifattach(ifp, ETHER_BPF_SUPPORTED); +#endif callout_handle_init(&sc->rue_stat_ch); usb_register_netisr(); sc->rue_dying = 0; - splx(s); + RUE_UNLOCK(sc); free(devinfo, M_USBDEV); USB_ATTACH_SUCCESS_RETURN; + error1: + RUE_UNLOCK(sc); +#if __FreeBSD_version >= 500000 + mtx_destroy(&sc->rue_mtx); +#endif error: - splx(s); free(devinfo, M_USBDEV); USB_ATTACH_ERROR_RETURN; } @@ -690,16 +712,18 @@ { struct rue_softc *sc; struct ifnet *ifp; - int s; - - s = splusb(); sc = device_get_softc(dev); + RUE_LOCK(sc); ifp = &sc->arpcom.ac_if; sc->rue_dying = 1; untimeout(rue_tick, sc, sc->rue_stat_ch); +#if __FreeBSD_version >= 500000 + ether_ifdetach(ifp); +#else ether_ifdetach(ifp, ETHER_BPF_SUPPORTED); +#endif if (sc->rue_ep[RUE_ENDPT_TX] != NULL) usbd_abort_pipe(sc->rue_ep[RUE_ENDPT_TX]); @@ -710,7 +734,10 @@ usbd_abort_pipe(sc->rue_ep[RUE_ENDPT_INTR]); #endif - splx(s); + RUE_UNLOCK(sc); +#if __FreeBSD_version >= 500000 + mtx_destroy(&sc->rue_mtx); +#endif return (0); } @@ -725,14 +752,14 @@ struct mbuf *m_new = NULL; if (m == NULL) { - MGETHDR(m_new, M_DONTWAIT, MT_DATA); + MGETHDR(m_new, M_NOWAIT, MT_DATA); if (m_new == NULL) { printf("rue%d: no memory for rx list " "-- packet dropped!\n", sc->rue_unit); return (ENOBUFS); } - MCLGET(m_new, M_DONTWAIT); + MCLGET(m_new, M_NOWAIT); if (!(m_new->m_flags & M_EXT)) { printf("rue%d: no memory for rx list " "-- packet dropped!\n", sc->rue_unit); @@ -809,26 +836,25 @@ struct rue_softc *sc = priv; struct ifnet *ifp; struct rue_intrpkt *p; - int s; - s = splimp(); + RUE_LOCK(sc); ifp = &sc->arpcom.ac_if; if (!(ifp->if_flags & IFF_RUNNING)) { - splx(s); + RUE_UNLOCK(sc); return; } if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) { - splx(s); + RUE_UNLOCK(sc); return; } printf("rue%d: usb error on intr: %s\n", sc->rue_unit, usbd_errstr(status)); if (status == USBD_STALLED) usbd_clear_endpoint_stall(sc->rue_ep[RUE_ENDPT_INTR]); - splx(s); + RUE_UNLOCK(sc); return; } @@ -838,7 +864,7 @@ ifp->if_ierrors += p->rue_crcerr_cnt; ifp->if_collisions += p->rue_col_cnt; - splx(s); + RUE_UNLOCK(sc); } #endif @@ -849,11 +875,12 @@ struct rue_chain *c; sc = ifp->if_softc; - + RUE_LOCK(sc); c = &sc->rue_cdata.rue_rx_chain[sc->rue_cdata.rue_rx_prod]; if (rue_newbuf(sc, c, NULL) == ENOBUFS) { ifp->if_ierrors++; + RUE_UNLOCK(sc); return; } @@ -862,6 +889,8 @@ c, mtod(c->rue_mbuf, char *), RUE_BUFSZ, USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, rue_rxeof); usbd_transfer(c->rue_xfer); + + RUE_UNLOCK(sc); } /* @@ -881,17 +910,22 @@ if (sc->rue_dying) return; - + RUE_LOCK(sc); ifp = &sc->arpcom.ac_if; - if (!(ifp->if_flags & IFF_RUNNING)) + if (!(ifp->if_flags & IFF_RUNNING)) { + RUE_UNLOCK(sc); return; + } if (status != USBD_NORMAL_COMPLETION) { - if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) + if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) { + RUE_UNLOCK(sc); return; - printf("rue%d: usb error on rx: %s\n", sc->rue_unit, - usbd_errstr(status)); + } + if (usbd_ratecheck(&sc->rue_rx_notice)) + printf("rue%d: usb error on rx: %s\n", sc->rue_unit, + usbd_errstr(status)); if (status == USBD_STALLED) usbd_clear_endpoint_stall(sc->rue_ep[RUE_ENDPT_RX]); goto done; @@ -923,6 +957,7 @@ /* Put the packet on the special USB input queue. */ usb_ether_input(m); + RUE_UNLOCK(sc); return; done: @@ -931,6 +966,7 @@ c, mtod(c->rue_mbuf, char *), RUE_BUFSZ, USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, rue_rxeof); usbd_transfer(xfer); + RUE_UNLOCK(sc); } /* @@ -945,22 +981,21 @@ struct rue_softc *sc = c->rue_sc; struct ifnet *ifp; usbd_status err; - int s; - s = splimp(); + RUE_LOCK(sc); ifp = &sc->arpcom.ac_if; if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) { - splx(s); + RUE_UNLOCK(sc); return; } printf("rue%d: usb error on tx: %s\n", sc->rue_unit, usbd_errstr(status)); if (status == USBD_STALLED) usbd_clear_endpoint_stall(sc->rue_ep[RUE_ENDPT_TX]); - splx(s); + RUE_UNLOCK(sc); return; } @@ -979,7 +1014,7 @@ else ifp->if_opackets++; - splx(s); + RUE_UNLOCK(sc); } Static void @@ -988,35 +1023,30 @@ struct rue_softc *sc = xsc; struct ifnet *ifp; struct mii_data *mii; - int s; - s = splimp(); - - if (sc == NULL) { - splx(s); + if (sc == NULL) return; - } + + RUE_LOCK(sc); ifp = &sc->arpcom.ac_if; - mii = device_get_softc(sc->rue_miibus); + mii = GET_MII(sc); if (mii == NULL) { - splx(s); + RUE_UNLOCK(sc); return; } mii_tick(mii); - if (!sc->rue_link) { - mii_pollstat(mii); - if (mii->mii_media_status & IFM_ACTIVE && - IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) - sc->rue_link++; - if (ifp->if_snd.ifq_head != NULL) - rue_start(ifp); + if (!sc->rue_link && mii->mii_media_status & IFM_ACTIVE && + IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { + sc->rue_link++; + if (ifp->if_snd.ifq_head != NULL) + rue_start(ifp); } sc->rue_stat_ch = timeout(rue_tick, sc, hz); - splx(s); + RUE_UNLOCK(sc); } Static int @@ -1066,19 +1096,28 @@ struct rue_softc *sc = ifp->if_softc; struct mbuf *m_head = NULL; - if (!sc->rue_link) + RUE_LOCK(sc); + + if (!sc->rue_link) { + RUE_UNLOCK(sc); return; + } - if (ifp->if_flags & IFF_OACTIVE) + if (ifp->if_flags & IFF_OACTIVE) { + RUE_UNLOCK(sc); return; + } IF_DEQUEUE(&ifp->if_snd, m_head); - if (m_head == NULL) + if (m_head == NULL) { + RUE_UNLOCK(sc); return; + } if (rue_encap(sc, m_head, 0)) { IF_PREPEND(&ifp->if_snd, m_head); ifp->if_flags |= IFF_OACTIVE; + RUE_UNLOCK(sc); return; } @@ -1086,8 +1125,7 @@ * If there's a BPF listener, bounce a copy of this frame * to him. */ - if (ifp->if_bpf) - bpf_mtap(ifp, m_head); + BPF_MTAP(ifp, m_head); ifp->if_flags |= IFF_OACTIVE; @@ -1095,6 +1133,8 @@ * Set a timeout in case the chip goes out to lunch. */ ifp->if_timer = 5; + + RUE_UNLOCK(sc); } Static void @@ -1102,38 +1142,38 @@ { struct rue_softc *sc = xsc; struct ifnet *ifp = &sc->arpcom.ac_if; - struct mii_data *mii; + struct mii_data *mii = GET_MII(sc); struct rue_chain *c; usbd_status err; - int i, s; + int i; int rxcfg; - if (ifp->if_flags & IFF_RUNNING) - return; + RUE_LOCK(sc); - s = splimp(); + if (ifp->if_flags & IFF_RUNNING) { + RUE_UNLOCK(sc); + return; + } /* * Cancel pending I/O and free all RX/TX buffers. */ rue_reset(sc); - mii = device_get_softc(sc->rue_miibus); - /* Set MAC address */ rue_write_mem(sc, RUE_IDR0, sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); /* Init TX ring. */ if (rue_tx_list_init(sc) == ENOBUFS) { printf("rue%d: tx list init failed\n", sc->rue_unit); - splx(s); + RUE_UNLOCK(sc); return; } /* Init RX ring. */ if (rue_rx_list_init(sc) == ENOBUFS) { printf("rue%d: rx list init failed\n", sc->rue_unit); - splx(s); + RUE_UNLOCK(sc); return; } @@ -1176,7 +1216,7 @@ if (err) { printf("rue%d: open rx pipe failed: %s\n", sc->rue_unit, usbd_errstr(err)); - splx(s); + RUE_UNLOCK(sc); return; } err = usbd_open_pipe(sc->rue_iface, sc->rue_ed[RUE_ENDPT_TX], @@ -1184,7 +1224,7 @@ if (err) { printf("rue%d: open tx pipe failed: %s\n", sc->rue_unit, usbd_errstr(err)); - splx(s); + RUE_UNLOCK(sc); return; } @@ -1197,7 +1237,7 @@ if (err) { printf("rue%d: open intr pipe failed: %s\n", sc->rue_unit, usbd_errstr(err)); - splx(s); + RUE_UNLOCK(sc); return; } #endif @@ -1214,9 +1254,9 @@ ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; - splx(s); - sc->rue_stat_ch = timeout(rue_tick, sc, hz); + + RUE_UNLOCK(sc); } /* @@ -1227,9 +1267,8 @@ rue_ifmedia_upd(struct ifnet *ifp) { struct rue_softc *sc = ifp->if_softc; - struct mii_data *mii; + struct mii_data *mii = GET_MII(sc); - mii = device_get_softc(sc->rue_miibus); sc->rue_link = 0; if (mii->mii_instance) { struct mii_softc *miisc; @@ -1249,9 +1288,7 @@ rue_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) { struct rue_softc *sc = ifp->if_softc; - struct mii_data *mii; - - mii = device_get_softc(sc->rue_miibus); + struct mii_data *mii = GET_MII(sc); mii_pollstat(mii); ifmr->ifm_active = mii->mii_media_active; @@ -1265,16 +1302,10 @@ struct ifreq *ifr = (struct ifreq *)data; struct mii_data *mii; int error = 0; - int s; - s = splimp(); + RUE_LOCK(sc); switch (command) { - case SIOCSIFADDR: - case SIOCGIFADDR: - case SIOCSIFMTU: - error = ether_ioctl(ifp, command, data); - break; case SIOCSIFFLAGS: if (ifp->if_flags & IFF_UP) { if (ifp->if_flags & IFF_RUNNING && @@ -1305,15 +1336,15 @@ break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: - mii = device_get_softc(sc->rue_miibus); + mii = GET_MII(sc); error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); break; default: - error = EINVAL; + error = ether_ioctl(ifp, command, data); break; } - splx(s); + RUE_UNLOCK(sc); return (error); } @@ -1325,6 +1356,8 @@ struct rue_chain *c; usbd_status stat; + RUE_LOCK(sc); + ifp->if_oerrors++; printf("rue%d: watchdog timeout\n", sc->rue_unit); @@ -1334,6 +1367,8 @@ if (ifp->if_snd.ifq_head != NULL) rue_start(ifp); + + RUE_UNLOCK(sc); } /* @@ -1348,6 +1383,8 @@ struct ifnet *ifp; int i; + RUE_LOCK(sc); + ifp = &sc->arpcom.ac_if; ifp->if_timer = 0; @@ -1441,6 +1478,8 @@ sc->rue_link = 0; ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); + + RUE_UNLOCK(sc); } /* @@ -1456,6 +1495,8 @@ sc = device_get_softc(dev); sc->rue_dying++; + RUE_LOCK(sc); rue_reset(sc); rue_stop(sc); + RUE_UNLOCK(sc); } Index: sys/dev/usb/if_ruereg.h =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/if_ruereg.h,v retrieving revision 1.1.4.1 diff -u -r1.1.4.1 if_ruereg.h --- sys/dev/usb/if_ruereg.h 30 Jul 2003 13:57:35 -0000 1.1.4.1 +++ sys/dev/usb/if_ruereg.h 4 Oct 2003 21:27:26 -0000 @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/usb/if_ruereg.h,v 1.1.4.1 2003/07/30 13:57:35 akiyama Exp $ + * $FreeBSD: src/sys/dev/usb/if_ruereg.h,v 1.2 2003/10/04 21:41:01 joe Exp $ */ #ifndef _IF_RUEREG_H_ @@ -32,6 +32,7 @@ #define RUE_INTR_PIPE 1 /* Use INTR PIPE */ #define RUE_CONFIG_NO 1 +#define RUE_IFACE_IDX 0 #define RUE_ENDPT_RX 0x0 #define RUE_ENDPT_TX 0x1 @@ -222,7 +223,27 @@ int rue_if_flags; struct rue_cdata rue_cdata; struct callout_handle rue_stat_ch; +#if __FreeBSD_version >= 500000 + struct mtx rue_mtx; +#endif char rue_dying; + struct timeval rue_rx_notice; }; + +#if defined(__FreeBSD__) +#define GET_MII(sc) (device_get_softc((sc)->rue_miibus)) +#elif defined(__NetBSD__) +#define GET_MII(sc) (&(sc)->rue_mii) +#elif defined(__OpenBSD__) +#define GET_MII(sc) (&(sc)->rue_mii) +#endif + +#if 0 +#define RUE_LOCK(_sc) mtx_lock(&(_sc)->rue_mtx) +#define RUE_UNLOCK(_sc) mtx_unlock(&(_sc)->rue_mtx) +#else +#define RUE_LOCK(_sc) +#define RUE_UNLOCK(_sc) +#endif #endif /* _IF_RUEREG_H_ */ Index: sys/dev/usb/kue_fw.h =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/kue_fw.h,v retrieving revision 1.1 diff -u -r1.1 kue_fw.h --- sys/dev/usb/kue_fw.h 5 Jan 2000 04:27:07 -0000 1.1 +++ sys/dev/usb/kue_fw.h 4 Oct 2003 18:54:40 -0000 @@ -29,7 +29,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/usb/kue_fw.h,v 1.1 2000/01/05 04:27:07 wpaul Exp $ + * $FreeBSD: src/sys/dev/usb/kue_fw.h,v 1.2 2000/04/03 20:58:23 n_hibma Exp $ */ /* @@ -85,7 +85,7 @@ #define KUE_QTINTR_LOAD_CODE_HIGH 0x9C /* Firmware code segment */ -static unsigned char kue_code_seg[] = +Static unsigned char kue_code_seg[] = { /******************************************/ /* NOTE: B6/C3 is data header signature */ @@ -577,7 +577,7 @@ }; /* Firmware fixup (data?) segment */ -static unsigned char kue_fix_seg[] = +Static unsigned char kue_fix_seg[] = { /******************************************/ /* NOTE: B6/C3 is data header signature */ @@ -680,6 +680,6 @@ /* Fixup command. */ #define KUE_TRIGCMD_OFFSET 5 -static unsigned char kue_trig_seg[] = { +Static unsigned char kue_trig_seg[] = { 0xb6, 0xc3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00 }; Index: sys/dev/usb/ohci.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/ohci.c,v retrieving revision 1.39.2.9 diff -u -r1.39.2.9 ohci.c --- sys/dev/usb/ohci.c 5 Mar 2003 17:09:44 -0000 1.39.2.9 +++ sys/dev/usb/ohci.c 4 Oct 2003 18:54:40 -0000 @@ -1,5 +1,23 @@ -/* $NetBSD: ohci.c,v 1.64 2000/01/19 00:23:58 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/ohci.c,v 1.39.2.9 2003/03/05 17:09:44 shiba Exp $ */ +/* $NetBSD: ohci.c,v 1.125 2002/05/28 12:42:38 augustss Exp $ */ + +/* Also, already ported: + * $NetBSD: ohci.c,v 1.127 2002/08/07 20:03:19 augustss Exp $ + * $NetBSD: ohci.c,v 1.128 2002/09/27 15:37:35 provos Exp $ + * $NetBSD: ohci.c,v 1.129 2002/09/29 20:58:25 augustss Exp $ + * $NetBSD: ohci.c,v 1.130 2002/09/29 20:59:30 augustss Exp $ + * $NetBSD: ohci.c,v 1.131 2002/09/30 16:36:19 augustss Exp $ + * $NetBSD: ohci.c,v 1.132 2002/12/07 06:52:11 toshii Exp $ + * $NetBSD: ohci.c,v 1.133 2002/12/07 07:14:28 toshii Exp $ + * $NetBSD: ohci.c,v 1.134 2002/12/07 07:33:20 toshii Exp $ + * $NetBSD: ohci.c,v 1.135 2002/12/10 14:07:37 toshii Exp $ + * $NetBSD: ohci.c,v 1.136 2003/01/20 05:30:09 simonb Exp $ + * $NetBSD: ohci.c,v 1.137 2003/01/20 07:12:13 simonb Exp $ + * $NetBSD: ohci.c,v 1.138 2003/02/08 03:32:50 ichiro Exp $ + * $NetBSD: ohci.c,v 1.140 2003/05/13 04:42:00 gson Exp $ + */ + +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/ohci.c,v 1.132 2003/08/24 17:55:54 obrien Exp $"); /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -41,18 +59,19 @@ /* * USB Open Host Controller driver. * - * OHCI spec: ftp://ftp.compaq.com/pub/supportinformation/papers/hcir1_0a.exe - * USB spec: http://www.usb.org/developers/data/usb11.pdf + * OHCI spec: http://www.compaq.com/productinfo/development/openhci.html + * USB spec: http://www.usb.org/developers/docs/usbspec.zip */ #include #include #include -#if defined(__NetBSD__) || defined(__OpenBSD__) #include +#if defined(__NetBSD__) || defined(__OpenBSD__) #include #include #elif defined(__FreeBSD__) +#include #include #include #include @@ -96,6 +115,9 @@ SYSCTL_NODE(_hw_usb, OID_AUTO, ohci, CTLFLAG_RW, 0, "USB ohci"); SYSCTL_INT(_hw_usb_ohci, OID_AUTO, debug, CTLFLAG_RW, &ohcidebug, 0, "ohci debug level"); +#ifndef __NetBSD__ +#define bitmask_snprintf(q,f,b,l) snprintf((b), (l), "%b", (q), (f)) +#endif #else #define DPRINTF(x) #define DPRINTFN(n,x) @@ -105,10 +127,14 @@ * The OHCI controller is little endian, so on big endian machines * the data strored in memory needs to be swapped. */ +#if defined(__OpenBSD__) #if BYTE_ORDER == BIG_ENDIAN -#define LE(x) (bswap32(x)) +#define htole32(x) (bswap32(x)) +#define le32toh(x) (bswap32(x)) #else -#define LE(x) (x) +#define htole32(x) (x) +#define le32toh(x) (x) +#endif #endif struct ohci_pipe; @@ -123,11 +149,11 @@ Static void ohci_free_sitd(ohci_softc_t *,ohci_soft_itd_t *); #if 0 -Static void ohci_free_std_chain(ohci_softc_t *, - ohci_soft_td_t *, ohci_soft_td_t *); +Static void ohci_free_std_chain(ohci_softc_t *, ohci_soft_td_t *, + ohci_soft_td_t *); #endif Static usbd_status ohci_alloc_std_chain(struct ohci_pipe *, - ohci_softc_t *, int, int, u_int16_t, usb_dma_t *, + ohci_softc_t *, int, int, usbd_xfer_handle, ohci_soft_td_t *, ohci_soft_td_t **); #if defined(__NetBSD__) || defined(__OpenBSD__) @@ -136,27 +162,25 @@ #endif Static usbd_status ohci_open(usbd_pipe_handle); Static void ohci_poll(struct usbd_bus *); -Static void ohci_waitintr(ohci_softc_t *, - usbd_xfer_handle); +Static void ohci_softintr(void *); +Static void ohci_waitintr(ohci_softc_t *, usbd_xfer_handle); +Static void ohci_add_done(ohci_softc_t *, ohci_physaddr_t); Static void ohci_rhsc(ohci_softc_t *, usbd_xfer_handle); -Static void ohci_process_done(ohci_softc_t *, - ohci_physaddr_t); Static usbd_status ohci_device_request(usbd_xfer_handle xfer); Static void ohci_add_ed(ohci_soft_ed_t *, ohci_soft_ed_t *); Static void ohci_rem_ed(ohci_soft_ed_t *, ohci_soft_ed_t *); -Static void ohci_hash_add_td(ohci_softc_t *, - ohci_soft_td_t *); -Static void ohci_hash_rem_td(ohci_softc_t *, - ohci_soft_td_t *); -Static ohci_soft_td_t *ohci_hash_find_td(ohci_softc_t *, - ohci_physaddr_t); +Static void ohci_hash_add_td(ohci_softc_t *, ohci_soft_td_t *); +Static void ohci_hash_rem_td(ohci_softc_t *, ohci_soft_td_t *); +Static ohci_soft_td_t *ohci_hash_find_td(ohci_softc_t *, ohci_physaddr_t); +Static void ohci_hash_add_itd(ohci_softc_t *, ohci_soft_itd_t *); +Static void ohci_hash_rem_itd(ohci_softc_t *, ohci_soft_itd_t *); +Static ohci_soft_itd_t *ohci_hash_find_itd(ohci_softc_t *, ohci_physaddr_t); Static usbd_status ohci_setup_isoc(usbd_pipe_handle pipe); Static void ohci_device_isoc_enter(usbd_xfer_handle); -Static usbd_status ohci_allocm(struct usbd_bus *, usb_dma_t *, - u_int32_t); +Static usbd_status ohci_allocm(struct usbd_bus *, usb_dma_t *, u_int32_t); Static void ohci_freem(struct usbd_bus *, usb_dma_t *); Static usbd_xfer_handle ohci_allocx(struct usbd_bus *); @@ -166,50 +190,50 @@ Static usbd_status ohci_root_ctrl_start(usbd_xfer_handle); Static void ohci_root_ctrl_abort(usbd_xfer_handle); Static void ohci_root_ctrl_close(usbd_pipe_handle); +Static void ohci_root_ctrl_done(usbd_xfer_handle); Static usbd_status ohci_root_intr_transfer(usbd_xfer_handle); Static usbd_status ohci_root_intr_start(usbd_xfer_handle); Static void ohci_root_intr_abort(usbd_xfer_handle); Static void ohci_root_intr_close(usbd_pipe_handle); -Static void ohci_root_intr_done (usbd_xfer_handle); +Static void ohci_root_intr_done(usbd_xfer_handle); Static usbd_status ohci_device_ctrl_transfer(usbd_xfer_handle); Static usbd_status ohci_device_ctrl_start(usbd_xfer_handle); Static void ohci_device_ctrl_abort(usbd_xfer_handle); Static void ohci_device_ctrl_close(usbd_pipe_handle); -Static void ohci_device_ctrl_done (usbd_xfer_handle); +Static void ohci_device_ctrl_done(usbd_xfer_handle); Static usbd_status ohci_device_bulk_transfer(usbd_xfer_handle); Static usbd_status ohci_device_bulk_start(usbd_xfer_handle); Static void ohci_device_bulk_abort(usbd_xfer_handle); Static void ohci_device_bulk_close(usbd_pipe_handle); -Static void ohci_device_bulk_done (usbd_xfer_handle); +Static void ohci_device_bulk_done(usbd_xfer_handle); Static usbd_status ohci_device_intr_transfer(usbd_xfer_handle); Static usbd_status ohci_device_intr_start(usbd_xfer_handle); Static void ohci_device_intr_abort(usbd_xfer_handle); Static void ohci_device_intr_close(usbd_pipe_handle); -Static void ohci_device_intr_done (usbd_xfer_handle); +Static void ohci_device_intr_done(usbd_xfer_handle); Static usbd_status ohci_device_isoc_transfer(usbd_xfer_handle); Static usbd_status ohci_device_isoc_start(usbd_xfer_handle); Static void ohci_device_isoc_abort(usbd_xfer_handle); Static void ohci_device_isoc_close(usbd_pipe_handle); -Static void ohci_device_isoc_done (usbd_xfer_handle); +Static void ohci_device_isoc_done(usbd_xfer_handle); -Static usbd_status ohci_device_setintr(ohci_softc_t *sc, +Static usbd_status ohci_device_setintr(ohci_softc_t *sc, struct ohci_pipe *pipe, int ival); -Static int ohci_str(usb_string_descriptor_t *, int, char *); +Static int ohci_str(usb_string_descriptor_t *, int, const char *); Static void ohci_timeout(void *); +Static void ohci_timeout_task(void *); Static void ohci_rhsc_able(ohci_softc_t *, int); +Static void ohci_rhsc_enable(void *); -Static void ohci_close_pipe(usbd_pipe_handle pipe, - ohci_soft_ed_t *head); -Static void ohci_abort_xfer(usbd_xfer_handle xfer, - usbd_status status); -Static void ohci_abort_xfer_end(void *); +Static void ohci_close_pipe(usbd_pipe_handle, ohci_soft_ed_t *); +Static void ohci_abort_xfer(usbd_xfer_handle, usbd_status); Static void ohci_device_clear_toggle(usbd_pipe_handle pipe); Static void ohci_noop(usbd_pipe_handle pipe); @@ -219,14 +243,24 @@ Static void ohci_dump_tds(ohci_soft_td_t *); Static void ohci_dump_td(ohci_soft_td_t *); Static void ohci_dump_ed(ohci_soft_ed_t *); +Static void ohci_dump_itd(ohci_soft_itd_t *); +Static void ohci_dump_itds(ohci_soft_itd_t *); #endif -#define OWRITE4(sc, r, x) bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x)) -#define OREAD4(sc, r) bus_space_read_4((sc)->iot, (sc)->ioh, (r)) -#define OREAD2(sc, r) bus_space_read_2((sc)->iot, (sc)->ioh, (r)) +#define OBARR(sc) bus_space_barrier((sc)->iot, (sc)->ioh, 0, (sc)->sc_size, \ + BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE) +#define OWRITE1(sc, r, x) \ + do { OBARR(sc); bus_space_write_1((sc)->iot, (sc)->ioh, (r), (x)); } while (0) +#define OWRITE2(sc, r, x) \ + do { OBARR(sc); bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x)); } while (0) +#define OWRITE4(sc, r, x) \ + do { OBARR(sc); bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x)); } while (0) +#define OREAD1(sc, r) (OBARR(sc), bus_space_read_1((sc)->iot, (sc)->ioh, (r))) +#define OREAD2(sc, r) (OBARR(sc), bus_space_read_2((sc)->iot, (sc)->ioh, (r))) +#define OREAD4(sc, r) (OBARR(sc), bus_space_read_4((sc)->iot, (sc)->ioh, (r))) /* Reverse the bits in a value 0 .. 31 */ -Static u_int8_t revbits[OHCI_NO_INTRS] = +Static u_int8_t revbits[OHCI_NO_INTRS] = { 0x00, 0x10, 0x08, 0x18, 0x04, 0x14, 0x0c, 0x1c, 0x02, 0x12, 0x0a, 0x1a, 0x06, 0x16, 0x0e, 0x1e, 0x01, 0x11, 0x09, 0x19, 0x05, 0x15, 0x0d, 0x1d, @@ -235,6 +269,7 @@ struct ohci_pipe { struct usbd_pipe pipe; ohci_soft_ed_t *sed; + u_int32_t aborting; union { ohci_soft_td_t *td; ohci_soft_itd_t *itd; @@ -268,6 +303,7 @@ Static struct usbd_bus_methods ohci_bus_methods = { ohci_open, + ohci_softintr, ohci_poll, ohci_allocm, ohci_freem, @@ -275,16 +311,16 @@ ohci_freex, }; -Static struct usbd_pipe_methods ohci_root_ctrl_methods = { +Static 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, + ohci_root_ctrl_done, }; -Static struct usbd_pipe_methods ohci_root_intr_methods = { +Static struct usbd_pipe_methods ohci_root_intr_methods = { ohci_root_intr_transfer, ohci_root_intr_start, ohci_root_intr_abort, @@ -293,7 +329,7 @@ ohci_root_intr_done, }; -Static struct usbd_pipe_methods ohci_device_ctrl_methods = { +Static struct usbd_pipe_methods ohci_device_ctrl_methods = { ohci_device_ctrl_transfer, ohci_device_ctrl_start, ohci_device_ctrl_abort, @@ -302,7 +338,7 @@ ohci_device_ctrl_done, }; -Static struct usbd_pipe_methods ohci_device_intr_methods = { +Static struct usbd_pipe_methods ohci_device_intr_methods = { ohci_device_intr_transfer, ohci_device_intr_start, ohci_device_intr_abort, @@ -311,7 +347,7 @@ ohci_device_intr_done, }; -Static struct usbd_pipe_methods ohci_device_bulk_methods = { +Static struct usbd_pipe_methods ohci_device_bulk_methods = { ohci_device_bulk_transfer, ohci_device_bulk_start, ohci_device_bulk_abort, @@ -344,6 +380,7 @@ case DVACT_DEACTIVATE: if (sc->sc_child != NULL) rv = config_deactivate(sc->sc_child); + sc->sc_dying = 1; break; } return (rv); @@ -356,14 +393,19 @@ if (sc->sc_child != NULL) rv = config_detach(sc->sc_child, flags); - + if (rv != 0) return (rv); -#if defined(__NetBSD__) + usb_uncallout(sc->sc_tmo_rhsc, ohci_rhsc_enable, sc); + +#if defined(__NetBSD__) || defined(__OpenBSD__) powerhook_disestablish(sc->sc_powerhook); shutdownhook_disestablish(sc->sc_shutdownhook); #endif + + usb_delay_ms(&sc->sc_bus, 300); /* XXX let stray task complete */ + /* free data structures XXX */ return (rv); @@ -383,10 +425,10 @@ err = usb_allocmem(&sc->sc_bus, OHCI_SED_SIZE * OHCI_SED_CHUNK, OHCI_ED_ALIGN, &dma); if (err) - return (0); + return (NULL); for(i = 0; i < OHCI_SED_CHUNK; i++) { offs = i * OHCI_SED_SIZE; - sed = (ohci_soft_ed_t *)((char *)KERNADDR(&dma, offs)); + sed = KERNADDR(&dma, offs); sed->physaddr = DMAADDR(&dma, offs); sed->next = sc->sc_freeeds; sc->sc_freeeds = sed; @@ -420,21 +462,24 @@ err = usb_allocmem(&sc->sc_bus, OHCI_STD_SIZE * OHCI_STD_CHUNK, OHCI_TD_ALIGN, &dma); if (err) - return (0); + return (NULL); + s = splusb(); for(i = 0; i < OHCI_STD_CHUNK; i++) { offs = i * OHCI_STD_SIZE; - std = (ohci_soft_td_t *)((char *)KERNADDR(&dma, offs)); + std = KERNADDR(&dma, offs); std->physaddr = DMAADDR(&dma, offs); std->nexttd = sc->sc_freetds; sc->sc_freetds = std; } + splx(s); } + + s = splusb(); std = sc->sc_freetds; sc->sc_freetds = std->nexttd; memset(&std->td, 0, sizeof(ohci_td_t)); std->nexttd = NULL; - - s = splusb(); + std->xfer = NULL; ohci_hash_add_td(sc, std); splx(s); @@ -448,54 +493,62 @@ s = splusb(); ohci_hash_rem_td(sc, std); - splx(s); - std->nexttd = sc->sc_freetds; sc->sc_freetds = std; + splx(s); } usbd_status ohci_alloc_std_chain(struct ohci_pipe *opipe, ohci_softc_t *sc, - int len, int rd, u_int16_t flags, usb_dma_t *dma, - ohci_soft_td_t *std, ohci_soft_td_t **rstd) + int alen, int rd, usbd_xfer_handle xfer, + ohci_soft_td_t *sp, ohci_soft_td_t **ep) { ohci_soft_td_t *next, *cur; - ohci_physaddr_t dataphys, dataphysend; - u_int32_t intr, tdflags; + ohci_physaddr_t dataphys; + u_int32_t tdflags; int offset = 0; - int curlen; - - DPRINTFN(len < 4096,("ohci_alloc_std_chain: start len=%d\n", len)); - - cur = std; - - dataphysend = OHCI_PAGE(DMAADDR(dma, len - 1)); - tdflags = - (rd ? OHCI_TD_IN : OHCI_TD_OUT) | - OHCI_TD_NOCC | OHCI_TD_TOGGLE_CARRY | - (flags & USBD_SHORT_XFER_OK ? OHCI_TD_R : 0); + int len, curlen; + usb_dma_t *dma = &xfer->dmabuf; + u_int16_t flags = xfer->flags; + + DPRINTFN(alen < 4096,("ohci_alloc_std_chain: start len=%d\n", alen)); + + len = alen; + cur = sp; + + tdflags = htole32( + (rd ? OHCI_TD_IN : OHCI_TD_OUT) | + (flags & USBD_SHORT_XFER_OK ? OHCI_TD_R : 0) | + OHCI_TD_NOCC | OHCI_TD_TOGGLE_CARRY | OHCI_TD_NOINTR); for (;;) { next = ohci_alloc_std(sc); - if (next == 0) + if (next == NULL) goto nomem; dataphys = DMAADDR(dma, offset); - /* The OHCI hardware can handle at most one page crossing. */ -#if defined(__NetBSD__) || defined(__OpenBSD__) - if (OHCI_PAGE(dataphys) == dataphysend || - OHCI_PAGE(dataphys) + OHCI_PAGE_SIZE == dataphysend) -#elif defined(__FreeBSD__) - /* XXX This is pretty broken: Because we do not allocate - * a contiguous buffer (contiguous in physical pages) we - * can only transfer one page in one go. - * So check whether the start and end of the buffer are on - * the same page. + /* + * The OHCI hardware can handle at most one 4k crossing. + * XXX - currently we only allocate contigous buffers, but + * the OHCI spec says: If during the data transfer the buffer + * address contained in the HC's working copy of + * CurrentBufferPointer crosses a 4K boundary, the upper 20 + * bits of Buffer End are copied to the working value of + * CurrentBufferPointer causing the next buffer address to + * be the 0th byte in the same 4K page that contains the + * last byte of the buffer (the 4K boundary crossing may + * occur within a data packet transfer.) + * + * If/when dma has multiple segments, this will need to + * properly handle fragmenting TD's. + * + * We can describe the above using maxsegsz = 4k and nsegs = 2 + * in the future. */ - if (OHCI_PAGE(dataphys) == dataphysend) -#endif - { + if (OHCI_PAGE(dataphys) == OHCI_PAGE(DMAADDR(dma, offset + + len - 1)) || len - (OHCI_PAGE_SIZE - + OHCI_PAGE_OFFSET(dataphys)) <= OHCI_PAGE_SIZE) { /* we can handle it in this TD */ curlen = len; } else { @@ -506,62 +559,62 @@ * the case of an mbuf cluster). You'll get an early * short packet. */ -#if defined(__NetBSD__) || defined(__OpenBSD__) /* must use multiple TDs, fill as much as possible. */ - curlen = 2 * OHCI_PAGE_SIZE - - OHCI_PAGE_MASK(dataphys); - if (curlen > len) /* may have fit in one page */ - curlen = len; -#elif defined(__FreeBSD__) - /* See comment above (XXX) */ - curlen = OHCI_PAGE_SIZE - - OHCI_PAGE_MASK(dataphys); + curlen = 2 * OHCI_PAGE_SIZE - + OHCI_PAGE_OFFSET(dataphys); + /* the length must be a multiple of the max size */ + curlen -= curlen % + UGETW(opipe->pipe.endpoint->edesc->wMaxPacketSize); +#ifdef DIAGNOSTIC + if (curlen == 0) + panic("ohci_alloc_std: curlen == 0"); #endif } DPRINTFN(4,("ohci_alloc_std_chain: dataphys=0x%08x " - "dataphysend=0x%08x len=%d curlen=%d\n", - dataphys, dataphysend, - len, curlen)); + "len=%d curlen=%d\n", + dataphys, len, curlen)); len -= curlen; - intr = len == 0 ? OHCI_TD_SET_DI(1) : OHCI_TD_NOINTR; - cur->td.td_flags = LE(tdflags | intr); - cur->td.td_cbp = LE(dataphys); + cur->td.td_flags = tdflags; + cur->td.td_cbp = htole32(dataphys); cur->nexttd = next; - cur->td.td_nexttd = LE(next->physaddr); - cur->td.td_be = LE(dataphys + curlen - 1); + cur->td.td_nexttd = htole32(next->physaddr); + cur->td.td_be = htole32(DMAADDR(dma, curlen - 1)); cur->len = curlen; cur->flags = OHCI_ADD_LEN; + cur->xfer = xfer; DPRINTFN(10,("ohci_alloc_std_chain: cbp=0x%08x be=0x%08x\n", dataphys, dataphys + curlen - 1)); if (len == 0) break; + if (len < 0) + panic("Length went negative: %d curlen %d dma %p offset %08x", len, curlen, dma, (int)0); + DPRINTFN(10,("ohci_alloc_std_chain: extend chain\n")); offset += curlen; cur = next; } if ((flags & USBD_FORCE_SHORT_XFER) && - len % UGETW(opipe->pipe.endpoint->edesc->wMaxPacketSize) == 0) { + alen % UGETW(opipe->pipe.endpoint->edesc->wMaxPacketSize) == 0) { /* Force a 0 length transfer at the end. */ - cur->td.td_flags = LE(tdflags | OHCI_TD_NOINTR); cur = next; next = ohci_alloc_std(sc); - if (next == 0) + if (next == NULL) goto nomem; - cur->td.td_flags = LE(tdflags | OHCI_TD_SET_DI(1)); + cur->td.td_flags = tdflags; cur->td.td_cbp = 0; /* indicate 0 length packet */ cur->nexttd = next; - cur->td.td_nexttd = LE(next->physaddr); + cur->td.td_nexttd = htole32(next->physaddr); cur->td.td_be = ~0; cur->len = 0; cur->flags = 0; + cur->xfer = xfer; DPRINTFN(2,("ohci_alloc_std_chain: add 0 xfer\n")); } - cur->flags = OHCI_CALL_DONE | OHCI_ADD_LEN; - *rstd = next; + *ep = cur; return (USBD_NORMAL_COMPLETION); @@ -589,35 +642,63 @@ { ohci_soft_itd_t *sitd; usbd_status err; - int i, offs; + int i, s, offs; usb_dma_t dma; if (sc->sc_freeitds == NULL) { DPRINTFN(2, ("ohci_alloc_sitd: allocating chunk\n")); - err = usb_allocmem(&sc->sc_bus, OHCI_STD_SIZE * OHCI_STD_CHUNK, - OHCI_TD_ALIGN, &dma); + err = usb_allocmem(&sc->sc_bus, OHCI_SITD_SIZE * OHCI_SITD_CHUNK, + OHCI_ITD_ALIGN, &dma); if (err) - return (0); - for(i = 0; i < OHCI_STD_CHUNK; i++) { - offs = i * OHCI_STD_SIZE; - sitd = (ohci_soft_itd_t *)((char*)KERNADDR(&dma, offs)); + return (NULL); + s = splusb(); + for(i = 0; i < OHCI_SITD_CHUNK; i++) { + offs = i * OHCI_SITD_SIZE; + sitd = KERNADDR(&dma, offs); sitd->physaddr = DMAADDR(&dma, offs); sitd->nextitd = sc->sc_freeitds; sc->sc_freeitds = sitd; } + splx(s); } + + s = splusb(); sitd = sc->sc_freeitds; sc->sc_freeitds = sitd->nextitd; memset(&sitd->itd, 0, sizeof(ohci_itd_t)); - sitd->nextitd = 0; + sitd->nextitd = NULL; + sitd->xfer = NULL; + ohci_hash_add_itd(sc, sitd); + splx(s); + +#ifdef DIAGNOSTIC + sitd->isdone = 0; +#endif + return (sitd); } void ohci_free_sitd(ohci_softc_t *sc, ohci_soft_itd_t *sitd) { + int s; + + DPRINTFN(10,("ohci_free_sitd: sitd=%p\n", sitd)); + +#ifdef DIAGNOSTIC + if (!sitd->isdone) { + panic("ohci_free_sitd: sitd=%p not done", sitd); + return; + } + /* Warn double free */ + sitd->isdone = 0; +#endif + + s = splusb(); + ohci_hash_rem_itd(sc, sitd); sitd->nextitd = sc->sc_freeitds; sc->sc_freeitds = sitd; + splx(s); } usbd_status @@ -626,7 +707,7 @@ ohci_soft_ed_t *sed, *psed; usbd_status err; int i; - u_int32_t s, ctl, ival, hcr, fm, per, rev; + u_int32_t s, ctl, ival, hcr, fm, per, rev, desca; DPRINTF(("ohci_init: start\n")); #if defined(__OpenBSD__) @@ -639,7 +720,7 @@ OHCI_REV_LEGACY(rev) ? ", legacy support" : ""); if (OHCI_REV_HI(rev) != 1 || OHCI_REV_LO(rev) != 0) { - printf("%s: unsupported OHCI revision\n", + printf("%s: unsupported OHCI revision\n", USBDEVNAME(sc->sc_bus.bdev)); sc->sc_bus.usbrev = USBREV_UNKNOWN; return (USBD_INVAL); @@ -648,15 +729,18 @@ for (i = 0; i < OHCI_HASH_SIZE; i++) LIST_INIT(&sc->sc_hash_tds[i]); + for (i = 0; i < OHCI_HASH_SIZE; i++) + LIST_INIT(&sc->sc_hash_itds[i]); SIMPLEQ_INIT(&sc->sc_free_xfers); + /* XXX determine alignment by R/W */ /* Allocate the HCCA area. */ - err = usb_allocmem(&sc->sc_bus, OHCI_HCCA_SIZE, + err = usb_allocmem(&sc->sc_bus, OHCI_HCCA_SIZE, OHCI_HCCA_ALIGN, &sc->sc_hccadma); if (err) return (err); - sc->sc_hcca = (struct ohci_hcca *)KERNADDR(&sc->sc_hccadma, 0); + sc->sc_hcca = KERNADDR(&sc->sc_hccadma, 0); memset(sc->sc_hcca, 0, OHCI_HCCA_SIZE); sc->sc_eintrs = OHCI_NORMAL_INTRS; @@ -667,7 +751,7 @@ err = USBD_NOMEM; goto bad1; } - sc->sc_ctrl_head->ed.ed_flags |= LE(OHCI_ED_SKIP); + sc->sc_ctrl_head->ed.ed_flags |= htole32(OHCI_ED_SKIP); /* Allocate dummy ED that starts the bulk list. */ sc->sc_bulk_head = ohci_alloc_sed(sc); @@ -675,7 +759,7 @@ err = USBD_NOMEM; goto bad2; } - sc->sc_bulk_head->ed.ed_flags |= LE(OHCI_ED_SKIP); + sc->sc_bulk_head->ed.ed_flags |= htole32(OHCI_ED_SKIP); /* Allocate dummy ED that starts the isochronous list. */ sc->sc_isoc_head = ohci_alloc_sed(sc); @@ -683,7 +767,7 @@ err = USBD_NOMEM; goto bad3; } - sc->sc_isoc_head->ed.ed_flags |= LE(OHCI_ED_SKIP); + sc->sc_isoc_head->ed.ed_flags |= htole32(OHCI_ED_SKIP); /* Allocate all the dummy EDs that make up the interrupt tree. */ for (i = 0; i < OHCI_NO_EDS; i++) { @@ -696,21 +780,32 @@ } /* All ED fields are set to 0. */ sc->sc_eds[i] = sed; - sed->ed.ed_flags |= LE(OHCI_ED_SKIP); + sed->ed.ed_flags |= htole32(OHCI_ED_SKIP); if (i != 0) psed = sc->sc_eds[(i-1) / 2]; else psed= sc->sc_isoc_head; sed->next = psed; - sed->ed.ed_nexted = LE(psed->physaddr); + sed->ed.ed_nexted = htole32(psed->physaddr); } - /* + /* * Fill HCCA interrupt table. The bit reversal is to get * the tree set up properly to spread the interrupts. */ for (i = 0; i < OHCI_NO_INTRS; i++) - sc->sc_hcca->hcca_interrupt_table[revbits[i]] = - LE(sc->sc_eds[OHCI_NO_EDS-OHCI_NO_INTRS+i]->physaddr); + sc->sc_hcca->hcca_interrupt_table[revbits[i]] = + htole32(sc->sc_eds[OHCI_NO_EDS-OHCI_NO_INTRS+i]->physaddr); + +#ifdef USB_DEBUG + if (ohcidebug > 15) { + for (i = 0; i < OHCI_NO_EDS; i++) { + printf("ed#%d ", i); + ohci_dump_ed(sc->sc_eds[i]); + } + printf("iso "); + ohci_dump_ed(sc->sc_isoc_head); + } +#endif /* Determine in what context we are running. */ ctl = OREAD4(sc, OHCI_CONTROL); @@ -729,6 +824,8 @@ OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); goto reset; } +#if 0 +/* Don't bother trying to reuse the BIOS init, we'll reset it anyway. */ } else if ((ctl & OHCI_HCFS_MASK) != OHCI_HCFS_RESET) { /* BIOS started controller. */ DPRINTF(("ohci_init: BIOS active\n")); @@ -736,6 +833,7 @@ OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_OPERATIONAL); usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY); } +#endif } else { DPRINTF(("ohci_init: cold started\n")); reset: @@ -800,24 +898,37 @@ per = OHCI_PERIODIC(ival); /* 90% periodic */ OWRITE4(sc, OHCI_PERIODIC_START, per); - OWRITE4(sc, OHCI_RH_STATUS, OHCI_LPSC); /* Enable port power */ + /* Fiddle the No OverCurrent Protection bit to avoid chip bug. */ + desca = OREAD4(sc, OHCI_RH_DESCRIPTOR_A); + OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca | OHCI_NOCP); + OWRITE4(sc, OHCI_RH_STATUS, OHCI_LPSC); /* Enable port power */ + usb_delay_ms(&sc->sc_bus, OHCI_ENABLE_POWER_DELAY); + OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca); + /* + * The AMD756 requires a delay before re-reading the register, + * otherwise it will occasionally report 0 ports. + */ + usb_delay_ms(&sc->sc_bus, OHCI_READ_DESC_DELAY); sc->sc_noport = OHCI_GET_NDP(OREAD4(sc, OHCI_RH_DESCRIPTOR_A)); #ifdef USB_DEBUG if (ohcidebug > 5) ohci_dumpregs(sc); #endif - + /* Set up the bus struct. */ sc->sc_bus.methods = &ohci_bus_methods; sc->sc_bus.pipe_size = sizeof(struct ohci_pipe); -#if defined(__NetBSD__) +#if defined(__NetBSD__) || defined(__OpenBSD__) + sc->sc_control = sc->sc_intre = 0; sc->sc_powerhook = powerhook_establish(ohci_power, sc); sc->sc_shutdownhook = shutdownhook_establish(ohci_shutdown, sc); #endif + usb_callout_init(sc->sc_tmo_rhsc); + return (USBD_NORMAL_COMPLETION); bad5: @@ -837,21 +948,13 @@ usbd_status ohci_allocm(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_bus, size, 0, dma)); + return (usb_allocmem(bus, size, 0, dma)); } void ohci_freem(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_bus, dma); + usb_freemem(bus, dma); } usbd_xfer_handle @@ -861,12 +964,23 @@ usbd_xfer_handle xfer; xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers); - if (xfer != NULL) + if (xfer != NULL) { SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, xfer, next); - else - xfer = malloc(sizeof(*xfer), M_USB, M_NOWAIT); - if (xfer != NULL) - memset(xfer, 0, sizeof *xfer); +#ifdef DIAGNOSTIC + if (xfer->busy_free != XFER_FREE) { + printf("ohci_allocx: xfer=%p not free, 0x%08x\n", xfer, + xfer->busy_free); + } +#endif + } else { + xfer = malloc(sizeof(struct ohci_xfer), M_USB, M_NOWAIT); + } + if (xfer != NULL) { + memset(xfer, 0, sizeof (struct ohci_xfer)); +#ifdef DIAGNOSTIC + xfer->busy_free = XFER_BUSY; +#endif + } return (xfer); } @@ -874,7 +988,23 @@ ohci_freex(struct usbd_bus *bus, usbd_xfer_handle xfer) { struct ohci_softc *sc = (struct ohci_softc *)bus; + struct ohci_xfer *oxfer = (struct ohci_xfer *)xfer; + ohci_soft_itd_t *sitd; + if (oxfer->ohci_xfer_flags & OHCI_ISOC_DIRTY) { + for (sitd = xfer->hcpriv; sitd != NULL && sitd->xfer == xfer; + sitd = sitd->nextitd) + ohci_free_sitd(sc, sitd); + } + +#ifdef DIAGNOSTIC + if (xfer->busy_free != XFER_BUSY) { + printf("ohci_freex: xfer=%p not busy, 0x%08x\n", xfer, + xfer->busy_free); + return; + } + xfer->busy_free = XFER_FREE; +#endif SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next); } @@ -901,13 +1031,62 @@ void ohci_power(int why, void *v) { -#ifdef USB_DEBUG ohci_softc_t *sc = v; + u_int32_t ctl; + int s; +#ifdef USB_DEBUG DPRINTF(("ohci_power: sc=%p, why=%d\n", sc, why)); - /* XXX should suspend/resume */ ohci_dumpregs(sc); #endif + + s = splhardusb(); + switch (why) { + case PWR_SUSPEND: + case PWR_STANDBY: + sc->sc_bus.use_polling++; + ctl = OREAD4(sc, OHCI_CONTROL) & ~OHCI_HCFS_MASK; + if (sc->sc_control == 0) { + /* + * Preserve register values, in case that APM BIOS + * does not recover them. + */ + sc->sc_control = ctl; + sc->sc_intre = OREAD4(sc, OHCI_INTERRUPT_ENABLE); + } + ctl |= OHCI_HCFS_SUSPEND; + OWRITE4(sc, OHCI_CONTROL, ctl); + usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT); + sc->sc_bus.use_polling--; + break; + case PWR_RESUME: + sc->sc_bus.use_polling++; + /* Some broken BIOSes do not recover these values */ + OWRITE4(sc, OHCI_HCCA, DMAADDR(&sc->sc_hccadma, 0)); + OWRITE4(sc, OHCI_CONTROL_HEAD_ED, sc->sc_ctrl_head->physaddr); + OWRITE4(sc, OHCI_BULK_HEAD_ED, sc->sc_bulk_head->physaddr); + if (sc->sc_intre) + OWRITE4(sc, OHCI_INTERRUPT_ENABLE, + sc->sc_intre & (OHCI_ALL_INTRS | OHCI_MIE)); + if (sc->sc_control) + ctl = sc->sc_control; + else + ctl = OREAD4(sc, OHCI_CONTROL); + ctl |= OHCI_HCFS_RESUME; + OWRITE4(sc, OHCI_CONTROL, ctl); + usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY); + ctl = (ctl & ~OHCI_HCFS_MASK) | OHCI_HCFS_OPERATIONAL; + OWRITE4(sc, OHCI_CONTROL, ctl); + usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY); + sc->sc_control = sc->sc_intre = 0; + sc->sc_bus.use_polling--; + break; + case PWR_SOFTSUSPEND: + case PWR_SOFTSTANDBY: + case PWR_SOFTRESUME: + break; + } + splx(s); } #endif @@ -947,8 +1126,8 @@ 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))); + le32toh(sc->sc_hcca->hcca_frame_number), + le32toh(sc->sc_hcca->hcca_done_head))); } #endif @@ -959,6 +1138,9 @@ { ohci_softc_t *sc = p; + if (sc == NULL || sc->sc_dying) + return (0); + /* If we get an interrupt while polling, then just ignore it. */ if (sc->sc_bus.use_polling) { #ifdef DIAGNOSTIC @@ -967,7 +1149,7 @@ return (0); } - return (ohci_intr1(sc)); + return (ohci_intr1(sc)); } Static int @@ -976,6 +1158,8 @@ u_int32_t intrs, eintrs; ohci_physaddr_t done; + DPRINTFN(14,("ohci_intr1: enter\n")); + /* In case the interrupt occurs before initialization has completed. */ if (sc == NULL || sc->sc_hcca == NULL) { #ifdef DIAGNOSTIC @@ -984,8 +1168,8 @@ return (0); } - intrs = 0; - done = LE(sc->sc_hcca->hcca_done_head); + intrs = 0; + done = le32toh(sc->sc_hcca->hcca_done_head); /* The LSb of done is used to inform the HC Driver that an interrupt * condition exists for both the Done list and for another event @@ -999,46 +1183,45 @@ * HcInterruptStatus should be checked to determine its cause. */ if (done != 0) { - sc->sc_hcca->hcca_done_head = 0; if (done & ~OHCI_DONE_INTRS) intrs = OHCI_WDH; if (done & OHCI_DONE_INTRS) { intrs |= OREAD4(sc, OHCI_INTERRUPT_STATUS); done &= ~OHCI_DONE_INTRS; } - } else { + sc->sc_hcca->hcca_done_head = 0; + } else intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS); - } - if (intrs == 0) { - /* nothing to be done ?! */ + if (intrs == 0) /* nothing to be done (PCI shared interrupt) */ return (0); - } - intrs &= ~OHCI_MIE; /* mask out Master Interrupt Enable */ - - /* Acknowledge any interrupts that have happened */ - OWRITE4(sc, OHCI_INTERRUPT_STATUS, intrs); - - /* Any interrupts we had enabled? */ + intrs &= ~OHCI_MIE; + OWRITE4(sc, OHCI_INTERRUPT_STATUS, intrs); /* Acknowledge */ eintrs = intrs & sc->sc_eintrs; if (!eintrs) return (0); sc->sc_bus.intr_context++; sc->sc_bus.no_intrs++; - DPRINTFN(7, ("ohci_intr: sc=%p intrs=%x(%x) eintr=%x\n", + DPRINTFN(7, ("ohci_intr: sc=%p intrs=0x%x(0x%x) eintrs=0x%x\n", sc, (u_int)intrs, OREAD4(sc, OHCI_INTERRUPT_STATUS), (u_int)eintrs)); if (eintrs & OHCI_SO) { - printf("%s: scheduling overrun\n",USBDEVNAME(sc->sc_bus.bdev)); + sc->sc_overrun_cnt++; + if (usbd_ratecheck(&sc->sc_overrun_ntc)) { + printf("%s: %u scheduling overruns\n", + USBDEVNAME(sc->sc_bus.bdev), sc->sc_overrun_cnt); + sc->sc_overrun_cnt = 0; + } /* XXX do what */ - intrs &= ~OHCI_SO; + eintrs &= ~OHCI_SO; } if (eintrs & OHCI_WDH) { - ohci_process_done(sc, done); - intrs &= ~OHCI_WDH; + ohci_add_done(sc, done &~ OHCI_DONE_INTRS); + usb_schedsoftintr(&sc->sc_bus); + eintrs &= ~OHCI_WDH; } if (eintrs & OHCI_RD) { printf("%s: resume detect\n", USBDEVNAME(sc->sc_bus.bdev)); @@ -1052,20 +1235,25 @@ } if (eintrs & OHCI_RHSC) { ohci_rhsc(sc, sc->sc_intrxfer); - intrs &= ~OHCI_RHSC; - - /* + /* * Disable RHSC interrupt for now, because it will be * on until the port has been reset. */ ohci_rhsc_able(sc, 0); + /* Do not allow RHSC interrupts > 1 per second */ + usb_callout(sc->sc_tmo_rhsc, hz, ohci_rhsc_enable, sc); + eintrs &= ~OHCI_RHSC; } sc->sc_bus.intr_context--; - /* Block unprocessed interrupts. XXX */ - OWRITE4(sc, OHCI_INTERRUPT_DISABLE, intrs); - sc->sc_eintrs &= ~intrs; + if (eintrs != 0) { + /* Block unprocessed interrupts. XXX */ + OWRITE4(sc, OHCI_INTERRUPT_DISABLE, eintrs); + sc->sc_eintrs &= ~eintrs; + printf("%s: blocking intrs 0x%x\n", + USBDEVNAME(sc->sc_bus.bdev), eintrs); + } return (1); } @@ -1083,6 +1271,17 @@ } } +void +ohci_rhsc_enable(void *v_sc) +{ + ohci_softc_t *sc = v_sc; + int s; + + s = splhardusb(); + ohci_rhsc_able(sc, 1); + splx(s); +} + #ifdef USB_DEBUG char *ohci_cc_strs[] = { "NO_ERROR", @@ -1105,77 +1304,111 @@ #endif void -ohci_process_done(ohci_softc_t *sc, ohci_physaddr_t done) +ohci_add_done(ohci_softc_t *sc, ohci_physaddr_t done) { - ohci_soft_td_t *std, *sdone, *stdnext; + ohci_soft_itd_t *sitd, *sidone, **ip; + ohci_soft_td_t *std, *sdone, **p; + + /* Reverse the done list. */ + for (sdone = NULL, sidone = NULL; done != 0; ) { + std = ohci_hash_find_td(sc, done); + if (std != NULL) { + std->dnext = sdone; + done = le32toh(std->td.td_nexttd); + sdone = std; + DPRINTFN(10,("add TD %p\n", std)); + continue; + } + sitd = ohci_hash_find_itd(sc, done); + if (sitd != NULL) { + sitd->dnext = sidone; + done = le32toh(sitd->itd.itd_nextitd); + sidone = sitd; + DPRINTFN(5,("add ITD %p\n", sitd)); + continue; + } + panic("ohci_add_done: addr 0x%08lx not found", (u_long)done); + } + + /* sdone & sidone now hold the done lists. */ + /* Put them on the already processed lists. */ + for (p = &sc->sc_sdone; *p != NULL; p = &(*p)->dnext) + ; + *p = sdone; + for (ip = &sc->sc_sidone; *ip != NULL; ip = &(*ip)->dnext) + ; + *ip = sidone; +} + +void +ohci_softintr(void *v) +{ + ohci_softc_t *sc = v; + ohci_soft_itd_t *sitd, *sidone, *sitdnext; + ohci_soft_td_t *std, *sdone, *stdnext; usbd_xfer_handle xfer; - int len, cc; + struct ohci_pipe *opipe; + int len, cc, s; - DPRINTFN(10,("ohci_process_done: done=0x%08lx\n", (u_long)done)); + DPRINTFN(10,("ohci_softintr: enter\n")); - /* Reverse the done list and store the reversed list in sdone */ - sdone = NULL; - for (; done; done = LE(std->td.td_nexttd)) { - std = ohci_hash_find_td(sc, done & LE(OHCI_TAILMASK)); - if (std == NULL) { -#ifdef USB_DEBUG - DPRINTF(("%s: Invalid done queue 0x%08x", - USBDEVNAME(sc->sc_bus.bdev), done)); - ohci_dumpregs(sc); -#endif - /* XXX Should we compare the list of active TDs with - * the list of TDs queued at EDs to handle the ones that - * are not listed on any of the ED queues and therefore - * must be finished? - */ - return; - } + sc->sc_bus.intr_context++; - std->dnext = sdone; - sdone = std; - } + s = splhardusb(); + sdone = sc->sc_sdone; + sc->sc_sdone = NULL; + sidone = sc->sc_sidone; + sc->sc_sidone = NULL; + splx(s); + + DPRINTFN(10,("ohci_softintr: sdone=%p sidone=%p\n", sdone, sidone)); #ifdef USB_DEBUG if (ohcidebug > 10) { DPRINTF(("ohci_process_done: TD done:\n")); - for (std = sdone; std; std = std->dnext) - ohci_dump_td(sdone); + ohci_dump_tds(sdone); } #endif for (std = sdone; std; std = stdnext) { xfer = std->xfer; stdnext = std->dnext; - DPRINTFN(5, ("ohci_process_done: std=%p xfer=%p hcpriv=%p\n", - std, xfer, (xfer? xfer->hcpriv:NULL))); + DPRINTFN(10, ("ohci_process_done: std=%p xfer=%p hcpriv=%p\n", + std, xfer, (xfer ? xfer->hcpriv : NULL))); if (xfer == NULL || (std->flags & OHCI_TD_HANDLED)) { - /* xfer == NULL: There seems to be no xfer associated + /* + * xfer == NULL: There seems to be no xfer associated * with this TD. It is tailp that happened to end up on * the done queue. * flags & OHCI_TD_HANDLED: The TD has already been * handled by process_done and should not be done again. + * Shouldn't happen, but some chips are broken(?). */ continue; } - cc = OHCI_TD_GET_CC(LE(std->td.td_flags)); - usb_untimeout(ohci_timeout, xfer, xfer->timo_handle); if (xfer->status == USBD_CANCELLED || xfer->status == USBD_TIMEOUT) { - DPRINTF(("ohci_process_done: cancel/timeout, xfer=%p\n", + DPRINTF(("ohci_process_done: cancel/timeout %p\n", xfer)); /* Handled by abort routine. */ - } else if (cc == OHCI_CC_NO_ERROR) { - DPRINTFN(15, ("ohci_process_done: no error, xfer=%p\n", - xfer)); + continue; + } + usb_uncallout(xfer->timeout_handle, ohci_timeout, xfer); + cc = OHCI_TD_GET_CC(le32toh(std->td.td_flags)); + 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; + len -= le32toh(std->td.td_be) - + le32toh(std->td.td_cbp) + 1; + DPRINTFN(10, ("ohci_process_done: len=%d, flags=0x%x\n", + len, std->flags)); if (std->flags & OHCI_ADD_LEN) xfer->actlen += len; if (std->flags & OHCI_CALL_DONE) { xfer->status = USBD_NORMAL_COMPLETION; + s = splusb(); usb_transfer_complete(xfer); + splx(s); } ohci_free_std(sc, std); } else { @@ -1185,13 +1418,12 @@ * the endpoint. */ ohci_soft_td_t *p, *n; - struct ohci_pipe *opipe = - (struct ohci_pipe *)xfer->pipe; + opipe = (struct ohci_pipe *)xfer->pipe; + + DPRINTFN(15,("ohci_process_done: error cc=%d (%s)\n", + OHCI_TD_GET_CC(le32toh(std->td.td_flags)), + ohci_cc_strs[OHCI_TD_GET_CC(le32toh(std->td.td_flags))])); - DPRINTF(("ohci_process_done: err cc=%d (%s), xfer=%p\n", - OHCI_TD_GET_CC(LE(std->td.td_flags)), - ohci_cc_strs[OHCI_TD_GET_CC(LE(std->td.td_flags))], - xfer)); /* Mark all the TDs in the done queue for the current * xfer as handled @@ -1201,34 +1433,100 @@ p->flags |= OHCI_TD_HANDLED; } - /* remove TDs for the current xfer from the ED */ + /* remove TDs */ for (p = std; p->xfer == xfer; p = n) { n = p->nexttd; ohci_free_std(sc, p); } - opipe->sed->ed.ed_headp = LE(p->physaddr); - /* XXX why is this being done? Why not OHCI_BLF too */ + /* clear halt */ + opipe->sed->ed.ed_headp = htole32(p->physaddr); OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); if (cc == OHCI_CC_STALL) xfer->status = USBD_STALLED; else xfer->status = USBD_IOERROR; + s = splusb(); + usb_transfer_complete(xfer); + splx(s); + } + } + +#ifdef USB_DEBUG + if (ohcidebug > 10) { + DPRINTF(("ohci_softintr: ITD done:\n")); + ohci_dump_itds(sidone); + } +#endif + for (sitd = sidone; sitd != NULL; sitd = sitdnext) { + xfer = sitd->xfer; + sitdnext = sitd->dnext; + sitd->flags |= OHCI_ITD_INTFIN; + DPRINTFN(1, ("ohci_process_done: sitd=%p xfer=%p hcpriv=%p\n", + sitd, xfer, xfer ? xfer->hcpriv : 0)); + if (xfer == NULL) + continue; + if (xfer->status == USBD_CANCELLED || + xfer->status == USBD_TIMEOUT) { + DPRINTF(("ohci_process_done: cancel/timeout %p\n", + xfer)); + /* Handled by abort routine. */ + continue; + } + if (xfer->pipe) + if (xfer->pipe->aborting) + continue; /*Ignore.*/ +#ifdef DIAGNOSTIC + if (sitd->isdone) + printf("ohci_softintr: sitd=%p is done\n", sitd); + sitd->isdone = 1; +#endif + opipe = (struct ohci_pipe *)xfer->pipe; + if (opipe->aborting) + continue; + + cc = OHCI_ITD_GET_CC(le32toh(sitd->itd.itd_flags)); + if (cc == OHCI_CC_NO_ERROR) { + /* XXX compute length for input */ + if (sitd->flags & OHCI_CALL_DONE) { + opipe->u.iso.inuse -= xfer->nframes; + /* XXX update frlengths with actual length */ + /* XXX xfer->actlen = actlen; */ + xfer->status = USBD_NORMAL_COMPLETION; + s = splusb(); + usb_transfer_complete(xfer); + splx(s); + } + } else { + /* XXX Do more */ + xfer->status = USBD_IOERROR; + s = splusb(); usb_transfer_complete(xfer); + splx(s); } } + +#ifdef USB_USE_SOFTINTR + if (sc->sc_softwake) { + sc->sc_softwake = 0; + wakeup(&sc->sc_softwake); + } +#endif /* USB_USE_SOFTINTR */ + + sc->sc_bus.intr_context--; + DPRINTFN(10,("ohci_softintr: done:\n")); } void ohci_device_ctrl_done(usbd_xfer_handle xfer) { - DPRINTFN(10,("ohci_ctrl_done: xfer=%p\n", xfer)); + DPRINTFN(10,("ohci_device_ctrl_done: xfer=%p\n", xfer)); #ifdef DIAGNOSTIC if (!(xfer->rqflags & URQ_REQUEST)) { - panic("ohci_ctrl_done: not a request\n"); + panic("ohci_device_ctrl_done: not a request"); } #endif xfer->hcpriv = NULL; @@ -1243,7 +1541,7 @@ ohci_soft_td_t *data, *tail; - DPRINTFN(10,("ohci_intr_done: xfer=%p, actlen=%d\n", + DPRINTFN(10,("ohci_device_intr_done: xfer=%p, actlen=%d\n", xfer, xfer->actlen)); xfer->hcpriv = NULL; @@ -1256,24 +1554,24 @@ return; } tail->xfer = NULL; - - data->td.td_flags = LE( - OHCI_TD_IN | OHCI_TD_NOCC | + + data->td.td_flags = htole32( + OHCI_TD_IN | OHCI_TD_NOCC | OHCI_TD_SET_DI(1) | OHCI_TD_TOGGLE_CARRY); if (xfer->flags & USBD_SHORT_XFER_OK) - data->td.td_flags |= LE(OHCI_TD_R); - data->td.td_cbp = LE(DMAADDR(&xfer->dmabuf, 0)); + data->td.td_flags |= htole32(OHCI_TD_R); + data->td.td_cbp = htole32(DMAADDR(&xfer->dmabuf, 0)); data->nexttd = tail; - data->td.td_nexttd = LE(tail->physaddr); - data->td.td_be = LE(LE(data->td.td_cbp) + xfer->length - 1); + data->td.td_nexttd = htole32(tail->physaddr); + data->td.td_be = htole32(le32toh(data->td.td_cbp) + + xfer->length - 1); data->len = xfer->length; data->xfer = xfer; data->flags = OHCI_CALL_DONE | OHCI_ADD_LEN; xfer->hcpriv = data; xfer->actlen = 0; - ohci_hash_add_td(sc, data); - sed->ed.ed_tailp = LE(tail->physaddr); + sed->ed.ed_tailp = htole32(tail->physaddr); opipe->tail.td = tail; } } @@ -1281,7 +1579,7 @@ void ohci_device_bulk_done(usbd_xfer_handle xfer) { - DPRINTFN(10,("ohci_bulk_done: xfer=%p, actlen=%d\n", + DPRINTFN(10,("ohci_device_bulk_done: xfer=%p, actlen=%d\n", xfer, xfer->actlen)); xfer->hcpriv = NULL; @@ -1297,7 +1595,7 @@ int hstatus; hstatus = OREAD4(sc, OHCI_RH_STATUS); - DPRINTF(("ohci_rhsc: sc=%p xfer=%p hstatus=0x%08x\n", + DPRINTF(("ohci_rhsc: sc=%p xfer=%p hstatus=0x%08x\n", sc, xfer, hstatus)); if (xfer == NULL) { @@ -1312,6 +1610,7 @@ m = min(sc->sc_noport, xfer->length * 8 - 1); memset(p, 0, xfer->length); for (i = 1; i <= m; i++) { + /* Pick out CHANGE bits from the status reg. */ if (OREAD4(sc, OHCI_RH_PORT_STATUS(i)) >> 16) p[i/8] |= 1 << (i%8); } @@ -1328,6 +1627,12 @@ xfer->hcpriv = NULL; } +void +ohci_root_ctrl_done(usbd_xfer_handle xfer) +{ + xfer->hcpriv = NULL; +} + /* * Wait here until controller claims to have an interrupt. * Then call ohci_intr and return. Use timeout to avoid waiting @@ -1343,6 +1648,8 @@ xfer->status = USBD_IN_PROGRESS; for (usecs = timo * 1000000 / hz; usecs > 0; usecs -= 1000) { usb_delay_ms(&sc->sc_bus, 1); + if (sc->sc_dying) + break; intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS) & sc->sc_eintrs; DPRINTFN(15,("ohci_waitintr: 0x%04x\n", intrs)); #ifdef USB_DEBUG @@ -1358,9 +1665,6 @@ /* Timeout */ DPRINTF(("ohci_waitintr: timeout\n")); -#ifdef USB_DEBUG - ohci_dumpregs(sc); -#endif xfer->status = USBD_TIMEOUT; usb_transfer_complete(xfer); /* XXX should free TD */ @@ -1370,6 +1674,15 @@ ohci_poll(struct usbd_bus *bus) { ohci_softc_t *sc = (ohci_softc_t *)bus; +#ifdef USB_DEBUG + static int last; + int new; + new = OREAD4(sc, OHCI_INTERRUPT_STATUS); + if (new != last) { + DPRINTFN(10,("ohci_poll: intrs=0x%04x\n", new)); + last = new; + } +#endif if (OREAD4(sc, OHCI_INTERRUPT_STATUS) & sc->sc_eintrs) ohci_intr1(sc); @@ -1383,7 +1696,7 @@ usbd_device_handle dev = opipe->pipe.device; ohci_softc_t *sc = (ohci_softc_t *)dev->bus; int addr = dev->address; - ohci_soft_td_t *setup, *data = 0, *stat, *next, *tail; + ohci_soft_td_t *setup, *stat, *next, *tail; ohci_soft_ed_t *sed; int isread; int len; @@ -1396,7 +1709,7 @@ DPRINTFN(3,("ohci_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), len, addr, + UGETW(req->wIndex), len, addr, opipe->pipe.endpoint->edesc->bEndpointAddress)); setup = opipe->tail.td; @@ -1417,58 +1730,49 @@ /* 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)) | + /* XXXX Should not touch ED here! */ + sed->ed.ed_flags = htole32( + (le32toh(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))); + next = stat; + /* Set up data transaction */ if (len != 0) { - data = ohci_alloc_std(sc); - if (data == NULL) { - err = USBD_NOMEM; - goto bad3; - } - data->td.td_flags = LE( - (isread ? OHCI_TD_IN : OHCI_TD_OUT) | OHCI_TD_NOCC | - OHCI_TD_TOGGLE_1 | OHCI_TD_NOINTR | - (xfer->flags & USBD_SHORT_XFER_OK ? OHCI_TD_R : 0)); - data->td.td_cbp = LE(DMAADDR(&xfer->dmabuf, 0)); - data->nexttd = stat; - data->td.td_nexttd = LE(stat->physaddr); - data->td.td_be = LE(LE(data->td.td_cbp) + len - 1); - data->len = len; - data->xfer = xfer; - data->flags = OHCI_ADD_LEN; + ohci_soft_td_t *std = stat; - next = data; - stat->flags = OHCI_CALL_DONE; - } else { - next = stat; - /* XXX ADD_LEN? */ - stat->flags = OHCI_CALL_DONE | OHCI_ADD_LEN; + err = ohci_alloc_std_chain(opipe, sc, len, isread, xfer, + std, &stat); + stat = stat->nexttd; /* point at free TD */ + if (err) + goto bad3; + /* Start toggle at 1 and then use the carried toggle. */ + std->td.td_flags &= htole32(~OHCI_TD_TOGGLE_MASK); + std->td.td_flags |= htole32(OHCI_TD_TOGGLE_1); } memcpy(KERNADDR(&opipe->u.ctl.reqdma, 0), req, sizeof *req); - 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, 0)); + setup->td.td_flags = htole32(OHCI_TD_SETUP | OHCI_TD_NOCC | + OHCI_TD_TOGGLE_0 | OHCI_TD_NOINTR); + setup->td.td_cbp = htole32(DMAADDR(&opipe->u.ctl.reqdma, 0)); setup->nexttd = next; - 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->td.td_nexttd = htole32(next->physaddr); + setup->td.td_be = htole32(le32toh(setup->td.td_cbp) + sizeof *req - 1); + setup->len = 0; setup->xfer = xfer; setup->flags = 0; xfer->hcpriv = setup; - 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_flags = htole32( + (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->nexttd = tail; - stat->td.td_nexttd = LE(tail->physaddr); + stat->td.td_nexttd = htole32(tail->physaddr); stat->td.td_be = 0; + stat->flags = OHCI_CALL_DONE; stat->len = 0; stat->xfer = xfer; @@ -1482,20 +1786,24 @@ /* Insert ED in schedule */ s = splusb(); - sed->ed.ed_tailp = LE(tail->physaddr); + sed->ed.ed_tailp = htole32(tail->physaddr); opipe->tail.td = tail; OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); if (xfer->timeout && !sc->sc_bus.use_polling) { - usb_timeout(ohci_timeout, xfer, - MS_TO_TICKS(xfer->timeout), xfer->timo_handle); + usb_callout(xfer->timeout_handle, MS_TO_TICKS(xfer->timeout), + ohci_timeout, xfer); } splx(s); #ifdef USB_DEBUG - if (ohcidebug > 25) { - usb_delay_ms(&sc->sc_bus, 5); + if (ohcidebug > 20) { + delay(10000); DPRINTF(("ohci_device_request: status=%x\n", OREAD4(sc, OHCI_COMMAND_STATUS))); + ohci_dumpregs(sc); + printf("ctrl head:\n"); + ohci_dump_ed(sc->sc_ctrl_head); + printf("sed:\n"); ohci_dump_ed(sed); ohci_dump_tds(setup); } @@ -1517,11 +1825,13 @@ void ohci_add_ed(ohci_soft_ed_t *sed, ohci_soft_ed_t *head) { + DPRINTFN(8,("ohci_add_ed: sed=%p head=%p\n", sed, head)); + SPLUSBCHECK; sed->next = head->next; sed->ed.ed_nexted = head->ed.ed_nexted; head->next = sed; - head->ed.ed_nexted = LE(sed->physaddr); + head->ed.ed_nexted = htole32(sed->physaddr); } /* @@ -1530,15 +1840,15 @@ void ohci_rem_ed(ohci_soft_ed_t *sed, ohci_soft_ed_t *head) { - ohci_soft_ed_t *p; + ohci_soft_ed_t *p; SPLUSBCHECK; /* XXX */ - for (p = head; p == NULL && p->next != sed; p = p->next) + for (p = head; p != NULL && p->next != sed; p = p->next) ; if (p == NULL) - panic("ohci_rem_ed: ED not found\n"); + panic("ohci_rem_ed: ED not found"); p->next = sed->next; p->ed.ed_nexted = sed->ed.ed_nexted; } @@ -1583,11 +1893,11 @@ /* if these are present they should be masked out at an earlier * stage. */ - KASSERT((a&~OHCI_TAILMASK) == 0, ("%s: 0x%b has lower bits set\n", + KASSERT((a&~OHCI_HEADMASK) == 0, ("%s: 0x%b has lower bits set\n", USBDEVNAME(sc->sc_bus.bdev), (int) a, "\20\1HALT\2TOGGLE")); - for (std = LIST_FIRST(&sc->sc_hash_tds[h]); + for (std = LIST_FIRST(&sc->sc_hash_tds[h]); std != NULL; std = LIST_NEXT(std, hnext)) if (std->physaddr == a) @@ -1595,21 +1905,78 @@ DPRINTF(("%s: ohci_hash_find_td: addr 0x%08lx not found\n", USBDEVNAME(sc->sc_bus.bdev), (u_long) a)); - return NULL; + return (NULL); +} + +/* Called at splusb() */ +void +ohci_hash_add_itd(ohci_softc_t *sc, ohci_soft_itd_t *sitd) +{ + int h = HASH(sitd->physaddr); + + SPLUSBCHECK; + + DPRINTFN(10,("ohci_hash_add_itd: sitd=%p physaddr=0x%08lx\n", + sitd, (u_long)sitd->physaddr)); + + LIST_INSERT_HEAD(&sc->sc_hash_itds[h], sitd, hnext); +} + +/* Called at splusb() */ +void +ohci_hash_rem_itd(ohci_softc_t *sc, ohci_soft_itd_t *sitd) +{ + SPLUSBCHECK; + + DPRINTFN(10,("ohci_hash_rem_itd: sitd=%p physaddr=0x%08lx\n", + sitd, (u_long)sitd->physaddr)); + + LIST_REMOVE(sitd, hnext); +} + +ohci_soft_itd_t * +ohci_hash_find_itd(ohci_softc_t *sc, ohci_physaddr_t a) +{ + int h = HASH(a); + ohci_soft_itd_t *sitd; + + for (sitd = LIST_FIRST(&sc->sc_hash_itds[h]); + sitd != NULL; + sitd = LIST_NEXT(sitd, hnext)) + if (sitd->physaddr == a) + return (sitd); + return (NULL); } void ohci_timeout(void *addr) { + struct ohci_xfer *oxfer = addr; + struct ohci_pipe *opipe = (struct ohci_pipe *)oxfer->xfer.pipe; + ohci_softc_t *sc = (ohci_softc_t *)opipe->pipe.device->bus; + + DPRINTF(("ohci_timeout: oxfer=%p\n", oxfer)); + + if (sc->sc_dying) { + ohci_abort_xfer(&oxfer->xfer, USBD_TIMEOUT); + return; + } + + /* Execute the abort in a process context. */ + usb_init_task(&oxfer->abort_task, ohci_timeout_task, addr); + usb_add_task(oxfer->xfer.pipe->device, &oxfer->abort_task); +} + +void +ohci_timeout_task(void *addr) +{ usbd_xfer_handle xfer = addr; int s; - DPRINTF(("ohci_timeout: xfer=%p\n", xfer)); + DPRINTF(("ohci_timeout_task: xfer=%p\n", xfer)); s = splusb(); - xfer->device->bus->intr_context++; ohci_abort_xfer(xfer, USBD_TIMEOUT); - xfer->device->bus->intr_context--; splx(s); } @@ -1624,34 +1991,71 @@ void ohci_dump_td(ohci_soft_td_t *std) { - 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))); + char sbuf[128]; + + bitmask_snprintf((u_int32_t)le32toh(std->td.td_flags), + "\20\23R\24OUT\25IN\31TOG1\32SETTOGGLE", + sbuf, sizeof(sbuf)); + + printf("TD(%p) at %08lx: %s delay=%d ec=%d cc=%d\ncbp=0x%08lx " + "nexttd=0x%08lx be=0x%08lx\n", + std, (u_long)std->physaddr, sbuf, + OHCI_TD_GET_DI(le32toh(std->td.td_flags)), + OHCI_TD_GET_EC(le32toh(std->td.td_flags)), + OHCI_TD_GET_CC(le32toh(std->td.td_flags)), + (u_long)le32toh(std->td.td_cbp), + (u_long)le32toh(std->td.td_nexttd), + (u_long)le32toh(std->td.td_be)); +} + +void +ohci_dump_itd(ohci_soft_itd_t *sitd) +{ + int i; + + printf("ITD(%p) at %08lx: sf=%d di=%d fc=%d cc=%d\n" + "bp0=0x%08lx next=0x%08lx be=0x%08lx\n", + sitd, (u_long)sitd->physaddr, + OHCI_ITD_GET_SF(le32toh(sitd->itd.itd_flags)), + OHCI_ITD_GET_DI(le32toh(sitd->itd.itd_flags)), + OHCI_ITD_GET_FC(le32toh(sitd->itd.itd_flags)), + OHCI_ITD_GET_CC(le32toh(sitd->itd.itd_flags)), + (u_long)le32toh(sitd->itd.itd_bp0), + (u_long)le32toh(sitd->itd.itd_nextitd), + (u_long)le32toh(sitd->itd.itd_be)); + for (i = 0; i < OHCI_ITD_NOFFSET; i++) + printf("offs[%d]=0x%04x ", i, + (u_int)le16toh(sitd->itd.itd_offset[i])); + printf("\n"); +} + +void +ohci_dump_itds(ohci_soft_itd_t *sitd) +{ + for (; sitd; sitd = sitd->nextitd) + ohci_dump_itd(sitd); } void ohci_dump_ed(ohci_soft_ed_t *sed) { - DPRINTF(("ED(%p) at %08lx: addr=%d endpt=%d maxp=%d %b\n" - "tailp=0x%8b headp=0x%8b 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", - (int)(uintptr_t)LE(sed->ed.ed_tailp), - "\20\1BIT1\2BIT2", - (int)(uintptr_t)LE(sed->ed.ed_headp), - "\20\1HALT\2CARRY", - (u_long)LE(sed->ed.ed_nexted))); + char sbuf[128], sbuf2[128]; + + bitmask_snprintf((u_int32_t)le32toh(sed->ed.ed_flags), + "\20\14OUT\15IN\16LOWSPEED\17SKIP\20ISO", + sbuf, sizeof(sbuf)); + bitmask_snprintf((u_int32_t)le32toh(sed->ed.ed_headp), + "\20\1HALT\2CARRY", sbuf2, sizeof(sbuf2)); + + printf("ED(%p) at 0x%08lx: addr=%d endpt=%d maxp=%d flags=%s\ntailp=0x%08lx " + "headflags=%s headp=0x%08lx nexted=0x%08lx\n", + sed, (u_long)sed->physaddr, + OHCI_ED_GET_FA(le32toh(sed->ed.ed_flags)), + OHCI_ED_GET_EN(le32toh(sed->ed.ed_flags)), + OHCI_ED_GET_MAXP(le32toh(sed->ed.ed_flags)), sbuf, + (u_long)le32toh(sed->ed.ed_tailp), sbuf2, + (u_long)le32toh(sed->ed.ed_headp), + (u_long)le32toh(sed->ed.ed_nexted)); } #endif @@ -1665,7 +2069,7 @@ u_int8_t addr = dev->address; u_int8_t xfertype = ed->bmAttributes & UE_XFERTYPE; ohci_soft_ed_t *sed; - ohci_soft_td_t *std = NULL; + ohci_soft_td_t *std; ohci_soft_itd_t *sitd; ohci_physaddr_t tdphys; u_int32_t fmt; @@ -1675,6 +2079,13 @@ DPRINTFN(1, ("ohci_open: pipe=%p, addr=%d, endpt=%d (%d)\n", pipe, addr, ed->bEndpointAddress, sc->sc_addr)); + + if (sc->sc_dying) + return (USBD_IOERROR); + + std = NULL; + sed = NULL; + if (addr == sc->sc_addr) { switch (ed->bEndpointAddress) { case USB_CONTROL_ENDPOINT: @@ -1693,36 +2104,37 @@ opipe->sed = sed; if (xfertype == UE_ISOCHRONOUS) { sitd = ohci_alloc_sitd(sc); - if (sitd == NULL) { - ohci_free_sitd(sc, sitd); + if (sitd == NULL) goto bad1; - } opipe->tail.itd = sitd; - tdphys = LE(sitd->physaddr); + opipe->aborting = 0; + tdphys = sitd->physaddr; fmt = OHCI_ED_FORMAT_ISO; + if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) + fmt |= OHCI_ED_DIR_IN; + else + fmt |= OHCI_ED_DIR_OUT; } else { std = ohci_alloc_std(sc); - if (std == NULL) { - ohci_free_std(sc, std); + if (std == NULL) goto bad1; - } opipe->tail.td = std; - tdphys = LE(std->physaddr); - fmt = OHCI_ED_FORMAT_GEN; + tdphys = std->physaddr; + fmt = OHCI_ED_FORMAT_GEN | OHCI_ED_DIR_TD; } - sed->ed.ed_flags = LE( - OHCI_ED_SET_FA(addr) | + sed->ed.ed_flags = htole32( + OHCI_ED_SET_FA(addr) | OHCI_ED_SET_EN(ed->bEndpointAddress) | - OHCI_ED_DIR_TD | - (dev->lowspeed ? OHCI_ED_SPEED : 0) | fmt | + (dev->speed == USB_SPEED_LOW ? OHCI_ED_SPEED : 0) | + fmt | OHCI_ED_SET_MAXP(UGETW(ed->wMaxPacketSize))); - sed->ed.ed_headp = sed->ed.ed_tailp = tdphys; + sed->ed.ed_headp = sed->ed.ed_tailp = htole32(tdphys); switch (xfertype) { case UE_CONTROL: pipe->methods = &ohci_device_ctrl_methods; - err = usb_allocmem(&sc->sc_bus, - sizeof(usb_device_request_t), + err = usb_allocmem(&sc->sc_bus, + sizeof(usb_device_request_t), 0, &opipe->u.ctl.reqdma); if (err) goto bad; @@ -1750,12 +2162,14 @@ return (USBD_NORMAL_COMPLETION); bad: - ohci_free_std(sc, std); + if (std != NULL) + ohci_free_std(sc, std); bad1: - ohci_free_sed(sc, sed); + if (sed != NULL) + ohci_free_sed(sc, sed); bad0: return (USBD_NOMEM); - + } /* @@ -1772,32 +2186,38 @@ 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_HEADMASK))) { - ohci_physaddr_t td = sed->ed.ed_headp; + sed->ed.ed_flags |= htole32(OHCI_ED_SKIP); + if ((le32toh(sed->ed.ed_tailp) & OHCI_HEADMASK) != + (le32toh(sed->ed.ed_headp) & OHCI_HEADMASK)) { ohci_soft_td_t *std; - for (std = LIST_FIRST(&sc->sc_hash_tds[HASH(td)]); - std != NULL; - std = LIST_NEXT(std, hnext)) - if (std->physaddr == td) - break; + std = ohci_hash_find_td(sc, le32toh(sed->ed.ed_headp)); 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), + (int)le32toh(sed->ed.ed_headp), + (int)le32toh(sed->ed.ed_tailp), pipe, std); +#ifdef USB_DEBUG + usbd_dump_pipe(&opipe->pipe); +#endif +#ifdef USB_DEBUG + ohci_dump_ed(sed); + if (std) + ohci_dump_td(std); +#endif usb_delay_ms(&sc->sc_bus, 2); - if ((sed->ed.ed_tailp & LE(OHCI_TAILMASK)) - != (sed->ed.ed_headp & LE(OHCI_HEADMASK))) + if ((le32toh(sed->ed.ed_tailp) & OHCI_HEADMASK) != + (le32toh(sed->ed.ed_headp) & OHCI_HEADMASK)) printf("ohci_close_pipe: pipe still not empty\n"); } #endif ohci_rem_ed(sed, head); + /* Make sure the host controller is not touching this ED */ + usb_delay_ms(&sc->sc_bus, 1); splx(s); 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 @@ -1811,70 +2231,99 @@ ohci_abort_xfer(usbd_xfer_handle xfer, usbd_status status) { struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe; - ohci_soft_ed_t *sed; + ohci_softc_t *sc = (ohci_softc_t *)opipe->pipe.device->bus; + ohci_soft_ed_t *sed = opipe->sed; + ohci_soft_td_t *p, *n; + ohci_physaddr_t headp; + int s, hit; - DPRINTF(("ohci_abort_xfer: xfer=%p pipe=%p\n", xfer, opipe)); + DPRINTF(("ohci_abort_xfer: xfer=%p pipe=%p sed=%p\n", xfer, opipe,sed)); - xfer->status = status; + if (sc->sc_dying) { + /* If we're dying, just do the software part. */ + s = splusb(); + xfer->status = status; /* make software ignore it */ + usb_uncallout(xfer->timeout_handle, ohci_timeout, xfer); + usb_transfer_complete(xfer); + splx(s); + } - usb_untimeout(ohci_timeout, xfer, xfer->timo_handle); + if (xfer->device->bus->intr_context || !curproc) + panic("ohci_abort_xfer: not in process context"); - sed = opipe->sed; - sed->ed.ed_flags |= LE(OHCI_ED_SKIP); /* force hardware skip */ -#ifdef USB_DEBUG + /* + * Step 1: Make interrupt routine and hardware ignore xfer. + */ + s = splusb(); + xfer->status = status; /* make software ignore it */ + usb_uncallout(xfer->timeout_handle, ohci_timeout, xfer); + splx(s); DPRINTFN(1,("ohci_abort_xfer: stop ed=%p\n", sed)); - ohci_dump_ed(sed); -#endif - -#if 1 - if (xfer->device->bus->intr_context) { - /* We have no process context, so we can't use tsleep(). */ - timeout(ohci_abort_xfer_end, xfer, hz / USB_FRAMES_PER_SECOND); - } else { -#if defined(DIAGNOSTIC) && defined(__i386__) && defined(__FreeBSD__) - KASSERT(intr_nesting_level == 0, - ("ohci_abort_req in interrupt context")); -#endif - usb_delay_ms(opipe->pipe.device->bus, 1); - ohci_abort_xfer_end(xfer); - } -#else - delay(1000); - ohci_abort_xfer_end(xfer); -#endif -} - -void -ohci_abort_xfer_end(void *v) -{ - usbd_xfer_handle xfer = v; - struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->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; + sed->ed.ed_flags |= htole32(OHCI_ED_SKIP); /* force hardware skip */ + /* + * Step 2: Wait until we know hardware has finished any possible + * use of the xfer. Also make sure the soft interrupt routine + * has run. + */ + usb_delay_ms(opipe->pipe.device->bus, 20); /* Hardware finishes in 1ms */ s = splusb(); +#ifdef USB_USE_SOFTINTR + sc->sc_softwake = 1; +#endif /* USB_USE_SOFTINTR */ + usb_schedsoftintr(&sc->sc_bus); +#ifdef USB_USE_SOFTINTR + tsleep(&sc->sc_softwake, PZERO, "ohciab", 0); +#endif /* USB_USE_SOFTINTR */ + splx(s); + /* + * Step 3: Remove any vestiges of the xfer from the hardware. + * The complication here is that the hardware may have executed + * beyond the xfer we're trying to abort. So as we're scanning + * the TDs of this xfer we check if the hardware points to + * any of them. + */ + s = splusb(); /* XXX why? */ p = xfer->hcpriv; #ifdef DIAGNOSTIC if (p == NULL) { - printf("ohci_abort_xfer: hcpriv==0\n"); splx(s); + printf("ohci_abort_xfer: hcpriv is NULL\n"); return; } #endif +#ifdef USB_DEBUG + if (ohcidebug > 1) { + DPRINTF(("ohci_abort_xfer: sed=\n")); + ohci_dump_ed(sed); + ohci_dump_tds(p); + } +#endif + headp = le32toh(sed->ed.ed_headp) & OHCI_HEADMASK; + hit = 0; for (; p->xfer == xfer; p = n) { + hit |= headp == p->physaddr; n = p->nexttd; ohci_free_std(sc, p); } + /* Zap headp register if hardware pointed inside the xfer. */ + if (hit) { + DPRINTFN(1,("ohci_abort_xfer: set hd=0x08%x, tl=0x%08x\n", + (int)p->physaddr, (int)le32toh(sed->ed.ed_tailp))); + sed->ed.ed_headp = htole32(p->physaddr); /* unlink TDs */ + } else { + DPRINTFN(1,("ohci_abort_xfer: no hit\n")); + } - sed = opipe->sed; - DPRINTFN(2,("ohci_abort_xfer: 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 */ + /* + * Step 4: Turn on hardware again. + */ + sed->ed.ed_flags &= htole32(~OHCI_ED_SKIP); /* remove hardware skip */ + /* + * Step 5: Execute callback. + */ usb_transfer_complete(xfer); splx(s); @@ -1941,7 +2390,7 @@ }; Static int -ohci_str(usb_string_descriptor_t *p, int l, char *s) +ohci_str(usb_string_descriptor_t *p, int l, const char *s) { int i; @@ -1987,6 +2436,9 @@ usbd_status err; u_int32_t v; + if (sc->sc_dying) + return (USBD_IOERROR); + #ifdef DIAGNOSTIC if (!(xfer->rqflags & URQ_REQUEST)) /* XXX panic */ @@ -1994,7 +2446,7 @@ #endif req = &xfer->request; - DPRINTFN(4,("ohci_root_ctrl_control type=0x%02x request=%02x\n", + DPRINTFN(4,("ohci_root_ctrl_control type=0x%02x request=%02x\n", req->bmRequestType, req->bRequest)); len = UGETW(req->wLength); @@ -2009,7 +2461,7 @@ case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE): case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE): case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT): - /* + /* * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops * for the integrated root hub. */ @@ -2133,6 +2585,7 @@ OWRITE4(sc, port, UPS_OVERCURRENT_INDICATOR); break; case UHF_PORT_POWER: + /* Yes, writing to the LOW_SPEED bit clears power. */ OWRITE4(sc, port, UPS_LOW_SPEED); break; case UHF_C_PORT_CONNECTION: @@ -2177,13 +2630,13 @@ hubd = ohci_hubd; hubd.bNbrPorts = sc->sc_noport; USETW(hubd.wHubCharacteristics, - (v & OHCI_NPS ? UHD_PWR_NO_SWITCH : + (v & OHCI_NPS ? UHD_PWR_NO_SWITCH : v & OHCI_PSM ? UHD_PWR_GANGED : UHD_PWR_INDIVIDUAL) /* XXX overcurrent */ ); hubd.bPwrOn2PwrGood = OHCI_GET_POTPGT(v); v = OREAD4(sc, OHCI_RH_DESCRIPTOR_B); - for (i = 0, l = sc->sc_noport; l > 0; i++, l -= 8, v >>= 8) + for (i = 0, l = sc->sc_noport; l > 0; i++, l -= 8, v >>= 8) hubd.DeviceRemovable[i++] = (u_int8_t)v; hubd.bDescLength = USB_HUB_DESCRIPTOR_SIZE + i; l = min(len, hubd.bDescLength); @@ -2240,8 +2693,13 @@ DPRINTFN(5,("ohci_root_ctrl_transfer: reset port %d\n", index)); OWRITE4(sc, port, UPS_RESET); - for (i = 0; i < 10; i++) { - usb_delay_ms(&sc->sc_bus, 10); + for (i = 0; i < 5; i++) { + usb_delay_ms(&sc->sc_bus, + USB_PORT_ROOT_RESET_DELAY); + if (sc->sc_dying) { + err = USBD_IOERROR; + goto ret; + } if ((OREAD4(sc, port) & UPS_RESET) == 0) break; } @@ -2307,6 +2765,9 @@ usbd_pipe_handle pipe = xfer->pipe; ohci_softc_t *sc = (ohci_softc_t *)pipe->device->bus; + if (sc->sc_dying) + return (USBD_IOERROR); + sc->sc_intrxfer = xfer; return (USBD_IN_PROGRESS); @@ -2333,7 +2794,7 @@ ohci_root_intr_close(usbd_pipe_handle pipe) { ohci_softc_t *sc = (ohci_softc_t *)pipe->device->bus; - + DPRINTF(("ohci_root_intr_close\n")); sc->sc_intrxfer = NULL; @@ -2361,6 +2822,9 @@ ohci_softc_t *sc = (ohci_softc_t *)xfer->pipe->device->bus; usbd_status err; + if (sc->sc_dying) + return (USBD_IOERROR); + #ifdef DIAGNOSTIC if (!(xfer->rqflags & URQ_REQUEST)) { /* XXX panic */ @@ -2405,7 +2869,7 @@ { struct ohci_pipe *opipe = (struct ohci_pipe *)pipe; - opipe->sed->ed.ed_headp &= LE(~OHCI_TOGGLECARRY); + opipe->sed->ed.ed_headp &= htole32(~OHCI_TOGGLECARRY); } Static void @@ -2439,6 +2903,9 @@ int s, len, isread, endpt; usbd_status err; + if (sc->sc_dying) + return (USBD_IOERROR); + #ifdef DIAGNOSTIC if (xfer->rqflags & URQ_REQUEST) { /* XXX panic */ @@ -2460,14 +2927,19 @@ opipe->u.bulk.length = len; /* Update device address */ - sed->ed.ed_flags = LE( - (LE(sed->ed.ed_flags) & ~OHCI_ED_ADDRMASK) | + sed->ed.ed_flags = htole32( + (le32toh(sed->ed.ed_flags) & ~OHCI_ED_ADDRMASK) | OHCI_ED_SET_FA(addr)); /* Allocate a chain of new TDs (including a new tail). */ data = opipe->tail.td; - err = ohci_alloc_std_chain(opipe, sc, len, isread, xfer->flags, - &xfer->dmabuf, data, &tail); + err = ohci_alloc_std_chain(opipe, sc, len, isread, xfer, + data, &tail); + /* We want interrupt at the end of the transfer. */ + tail->td.td_flags &= htole32(~OHCI_TD_INTR_MASK); + tail->td.td_flags |= htole32(OHCI_TD_SET_DI(1)); + tail->flags |= OHCI_CALL_DONE; + tail = tail->nexttd; /* point at sentinel */ if (err) return (err); @@ -2476,11 +2948,13 @@ 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(data->td.td_flags), - (int)LE(data->td.td_cbp), (int)LE(data->td.td_be))); + (int)le32toh(sed->ed.ed_flags), + (int)le32toh(data->td.td_flags), + (int)le32toh(data->td.td_cbp), + (int)le32toh(data->td.td_be))); #ifdef USB_DEBUG - if (ohcidebug > 4) { + if (ohcidebug > 5) { ohci_dump_ed(sed); ohci_dump_tds(data); } @@ -2490,21 +2964,20 @@ s = splusb(); for (tdp = data; tdp != tail; tdp = tdp->nexttd) { tdp->xfer = xfer; - ohci_hash_add_td(sc, tdp); } - sed->ed.ed_tailp = LE(tail->physaddr); + sed->ed.ed_tailp = htole32(tail->physaddr); opipe->tail.td = tail; - sed->ed.ed_flags &= LE(~OHCI_ED_SKIP); + sed->ed.ed_flags &= htole32(~OHCI_ED_SKIP); OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF); if (xfer->timeout && !sc->sc_bus.use_polling) { - usb_timeout(ohci_timeout, xfer, - MS_TO_TICKS(xfer->timeout), xfer->timo_handle); + usb_callout(xfer->timeout_handle, MS_TO_TICKS(xfer->timeout), + ohci_timeout, xfer); } #if 0 /* This goes wrong if we are too slow. */ - if (ohcidebug > 5) { - usb_delay_ms(&sc->sc_bus, 5); + if (ohcidebug > 10) { + delay(10000); DPRINTF(("ohci_device_intr_transfer: status=%x\n", OREAD4(sc, OHCI_COMMAND_STATUS))); ohci_dump_ed(sed); @@ -2524,7 +2997,7 @@ ohci_abort_xfer(xfer, USBD_CANCELLED); } -/* +/* * Close a device bulk pipe. */ Static void @@ -2565,13 +3038,16 @@ int len; int s; + if (sc->sc_dying) + return (USBD_IOERROR); + DPRINTFN(3, ("ohci_device_intr_transfer: xfer=%p len=%d " "flags=%d priv=%p\n", xfer, xfer->length, xfer->flags, xfer->priv)); #ifdef DIAGNOSTIC if (xfer->rqflags & URQ_REQUEST) - panic("ohci_device_intr_transfer: a request\n"); + panic("ohci_device_intr_transfer: a request"); #endif len = xfer->length; @@ -2582,15 +3058,15 @@ return (USBD_NOMEM); tail->xfer = NULL; - data->td.td_flags = LE( - OHCI_TD_IN | OHCI_TD_NOCC | + data->td.td_flags = htole32( + OHCI_TD_IN | OHCI_TD_NOCC | OHCI_TD_SET_DI(1) | OHCI_TD_TOGGLE_CARRY); if (xfer->flags & USBD_SHORT_XFER_OK) - data->td.td_flags |= LE(OHCI_TD_R); - data->td.td_cbp = LE(DMAADDR(&xfer->dmabuf, 0)); + data->td.td_flags |= htole32(OHCI_TD_R); + data->td.td_cbp = htole32(DMAADDR(&xfer->dmabuf, 0)); data->nexttd = tail; - data->td.td_nexttd = LE(tail->physaddr); - data->td.td_be = LE(LE(data->td.td_cbp) + len - 1); + data->td.td_nexttd = htole32(tail->physaddr); + data->td.td_be = htole32(le32toh(data->td.td_cbp) + len - 1); data->len = len; data->xfer = xfer; data->flags = OHCI_CALL_DONE | OHCI_ADD_LEN; @@ -2606,10 +3082,9 @@ /* Insert ED in schedule */ s = splusb(); - ohci_hash_add_td(sc, data); - sed->ed.ed_tailp = LE(tail->physaddr); + sed->ed.ed_tailp = htole32(tail->physaddr); opipe->tail.td = tail; - sed->ed.ed_flags &= LE(~OHCI_ED_SKIP); + sed->ed.ed_flags &= htole32(~OHCI_ED_SKIP); #if 0 /* @@ -2656,14 +3131,14 @@ 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 & LE(OHCI_HEADMASK))) + sed->ed.ed_flags |= htole32(OHCI_ED_SKIP); + if ((le32toh(sed->ed.ed_tailp) & OHCI_HEADMASK) != + (le32toh(sed->ed.ed_headp) & OHCI_HEADMASK)) usb_delay_ms(&sc->sc_bus, 2); #ifdef DIAGNOSTIC - if ((sed->ed.ed_tailp & LE(OHCI_TAILMASK)) - != (sed->ed.ed_headp & LE(OHCI_HEADMASK))) - panic("%s: Intr pipe %p still has TDs queued\n", + if ((le32toh(sed->ed.ed_tailp) & OHCI_HEADMASK) != + (le32toh(sed->ed.ed_headp) & OHCI_HEADMASK)) + panic("%s: Intr pipe %p still has TDs queued", USBDEVNAME(sc->sc_bus.bdev), pipe); #endif @@ -2671,7 +3146,7 @@ ; #ifdef DIAGNOSTIC if (p == NULL) - panic("ohci_device_intr_close: ED not found\n"); + panic("ohci_device_intr_close: ED not found"); #endif p->next = sed->next; p->ed.ed_nexted = sed->ed.ed_nexted; @@ -2726,7 +3201,7 @@ bestbw = bw; } } - DPRINTFN(2, ("ohci_setintr: best=%d(%d..%d) bestbw=%d\n", + DPRINTFN(2, ("ohci_setintr: best=%d(%d..%d) bestbw=%d\n", best, slow, shigh, bestbw)); s = splusb(); @@ -2734,7 +3209,7 @@ sed->next = hsed->next; sed->ed.ed_nexted = hsed->ed.ed_nexted; hsed->next = sed; - hsed->ed.ed_nexted = LE(sed->physaddr); + hsed->ed.ed_nexted = htole32(sed->physaddr); splx(s); for (j = 0; j < nslots; j++) @@ -2767,7 +3242,7 @@ /* insert into schedule, */ ohci_device_isoc_enter(xfer); - /* and put on interrupt list if the pipe wasn't running */ + /* and start if the pipe wasn't running */ if (!err) ohci_device_isoc_start(SIMPLEQ_FIRST(&xfer->pipe->queue)); @@ -2782,97 +3257,294 @@ ohci_softc_t *sc = (ohci_softc_t *)dev->bus; ohci_soft_ed_t *sed = opipe->sed; struct iso *iso = &opipe->u.iso; - ohci_soft_itd_t *sitd, *nsitd; - ohci_physaddr_t buf, offs; + struct ohci_xfer *oxfer = (struct ohci_xfer *)xfer; + ohci_soft_itd_t *sitd, *nsitd; + ohci_physaddr_t buf, offs, noffs, bp0, tdphys; int i, ncur, nframes; - int ncross = 0; int s; - s = splusb(); + DPRINTFN(1,("ohci_device_isoc_enter: used=%d next=%d xfer=%p " + "nframes=%d\n", + iso->inuse, iso->next, xfer, xfer->nframes)); + + if (sc->sc_dying) + return; + + if (iso->next == -1) { + /* Not in use yet, schedule it a few frames ahead. */ + iso->next = le32toh(sc->sc_hcca->hcca_frame_number) + 5; + DPRINTFN(2,("ohci_device_isoc_enter: start next=%d\n", + iso->next)); + } + + if (xfer->hcpriv) { + for (sitd = xfer->hcpriv; sitd != NULL && sitd->xfer == xfer; + sitd = sitd->nextitd) + ohci_free_sitd(sc, sitd); /* Free ITDs in prev xfer*/ + + if (sitd == NULL) { + sitd = ohci_alloc_sitd(sc); + if (sitd == NULL) + panic("cant alloc isoc"); + opipe->tail.itd = sitd; + tdphys = sitd->physaddr; + sed->ed.ed_flags |= htole32(OHCI_ED_SKIP); /* Stop*/ + sed->ed.ed_headp = + sed->ed.ed_tailp = htole32(tdphys); + sed->ed.ed_flags &= htole32(~OHCI_ED_SKIP); /* Start.*/ + } + } + sitd = opipe->tail.itd; buf = DMAADDR(&xfer->dmabuf, 0); - sitd->itd.itd_bp0 = LE(buf & OHCI_ITD_PAGE_MASK); + bp0 = OHCI_PAGE(buf); + offs = OHCI_PAGE_OFFSET(buf); nframes = xfer->nframes; - offs = buf & OHCI_ITD_OFFSET_MASK; + xfer->hcpriv = sitd; for (i = ncur = 0; i < nframes; i++, ncur++) { + noffs = offs + xfer->frlengths[i]; if (ncur == OHCI_ITD_NOFFSET || /* all offsets used */ - ncross > 1) { /* too many page crossings */ - + OHCI_PAGE(buf + noffs) > bp0 + OHCI_PAGE_SIZE) { /* too many page crossings */ + + /* Allocate next ITD */ nsitd = ohci_alloc_sitd(sc); if (nsitd == NULL) { /* XXX what now? */ - splx(s); + printf("%s: isoc TD alloc failed\n", + USBDEVNAME(sc->sc_bus.bdev)); return; } - sitd->nextitd = nsitd; - sitd->itd.itd_nextitd = LE(nsitd->physaddr); - sitd->itd.itd_flags = LE( - OHCI_ITD_NOCC | + + /* Fill current ITD */ + sitd->itd.itd_flags = htole32( + OHCI_ITD_NOCC | OHCI_ITD_SET_SF(iso->next) | - OHCI_ITD_NOINTR | - OHCI_ITD_SET_FC(OHCI_ITD_NOFFSET)); - sitd->itd.itd_be = LE(LE(sitd->itd.itd_bp0) + offs - 1); - nsitd->itd.itd_bp0 = LE((buf + offs) & OHCI_ITD_PAGE_MASK); + OHCI_ITD_SET_DI(6) | /* delay intr a little */ + OHCI_ITD_SET_FC(ncur)); + sitd->itd.itd_bp0 = htole32(bp0); + sitd->nextitd = nsitd; + sitd->itd.itd_nextitd = htole32(nsitd->physaddr); + sitd->itd.itd_be = htole32(bp0 + offs - 1); + sitd->xfer = xfer; + sitd->flags = OHCI_ITD_ACTIVE; + sitd = nsitd; - iso->next = iso->next + ncur; + iso->next = iso->next + ncur; + bp0 = OHCI_PAGE(buf + offs); ncur = 0; - ncross = 0; } - /* XXX byte order */ - sitd->itd.itd_offset[i] = - offs | (ncross == 1 ? OHCI_ITD_PAGE_SELECT : 0); - offs += xfer->frlengths[i]; - /* XXX update ncross */ + sitd->itd.itd_offset[ncur] = htole16(OHCI_ITD_MK_OFFS(offs)); + offs = noffs; } nsitd = ohci_alloc_sitd(sc); if (nsitd == NULL) { /* XXX what now? */ - splx(s); + printf("%s: isoc TD alloc failed\n", + USBDEVNAME(sc->sc_bus.bdev)); return; } - sitd->nextitd = nsitd; - sitd->itd.itd_nextitd = LE(nsitd->physaddr); - sitd->itd.itd_flags = LE( - OHCI_ITD_NOCC | + /* Fixup last used ITD */ + sitd->itd.itd_flags = htole32( + OHCI_ITD_NOCC | OHCI_ITD_SET_SF(iso->next) | OHCI_ITD_SET_DI(0) | OHCI_ITD_SET_FC(ncur)); - sitd->itd.itd_be = LE(LE(sitd->itd.itd_bp0) + offs - 1); + sitd->itd.itd_bp0 = htole32(bp0); + sitd->nextitd = nsitd; + sitd->itd.itd_nextitd = htole32(nsitd->physaddr); + sitd->itd.itd_be = htole32(bp0 + offs - 1); + sitd->xfer = xfer; + sitd->flags = OHCI_CALL_DONE | OHCI_ITD_ACTIVE; + iso->next = iso->next + ncur; + iso->inuse += nframes; + + xfer->actlen = offs; /* XXX pretend we did it all */ + + xfer->status = USBD_IN_PROGRESS; + + oxfer->ohci_xfer_flags |= OHCI_ISOC_DIRTY; +#ifdef USB_DEBUG + if (ohcidebug > 5) { + DPRINTF(("ohci_device_isoc_enter: frame=%d\n", + le32toh(sc->sc_hcca->hcca_frame_number))); + ohci_dump_itds(xfer->hcpriv); + ohci_dump_ed(sed); + } +#endif + + s = splusb(); opipe->tail.itd = nsitd; - sed->ed.ed_tailp = LE(nsitd->physaddr); - /* XXX update ED */ + sed->ed.ed_flags &= htole32(~OHCI_ED_SKIP); + sed->ed.ed_tailp = htole32(nsitd->physaddr); splx(s); + +#ifdef USB_DEBUG + if (ohcidebug > 5) { + delay(150000); + DPRINTF(("ohci_device_isoc_enter: after frame=%d\n", + le32toh(sc->sc_hcca->hcca_frame_number))); + ohci_dump_itds(xfer->hcpriv); + ohci_dump_ed(sed); + } +#endif } usbd_status ohci_device_isoc_start(usbd_xfer_handle xfer) { - printf("ohci_device_isoc_start: not implemented\n"); - return (USBD_INVAL); + struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe; + ohci_softc_t *sc = (ohci_softc_t *)opipe->pipe.device->bus; + ohci_soft_ed_t *sed; + int s; + + DPRINTFN(5,("ohci_device_isoc_start: xfer=%p\n", xfer)); + + if (sc->sc_dying) + return (USBD_IOERROR); + +#ifdef DIAGNOSTIC + if (xfer->status != USBD_IN_PROGRESS) + printf("ohci_device_isoc_start: not in progress %p\n", xfer); +#endif + + /* XXX anything to do? */ + + s = splusb(); + sed = opipe->sed; /* Turn off ED skip-bit to start processing */ + sed->ed.ed_flags &= htole32(~OHCI_ED_SKIP); /* ED's ITD list.*/ + splx(s); + + return (USBD_IN_PROGRESS); } void ohci_device_isoc_abort(usbd_xfer_handle xfer) { + struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe; + ohci_softc_t *sc = (ohci_softc_t *)opipe->pipe.device->bus; + ohci_soft_ed_t *sed; + ohci_soft_itd_t *sitd, *tmp_sitd; + int s,undone,num_sitds; + + s = splusb(); + opipe->aborting = 1; + + DPRINTFN(1,("ohci_device_isoc_abort: xfer=%p\n", xfer)); + + /* Transfer is already done. */ + if (xfer->status != USBD_NOT_STARTED && + xfer->status != USBD_IN_PROGRESS) { + splx(s); + printf("ohci_device_isoc_abort: early return\n"); + return; + } + + /* Give xfer the requested abort code. */ + xfer->status = USBD_CANCELLED; + + sed = opipe->sed; + sed->ed.ed_flags |= htole32(OHCI_ED_SKIP); /* force hardware skip */ + + num_sitds = 0; + sitd = xfer->hcpriv; +#ifdef DIAGNOSTIC + if (sitd == NULL) { + splx(s); + printf("ohci_device_isoc_abort: hcpriv==0\n"); + return; + } +#endif + for (; sitd != NULL && sitd->xfer == xfer; sitd = sitd->nextitd) { + num_sitds++; +#ifdef DIAGNOSTIC + DPRINTFN(1,("abort sets done sitd=%p\n", sitd)); + sitd->isdone = 1; +#endif + } + + splx(s); + + /* + * Each sitd has up to OHCI_ITD_NOFFSET transfers, each can + * take a usb 1ms cycle. Conservatively wait for it to drain. + * Even with DMA done, it can take awhile for the "batch" + * delivery of completion interrupts to occur thru the controller. + */ + + do { + usb_delay_ms(&sc->sc_bus, 2*(num_sitds*OHCI_ITD_NOFFSET)); + + undone = 0; + tmp_sitd = xfer->hcpriv; + for (; tmp_sitd != NULL && tmp_sitd->xfer == xfer; + tmp_sitd = tmp_sitd->nextitd) { + if (OHCI_CC_NO_ERROR == + OHCI_ITD_GET_CC(le32toh(tmp_sitd->itd.itd_flags)) && + tmp_sitd->flags & OHCI_ITD_ACTIVE && + (tmp_sitd->flags & OHCI_ITD_INTFIN) == 0) + undone++; + } + } while( undone != 0 ); + + + s = splusb(); + + /* Run callback. */ + usb_transfer_complete(xfer); + + if (sitd != NULL) + /* + * Only if there is a `next' sitd in next xfer... + * unlink this xfer's sitds. + */ + sed->ed.ed_headp = htole32(sitd->physaddr); + else + sed->ed.ed_headp = 0; + + sed->ed.ed_flags &= htole32(~OHCI_ED_SKIP); /* remove hardware skip */ + + splx(s); } void ohci_device_isoc_done(usbd_xfer_handle xfer) { - printf("ohci_device_isoc_done: not implemented\n"); + /* This null routine corresponds to non-isoc "done()" routines + * that free the stds associated with an xfer after a completed + * xfer interrupt. However, in the case of isoc transfers, the + * sitds associated with the transfer have already been processed + * and reallocated for the next iteration by + * "ohci_device_isoc_transfer()". + * + * Routine "usb_transfer_complete()" is called at the end of every + * relevant usb interrupt. "usb_transfer_complete()" indirectly + * calls 1) "ohci_device_isoc_transfer()" (which keeps pumping the + * pipeline by setting up the next transfer iteration) and 2) then + * calls "ohci_device_isoc_done()". Isoc transfers have not been + * working for the ohci usb because this routine was trashing the + * xfer set up for the next iteration (thus, only the first + * UGEN_NISOREQS xfers outstanding on an open would work). Perhaps + * this could all be re-factored, but that's another pass... + */ } usbd_status ohci_setup_isoc(usbd_pipe_handle pipe) { struct ohci_pipe *opipe = (struct ohci_pipe *)pipe; + ohci_softc_t *sc = (ohci_softc_t *)pipe->device->bus; struct iso *iso = &opipe->u.iso; + int s; iso->next = -1; iso->inuse = 0; + s = splusb(); + ohci_add_ed(opipe->sed, sc->sc_isoc_head); + splx(s); + return (USBD_NORMAL_COMPLETION); } @@ -2881,8 +3553,19 @@ { struct ohci_pipe *opipe = (struct ohci_pipe *)pipe; ohci_softc_t *sc = (ohci_softc_t *)pipe->device->bus; + ohci_soft_ed_t *sed; DPRINTF(("ohci_device_isoc_close: pipe=%p\n", pipe)); - ohci_close_pipe(pipe, sc->sc_isoc_head); - ohci_free_sitd(sc, opipe->tail.itd); + + sed = opipe->sed; + sed->ed.ed_flags |= htole32(OHCI_ED_SKIP); /* Stop device. */ + + ohci_close_pipe(pipe, sc->sc_isoc_head); /* Stop isoc list, free ED.*/ + + /* up to NISOREQs xfers still outstanding. */ + +#ifdef DIAGNOSTIC + opipe->tail.itd->isdone = 1; +#endif + ohci_free_sitd(sc, opipe->tail.itd); /* Next `avail free' sitd.*/ } Index: sys/dev/usb/ohcireg.h =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/ohcireg.h,v retrieving revision 1.13.2.1 diff -u -r1.13.2.1 ohcireg.h --- sys/dev/usb/ohcireg.h 2 Jul 2000 11:43:58 -0000 1.13.2.1 +++ sys/dev/usb/ohcireg.h 4 Oct 2003 18:54:40 -0000 @@ -1,5 +1,5 @@ -/* $NetBSD: ohcireg.h,v 1.11 2000/01/16 10:35:24 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/ohcireg.h,v 1.13.2.1 2000/07/02 11:43:58 n_hibma Exp $ */ +/* $NetBSD: ohcireg.h,v 1.17 2000/04/01 09:27:35 augustss Exp $ */ +/* $FreeBSD: src/sys/dev/usb/ohcireg.h,v 1.20 2003/07/15 23:12:54 jmg Exp $ */ /* @@ -110,6 +110,9 @@ #define OHCI_GET_NDP(s) ((s) & 0xff) #define OHCI_PSM 0x0100 /* Power Switching Mode */ #define OHCI_NPS 0x0200 /* No Power Switching */ +#define OHCI_DT 0x0400 /* Device Type */ +#define OHCI_OCPM 0x0800 /* Overcurrent Protection Mode */ +#define OHCI_NOCP 0x1000 /* No Overcurrent Protection */ #define OHCI_GET_POTPGT(s) ((s) >> 24) #define OHCI_RH_DESCRIPTOR_B 0x4c #define OHCI_RH_STATUS 0x50 @@ -143,6 +146,7 @@ #define OHCI_PAGE_SIZE 0x1000 #define OHCI_PAGE(x) ((x) &~ 0xfff) +#define OHCI_PAGE_OFFSET(x) ((x) & 0xfff) #define OHCI_PAGE_MASK(x) ((x) & 0xfff) typedef struct { @@ -164,7 +168,6 @@ #define OHCI_ED_SET_MAXP(s) ((s) << 16) #define OHCI_ED_MAXPMASK (0x7ff << 16) ohci_physaddr_t ed_tailp; -#define OHCI_TAILMASK 0xfffffffc ohci_physaddr_t ed_headp; #define OHCI_HALTED 0x00000001 #define OHCI_TOGGLECARRY 0x00000002 @@ -184,9 +187,11 @@ #define OHCI_TD_GET_DI(x) (((x) >> 21) & 7) /* Delay Interrupt */ #define OHCI_TD_SET_DI(x) ((x) << 21) #define OHCI_TD_NOINTR 0x00e00000 +#define OHCI_TD_INTR_MASK 0x00e00000 #define OHCI_TD_TOGGLE_CARRY 0x00000000 #define OHCI_TD_TOGGLE_0 0x02000000 #define OHCI_TD_TOGGLE_1 0x03000000 +#define OHCI_TD_TOGGLE_MASK 0x03000000 #define OHCI_TD_GET_EC(x) (((x) >> 26) & 3) /* Error Count */ #define OHCI_TD_GET_CC(x) ((x) >> 28) /* Condition Code */ #define OHCI_TD_NOCC 0xf0000000 @@ -210,19 +215,18 @@ #define OHCI_ITD_GET_CC(x) ((x) >> 28) /* Condition Code */ #define OHCI_ITD_NOCC 0xf0000000 ohci_physaddr_t itd_bp0; /* Buffer Page 0 */ -#define OHCI_ITD_OFFSET_MASK 0x00000fff -#define OHCI_ITD_PAGE_MASK (~OHCI_ITD_OFFSET_MASK) ohci_physaddr_t itd_nextitd; /* Next ITD */ ohci_physaddr_t itd_be; /* Buffer End */ u_int16_t itd_offset[OHCI_ITD_NOFFSET]; /* Buffer offsets */ #define itd_pswn itd_offset /* Packet Status Word*/ #define OHCI_ITD_PAGE_SELECT 0x00001000 +#define OHCI_ITD_MK_OFFS(len) (0xe000 | ((len) & 0x1fff)) #define OHCI_ITD_PSW_LENGTH(x) ((x) & 0xfff) /* Transfer length */ #define OHCI_ITD_PSW_GET_CC(x) ((x) >> 12) /* Condition Code */ } ohci_itd_t; /* #define OHCI_ITD_SIZE 32 */ #define OHCI_ITD_ALIGN 32 - + #define OHCI_CC_NO_ERROR 0 #define OHCI_CC_CRC 1 @@ -237,5 +241,9 @@ #define OHCI_CC_BUFFER_OVERRUN 12 #define OHCI_CC_BUFFER_UNDERRUN 13 #define OHCI_CC_NOT_ACCESSED 15 + +/* Some delay needed when changing certain registers. */ +#define OHCI_ENABLE_POWER_DELAY 5 +#define OHCI_READ_DESC_DELAY 5 #endif /* _DEV_PCI_OHCIREG_H_ */ Index: sys/dev/usb/ohcivar.h =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/ohcivar.h,v retrieving revision 1.15.2.4 diff -u -r1.15.2.4 ohcivar.h --- sys/dev/usb/ohcivar.h 31 Oct 2000 23:23:29 -0000 1.15.2.4 +++ sys/dev/usb/ohcivar.h 4 Oct 2003 18:54:40 -0000 @@ -1,5 +1,5 @@ -/* $NetBSD: ohcivar.h,v 1.18 2000/01/18 20:11:00 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/ohcivar.h,v 1.15.2.4 2000/10/31 23:23:29 n_hibma Exp $ */ +/* $NetBSD: ohcivar.h,v 1.30 2001/12/31 12:20:35 augustss Exp $ */ +/* $FreeBSD: src/sys/dev/usb/ohcivar.h,v 1.35 2003/07/15 23:19:49 jmg Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -44,7 +44,7 @@ ohci_physaddr_t physaddr; } ohci_soft_ed_t; #define OHCI_SED_SIZE ((sizeof (struct ohci_soft_ed) + OHCI_ED_ALIGN - 1) / OHCI_ED_ALIGN * OHCI_ED_ALIGN) -#define OHCI_SED_CHUNK 128 +#define OHCI_SED_CHUNK (PAGE_SIZE / OHCI_SED_SIZE) typedef struct ohci_soft_td { ohci_td_t td; @@ -60,15 +60,24 @@ #define OHCI_TD_HANDLED 0x0004 /* signal process_done has seen it */ } ohci_soft_td_t; #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_STD_CHUNK (PAGE_SIZE / OHCI_STD_SIZE) typedef struct ohci_soft_itd { ohci_itd_t itd; struct ohci_soft_itd *nextitd; /* mirrors nexttd in ITD */ + struct ohci_soft_itd *dnext; /* next in done list */ ohci_physaddr_t physaddr; + LIST_ENTRY(ohci_soft_itd) hnext; + usbd_xfer_handle xfer; + u_int16_t flags; +#define OHCI_ITD_ACTIVE 0x0010 /* Hardware op in progress */ +#define OHCI_ITD_INTFIN 0x0020 /* Hw completion interrupt seen.*/ +#ifdef DIAGNOSTIC + char isdone; +#endif } ohci_soft_itd_t; #define OHCI_SITD_SIZE ((sizeof (struct ohci_soft_itd) + OHCI_ITD_ALIGN - 1) / OHCI_ITD_ALIGN * OHCI_ITD_ALIGN) -#define OHCI_SITD_CHUNK 64 +#define OHCI_SITD_CHUNK (PAGE_SIZE / OHCI_SITD_SIZE) #define OHCI_NO_EDS (2*OHCI_NO_INTRS-1) @@ -78,6 +87,7 @@ struct usbd_bus sc_bus; /* base device */ bus_space_tag_t iot; bus_space_handle_t ioh; + bus_size_t sc_size; #if defined(__FreeBSD__) void *ih; @@ -97,12 +107,17 @@ ohci_soft_ed_t *sc_ctrl_head; ohci_soft_ed_t *sc_bulk_head; - LIST_HEAD(, ohci_soft_td) sc_hash_tds[OHCI_HASH_SIZE]; + LIST_HEAD(, ohci_soft_td) sc_hash_tds[OHCI_HASH_SIZE]; + LIST_HEAD(, ohci_soft_itd) sc_hash_itds[OHCI_HASH_SIZE]; int sc_noport; u_int8_t sc_addr; /* device address */ u_int8_t sc_conf; /* device configuration */ +#ifdef USB_USE_SOFTINTR + char sc_softwake; +#endif /* USB_USE_SOFTINTR */ + ohci_soft_ed_t *sc_freeeds; ohci_soft_td_t *sc_freetds; ohci_soft_itd_t *sc_freeitds; @@ -111,16 +126,36 @@ usbd_xfer_handle sc_intrxfer; + ohci_soft_itd_t *sc_sidone; + ohci_soft_td_t *sc_sdone; + char sc_vendor[16]; int sc_id_vendor; -#if defined(__NetBSD__) - void *sc_powerhook; +#if defined(__NetBSD__) || defined(__OpenBSD__) + void *sc_powerhook; /* cookie from power hook */ void *sc_shutdownhook; /* cookie from shutdown hook */ #endif + u_int32_t sc_control; /* Preserved during suspend/standby */ + u_int32_t sc_intre; + + u_int sc_overrun_cnt; + struct timeval sc_overrun_ntc; + + usb_callout_t sc_tmo_rhsc; device_ptr_t sc_child; + char sc_dying; } ohci_softc_t; + +struct ohci_xfer { + struct usbd_xfer xfer; + struct usb_task abort_task; + u_int32_t ohci_xfer_flags; +}; +#define OHCI_ISOC_DIRTY 0x01 + +#define OXFER(xfer) ((struct ohci_xfer *)(xfer)) usbd_status ohci_init(ohci_softc_t *); int ohci_intr(void *); Index: sys/dev/usb/rio500_usb.h =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/rio500_usb.h,v retrieving revision 1.1.2.1 diff -u -r1.1.2.1 rio500_usb.h --- sys/dev/usb/rio500_usb.h 27 Sep 2001 17:43:05 -0000 1.1.2.1 +++ sys/dev/usb/rio500_usb.h 4 Oct 2003 18:54:40 -0000 @@ -19,7 +19,7 @@ ---------------------------------------------------------------------- */ -/* $FreeBSD: src/sys/dev/usb/rio500_usb.h,v 1.1.2.1 2001/09/27 17:43:05 alfred Exp $ */ +/* $FreeBSD: src/sys/dev/usb/rio500_usb.h,v 1.1 2000/04/08 17:02:13 n_hibma Exp $ */ #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) #include Index: sys/dev/usb/ubsa.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/ubsa.c,v retrieving revision 1.2.2.1 diff -u -r1.2.2.1 ubsa.c --- sys/dev/usb/ubsa.c 11 Dec 2002 20:54:47 -0000 1.2.2.1 +++ sys/dev/usb/ubsa.c 4 Oct 2003 21:27:27 -0000 @@ -23,6 +23,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ + +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/ubsa.c,v 1.9 2003/10/04 21:41:01 joe Exp $"); /* * Copyright (c) 2001 The NetBSD Foundation, Inc. * All rights reserved. @@ -60,7 +63,7 @@ */ #include -__FBSDID("$FreeBSD: src/sys/dev/usb/ubsa.c,v 1.2.2.1 2002/12/11 20:54:47 kan Exp $"); +__FBSDID("$FreeBSD: src/sys/dev/usb/ubsa.c,v 1.9 2003/10/04 21:41:01 joe Exp $"); #include #include @@ -69,6 +72,7 @@ #include #include #include +#include #include #include #include @@ -92,7 +96,7 @@ #include -#ifdef UBSA_DEBUG +#ifdef USB_DEBUG Static int ubsadebug = 0; SYSCTL_NODE(_hw_usb, OID_AUTO, ubsa, CTLFLAG_RW, 0, "USB ubsa"); SYSCTL_INT(_hw_usb_ubsa, OID_AUTO, debug, CTLFLAG_RW, @@ -177,9 +181,13 @@ u_char sc_lsr; /* Local status register */ u_char sc_msr; /* ubsa status register */ +#if __FreeBSD_version >= 500000 + void *sc_swicookie; +#endif }; Static void ubsa_intr(usbd_xfer_handle, usbd_private_handle, usbd_status); +Static void ubsa_notify(void *); Static void ubsa_get_status(void *, int, u_char *, u_char *); Static void ubsa_set(void *, int, int, int); @@ -247,6 +255,10 @@ MODULE_DEPEND(ubsa, ucom, UCOM_MINVER, UCOM_PREFVER, UCOM_MAXVER); MODULE_VERSION(ubsa, UBSA_MODVER); +#if __FreeBSD_version >= 500000 +static struct ithd *ucom_ithd; +#endif + USB_MATCH(ubsa) { USB_MATCH_START(ubsa, uaa); @@ -401,6 +413,11 @@ DPRINTF(("ubsa: in = 0x%x, out = 0x%x, intr = 0x%x\n", ucom->sc_bulkin_no, ucom->sc_bulkout_no, sc->sc_intr_number)); +#if __FreeBSD_version >= 500000 + swi_add(&ucom_ithd, "ucom", ubsa_notify, sc, SWI_TTY, 0, + &sc->sc_swicookie); +#endif + ucom_attach(ucom); free(devinfo, M_USBDEV); @@ -430,6 +447,10 @@ rv = ucom_detach(&sc->sc_ucom); +#if __FreeBSD_version >= 500000 + ithread_remove_handler(sc->sc_swicookie); +#endif + return (rv); } @@ -617,9 +638,10 @@ { struct ubsa_softc *sc; + sc = addr; + DPRINTF(("ubsa_param: sc = %p\n", sc)); - sc = addr; ubsa_baudrate(sc, ti->c_ospeed); ubsa_parity(sc, ti->c_cflag); ubsa_databits(sc, ti->c_cflag); @@ -720,6 +742,20 @@ DPRINTF(("%s: ubsa lsr = 0x%02x, msr = 0x%02x\n", USBDEVNAME(sc->sc_ucom.sc_dev), sc->sc_lsr, sc->sc_msr)); +#if __FreeBSD_version >= 500000 + swi_sched(sc->sc_swicookie, 0); +#else + ubsa_notify(sc); +#endif +} + +/* Handle delayed events. */ +Static void +ubsa_notify(void *arg) +{ + struct ubsa_softc *sc; + + sc = arg; ucom_status_change(&sc->sc_ucom); } Index: sys/dev/usb/ucom.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/ucom.c,v retrieving revision 1.24.2.4 diff -u -r1.24.2.4 ucom.c --- sys/dev/usb/ucom.c 21 Jul 2003 13:10:57 -0000 1.24.2.4 +++ sys/dev/usb/ucom.c 4 Oct 2003 21:27:27 -0000 @@ -1,5 +1,4 @@ -/* $NetBSD: ucom.c,v 1.39 2001/08/16 22:31:24 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/ucom.c,v 1.24.2.4 2003/07/21 13:10:57 akiyama Exp $ */ +/* $NetBSD: ucom.c,v 1.40 2001/11/13 06:24:54 lukem Exp $ */ /*- * Copyright (c) 2001-2002, Shunsuke Akiyama . @@ -27,6 +26,9 @@ * SUCH DAMAGE. */ +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/ucom.c,v 1.33 2003/08/25 22:01:05 joe Exp $"); + /* * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc. * All rights reserved. @@ -128,23 +130,19 @@ #define UCOM_CDEV_MAJOR 138 static struct cdevsw ucom_cdevsw = { - /* open */ ucomopen, - /* close */ ucomclose, - /* read */ ucomread, - /* write */ ucomwrite, - /* ioctl */ ucomioctl, - /* poll */ ttypoll, - /* mmap */ nommap, - /* strategy */ nostrategy, - /* name */ "ucom", - /* maj */ UCOM_CDEV_MAJOR, - /* dump */ nodump, - /* psize */ nopsize, - /* flags */ D_TTY | D_KQFILTER, + .d_open = ucomopen, + .d_close = ucomclose, + .d_read = ucomread, + .d_write = ucomwrite, + .d_ioctl = ucomioctl, + .d_poll = ttypoll, + .d_name = "ucom", + .d_maj = UCOM_CDEV_MAJOR, + .d_flags = D_TTY, #if __FreeBSD_version < 500014 - /* bmaj */ -1, + .d_bmaj = -1, #endif - /* kqfilter */ ttykqfilter, + .d_kqfilter = ttykqfilter, }; Static void ucom_cleanup(struct ucom_softc *); @@ -344,7 +342,7 @@ &sc->sc_bulkin_pipe); if (err) { printf("%s: open bulk in error (addr %d): %s\n", - USBDEVNAME(sc->sc_dev), sc->sc_bulkin_no, + USBDEVNAME(sc->sc_dev), sc->sc_bulkin_no, usbd_errstr(err)); error = EIO; goto fail_0; @@ -726,7 +724,7 @@ if (sc->sc_callback->ucom_set == NULL) return; - sc->sc_callback->ucom_set(sc->sc_parent, sc->sc_portno, + sc->sc_callback->ucom_set(sc->sc_parent, sc->sc_portno, UCOM_SET_DTR, onoff); } @@ -737,7 +735,7 @@ if (sc->sc_callback->ucom_set == NULL) return; - sc->sc_callback->ucom_set(sc->sc_parent, sc->sc_portno, + sc->sc_callback->ucom_set(sc->sc_parent, sc->sc_portno, UCOM_SET_RTS, onoff); } @@ -911,7 +909,7 @@ memcpy(sc->sc_obuf, data, cnt); DPRINTF(("ucomstart: %d chars\n", cnt)); - usbd_setup_xfer(sc->sc_oxfer, sc->sc_bulkout_pipe, + usbd_setup_xfer(sc->sc_oxfer, sc->sc_bulkout_pipe, (usbd_private_handle)sc, sc->sc_obuf, cnt, USBD_NO_COPY, USBD_NO_TIMEOUT, ucomwritecb); /* What can we do on error? */ @@ -1017,8 +1015,8 @@ if (sc->sc_bulkin_pipe == NULL) return (USBD_NORMAL_COMPLETION); - usbd_setup_xfer(sc->sc_ixfer, sc->sc_bulkin_pipe, - (usbd_private_handle)sc, + usbd_setup_xfer(sc->sc_ixfer, sc->sc_bulkin_pipe, + (usbd_private_handle)sc, sc->sc_ibuf, sc->sc_ibufsize, USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT, ucomreadcb); Index: sys/dev/usb/ucomvar.h =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/ucomvar.h,v retrieving revision 1.2.2.1 diff -u -r1.2.2.1 ucomvar.h --- sys/dev/usb/ucomvar.h 8 Aug 2002 18:45:04 -0000 1.2.2.1 +++ sys/dev/usb/ucomvar.h 4 Oct 2003 18:54:40 -0000 @@ -1,5 +1,5 @@ /* $NetBSD: ucomvar.h,v 1.9 2001/01/23 21:56:17 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/ucomvar.h,v 1.2.2.1 2002/08/08 18:45:04 joe Exp $ */ +/* $FreeBSD: src/sys/dev/usb/ucomvar.h,v 1.2 2002/07/31 14:34:35 joe Exp $ */ /*- * Copyright (c) 2001-2002, Shunsuke Akiyama . Index: sys/dev/usb/ufm.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/ufm.c,v retrieving revision 1.1.2.3 diff -u -r1.1.2.3 ufm.c --- sys/dev/usb/ufm.c 6 Nov 2002 14:41:01 -0000 1.1.2.3 +++ sys/dev/usb/ufm.c 4 Oct 2003 21:27:27 -0000 @@ -28,7 +28,9 @@ * its contributors. */ -/* $FreeBSD: src/sys/dev/usb/ufm.c,v 1.1.2.3 2002/11/06 14:41:01 joe Exp $ */ +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/ufm.c,v 1.16 2003/10/04 21:41:01 joe Exp $"); + #include #include @@ -87,15 +89,20 @@ d_close_t ufmclose; d_ioctl_t ufmioctl; +#if __FreeBSD_version >= 500000 +#define UFM_CDEV_MAJOR MAJOR_AUTO +#else #define UFM_CDEV_MAJOR 200 +#endif Static struct cdevsw ufm_cdevsw = { - ufmopen, ufmclose, noread, nowrite, - ufmioctl, nopoll, nommap, nostrategy, - "ufm", UFM_CDEV_MAJOR, nodump, nopsize, - 0, -#if (__FreeBSD__ < 5) - -1 + .d_open = ufmopen, + .d_close = ufmclose, + .d_ioctl = ufmioctl, + .d_name = "ufm", + .d_maj = UFM_CDEV_MAJOR, +#if (__FreeBSD_version < 500014) + .d_bmaj = -1 #endif }; #endif /*defined(__FreeBSD__)*/ @@ -156,7 +163,7 @@ usbd_status r; char * ermsg = ""; - DPRINTFN(10,("ufm_attach: sc=%p\n", sc)); + DPRINTFN(10,("ufm_attach: sc=%p\n", sc)); usbd_devinfo(uaa->device, 0, devinfo); USB_ATTACH_SETUP; printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo); @@ -177,12 +184,12 @@ r = usbd_interface_count(udev, &niface); if (r) { ermsg = "iface"; - goto nobulk; + goto nobulk; } r = usbd_device2interface_handle(udev, 0, &iface); if (r) { ermsg = "iface"; - goto nobulk; + goto nobulk; } sc->sc_iface = iface; #endif @@ -190,7 +197,7 @@ sc->sc_refcnt = 0; r = usbd_endpoint_count(iface, &epcount); - if (r != USBD_NORMAL_COMPLETION) { + if (r != USBD_NORMAL_COMPLETION) { ermsg = "endpoints"; goto nobulk; } @@ -230,7 +237,7 @@ int unit = UFMUNIT(dev); USB_GET_SC_OPEN(ufm, unit, sc); - DPRINTFN(5, ("ufmopen: flag=%d, mode=%d, unit=%d\n", + DPRINTFN(5, ("ufmopen: flag=%d, mode=%d, unit=%d\n", flag, mode, unit)); if (sc->sc_opened) @@ -254,7 +261,7 @@ DPRINTFN(5, ("ufmclose: flag=%d, mode=%d, unit=%d\n", flag, mode, unit)); sc->sc_opened = 0; sc->sc_refcnt = 0; - return 0; + return 0; } static int @@ -271,7 +278,8 @@ USETW(req.wValue, value); USETW(req.wIndex, index); USETW(req.wLength, len); - err = usbd_do_request_flags(sc->sc_udev, &req, retbuf, 0, NULL); + err = usbd_do_request_flags(sc->sc_udev, &req, retbuf, 0, NULL, + USBD_DEFAULT_TIMEOUT); splx(s); if (err) { printf("usbd_do_request_flags returned %#x\n", err); @@ -291,7 +299,7 @@ * that the radio wants. This frequency is 10.7MHz above * the actual frequency. We then need to convert to * units of 12.5kHz. We add one to the IFM to make rounding - * easier. + * easier. */ sc->sc_freq = freq; freq = (freq + 10700001) / 12500; @@ -300,7 +308,7 @@ freq, 1, &ret) != 0) return (EIO); /* Not sure what this does */ - if (ufm_do_req(sc, UT_READ_VENDOR_DEVICE, FM_CMD0, 0x96, 0xb7, 1, + if (ufm_do_req(sc, UT_READ_VENDOR_DEVICE, FM_CMD0, 0x96, 0xb7, 1, &ret) != 0) return (EIO); return (0); @@ -318,8 +326,8 @@ ufm_start(struct ufm_softc *sc, caddr_t addr) { u_int8_t ret; - - if (ufm_do_req(sc, UT_READ_VENDOR_DEVICE, FM_CMD0, 0x00, 0xc7, + + if (ufm_do_req(sc, UT_READ_VENDOR_DEVICE, FM_CMD0, 0x00, 0xc7, 1, &ret)) return (EIO); if (ufm_do_req(sc, UT_READ_VENDOR_DEVICE, FM_CMD2, 0x01, 0x00, @@ -334,7 +342,7 @@ ufm_stop(struct ufm_softc *sc, caddr_t addr) { u_int8_t ret; - + if (ufm_do_req(sc, UT_READ_VENDOR_DEVICE, FM_CMD0, 0x16, 0x1C, 1, &ret)) return (EIO); @@ -348,7 +356,7 @@ ufm_get_stat(struct ufm_softc *sc, caddr_t addr) { u_int8_t ret; - + /* * Note, there's a 240ms settle time before the status * will be valid, so tsleep that amount. hz/4 is a good @@ -361,7 +369,7 @@ 1, &ret)) return (EIO); *(int *)addr = ret; - + return (0); } @@ -463,7 +471,7 @@ #if defined(__FreeBSD__) Static int ufm_detach(device_t self) -{ +{ DPRINTF(("%s: disconnected\n", USBDEVNAME(self))); return 0; } Index: sys/dev/usb/uftdi.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/uftdi.c,v retrieving revision 1.3.2.3 diff -u -r1.3.2.3 uftdi.c --- sys/dev/usb/uftdi.c 21 Jul 2003 11:50:06 -0000 1.3.2.3 +++ sys/dev/usb/uftdi.c 4 Oct 2003 18:54:40 -0000 @@ -1,5 +1,4 @@ -/* $NetBSD: uftdi.c,v 1.12 2002/07/18 14:44:10 scw Exp $ */ -/* $FreeBSD: src/sys/dev/usb/uftdi.c,v 1.3.2.3 2003/07/21 11:50:06 akiyama Exp $ */ +/* $NetBSD: uftdi.c,v 1.13 2002/09/23 05:51:23 simonb Exp $ */ /* * Copyright (c) 2000 The NetBSD Foundation, Inc. @@ -37,6 +36,9 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/uftdi.c,v 1.10 2003/08/24 17:55:55 obrien Exp $"); + /* * FTDI FT8U100AX serial adapter driver */ @@ -106,7 +108,7 @@ struct uftdi_softc { struct ucom_softc sc_ucom; - + usbd_interface_handle sc_iface; /* interface */ enum uftdi_type sc_type; @@ -210,9 +212,9 @@ default: /* Can't happen */ goto bad; } - + ucom->sc_bulkin_no = ucom->sc_bulkout_no = -1; - + for (i = 0; i < id->bNumEndpoints; i++) { int addr, dir, attr; ed = usbd_interface2endpoint_descriptor(iface, i); @@ -221,7 +223,7 @@ ": %s\n", devname, usbd_errstr(err)); goto bad; } - + addr = ed->bEndpointAddress; dir = UE_GET_DIR(ed->bEndpointAddress); attr = ed->bmAttributes & UE_XFERTYPE; @@ -262,7 +264,7 @@ DPRINTF(("uftdi: in=0x%x out=0x%x\n", ucom->sc_bulkin_no, ucom->sc_bulkout_no)); ucom_attach(&sc->sc_ucom); free(devinfo, M_USBDEV); - + USB_ATTACH_SUCCESS_RETURN; bad: @@ -282,7 +284,6 @@ switch (act) { case DVACT_ACTIVATE: return (EOPNOTSUPP); - break; case DVACT_DEACTIVATE: if (sc->sc_subdev != NULL) @@ -297,7 +298,7 @@ USB_DETACH(uftdi) { USB_DETACH_START(uftdi, sc); - + int rv = 0; DPRINTF(("uftdi_detach: sc=%p\n", sc)); Index: sys/dev/usb/uftdireg.h =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/uftdireg.h,v retrieving revision 1.1.2.1 diff -u -r1.1.2.1 uftdireg.h --- sys/dev/usb/uftdireg.h 21 Nov 2002 01:28:17 -0000 1.1.2.1 +++ sys/dev/usb/uftdireg.h 4 Oct 2003 18:54:40 -0000 @@ -1,5 +1,5 @@ /* $NetBSD: uftdireg.h,v 1.6 2002/07/11 21:14:28 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/uftdireg.h,v 1.1.2.1 2002/11/21 01:28:17 ticso Exp $ */ +/* $FreeBSD: src/sys/dev/usb/uftdireg.h,v 1.1 2002/08/11 23:32:33 joe Exp $ */ /* * Definitions for the FTDI USB Single Port Serial Converter - Index: sys/dev/usb/ugen.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/ugen.c,v retrieving revision 1.38.2.9 diff -u -r1.38.2.9 ugen.c --- sys/dev/usb/ugen.c 6 Nov 2002 14:41:01 -0000 1.38.2.9 +++ sys/dev/usb/ugen.c 4 Oct 2003 21:27:27 -0000 @@ -1,5 +1,13 @@ -/* $NetBSD: ugen.c,v 1.27 1999/10/28 12:08:38 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/ugen.c,v 1.38.2.9 2002/11/06 14:41:01 joe Exp $ */ +/* $NetBSD: ugen.c,v 1.59 2002/07/11 21:14:28 augustss Exp $ */ + +/* Also already merged from NetBSD: + * $NetBSD: ugen.c,v 1.61 2002/09/23 05:51:20 simonb Exp $ + * $NetBSD: ugen.c,v 1.64 2003/06/28 14:21:46 darrenr Exp $ + * $NetBSD: ugen.c,v 1.65 2003/06/29 22:30:56 fvdl Exp $ + */ + +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/ugen.c,v 1.79 2003/10/01 14:49:53 ticso Exp $"); /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -56,8 +64,11 @@ #endif #include #include +#if __FreeBSD_version >= 500014 +#include +#else #include -#include +#endif #include #include #include @@ -135,34 +146,35 @@ #define UGEN_CDEV_MAJOR 114 Static struct cdevsw ugen_cdevsw = { - /* open */ ugenopen, - /* close */ ugenclose, - /* read */ ugenread, - /* write */ ugenwrite, - /* ioctl */ ugenioctl, - /* poll */ ugenpoll, - /* mmap */ nommap, - /* strategy */ nostrategy, - /* name */ "ugen", - /* maj */ UGEN_CDEV_MAJOR, - /* dump */ nodump, - /* psize */ nopsize, - /* flags */ 0, - /* bmaj */ -1 + .d_open = ugenopen, + .d_close = ugenclose, + .d_read = ugenread, + .d_write = ugenwrite, + .d_ioctl = ugenioctl, + .d_poll = ugenpoll, + .d_name = "ugen", + .d_maj = UGEN_CDEV_MAJOR, +#if __FreeBSD_version < 500014 + .d_bmaj -1 +#endif }; #endif -Static void ugenintr(usbd_xfer_handle xfer, usbd_private_handle addr, - usbd_status status); +Static void ugenintr(usbd_xfer_handle xfer, usbd_private_handle addr, + usbd_status status); Static void ugen_isoc_rintr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status); Static int ugen_do_read(struct ugen_softc *, int, struct uio *, int); Static int ugen_do_write(struct ugen_softc *, int, struct uio *, int); -Static int ugen_do_ioctl(struct ugen_softc *, int, u_long, - caddr_t, int, usb_proc_ptr); +Static int ugen_do_ioctl(struct ugen_softc *, int, u_long, + caddr_t, int, usb_proc_ptr); +#if defined(__FreeBSD__) +Static void ugen_make_devnodes(struct ugen_softc *sc); +Static void ugen_destroy_devnodes(struct ugen_softc *sc); +#endif Static int ugen_set_config(struct ugen_softc *sc, int configno); Static usb_config_descriptor_t *ugen_get_cdesc(struct ugen_softc *sc, - int index, int *lenp); + int index, int *lenp); Static usbd_status ugen_set_interface(struct ugen_softc *, int, int); Static int ugen_get_alt_index(struct ugen_softc *sc, int ifaceidx); @@ -176,6 +188,10 @@ { USB_MATCH_START(ugen, uaa); +#if 0 + if (uaa->matchlvl) + return (uaa->matchlvl); +#endif if (uaa->usegeneric) return (UMATCH_GENERIC); else @@ -189,7 +205,7 @@ char devinfo[1024]; usbd_status err; int conf; - + usbd_devinfo(uaa->device, 0, devinfo); USB_ATTACH_SETUP; printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo); @@ -201,7 +217,7 @@ /* First set configuration index 0, the default one for ugen. */ err = usbd_set_config_index(udev, 0, 0); if (err) { - printf("%s: setting configuration index 0 failed\n", + printf("%s: setting configuration index 0 failed\n", USBDEVNAME(sc->sc_dev)); sc->sc_dying = 1; USB_ATTACH_ERROR_RETURN; @@ -211,15 +227,78 @@ /* Set up all the local state for this configuration. */ err = ugen_set_config(sc, conf); if (err) { - printf("%s: setting configuration %d failed\n", + printf("%s: setting configuration %d failed\n", USBDEVNAME(sc->sc_dev), conf); sc->sc_dying = 1; USB_ATTACH_ERROR_RETURN; } +#if defined(__FreeBSD__) + /* the main device, ctrl endpoint */ + make_dev(&ugen_cdevsw, UGENMINOR(USBDEVUNIT(sc->sc_dev), 0), + UID_ROOT, GID_OPERATOR, 0644, "%s", USBDEVNAME(sc->sc_dev)); +#endif + USB_ATTACH_SUCCESS_RETURN; } +#if defined(__FreeBSD__) +Static void +ugen_make_devnodes(struct ugen_softc *sc) +{ + int endptno; + + for (endptno = 1; endptno < USB_MAX_ENDPOINTS; endptno++) { + if (sc->sc_endpoints[endptno][IN].sc != NULL || + sc->sc_endpoints[endptno][OUT].sc != NULL ) { + /* endpt can be 0x81 and 0x01, representing + * endpoint address 0x01 and IN/OUT directions. + * We map both endpts to the same device, + * IN is reading from it, OUT is writing to it. + * + * In the if clause above we check whether one + * of the structs is populated. + */ + make_dev(&ugen_cdevsw, + UGENMINOR(USBDEVUNIT(sc->sc_dev), endptno), + UID_ROOT, GID_OPERATOR, 0644, + "%s.%d", + USBDEVNAME(sc->sc_dev), endptno); + } + } +} + +Static void +ugen_destroy_devnodes(struct ugen_softc *sc) +{ + int endptno; + dev_t dev; + struct vnode *vp; + + /* destroy all devices for the other (existing) endpoints as well */ + for (endptno = 1; endptno < USB_MAX_ENDPOINTS; endptno++) { + if (sc->sc_endpoints[endptno][IN].sc != NULL || + sc->sc_endpoints[endptno][OUT].sc != NULL ) { + /* endpt can be 0x81 and 0x01, representing + * endpoint address 0x01 and IN/OUT directions. + * We map both endpoint addresses to the same device, + * IN is reading from it, OUT is writing to it. + * + * In the if clause above we check whether one + * of the structs is populated. + */ + dev = makedev(UGEN_CDEV_MAJOR, + UGENMINOR(USBDEVUNIT(sc->sc_dev), endptno)); + vp = SLIST_FIRST(&dev->si_hlist); + if (vp) + VOP_REVOKE(vp, REVOKEALL); + + destroy_dev(dev); + } + } +} +#endif + Static int ugen_set_config(struct ugen_softc *sc, int configno) { @@ -235,6 +314,10 @@ DPRINTFN(1,("ugen_set_config: %s to configno %d, sc=%p\n", USBDEVNAME(sc->sc_dev), configno, sc)); +#if defined(__FreeBSD__) + ugen_destroy_devnodes(sc); +#endif + /* We start at 1, not 0, because we don't care whether the * control endpoint is open or not. It is always present. */ @@ -246,9 +329,9 @@ return (USBD_IN_USE); } + /* Avoid setting the current value. */ if (usbd_get_config_descriptor(dev)->bConfigurationValue != configno) { - /* Avoid setting the current value. */ - err = usbd_set_config_no(dev, configno, 0); + err = usbd_set_config_no(dev, configno, 1); if (err) return (err); } @@ -267,45 +350,21 @@ return (err); for (endptno = 0; endptno < nendpt; endptno++) { ed = usbd_interface2endpoint_descriptor(iface,endptno); - endpt = UE_GET_ADDR(ed->bEndpointAddress); - dir = UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN? - IN : OUT; - - sce = &sc->sc_endpoints[endpt][dir]; + endpt = ed->bEndpointAddress; + 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, endpt, dir, sce)); - + "(%d,%d), sce=%p\n", + endptno, endpt, UE_GET_ADDR(endpt), + UE_GET_DIR(endpt), sce)); sce->sc = sc; sce->edesc = ed; sce->iface = iface; } } - #if defined(__FreeBSD__) - /* the main device, ctrl endpoint */ - make_dev(&ugen_cdevsw, UGENMINOR(USBDEVUNIT(sc->sc_dev), 0), - UID_ROOT, GID_OPERATOR, 0644, "%s", USBDEVNAME(sc->sc_dev)); - - for (endptno = 1; endptno < USB_MAX_ENDPOINTS; endptno++) { - if (sc->sc_endpoints[endptno][IN].sc != NULL || - sc->sc_endpoints[endptno][OUT].sc != NULL ) { - /* endpt can be 0x81 and 0x01, representing - * endpoint address 0x01 and IN/OUT directions. - * We map both endpts to the same device, - * IN is reading from it, OUT is writing to it. - * - * In the if clause above we check whether one - * of the structs is populated. - */ - make_dev(&ugen_cdevsw, - UGENMINOR(USBDEVUNIT(sc->sc_dev), endptno), - UID_ROOT, GID_OPERATOR, 0644, - "%s.%d", - USBDEVNAME(sc->sc_dev), endptno); - } - } + ugen_make_devnodes(sc); #endif return (USBD_NORMAL_COMPLETION); @@ -327,7 +386,7 @@ 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 == NULL || sc->sc_dying) @@ -358,22 +417,29 @@ 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", + DPRINTFN(5, ("ugenopen: sc=%p, endpt=%d, dir=%d, sce=%p\n", sc, endpt, dir, sce)); edesc = sce->edesc; switch (edesc->bmAttributes & UE_XFERTYPE) { case UE_INTERRUPT: + if (dir == OUT) { + err = usbd_open_pipe(sce->iface, + edesc->bEndpointAddress, 0, &sce->pipeh); + if (err) + return (EIO); + break; + } isize = UGETW(edesc->wMaxPacketSize); if (isize == 0) /* shouldn't happen */ return (EINVAL); sce->ibuf = malloc(isize, M_USBDEV, M_WAITOK); - DPRINTFN(5, ("ugenopen: intr endpt=%d,isize=%d\n", + DPRINTFN(5, ("ugenopen: intr endpt=%d,isize=%d\n", endpt, isize)); if (clalloc(&sce->q, UGEN_IBSIZE, 0) == -1) return (ENOMEM); - err = usbd_open_pipe_intr(sce->iface, - edesc->bEndpointAddress, - USBD_SHORT_XFER_OK, &sce->pipeh, sce, + err = usbd_open_pipe_intr(sce->iface, + edesc->bEndpointAddress, + USBD_SHORT_XFER_OK, &sce->pipeh, sce, sce->ibuf, isize, ugenintr, USBD_DEFAULT_INTERVAL); if (err) { @@ -384,7 +450,7 @@ DPRINTFN(5, ("ugenopen: interrupt open done\n")); break; case UE_BULK: - err = usbd_open_pipe(sce->iface, + err = usbd_open_pipe(sce->iface, edesc->bEndpointAddress, 0, &sce->pipeh); if (err) return (EIO); @@ -399,7 +465,7 @@ M_USBDEV, M_WAITOK); sce->cur = sce->fill = sce->ibuf; sce->limit = sce->ibuf + isize * UGEN_NISOFRAMES; - DPRINTFN(5, ("ugenopen: isoc endpt=%d, isize=%d\n", + DPRINTFN(5, ("ugenopen: isoc endpt=%d, isize=%d\n", endpt, isize)); err = usbd_open_pipe(sce->iface, edesc->bEndpointAddress, 0, &sce->pipeh); @@ -436,6 +502,7 @@ usbd_free_xfer(sce->isoreqs[i].xfer); return (ENOMEM); case UE_CONTROL: + sce->timeout = USBD_DEFAULT_TIMEOUT; return (EINVAL); } } @@ -476,7 +543,7 @@ sce = &sc->sc_endpoints[endpt][dir]; if (sce == NULL || sce->pipeh == NULL) continue; - DPRINTFN(5, ("ugenclose: endpt=%d dir=%d sce=%p\n", + DPRINTFN(5, ("ugenclose: endpt=%d dir=%d sce=%p\n", endpt, dir, sce)); usbd_abort_pipe(sce->pipeh); @@ -498,6 +565,7 @@ if (sce->ibuf != NULL) { free(sce->ibuf, M_USBDEV); sce->ibuf = NULL; + clfree(&sce->q); } } sc->sc_is_open[endpt] = 0; @@ -525,7 +593,9 @@ if (endpt == USB_CONTROL_ENDPOINT) return (ENODEV); -#ifdef DIAGNOSTIC + if (sce == NULL) + return (EINVAL); + if (sce->edesc == NULL) { printf("ugenread: no edesc\n"); return (EIO); @@ -534,11 +604,10 @@ printf("ugenread: no pipe\n"); return (EIO); } -#endif switch (sce->edesc->bmAttributes & UE_XFERTYPE) { case UE_INTERRUPT: - /* Block until activity occured. */ + /* Block until activity occurred. */ s = splusb(); while (sce->q.c_cc == 0) { if (flag & IO_NDELAY) { @@ -546,7 +615,7 @@ return (EWOULDBLOCK); } sce->state |= UGEN_ASLP; - DPRINTFN(5, ("ugenread: sleep on %p\n", sc)); + DPRINTFN(5, ("ugenread: sleep on %p\n", sce)); error = tsleep(sce, PZERO | PCATCH, "ugenri", 0); DPRINTFN(5, ("ugenread: woke, error=%d\n", error)); if (sc->sc_dying) @@ -583,8 +652,8 @@ tn = n; err = usbd_bulk_transfer( xfer, sce->pipeh, - sce->state & UGEN_SHORT_OK ? - USBD_SHORT_XFER_OK : 0, + sce->state & UGEN_SHORT_OK ? + USBD_SHORT_XFER_OK : 0, sce->timeout, buf, &tn, "ugenrb"); if (err) { if (err == USBD_INTERRUPTED) @@ -610,7 +679,7 @@ return (EWOULDBLOCK); } sce->state |= UGEN_ASLP; - DPRINTFN(5, ("ugenread: sleep on %p\n", sc)); + DPRINTFN(5, ("ugenread: sleep on %p\n", sce)); error = tsleep(sce, PZERO | PCATCH, "ugenri", 0); DPRINTFN(5, ("ugenread: woke, error=%d\n", error)); if (sc->sc_dying) @@ -640,7 +709,7 @@ splx(s); break; - + default: return (ENXIO); } @@ -673,7 +742,7 @@ usbd_xfer_handle xfer; usbd_status err; - DPRINTFN(5, ("%s: ugen_do_write: %d\n", USBDEVNAME(sc->sc_dev), endpt)); + DPRINTFN(5, ("%s: ugenwrite: %d\n", USBDEVNAME(sc->sc_dev), endpt)); if (sc->sc_dying) return (EIO); @@ -681,16 +750,17 @@ if (endpt == USB_CONTROL_ENDPOINT) return (ENODEV); -#ifdef DIAGNOSTIC + if (sce == NULL) + return (EINVAL); + if (sce->edesc == NULL) { - printf("ugen_do_write: no edesc\n"); + printf("ugenwrite: no edesc\n"); return (EIO); } if (sce->pipeh == NULL) { - printf("ugen_do_write: no pipe\n"); + printf("ugenwrite: no pipe\n"); return (EIO); } -#endif switch (sce->edesc->bmAttributes & UE_XFERTYPE) { case UE_BULK: @@ -701,12 +771,38 @@ error = uiomove(buf, n, uio); if (error) break; - DPRINTFN(1, ("ugen_do_write: transfer %d bytes\n", n)); - err = usbd_bulk_transfer(xfer, sce->pipeh, 0, + DPRINTFN(1, ("ugenwrite: transfer %d bytes\n", n)); + err = usbd_bulk_transfer(xfer, sce->pipeh, 0, sce->timeout, buf, &n,"ugenwb"); if (err) { if (err == USBD_INTERRUPTED) error = EINTR; + else if (err == USBD_TIMEOUT) + error = ETIMEDOUT; + else + error = EIO; + break; + } + } + usbd_free_xfer(xfer); + break; + case UE_INTERRUPT: + xfer = usbd_alloc_xfer(sc->sc_udev); + if (xfer == 0) + return (EIO); + while ((n = min(UGETW(sce->edesc->wMaxPacketSize), + uio->uio_resid)) != 0) { + error = uiomove(buf, n, uio); + if (error) + break; + DPRINTFN(1, ("ugenwrite: transfer %d bytes\n", n)); + err = usbd_intr_transfer(xfer, sce->pipeh, 0, + sce->timeout, buf, &n,"ugenwi"); + if (err) { + if (err == USBD_INTERRUPTED) + error = EINTR; + else if (err == USBD_TIMEOUT) + error = ETIMEDOUT; else error = EIO; break; @@ -745,7 +841,6 @@ switch (act) { case DVACT_ACTIVATE: return (EOPNOTSUPP); - break; case DVACT_DEACTIVATE: sc->sc_dying = 1; @@ -764,7 +859,6 @@ #if defined(__NetBSD__) || defined(__OpenBSD__) int maj, mn; #elif defined(__FreeBSD__) - int endptno; dev_t dev; struct vnode *vp; #endif @@ -811,28 +905,7 @@ if (vp) VOP_REVOKE(vp, REVOKEALL); destroy_dev(dev); - - /* destroy all devices for the other (existing) endpoints as well */ - for (endptno = 1; endptno < USB_MAX_ENDPOINTS; endptno++) { - if (sc->sc_endpoints[endptno][IN].sc != NULL || - sc->sc_endpoints[endptno][OUT].sc != NULL ) { - /* endpt can be 0x81 and 0x01, representing - * endpoint address 0x01 and IN/OUT directions. - * We map both endpoint addresses to the same device, - * IN is reading from it, OUT is writing to it. - * - * In the if clause above we check whether one - * of the structs is populated. - */ - dev = makedev(UGEN_CDEV_MAJOR, - UGENMINOR(USBDEVUNIT(sc->sc_dev), endptno)); - vp = SLIST_FIRST(&dev->si_hlist); - if (vp) - VOP_REVOKE(vp, REVOKEALL); - - destroy_dev(dev); - } - } + ugen_destroy_devnodes(sc); #endif return (0); @@ -851,20 +924,21 @@ if (status != USBD_NORMAL_COMPLETION) { DPRINTF(("ugenintr: status=%d\n", status)); - usbd_clear_endpoint_stall_async(sce->pipeh); + if (status == USBD_STALLED) + usbd_clear_endpoint_stall_async(sce->pipeh); return; } usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL); ibuf = sce->ibuf; - DPRINTFN(5, ("ugenintr: xfer=%p status=%d count=%d\n", + DPRINTFN(5, ("ugenintr: xfer=%p status=%d count=%d\n", xfer, status, count)); DPRINTFN(5, (" data = %02x %02x %02x\n", ibuf[0], ibuf[1], ibuf[2])); (void)b_to_q(ibuf, count, &sce->q); - + if (sce->state & UGEN_ASLP) { sce->state &= ~UGEN_ASLP; DPRINTFN(5, ("ugen_intr: waking %p\n", sce)); @@ -874,19 +948,21 @@ } Static void -ugen_isoc_rintr(usbd_xfer_handle xfer, usbd_private_handle addr, +ugen_isoc_rintr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status) { struct isoreq *req = addr; struct ugen_endpoint *sce = req->sce; u_int32_t count, n; + int i, isize; /* Return if we are aborting. */ if (status == USBD_CANCELLED) return; usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL); - DPRINTFN(5,("ugen_isoc_rintr: xfer %d, count=%d\n", req - sce->isoreqs, + DPRINTFN(5,("ugen_isoc_rintr: xfer %d, count=%d\n", + (int)(req - sce->isoreqs), count)); /* throw away oldest input if the buffer is full */ @@ -898,15 +974,25 @@ count)); } - /* copy data to buffer */ - while (count > 0) { - n = min(count, sce->limit - sce->fill); - memcpy(sce->fill, req->dmabuf, n); - - count -= n; - sce->fill += n; - if(sce->fill == sce->limit) - sce->fill = sce->ibuf; + isize = UGETW(sce->edesc->wMaxPacketSize); + for (i = 0; i < UGEN_NISORFRMS; i++) { + u_int32_t actlen = req->sizes[i]; + char const *buf = (char const *)req->dmabuf + isize * i; + + /* copy data to buffer */ + while (actlen > 0) { + n = min(actlen, sce->limit - sce->fill); + memcpy(sce->fill, buf, n); + + buf += n; + actlen -= n; + sce->fill += n; + if(sce->fill == sce->limit) + sce->fill = sce->ibuf; + } + + /* setup size for next transfer */ + req->sizes[i] = isize; } usbd_setup_isoc_xfer(xfer, sce->pipeh, req, req->sizes, UGEN_NISORFRMS, @@ -938,13 +1024,20 @@ return (err); if (ifaceidx < 0 || ifaceidx >= niface) return (USBD_INVAL); - + err = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface); if (err) return (err); err = usbd_endpoint_count(iface, &nendpt); if (err) return (err); + +#if defined(__FreeBSD__) + /* destroy the existing devices, we remake the new ones in a moment */ + ugen_destroy_devnodes(sc); +#endif + + /* XXX should only do this after setting new altno has succeeded */ for (endptno = 0; endptno < nendpt; endptno++) { ed = usbd_interface2endpoint_descriptor(iface,endptno); endpt = ed->bEndpointAddress; @@ -972,6 +1065,12 @@ sce->edesc = ed; sce->iface = iface; } + +#if defined(__FreeBSD__) + /* make the new devices */ + ugen_make_devnodes(sc); +#endif + return (0); } @@ -1017,7 +1116,7 @@ err = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface); if (err) - return (-1); + return (-1); return (usbd_get_interface_altindex(iface)); } @@ -1053,12 +1152,12 @@ sce = &sc->sc_endpoints[endpt][IN]; if (sce == NULL) return (EINVAL); -#ifdef DIAGNOSTIC + if (sce->pipeh == NULL) { printf("ugenioctl: USB_SET_SHORT_XFER, no pipe\n"); return (EIO); } -#endif + if (*(int *)addr) sce->state |= UGEN_SHORT_OK; else @@ -1068,12 +1167,6 @@ sce = &sc->sc_endpoints[endpt][IN]; if (sce == NULL) return (EINVAL); -#ifdef DIAGNOSTIC - if (sce->pipeh == NULL) { - printf("ugenioctl: USB_SET_TIMEOUT, no pipe\n"); - return (EIO); - } -#endif sce->timeout = *(int *)addr; return (0); default: @@ -1110,7 +1203,7 @@ break; case USB_GET_ALTINTERFACE: ai = (struct usb_alt_interface *)addr; - err = usbd_device2interface_handle(sc->sc_udev, + err = usbd_device2interface_handle(sc->sc_udev, ai->uai_interface_index, &iface); if (err) return (EINVAL); @@ -1123,7 +1216,7 @@ if (!(flag & FWRITE)) return (EPERM); ai = (struct usb_alt_interface *)addr; - err = usbd_device2interface_handle(sc->sc_udev, + err = usbd_device2interface_handle(sc->sc_udev, ai->uai_interface_index, &iface); if (err) return (EINVAL); @@ -1184,7 +1277,7 @@ alt = ugen_get_alt_index(sc, ed->ued_interface_index); else alt = ed->ued_alt_index; - edesc = usbd_find_edesc(cdesc, ed->ued_interface_index, + edesc = usbd_find_edesc(cdesc, ed->ued_interface_index, alt, ed->ued_endpoint_index); if (edesc == NULL) { free(cdesc, M_TEMP); @@ -1213,17 +1306,13 @@ 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); } case USB_GET_STRING_DESC: si = (struct usb_string_desc *)addr; - err = usbd_get_string_desc(sc->sc_udev, si->usd_string_index, + err = usbd_get_string_desc(sc->sc_udev, si->usd_string_index, si->usd_language_id, &si->usd_desc); if (err) return (EINVAL); @@ -1260,7 +1349,7 @@ uio.uio_offset = 0; uio.uio_segflg = UIO_USERSPACE; uio.uio_rw = - ur->ucr_request.bmRequestType & UT_READ ? + ur->ucr_request.bmRequestType & UT_READ ? UIO_READ : UIO_WRITE; uio.uio_procp = p; ptr = malloc(len, M_TEMP, M_WAITOK); @@ -1270,8 +1359,9 @@ goto ret; } } - err = usbd_do_request_flags(sc->sc_udev, &ur->ucr_request, - ptr, ur->ucr_flags, &ur->ucr_actlen); + sce = &sc->sc_endpoints[endpt][IN]; + err = usbd_do_request_flags(sc->sc_udev, &ur->ucr_request, + ptr, ur->ucr_flags, &ur->ucr_actlen, sce->timeout); if (err) { error = EIO; goto ret; @@ -1290,7 +1380,7 @@ } case USB_GET_DEVICEINFO: usbd_fill_deviceinfo(sc->sc_udev, - (struct usb_device_info *)addr); + (struct usb_device_info *)addr, 1); break; default: return (EINVAL); @@ -1331,7 +1421,7 @@ sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN]; if (sce == NULL) return (EINVAL); -#ifdef DIAGNOSTIC + if (!sce->edesc) { printf("ugenpoll: no edesc\n"); return (EIO); @@ -1340,7 +1430,7 @@ printf("ugenpoll: no pipe\n"); return (EIO); } -#endif + s = splusb(); switch (sce->edesc->bmAttributes & UE_XFERTYPE) { case UE_INTERRUPT: @@ -1360,12 +1450,12 @@ } break; case UE_BULK: - /* + /* * We have no easy way of determining if a read will * yield any data or a write will happen. * Pretend they will. */ - revents |= events & + revents |= events & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM); break; default: Index: sys/dev/usb/ugraphire_rdesc.h =================================================================== RCS file: sys/dev/usb/ugraphire_rdesc.h diff -N sys/dev/usb/ugraphire_rdesc.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/dev/usb/ugraphire_rdesc.h 4 Oct 2003 18:54:40 -0000 @@ -0,0 +1,92 @@ +/* $NetBSD: usb/ugraphire_rdesc.h,v 1.1 2000/12/29 01:47:49 augustss Exp $ */ +/* $FreeBSD: src/sys/dev/usb/ugraphire_rdesc.h,v 1.1 2002/04/07 17:04:01 joe Exp $ */ +/* + * Copyright (c) 2000 Nick Hibma + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +static uByte uhid_graphire_report_descr[] = { + 0x05, 0x0d, /* USAGE_PAGE (Digitizers) */ + 0x09, 0x01, /* USAGE (Digitizer) */ + 0xa1, 0x01, /* COLLECTION (Application) */ + 0x85, 0x02, /* REPORT_ID (2) */ + 0x05, 0x0d, /* USAGE_PAGE (Digitizers) */ + 0x09, 0x01, /* USAGE (Digitizer) */ + 0xa1, 0x00, /* COLLECTION (Physical) */ + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ + 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ + 0x09, 0x33, /* USAGE (Touch) */ + 0x95, 0x01, /* REPORT_COUNT (1) */ + 0x75, 0x01, /* REPORT_SIZE (1) */ + 0x81, 0x02, /* INPUT (Data,Var,Abs) */ + 0x09, 0x44, /* USAGE (Barrel Switch) */ + 0x95, 0x02, /* REPORT_COUNT (2) */ + 0x75, 0x01, /* REPORT_SIZE (1) */ + 0x81, 0x02, /* INPUT (Data,Var,Abs) */ + 0x09, 0x00, /* USAGE (Undefined) */ + 0x95, 0x02, /* REPORT_COUNT (2) */ + 0x75, 0x01, /* REPORT_SIZE (1) */ + 0x81, 0x03, /* INPUT (Cnst,Var,Abs) */ + 0x09, 0x3c, /* USAGE (Invert) */ + 0x95, 0x01, /* REPORT_COUNT (1) */ + 0x75, 0x01, /* REPORT_SIZE (1) */ + 0x81, 0x02, /* INPUT (Data,Var,Abs) */ + 0x09, 0x38, /* USAGE (Transducer Index) */ + 0x95, 0x01, /* REPORT_COUNT (1) */ + 0x75, 0x01, /* REPORT_SIZE (1) */ + 0x81, 0x02, /* INPUT (Data,Var,Abs) */ + 0x09, 0x32, /* USAGE (In Range) */ + 0x95, 0x01, /* REPORT_COUNT (1) */ + 0x75, 0x01, /* REPORT_SIZE (1) */ + 0x81, 0x02, /* INPUT (Data,Var,Abs) */ + 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ + 0x09, 0x30, /* USAGE (X) */ + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ + 0x26, 0xde, 0x27, /* LOGICAL_MAXIMUM (10206) */ + 0x95, 0x01, /* REPORT_COUNT (1) */ + 0x75, 0x10, /* REPORT_SIZE (16) */ + 0x81, 0x02, /* INPUT (Data,Var,Abs) */ + 0x09, 0x31, /* USAGE (Y) */ + 0x26, 0xfe, 0x1c, /* LOGICAL_MAXIMUM (7422) */ + 0x95, 0x01, /* REPORT_COUNT (1) */ + 0x75, 0x10, /* REPORT_SIZE (16) */ + 0x81, 0x02, /* INPUT (Data,Var,Abs) */ + 0x05, 0x0d, /* USAGE_PAGE (Digitizers) */ + 0x09, 0x30, /* USAGE (Tip Pressure) */ + 0x26, 0xff, 0x01, /* LOGICAL_MAXIMUM (511) */ + 0x95, 0x01, /* REPORT_COUNT (1) */ + 0x75, 0x10, /* REPORT_SIZE (16) */ + 0x81, 0x02, /* INPUT (Data,Var,Abs) */ + 0xc0, /* END_COLLECTION */ + 0x05, 0x0d, /* USAGE_PAGE (Digitizers) */ + 0x09, 0x00, /* USAGE (Undefined) */ + 0x85, 0x02, /* REPORT_ID (2) */ + 0x95, 0x01, /* REPORT_COUNT (1) */ + 0xb1, 0x02, /* FEATURE (Data,Var,Abs) */ + 0x09, 0x00, /* USAGE (Undefined) */ + 0x85, 0x03, /* REPORT_ID (3) */ + 0x95, 0x01, /* REPORT_COUNT (1) */ + 0xb1, 0x02, /* FEATURE (Data,Var,Abs) */ + 0xc0, /* END_COLLECTION */ +}; Index: sys/dev/usb/uhci.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/uhci.c,v retrieving revision 1.40.2.11 diff -u -r1.40.2.11 uhci.c --- sys/dev/usb/uhci.c 22 Aug 2003 06:59:11 -0000 1.40.2.11 +++ sys/dev/usb/uhci.c 4 Oct 2003 18:54:40 -0000 @@ -1,5 +1,22 @@ -/* $NetBSD: uhci.c,v 1.80 2000/01/19 01:16:38 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/uhci.c,v 1.40.2.11 2003/08/22 06:59:11 njl Exp $ */ +/* $NetBSD: uhci.c,v 1.160 2002/05/28 12:42:39 augustss Exp $ */ + +/* Also already incorporated from NetBSD: + * $NetBSD: uhci.c,v 1.162 2002/07/11 21:14:28 augustss Exp $ + * $NetBSD: uhci.c,v 1.163 2002/09/27 15:37:36 provos Exp $ + * $NetBSD: uhci.c,v 1.164 2002/09/29 21:13:01 augustss Exp $ + * $NetBSD: uhci.c,v 1.165 2002/12/31 02:04:49 dsainty Exp $ + * $NetBSD: uhci.c,v 1.166 2002/12/31 02:21:31 dsainty Exp $ + * $NetBSD: uhci.c,v 1.167 2003/01/01 16:25:59 augustss Exp $ + * $NetBSD: uhci.c,v 1.168 2003/02/08 03:32:51 ichiro Exp $ + * $NetBSD: uhci.c,v 1.169 2003/02/16 23:15:28 augustss Exp $ + * $NetBSD: uhci.c,v 1.170 2003/02/19 01:35:04 augustss Exp $ + * $NetBSD: uhci.c,v 1.172 2003/02/23 04:19:26 simonb Exp $ + * $NetBSD: uhci.c,v 1.173 2003/05/13 04:41:59 gson Exp $ + */ + +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/uhci.c,v 1.145 2003/08/24 17:55:55 obrien Exp $"); + /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -42,8 +59,8 @@ * USB Universal Host Controller driver. * Handles e.g. PIIX3 and PIIX4. * - * UHCI spec: http://www.intel.com/design/usb/uhci11d.pdf - * USB spec: http://www.usb.org/developers/data/usb11.pdf + * UHCI spec: http://developer.intel.com/design/USB/UHCI11D.htm + * USB spec: http://www.usb.org/developers/docs/usbspec.zip * PIIXn spec: ftp://download.intel.com/design/intarch/datashts/29055002.pdf * ftp://download.intel.com/design/intarch/datashts/29056201.pdf */ @@ -56,6 +73,7 @@ #include #include #elif defined(__FreeBSD__) +#include #include #include #include @@ -79,6 +97,9 @@ #include #include +/* Use bandwidth reclamation for control transfers. Some devices choke on it. */ +/*#define UHCI_CTL_LOOP */ + #if defined(__FreeBSD__) #include @@ -94,12 +115,19 @@ #endif #ifdef USB_DEBUG +uhci_softc_t *thesc; #define DPRINTF(x) if (uhcidebug) printf x #define DPRINTFN(n,x) if (uhcidebug>(n)) printf x int uhcidebug = 0; +int uhcinoloop = 0; SYSCTL_NODE(_hw_usb, OID_AUTO, uhci, CTLFLAG_RW, 0, "USB uhci"); SYSCTL_INT(_hw_usb_uhci, OID_AUTO, debug, CTLFLAG_RW, &uhcidebug, 0, "uhci debug level"); +SYSCTL_INT(_hw_usb_uhci, OID_AUTO, loop, CTLFLAG_RW, + &uhcinoloop, 0, "uhci noloop"); +#ifndef __NetBSD__ +#define bitmask_snprintf(q,f,b,l) snprintf((b), (l), "%b", (q), (f)) +#endif #else #define DPRINTF(x) #define DPRINTFN(n,x) @@ -109,16 +137,23 @@ * The UHCI controller is little endian, so on big endian machines * the data strored in memory needs to be swapped. */ +#if defined(__OpenBSD__) #if BYTE_ORDER == BIG_ENDIAN -#define LE(x) (bswap32(x)) +#define htole32(x) (bswap32(x)) +#define le32toh(x) (bswap32(x)) #else -#define LE(x) (x) +#define htole32(x) (x) +#define le32toh(x) (x) +#endif #endif struct uhci_pipe { struct usbd_pipe pipe; - uhci_intr_info_t *iinfo; int nexttoggle; + + u_char aborting; + usbd_xfer_handle abortstart, abortend; + /* Info needed for different pipe kinds. */ union { /* Control pipe */ @@ -131,6 +166,7 @@ /* Interrupt pipe */ struct { int npoll; + int isread; uhci_soft_qh_t **qhs; } intr; /* Bulk pipe */ @@ -147,47 +183,47 @@ } u; }; -/* - * The uhci_intr_info free list can be global since they contain - * no dma specific data. The other free lists do. - */ -LIST_HEAD(, uhci_intr_info) uhci_ii_free; - -Static void uhci_busreset(uhci_softc_t *); +Static void uhci_globalreset(uhci_softc_t *); +Static usbd_status uhci_portreset(uhci_softc_t*, int); +Static void uhci_reset(uhci_softc_t *); +#if defined(__NetBSD__) || defined(__OpenBSD__) +Static void uhci_shutdown(void *v); +Static void uhci_power(int, void *); +#endif Static usbd_status uhci_run(uhci_softc_t *, int run); -Static uhci_soft_td_t *uhci_alloc_std(uhci_softc_t *); +Static uhci_soft_td_t *uhci_alloc_std(uhci_softc_t *); Static void uhci_free_std(uhci_softc_t *, uhci_soft_td_t *); -Static uhci_soft_qh_t *uhci_alloc_sqh(uhci_softc_t *); +Static uhci_soft_qh_t *uhci_alloc_sqh(uhci_softc_t *); Static void uhci_free_sqh(uhci_softc_t *, uhci_soft_qh_t *); -Static uhci_intr_info_t *uhci_alloc_intr_info(uhci_softc_t *); -Static void uhci_free_intr_info(uhci_intr_info_t *ii); #if 0 Static void uhci_enter_ctl_q(uhci_softc_t *, uhci_soft_qh_t *, - uhci_intr_info_t *); + uhci_intr_info_t *); Static void uhci_exit_ctl_q(uhci_softc_t *, uhci_soft_qh_t *); #endif -Static void uhci_free_std_chain(uhci_softc_t *, - uhci_soft_td_t *, uhci_soft_td_t *); +Static void uhci_free_std_chain(uhci_softc_t *, + uhci_soft_td_t *, uhci_soft_td_t *); Static usbd_status uhci_alloc_std_chain(struct uhci_pipe *, - uhci_softc_t *, int, int, u_int16_t, usb_dma_t *, + uhci_softc_t *, int, int, u_int16_t, usb_dma_t *, uhci_soft_td_t **, uhci_soft_td_t **); -Static void uhci_timo(void *); +Static void uhci_poll_hub(void *); Static void uhci_waitintr(uhci_softc_t *, usbd_xfer_handle); Static void uhci_check_intr(uhci_softc_t *, uhci_intr_info_t *); Static void uhci_idone(uhci_intr_info_t *); Static void uhci_abort_xfer(usbd_xfer_handle, usbd_status status); -Static void uhci_abort_xfer_end(void *v); Static void uhci_timeout(void *); -Static void uhci_lock_frames(uhci_softc_t *); -Static void uhci_unlock_frames(uhci_softc_t *); -Static void uhci_add_ctrl(uhci_softc_t *, uhci_soft_qh_t *); +Static void uhci_timeout_task(void *); +Static void uhci_add_ls_ctrl(uhci_softc_t *, uhci_soft_qh_t *); +Static void uhci_add_hs_ctrl(uhci_softc_t *, uhci_soft_qh_t *); Static void uhci_add_bulk(uhci_softc_t *, uhci_soft_qh_t *); -Static void uhci_remove_ctrl(uhci_softc_t *,uhci_soft_qh_t *); +Static void uhci_remove_ls_ctrl(uhci_softc_t *,uhci_soft_qh_t *); +Static void uhci_remove_hs_ctrl(uhci_softc_t *,uhci_soft_qh_t *); Static void uhci_remove_bulk(uhci_softc_t *,uhci_soft_qh_t *); Static int uhci_str(usb_string_descriptor_t *, int, char *); +Static void uhci_add_loop(uhci_softc_t *sc); +Static void uhci_rem_loop(uhci_softc_t *sc); Static usbd_status uhci_setup_isoc(usbd_pipe_handle pipe); Static void uhci_device_isoc_enter(usbd_xfer_handle); @@ -202,69 +238,85 @@ Static usbd_status uhci_device_ctrl_start(usbd_xfer_handle); Static void uhci_device_ctrl_abort(usbd_xfer_handle); Static void uhci_device_ctrl_close(usbd_pipe_handle); -Static void uhci_device_ctrl_done (usbd_xfer_handle); +Static void uhci_device_ctrl_done(usbd_xfer_handle); Static usbd_status uhci_device_intr_transfer(usbd_xfer_handle); Static usbd_status uhci_device_intr_start(usbd_xfer_handle); Static void uhci_device_intr_abort(usbd_xfer_handle); Static void uhci_device_intr_close(usbd_pipe_handle); -Static void uhci_device_intr_done (usbd_xfer_handle); +Static void uhci_device_intr_done(usbd_xfer_handle); Static usbd_status uhci_device_bulk_transfer(usbd_xfer_handle); Static usbd_status uhci_device_bulk_start(usbd_xfer_handle); Static void uhci_device_bulk_abort(usbd_xfer_handle); Static void uhci_device_bulk_close(usbd_pipe_handle); -Static void uhci_device_bulk_done (usbd_xfer_handle); +Static void uhci_device_bulk_done(usbd_xfer_handle); Static usbd_status uhci_device_isoc_transfer(usbd_xfer_handle); Static usbd_status uhci_device_isoc_start(usbd_xfer_handle); Static void uhci_device_isoc_abort(usbd_xfer_handle); Static void uhci_device_isoc_close(usbd_pipe_handle); -Static void uhci_device_isoc_done (usbd_xfer_handle); +Static void uhci_device_isoc_done(usbd_xfer_handle); Static usbd_status uhci_root_ctrl_transfer(usbd_xfer_handle); Static usbd_status uhci_root_ctrl_start(usbd_xfer_handle); Static void uhci_root_ctrl_abort(usbd_xfer_handle); Static void uhci_root_ctrl_close(usbd_pipe_handle); +Static void uhci_root_ctrl_done(usbd_xfer_handle); Static usbd_status uhci_root_intr_transfer(usbd_xfer_handle); Static usbd_status uhci_root_intr_start(usbd_xfer_handle); Static void uhci_root_intr_abort(usbd_xfer_handle); Static void uhci_root_intr_close(usbd_pipe_handle); -Static void uhci_root_intr_done (usbd_xfer_handle); +Static void uhci_root_intr_done(usbd_xfer_handle); Static usbd_status uhci_open(usbd_pipe_handle); Static void uhci_poll(struct usbd_bus *); +Static void uhci_softintr(void *); Static usbd_status uhci_device_request(usbd_xfer_handle xfer); -Static void uhci_add_intr(uhci_softc_t *, int, uhci_soft_qh_t *); -Static void uhci_remove_intr(uhci_softc_t *, int, uhci_soft_qh_t *); -Static usbd_status uhci_device_setintr(uhci_softc_t *sc, +Static void uhci_add_intr(uhci_softc_t *, uhci_soft_qh_t *); +Static void uhci_remove_intr(uhci_softc_t *, uhci_soft_qh_t *); +Static usbd_status uhci_device_setintr(uhci_softc_t *sc, struct uhci_pipe *pipe, int ival); Static void uhci_device_clear_toggle(usbd_pipe_handle pipe); Static void uhci_noop(usbd_pipe_handle pipe); +Static __inline__ uhci_soft_qh_t *uhci_find_prev_qh(uhci_soft_qh_t *, + uhci_soft_qh_t *); + #ifdef USB_DEBUG +Static void uhci_dump_all(uhci_softc_t *); Static void uhci_dumpregs(uhci_softc_t *); Static void uhci_dump_qhs(uhci_soft_qh_t *); Static void uhci_dump_qh(uhci_soft_qh_t *); Static void uhci_dump_tds(uhci_soft_td_t *); Static void uhci_dump_td(uhci_soft_td_t *); +Static void uhci_dump_ii(uhci_intr_info_t *ii); +void uhci_dump(void); #endif -#define UWRITE1(sc, r, x) bus_space_write_1((sc)->iot, (sc)->ioh, (r), (x)) -#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)) +#define UBARR(sc) bus_space_barrier((sc)->iot, (sc)->ioh, 0, (sc)->sc_size, \ + BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE) +#define UWRITE1(sc, r, x) \ + do { UBARR(sc); bus_space_write_1((sc)->iot, (sc)->ioh, (r), (x)); \ + } while (/*CONSTCOND*/0) +#define UWRITE2(sc, r, x) \ + do { UBARR(sc); bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x)); \ + } while (/*CONSTCOND*/0) +#define UWRITE4(sc, r, x) \ + do { UBARR(sc); bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x)); \ + } while (/*CONSTCOND*/0) +#define UREAD1(sc, r) (UBARR(sc), bus_space_read_1((sc)->iot, (sc)->ioh, (r))) +#define UREAD2(sc, r) (UBARR(sc), bus_space_read_2((sc)->iot, (sc)->ioh, (r))) +#define UREAD4(sc, r) (UBARR(sc), bus_space_read_4((sc)->iot, (sc)->ioh, (r))) #define UHCICMD(sc, cmd) UWRITE2(sc, UHCI_CMD, cmd) #define UHCISTS(sc) UREAD2(sc, UHCI_STS) -#define UHCI_RESET_TIMEOUT 100 /* reset timeout */ +#define UHCI_RESET_TIMEOUT 100 /* ms, reset timeout */ #define UHCI_CURFRAME(sc) (UREAD2(sc, UHCI_FRNUM) & UHCI_FRNUM_MASK) @@ -272,6 +324,7 @@ struct usbd_bus_methods uhci_bus_methods = { uhci_open, + uhci_softintr, uhci_poll, uhci_allocm, uhci_freem, @@ -279,16 +332,16 @@ uhci_freex, }; -struct usbd_pipe_methods uhci_root_ctrl_methods = { +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, + uhci_root_ctrl_done, }; -struct usbd_pipe_methods uhci_root_intr_methods = { +struct usbd_pipe_methods uhci_root_intr_methods = { uhci_root_intr_transfer, uhci_root_intr_start, uhci_root_intr_abort, @@ -333,8 +386,33 @@ uhci_device_isoc_done, }; +#define uhci_add_intr_info(sc, ii) \ + LIST_INSERT_HEAD(&(sc)->sc_intrhead, (ii), list) +#define uhci_del_intr_info(ii) \ + do { \ + LIST_REMOVE((ii), list); \ + (ii)->list.le_prev = NULL; \ + } while (0) +#define uhci_active_intr_info(ii) ((ii)->list.le_prev != NULL) + +Static __inline__ uhci_soft_qh_t * +uhci_find_prev_qh(uhci_soft_qh_t *pqh, uhci_soft_qh_t *sqh) +{ + DPRINTFN(15,("uhci_find_prev_qh: pqh=%p sqh=%p\n", pqh, sqh)); + + for (; pqh->hlink != sqh; pqh = pqh->hlink) { +#if defined(DIAGNOSTIC) || defined(USB_DEBUG) + if (le32toh(pqh->qh.qh_hlink) & UHCI_PTR_T) { + printf("uhci_find_prev_qh: QH not found\n"); + return (NULL); + } +#endif + } + return (pqh); +} + void -uhci_busreset(uhci_softc_t *sc) +uhci_globalreset(uhci_softc_t *sc) { UHCICMD(sc, UHCI_CMD_GRESET); /* global reset */ usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); /* wait a little */ @@ -346,23 +424,24 @@ { usbd_status err; int i, j; - uhci_soft_qh_t *csqh, *bsqh, *sqh; + uhci_soft_qh_t *clsqh, *chsqh, *bsqh, *sqh, *lsqh; uhci_soft_td_t *std; DPRINTFN(1,("uhci_init: start\n")); #ifdef USB_DEBUG + thesc = sc; + if (uhcidebug > 2) uhci_dumpregs(sc); #endif - uhci_run(sc, 0); /* stop the controller */ UWRITE2(sc, UHCI_INTR, 0); /* disable interrupts */ - - uhci_busreset(sc); + uhci_globalreset(sc); /* reset the controller */ + uhci_reset(sc); /* Allocate and initialize real frame array. */ - err = usb_allocmem(&sc->sc_bus, + err = usb_allocmem(&sc->sc_bus, UHCI_FRAMELIST_COUNT * sizeof(uhci_physaddr_t), UHCI_FRAMELIST_ALIGN, &sc->sc_dma); if (err) @@ -371,24 +450,61 @@ UWRITE2(sc, UHCI_FRNUM, 0); /* set frame number to 0 */ UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma, 0)); /* set frame list*/ + /* + * Allocate a TD, inactive, that hangs from the last QH. + * This is to avoid a bug in the PIIX that makes it run berserk + * otherwise. + */ + std = uhci_alloc_std(sc); + if (std == NULL) + return (USBD_NOMEM); + std->link.std = NULL; + std->td.td_link = htole32(UHCI_PTR_T); + std->td.td_status = htole32(0); /* inactive */ + std->td.td_token = htole32(0); + std->td.td_buffer = htole32(0); + + /* Allocate the dummy QH marking the end and used for looping the QHs.*/ + lsqh = uhci_alloc_sqh(sc); + if (lsqh == NULL) + return (USBD_NOMEM); + lsqh->hlink = NULL; + lsqh->qh.qh_hlink = htole32(UHCI_PTR_T); /* end of QH chain */ + lsqh->elink = std; + lsqh->qh.qh_elink = htole32(std->physaddr | UHCI_PTR_TD); + sc->sc_last_qh = lsqh; + /* Allocate the dummy QH where bulk traffic will be queued. */ bsqh = uhci_alloc_sqh(sc); if (bsqh == NULL) return (USBD_NOMEM); - bsqh->qh.qh_hlink = LE(UHCI_PTR_T); /* end of QH chain */ - bsqh->qh.qh_elink = LE(UHCI_PTR_T); + bsqh->hlink = lsqh; + bsqh->qh.qh_hlink = htole32(lsqh->physaddr | UHCI_PTR_QH); + bsqh->elink = NULL; + bsqh->qh.qh_elink = htole32(UHCI_PTR_T); sc->sc_bulk_start = sc->sc_bulk_end = bsqh; - /* Allocate the dummy QH where control traffic will be queued. */ - csqh = uhci_alloc_sqh(sc); - if (csqh == NULL) + /* Allocate dummy QH where high speed control traffic will be queued. */ + chsqh = uhci_alloc_sqh(sc); + if (chsqh == NULL) 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; + chsqh->hlink = bsqh; + chsqh->qh.qh_hlink = htole32(bsqh->physaddr | UHCI_PTR_QH); + chsqh->elink = NULL; + chsqh->qh.qh_elink = htole32(UHCI_PTR_T); + sc->sc_hctl_start = sc->sc_hctl_end = chsqh; + + /* Allocate dummy QH where control traffic will be queued. */ + clsqh = uhci_alloc_sqh(sc); + if (clsqh == NULL) + return (USBD_NOMEM); + clsqh->hlink = bsqh; + clsqh->qh.qh_hlink = htole32(chsqh->physaddr | UHCI_PTR_QH); + clsqh->elink = NULL; + clsqh->qh.qh_elink = htole32(UHCI_PTR_T); + sc->sc_lctl_start = sc->sc_lctl_end = clsqh; - /* + /* * Make all (virtual) frame list pointers point to the interrupt * queue heads and the interrupt queue heads at the control * queue head and point the physical frame list to the virtual. @@ -399,39 +515,42 @@ if (std == NULL || sqh == NULL) 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); + std->td.td_link = htole32(sqh->physaddr | UHCI_PTR_QH); + std->td.td_status = htole32(UHCI_TD_IOS); /* iso, inactive */ + std->td.td_token = htole32(0); + std->td.td_buffer = htole32(0); + sqh->hlink = clsqh; + sqh->qh.qh_hlink = htole32(clsqh->physaddr | UHCI_PTR_QH); + sqh->elink = NULL; + sqh->qh.qh_elink = htole32(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; - for (j = i; - j < UHCI_FRAMELIST_COUNT; + for (j = i; + j < UHCI_FRAMELIST_COUNT; j += UHCI_VFRAMELIST_COUNT) - sc->sc_pframes[j] = LE(std->physaddr); + sc->sc_pframes[j] = htole32(std->physaddr); } LIST_INIT(&sc->sc_intrhead); SIMPLEQ_INIT(&sc->sc_free_xfers); + usb_callout_init(sc->sc_poll_handle); + /* Set up the bus struct. */ sc->sc_bus.methods = &uhci_bus_methods; sc->sc_bus.pipe_size = sizeof(struct uhci_pipe); +#if defined(__NetBSD__) || defined(__OpenBSD__) sc->sc_suspend = PWR_RESUME; -#if defined(__NetBSD__) sc->sc_powerhook = powerhook_establish(uhci_power, sc); sc->sc_shutdownhook = shutdownhook_establish(uhci_shutdown, sc); #endif + DPRINTFN(1,("uhci_init: enabling\n")); - UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE | + UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE | UHCI_INTR_IOCE | UHCI_INTR_SPIE); /* enable interrupts */ UHCICMD(sc, UHCI_CMD_MAXP); /* Assume 64 byte packets at frame end */ @@ -449,7 +568,6 @@ switch (act) { case DVACT_ACTIVATE: return (EOPNOTSUPP); - break; case DVACT_DEACTIVATE: if (sc->sc_child != NULL) @@ -467,11 +585,11 @@ if (sc->sc_child != NULL) rv = config_detach(sc->sc_child, flags); - + if (rv != 0) return (rv); -#if defined(__NetBSD__) +#if defined(__NetBSD__) || defined(__OpenBSD__) powerhook_disestablish(sc->sc_powerhook); shutdownhook_disestablish(sc->sc_shutdownhook); #endif @@ -483,7 +601,7 @@ break; SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, xfer, next); free(xfer, M_USB); - } + } /* XXX free other data structures XXX */ @@ -494,14 +612,13 @@ usbd_status uhci_allocm(struct usbd_bus *bus, usb_dma_t *dma, u_int32_t size) { - return (usb_allocmem(&((struct uhci_softc *)bus)->sc_bus, size, 0, - dma)); + return (usb_allocmem(bus, size, 0, dma)); } void uhci_freem(struct usbd_bus *bus, usb_dma_t *dma) { - usb_freemem(&((struct uhci_softc *)bus)->sc_bus, dma); + usb_freemem(bus, dma); } usbd_xfer_handle @@ -511,12 +628,25 @@ usbd_xfer_handle xfer; xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers); - if (xfer != NULL) + if (xfer != NULL) { SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, xfer, next); - else - xfer = malloc(sizeof(*xfer), M_USB, M_NOWAIT); - if (xfer != NULL) - memset(xfer, 0, sizeof *xfer); +#ifdef DIAGNOSTIC + if (xfer->busy_free != XFER_FREE) { + printf("uhci_allocx: xfer=%p not free, 0x%08x\n", xfer, + xfer->busy_free); + } +#endif + } else { + xfer = malloc(sizeof(struct uhci_xfer), M_USB, M_NOWAIT); + } + if (xfer != NULL) { + memset(xfer, 0, sizeof (struct uhci_xfer)); + UXFER(xfer)->iinfo.sc = sc; +#ifdef DIAGNOSTIC + UXFER(xfer)->iinfo.isdone = 1; + xfer->busy_free = XFER_BUSY; +#endif + } return (xfer); } @@ -525,6 +655,18 @@ { struct uhci_softc *sc = (struct uhci_softc *)bus; +#ifdef DIAGNOSTIC + if (xfer->busy_free != XFER_BUSY) { + printf("uhci_freex: xfer=%p not busy, 0x%08x\n", xfer, + xfer->busy_free); + return; + } + xfer->busy_free = XFER_FREE; + if (!UXFER(xfer)->iinfo.isdone) { + printf("uhci_freex: !isdone\n"); + return; + } +#endif SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next); } @@ -544,7 +686,7 @@ * 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 + * called from an interrupt context. This is all right since we * are almost suspended anyway. */ void @@ -554,10 +696,10 @@ int cmd; int s; - s = splusb(); + s = splhardusb(); cmd = UREAD2(sc, UHCI_CMD); - DPRINTF(("uhci_power: sc=%p, why=%d (was %d), cmd=0x%x\n", + DPRINTF(("uhci_power: sc=%p, why=%d (was %d), cmd=0x%x\n", sc, why, sc->sc_suspend, cmd)); if (why != PWR_RESUME) { @@ -565,9 +707,9 @@ if (uhcidebug > 2) uhci_dumpregs(sc); #endif - if (sc->sc_has_timo != NULL) - usb_untimeout(uhci_timo, sc->sc_has_timo, - sc->sc_has_timo->timo_handle); + if (sc->sc_intr_xfer != NULL) + usb_uncallout(sc->sc_poll_handle, uhci_poll_hub, + sc->sc_intr_xfer); sc->sc_bus.use_polling++; uhci_run(sc, 0); /* stop the controller */ @@ -575,6 +717,8 @@ sc->sc_saved_frnum = UREAD2(sc, UHCI_FRNUM); sc->sc_saved_sof = UREAD1(sc, UHCI_SOF); + UWRITE2(sc, UHCI_INTR, 0); /* disable intrs */ + UHCICMD(sc, cmd | UHCI_CMD_EGSM); /* enter global suspend */ usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT); sc->sc_suspend = why; @@ -598,15 +742,15 @@ 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 | + UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE | UHCI_INTR_IOCE | UHCI_INTR_SPIE); /* re-enable intrs */ UHCICMD(sc, UHCI_CMD_MAXP); uhci_run(sc, 1); /* and start traffic again */ usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY); sc->sc_bus.use_polling--; - if (sc->sc_has_timo != NULL) - usb_timeout(uhci_timo, sc->sc_has_timo, - sc->sc_ival, sc->sc_has_timo->timo_handle); + if (sc->sc_intr_xfer != NULL) + usb_callout(sc->sc_poll_handle, sc->sc_ival, + uhci_poll_hub, sc->sc_intr_xfer); #ifdef USB_DEBUG if (uhcidebug > 2) uhci_dumpregs(sc); @@ -635,49 +779,59 @@ void uhci_dump_td(uhci_soft_td_t *p) { + char sbuf[128], sbuf2[128]; + 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)))); + (long)le32toh(p->td.td_link), + (long)le32toh(p->td.td_status), + (long)le32toh(p->td.td_token), + (long)le32toh(p->td.td_buffer))); + + bitmask_snprintf((u_int32_t)le32toh(p->td.td_link), "\20\1T\2Q\3VF", + sbuf, sizeof(sbuf)); + bitmask_snprintf((u_int32_t)le32toh(p->td.td_status), + "\20\22BITSTUFF\23CRCTO\24NAK\25BABBLE\26DBUFFER\27" + "STALLED\30ACTIVE\31IOC\32ISO\33LS\36SPD", + sbuf2, sizeof(sbuf2)); + + DPRINTFN(-1,(" %s %s,errcnt=%d,actlen=%d pid=%02x,addr=%d,endpt=%d," + "D=%d,maxlen=%d\n", sbuf, sbuf2, + UHCI_TD_GET_ERRCNT(le32toh(p->td.td_status)), + UHCI_TD_GET_ACTLEN(le32toh(p->td.td_status)), + UHCI_TD_GET_PID(le32toh(p->td.td_token)), + UHCI_TD_GET_DEVADDR(le32toh(p->td.td_token)), + UHCI_TD_GET_ENDPT(le32toh(p->td.td_token)), + UHCI_TD_GET_DT(le32toh(p->td.td_token)), + UHCI_TD_GET_MAXLEN(le32toh(p->td.td_token)))); } void uhci_dump_qh(uhci_soft_qh_t *sqh) { DPRINTFN(-1,("QH(%p) at %08x: hlink=%08x elink=%08x\n", sqh, - (int)sqh->physaddr, LE(sqh->qh.qh_hlink), LE(sqh->qh.qh_elink))); + (int)sqh->physaddr, le32toh(sqh->qh.qh_hlink), + le32toh(sqh->qh.qh_elink))); } -#if 0 +#if 1 void -uhci_dump() +uhci_dump(void) { - uhci_softc_t *sc = uhci; + uhci_dump_all(thesc); +} +#endif +void +uhci_dump_all(uhci_softc_t *sc) +{ uhci_dumpregs(sc); printf("intrs=%d\n", sc->sc_bus.no_intrs); - printf("framelist[i].link = %08x\n", sc->sc_framelist[0].link); - uhci_dump_qh(sc->sc_ctl_start->qh.hlink); + /*printf("framelist[i].link = %08x\n", sc->sc_framelist[0].link);*/ + uhci_dump_qh(sc->sc_lctl_start); } -#endif void @@ -700,12 +854,12 @@ */ - if (sqh->hlink != NULL && !(sqh->qh.qh_hlink & UHCI_PTR_T)) + if (sqh->hlink != NULL && !(le32toh(sqh->qh.qh_hlink) & UHCI_PTR_T)) uhci_dump_qhs(sqh->hlink); else DPRINTF(("No QH\n")); - if (sqh->elink != NULL && !(sqh->qh.qh_elink & UHCI_PTR_T)) + if (sqh->elink != NULL && !(le32toh(sqh->qh.qh_elink) & UHCI_PTR_T)) uhci_dump_tds(sqh->elink); else DPRINTF(("No TD\n")); @@ -724,11 +878,74 @@ * printing the free list in case the queue/TD has * already been moved there (seatbelt). */ - if (td->td.td_link & UHCI_PTR_T || - td->td.td_link == 0) + if (le32toh(td->td.td_link) & UHCI_PTR_T || + le32toh(td->td.td_link) == 0) break; } } + +Static void +uhci_dump_ii(uhci_intr_info_t *ii) +{ + usbd_pipe_handle pipe; + usb_endpoint_descriptor_t *ed; + usbd_device_handle dev; + +#ifdef DIAGNOSTIC +#define DONE ii->isdone +#else +#define DONE 0 +#endif + if (ii == NULL) { + printf("ii NULL\n"); + return; + } + if (ii->xfer == NULL) { + printf("ii %p: done=%d xfer=NULL\n", + ii, DONE); + return; + } + pipe = ii->xfer->pipe; + if (pipe == NULL) { + printf("ii %p: done=%d xfer=%p pipe=NULL\n", + ii, DONE, ii->xfer); + return; + } + if (pipe->endpoint == NULL) { + printf("ii %p: done=%d xfer=%p pipe=%p pipe->endpoint=NULL\n", + ii, DONE, ii->xfer, pipe); + return; + } + if (pipe->device == NULL) { + printf("ii %p: done=%d xfer=%p pipe=%p pipe->device=NULL\n", + ii, DONE, ii->xfer, pipe); + return; + } + ed = pipe->endpoint->edesc; + dev = pipe->device; + printf("ii %p: done=%d xfer=%p dev=%p vid=0x%04x pid=0x%04x addr=%d pipe=%p ep=0x%02x attr=0x%02x\n", + ii, DONE, ii->xfer, dev, + UGETW(dev->ddesc.idVendor), + UGETW(dev->ddesc.idProduct), + dev->address, pipe, + ed->bEndpointAddress, ed->bmAttributes); +#undef DONE +} + +void uhci_dump_iis(struct uhci_softc *sc); +void +uhci_dump_iis(struct uhci_softc *sc) +{ + uhci_intr_info_t *ii; + + printf("intr_info list:\n"); + for (ii = LIST_FIRST(&sc->sc_intrhead); ii; ii = LIST_NEXT(ii, list)) + uhci_dump_ii(ii); +} + +void iidump(void); +void iidump(void) { uhci_dump_iis(thesc); } + #endif /* @@ -736,7 +953,7 @@ * from the root controller interrupt pipe for port status change. */ void -uhci_timo(void *addr) +uhci_poll_hub(void *addr) { usbd_xfer_handle xfer = addr; usbd_pipe_handle pipe = xfer->pipe; @@ -744,9 +961,9 @@ int s; u_char *p; - DPRINTFN(20, ("uhci_timo\n")); + DPRINTFN(20, ("uhci_poll_hub\n")); - usb_timeout(uhci_timo, xfer, sc->sc_ival, xfer->timo_handle); + usb_callout(sc->sc_poll_handle, sc->sc_ival, uhci_poll_hub, xfer); p = KERNADDR(&xfer->dmabuf, 0); p[0] = 0; @@ -761,7 +978,6 @@ xfer->actlen = 1; xfer->status = USBD_NORMAL_COMPLETION; s = splusb(); - xfer->hcpriv = 0; xfer->device->bus->intr_context++; usb_transfer_complete(xfer); xfer->device->bus->intr_context--; @@ -774,97 +990,132 @@ } void -uhci_lock_frames(uhci_softc_t *sc) +uhci_root_ctrl_done(usbd_xfer_handle xfer) { - int s = splusb(); +} - while (sc->sc_vflock & UHCI_HAS_LOCK) { - sc->sc_vflock |= UHCI_WANT_LOCK; - tsleep(&sc->sc_vflock, PRIBIO, "uhcqhl", 0); +/* + * Let the last QH loop back to the high speed control transfer QH. + * This is what intel calls "bandwidth reclamation" and improves + * USB performance a lot for some devices. + * If we are already looping, just count it. + */ +void +uhci_add_loop(uhci_softc_t *sc) { +#ifdef USB_DEBUG + if (uhcinoloop) + return; +#endif + if (++sc->sc_loops == 1) { + DPRINTFN(5,("uhci_start_loop: add\n")); + /* Note, we don't loop back the soft pointer. */ + sc->sc_last_qh->qh.qh_hlink = + htole32(sc->sc_hctl_start->physaddr | UHCI_PTR_QH); } - sc->sc_vflock = UHCI_HAS_LOCK; - splx(s); } void -uhci_unlock_frames(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); +uhci_rem_loop(uhci_softc_t *sc) { +#ifdef USB_DEBUG + if (uhcinoloop) + return; +#endif + if (--sc->sc_loops == 0) { + DPRINTFN(5,("uhci_end_loop: remove\n")); + sc->sc_last_qh->qh.qh_hlink = htole32(UHCI_PTR_T); + } } -/* - * Allocate an interrupt information struct. A free list is kept - * for fast allocation. - */ -uhci_intr_info_t * -uhci_alloc_intr_info(uhci_softc_t *sc) +/* Add high speed control QH, called at splusb(). */ +void +uhci_add_hs_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh) { - uhci_intr_info_t *ii; + uhci_soft_qh_t *eqh; - 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 + SPLUSBCHECK; - return ii; + DPRINTFN(10, ("uhci_add_ctrl: sqh=%p\n", sqh)); + eqh = sc->sc_hctl_end; + sqh->hlink = eqh->hlink; + sqh->qh.qh_hlink = eqh->qh.qh_hlink; + eqh->hlink = sqh; + eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH); + sc->sc_hctl_end = sqh; +#ifdef UHCI_CTL_LOOP + uhci_add_loop(sc); +#endif } +/* Remove high speed control QH, called at splusb(). */ void -uhci_free_intr_info(uhci_intr_info_t *ii) +uhci_remove_hs_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh) { - LIST_INSERT_HEAD(&uhci_ii_free, ii, list); /* and put on free list */ + uhci_soft_qh_t *pqh; + + SPLUSBCHECK; + + DPRINTFN(10, ("uhci_remove_hs_ctrl: sqh=%p\n", sqh)); +#ifdef UHCI_CTL_LOOP + uhci_rem_loop(sc); +#endif + /* + * The T bit should be set in the elink of the QH so that the HC + * doesn't follow the pointer. This condition may fail if the + * the transferred packet was short so that the QH still points + * at the last used TD. + * In this case we set the T bit and wait a little for the HC + * to stop looking at the TD. + */ + if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) { + sqh->qh.qh_elink = htole32(UHCI_PTR_T); + delay(UHCI_QH_REMOVE_DELAY); + } + + pqh = uhci_find_prev_qh(sc->sc_hctl_start, sqh); + pqh->hlink = sqh->hlink; + pqh->qh.qh_hlink = sqh->qh.qh_hlink; + delay(UHCI_QH_REMOVE_DELAY); + if (sc->sc_hctl_end == sqh) + sc->sc_hctl_end = pqh; } -/* Add control QH, called at splusb(). */ +/* Add low speed control QH, called at splusb(). */ void -uhci_add_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh) +uhci_add_ls_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh) { uhci_soft_qh_t *eqh; SPLUSBCHECK; - DPRINTFN(10, ("uhci_add_ctrl: sqh=%p\n", sqh)); - eqh = sc->sc_ctl_end; - sqh->hlink = eqh->hlink; + DPRINTFN(10, ("uhci_add_ls_ctrl: sqh=%p\n", sqh)); + eqh = sc->sc_lctl_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; + eqh->hlink = sqh; + eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH); + sc->sc_lctl_end = sqh; } -/* Remove control QH, called at splusb(). */ +/* Remove low speed control QH, called at splusb(). */ void -uhci_remove_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh) +uhci_remove_ls_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh) { uhci_soft_qh_t *pqh; SPLUSBCHECK; - 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(USB_DEBUG) - if (LE(pqh->qh.qh_hlink) & UHCI_PTR_T) { - printf("uhci_remove_ctrl: QH not found\n"); - return; - } -#else - ; -#endif - pqh->hlink = sqh->hlink; + DPRINTFN(10, ("uhci_remove_ls_ctrl: sqh=%p\n", sqh)); + /* See comment in uhci_remove_hs_ctrl() */ + if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) { + sqh->qh.qh_elink = htole32(UHCI_PTR_T); + delay(UHCI_QH_REMOVE_DELAY); + } + pqh = uhci_find_prev_qh(sc->sc_lctl_start, sqh); + pqh->hlink = sqh->hlink; pqh->qh.qh_hlink = sqh->qh.qh_hlink; - if (sc->sc_ctl_end == sqh) - sc->sc_ctl_end = pqh; + delay(UHCI_QH_REMOVE_DELAY); + if (sc->sc_lctl_end == sqh) + sc->sc_lctl_end = pqh; } /* Add bulk QH, called at splusb(). */ @@ -877,11 +1128,12 @@ DPRINTFN(10, ("uhci_add_bulk: sqh=%p\n", sqh)); eqh = sc->sc_bulk_end; - sqh->hlink = eqh->hlink; + 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); + eqh->hlink = sqh; + eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH); sc->sc_bulk_end = sqh; + uhci_add_loop(sc); } /* Remove bulk QH, called at splusb(). */ @@ -893,28 +1145,46 @@ SPLUSBCHECK; 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(USB_DEBUG) - if (LE(pqh->qh.qh_hlink) & UHCI_PTR_T) { - printf("uhci_remove_bulk: QH not found\n"); - return; - } -#else - ; -#endif + uhci_rem_loop(sc); + /* See comment in uhci_remove_hs_ctrl() */ + if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) { + sqh->qh.qh_elink = htole32(UHCI_PTR_T); + delay(UHCI_QH_REMOVE_DELAY); + } + pqh = uhci_find_prev_qh(sc->sc_bulk_start, sqh); pqh->hlink = sqh->hlink; pqh->qh.qh_hlink = sqh->qh.qh_hlink; + delay(UHCI_QH_REMOVE_DELAY); if (sc->sc_bulk_end == sqh) sc->sc_bulk_end = pqh; } +Static int uhci_intr1(uhci_softc_t *); + int uhci_intr(void *arg) { uhci_softc_t *sc = arg; + + if (sc->sc_dying) + return (0); + + DPRINTFN(15,("uhci_intr: real interrupt\n")); + if (sc->sc_bus.use_polling) { +#ifdef DIAGNOSTIC + printf("uhci_intr: ignored interrupt while polling\n"); +#endif + return (0); + } + return (uhci_intr1(sc)); +} + +int +uhci_intr1(uhci_softc_t *sc) +{ + int status; int ack; - uhci_intr_info_t *ii; /* * It can happen that an interrupt will be delivered to @@ -934,12 +1204,11 @@ #ifdef USB_DEBUG if (uhcidebug > 15) { - DPRINTF(("%s: uhci_intr\n", USBDEVNAME(sc->sc_bus.bdev))); + DPRINTF(("%s: uhci_intr1\n", USBDEVNAME(sc->sc_bus.bdev))); uhci_dumpregs(sc); } #endif - - status = UREAD2(sc, UHCI_STS); + status = UREAD2(sc, UHCI_STS) & UHCI_STS_ALLINTRS; if (status == 0) /* The interrupt was not for us. */ return (0); @@ -948,6 +1217,13 @@ printf("uhci_intr: suspended sts=0x%x\n", status); #endif + if (sc->sc_suspend != PWR_RESUME) { + printf("%s: interrupt while not operating ignored\n", + USBDEVNAME(sc->sc_bus.bdev)); + UWRITE2(sc, UHCI_STS, status); /* acknowledge the ints */ + return (0); + } + ack = 0; if (status & UHCI_STS_USBINT) ack |= UHCI_STS_USBINT; @@ -955,7 +1231,9 @@ ack |= UHCI_STS_USBEI; if (status & UHCI_STS_RD) { ack |= UHCI_STS_RD; +#ifdef USB_DEBUG printf("%s: resume detect\n", USBDEVNAME(sc->sc_bus.bdev)); +#endif } if (status & UHCI_STS_HSE) { ack |= UHCI_STS_HSE; @@ -963,22 +1241,43 @@ } if (status & UHCI_STS_HCPE) { ack |= UHCI_STS_HCPE; - printf("%s: host controller process error\n", + printf("%s: host controller process 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)); + if (!sc->sc_dying) { + printf("%s: host controller halted\n", + USBDEVNAME(sc->sc_bus.bdev)); +#ifdef USB_DEBUG + uhci_dump_all(sc); +#endif + } + sc->sc_dying = 1; } - if (ack) /* acknowledge the ints */ - UWRITE2(sc, UHCI_STS, ack); - else /* nothing to acknowledge */ - return (0); + if (!ack) + return (0); /* nothing to acknowledge */ + UWRITE2(sc, UHCI_STS, ack); /* acknowledge the ints */ - sc->sc_bus.intr_context++; sc->sc_bus.no_intrs++; + usb_schedsoftintr(&sc->sc_bus); + + DPRINTFN(10, ("%s: uhci_intr: exit\n", USBDEVNAME(sc->sc_bus.bdev))); + + return (1); +} + +void +uhci_softintr(void *v) +{ + uhci_softc_t *sc = v; + uhci_intr_info_t *ii; + + DPRINTFN(10,("%s: uhci_softintr (%d)\n", USBDEVNAME(sc->sc_bus.bdev), + sc->sc_bus.intr_context)); + + sc->sc_bus.intr_context++; /* * Interrupts on UHCI really suck. When the host controller @@ -991,14 +1290,17 @@ * We scan all interrupt descriptors to see if any have * completed. */ - for (ii = LIST_FIRST(&sc->sc_intrhead); ii; ii = LIST_NEXT(ii, list)) + LIST_FOREACH(ii, &sc->sc_intrhead, list) uhci_check_intr(sc, ii); - DPRINTFN(10, ("%s: uhci_intr: exit\n", USBDEVNAME(sc->sc_bus.bdev))); +#ifdef USB_USE_SOFTINTR + if (sc->sc_softwake) { + sc->sc_softwake = 0; + wakeup(&sc->sc_softwake); + } +#endif /* USB_USE_SOFTINTR */ sc->sc_bus.intr_context--; - - return (1); } /* Check for an interrupt. */ @@ -1015,6 +1317,12 @@ return; } #endif + if (ii->xfer->status == USBD_CANCELLED || + ii->xfer->status == USBD_TIMEOUT) { + DPRINTF(("uhci_check_intr: aborted xfer=%p\n", ii->xfer)); + return; + } + if (ii->stdstart == NULL) return; lstd = ii->stdend; @@ -1024,37 +1332,34 @@ 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 + * is 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)); + if (le32toh(lstd->td.td_status) & UHCI_TD_ACTIVE) { + DPRINTFN(12, ("uhci_check_intr: active ii=%p\n", ii)); for (std = ii->stdstart; std != lstd; std = std->link.std) { - status = LE(std->td.td_status); + status = le32toh(std->td.td_status); /* If there's an active TD the xfer isn't done. */ if (status & UHCI_TD_ACTIVE) break; /* Any kind of error makes the xfer done. */ if (status & UHCI_TD_STALLED) goto done; - /* - * We want short packets, - * and it is short: it's done - */ + /* We want short packets, and it is short: it's done */ if ((status & UHCI_TD_SPD) && - UHCI_TD_GET_ACTLEN(status) < - UHCI_TD_GET_MAXLEN(LE(std->td.td_token))) + UHCI_TD_GET_ACTLEN(status) < + UHCI_TD_GET_MAXLEN(le32toh(std->td.td_token))) goto done; } - DPRINTFN(15, ("uhci_check_intr: ii=%p std=%p still active\n", - ii, ii->stdstart)); + DPRINTFN(12, ("uhci_check_intr: ii=%p std=%p still active\n", + ii, ii->stdstart)); return; } -done: - - usb_untimeout(uhci_timeout, ii, ii->timeout_handle); + done: + DPRINTFN(12, ("uhci_check_intr: ii=%p done\n", ii)); + usb_uncallout(ii->xfer->timeout_handle, uhci_timeout, ii); uhci_idone(ii); } @@ -1068,12 +1373,18 @@ u_int32_t status = 0, nstatus; int actlen; + DPRINTFN(12, ("uhci_idone: ii=%p\n", ii)); #ifdef DIAGNOSTIC { int s = splhigh(); if (ii->isdone) { splx(s); +#ifdef USB_DEBUG + printf("uhci_idone: ii is done!\n "); + uhci_dump_ii(ii); +#else printf("uhci_idone: ii=%p is done!\n", ii); +#endif return; } ii->isdone = 1; @@ -1081,22 +1392,16 @@ } #endif - if (xfer->status == USBD_CANCELLED || - xfer->status == USBD_TIMEOUT) { - DPRINTF(("uhci_idone: aborted xfer=%p\n", xfer)); - return; - } - if (xfer->nframes != 0) { /* Isoc transfer, do things differently. */ uhci_soft_td_t **stds = upipe->u.iso.stds; - int i, n, nframes; + int i, n, nframes, len; DPRINTFN(5,("uhci_idone: ii=%p isoc ready\n", ii)); nframes = xfer->nframes; actlen = 0; - n = xfer->hcprivint; + n = UXFER(xfer)->curframe; for (i = 0; i < nframes; i++) { std = stds[n]; #ifdef USB_DEBUG @@ -1107,15 +1412,15 @@ #endif if (++n >= UHCI_VFRAMELIST_COUNT) n = 0; - status = LE(std->td.td_status); - actlen += UHCI_TD_GET_ACTLEN(status); + status = le32toh(std->td.td_status); + len = UHCI_TD_GET_ACTLEN(status); + xfer->frlengths[i] = len; + actlen += len; } upipe->u.iso.inuse -= nframes; xfer->actlen = actlen; xfer->status = USBD_NORMAL_COMPLETION; - xfer->hcpriv = ii; - usb_transfer_complete(xfer); - return; + goto end; } #ifdef USB_DEBUG @@ -1128,31 +1433,40 @@ /* The transfer is done, compute actual length and status. */ actlen = 0; for (std = ii->stdstart; std != NULL; std = std->link.std) { - nstatus = LE(std->td.td_status); + nstatus = le32toh(std->td.td_status); if (nstatus & UHCI_TD_ACTIVE) break; status = nstatus; - if (UHCI_TD_GET_PID(LE(std->td.td_token)) != UHCI_TD_PID_SETUP) + if (UHCI_TD_GET_PID(le32toh(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 != NULL) - upipe->nexttoggle = UHCI_TD_GET_DT(LE(std->td.td_token)); + upipe->nexttoggle = UHCI_TD_GET_DT(le32toh(std->td.td_token)); status &= UHCI_TD_ERROR; - DPRINTFN(10, ("uhci_check_intr: actlen=%d, status=0x%x\n", + DPRINTFN(10, ("uhci_idone: actlen=%d, status=0x%x\n", actlen, status)); xfer->actlen = actlen; if (status != 0) { +#ifdef USB_DEBUG + char sbuf[128]; + + bitmask_snprintf((u_int32_t)status, + "\20\22BITSTUFF\23CRCTO\24NAK\25" + "BABBLE\26DBUFFER\27STALLED\30ACTIVE", + sbuf, sizeof(sbuf)); + DPRINTFN((status == UHCI_TD_STALLED)*10, ("uhci_idone: error, addr=%d, endpt=0x%02x, " - "status 0x%b\n", + "status 0x%s\n", xfer->pipe->device->address, xfer->pipe->endpoint->edesc->bEndpointAddress, - (int)status, - "\20\22BITSTUFF\23CRCTO\24NAK\25BABBLE\26DBUFFER\27" - "STALLED\30ACTIVE")); + sbuf)); +#endif + if (status == UHCI_TD_STALLED) xfer->status = USBD_STALLED; else @@ -1160,8 +1474,10 @@ } else { xfer->status = USBD_NORMAL_COMPLETION; } - xfer->hcpriv = ii; + + end: usb_transfer_complete(xfer); + DPRINTFN(12, ("uhci_idone: ii=%p done\n", ii)); } /* @@ -1171,17 +1487,33 @@ uhci_timeout(void *addr) { uhci_intr_info_t *ii = addr; + struct uhci_xfer *uxfer = UXFER(ii->xfer); + struct uhci_pipe *upipe = (struct uhci_pipe *)uxfer->xfer.pipe; + uhci_softc_t *sc = (uhci_softc_t *)upipe->pipe.device->bus; - DPRINTF(("uhci_timeout: ii=%p\n", ii)); + DPRINTF(("uhci_timeout: uxfer=%p\n", uxfer)); -#ifdef USB_DEBUG - if (uhcidebug > 10) - uhci_dump_tds(ii->stdstart); -#endif + if (sc->sc_dying) { + uhci_abort_xfer(&uxfer->xfer, USBD_TIMEOUT); + return; + } - ii->xfer->device->bus->intr_context++; - uhci_abort_xfer(ii->xfer, USBD_TIMEOUT); - ii->xfer->device->bus->intr_context--; + /* Execute the abort in a process context. */ + usb_init_task(&uxfer->abort_task, uhci_timeout_task, ii->xfer); + usb_add_task(uxfer->xfer.pipe->device, &uxfer->abort_task); +} + +void +uhci_timeout_task(void *addr) +{ + usbd_xfer_handle xfer = addr; + int s; + + DPRINTF(("uhci_timeout_task: xfer=%p\n", xfer)); + + s = splusb(); + uhci_abort_xfer(xfer, USBD_TIMEOUT); + splx(s); } /* @@ -1203,7 +1535,7 @@ 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); + uhci_intr1(sc); if (xfer->status != USBD_IN_PROGRESS) return; } @@ -1211,12 +1543,12 @@ /* Timeout */ DPRINTF(("uhci_waitintr: timeout\n")); for (ii = LIST_FIRST(&sc->sc_intrhead); - ii != NULL && ii->xfer != xfer; + ii != NULL && ii->xfer != xfer; ii = LIST_NEXT(ii, list)) ; #ifdef DIAGNOSTIC if (ii == NULL) - panic("uhci_waitintr: lost intr_info\n"); + panic("uhci_waitintr: lost intr_info"); #endif uhci_idone(ii); } @@ -1227,26 +1559,23 @@ uhci_softc_t *sc = (uhci_softc_t *)bus; if (UREAD2(sc, UHCI_STS) & UHCI_STS_USBINT) - uhci_intr(sc); + uhci_intr1(sc); } -#if 0 void -uhci_reset(void *p) +uhci_reset(uhci_softc_t *sc) { - uhci_softc_t *sc = p; int n; UHCICMD(sc, UHCI_CMD_HCRESET); /* The reset bit goes low when the controller is done. */ - for (n = 0; n < UHCI_RESET_TIMEOUT && + for (n = 0; n < UHCI_RESET_TIMEOUT && (UREAD2(sc, UHCI_CMD) & UHCI_CMD_HCRESET); n++) - delay(100); + usb_delay_ms(&sc->sc_bus, 1); if (n >= UHCI_RESET_TIMEOUT) - printf("%s: controller did not reset\n", + printf("%s: controller did not reset\n", USBDEVNAME(sc->sc_bus.bdev)); } -#endif usbd_status uhci_run(uhci_softc_t *sc, int run) @@ -1255,7 +1584,7 @@ u_int16_t cmd; run = run != 0; - s = splusb(); + s = splhardusb(); DPRINTF(("uhci_run: setting run=%d\n", run)); cmd = UREAD2(sc, UHCI_CMD); if (run) @@ -1306,7 +1635,7 @@ 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 = KERNADDR(&dma, offs); std->physaddr = DMAADDR(&dma, offs); std->link.std = sc->sc_freetds; sc->sc_freetds = std; @@ -1323,11 +1652,11 @@ { #ifdef DIAGNOSTIC #define TD_IS_FREE 0x12345678 - if (std->td.td_token == LE(TD_IS_FREE)) { + if (le32toh(std->td.td_token) == TD_IS_FREE) { printf("uhci_free_std: freeing free TD %p\n", std); return; } - std->td.td_token = LE(TD_IS_FREE); + std->td.td_token = htole32(TD_IS_FREE); #endif std->link.std = sc->sc_freetds; sc->sc_freetds = std; @@ -1349,7 +1678,7 @@ 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 = KERNADDR(&dma, offs); sqh->physaddr = DMAADDR(&dma, offs); sqh->hlink = sc->sc_freeqhs; sc->sc_freeqhs = sqh; @@ -1368,22 +1697,9 @@ sc->sc_freeqhs = sqh; } -#if 0 -/* - * Enter a list of transfers onto a control queue. - * Called at splusb() - */ -void -uhci_enter_ctl_q(uhci_softc_t *sc, uhci_soft_qh_t *sqh, uhci_intr_info_t *ii) -{ - DPRINTFN(5, ("uhci_enter_ctl_q: sqh=%p\n", sqh)); - -} -#endif - void uhci_free_std_chain(uhci_softc_t *sc, uhci_soft_td_t *std, - uhci_soft_td_t *stdend) + uhci_soft_td_t *stdend) { uhci_soft_td_t *p; @@ -1394,9 +1710,9 @@ } usbd_status -uhci_alloc_std_chain(struct uhci_pipe *upipe, uhci_softc_t *sc, - int len, int rd, u_int16_t flags, usb_dma_t *dma, - uhci_soft_td_t **sp, uhci_soft_td_t **ep) +uhci_alloc_std_chain(struct uhci_pipe *upipe, uhci_softc_t *sc, int len, + int rd, u_int16_t flags, usb_dma_t *dma, + uhci_soft_td_t **sp, uhci_soft_td_t **ep) { uhci_soft_td_t *p, *lastp; uhci_physaddr_t lastlink; @@ -1405,9 +1721,9 @@ int addr = upipe->pipe.device->address; int endpt = upipe->pipe.endpoint->edesc->bEndpointAddress; - DPRINTFN(8, ("uhci_alloc_std_chain: addr=%d endpt=%d len=%d ls=%d " - "flags=0x%x\n", addr, UE_GET_ADDR(endpt), len, - upipe->pipe.device->lowspeed, flags)); + DPRINTFN(8, ("uhci_alloc_std_chain: addr=%d endpt=%d len=%d speed=%d " + "flags=0x%x\n", addr, UE_GET_ADDR(endpt), len, + upipe->pipe.device->speed, flags)); maxp = UGETW(upipe->pipe.endpoint->edesc->wMaxPacketSize); if (maxp == 0) { printf("uhci_alloc_std_chain: maxp=0\n"); @@ -1426,28 +1742,25 @@ if (ntd % 2 == 0) tog ^= 1; upipe->nexttoggle = tog ^ 1; - lastp = 0; + lastp = NULL; lastlink = UHCI_PTR_T; ntd--; status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(3) | UHCI_TD_ACTIVE); - if (upipe->pipe.device->lowspeed) + if (upipe->pipe.device->speed == USB_SPEED_LOW) status |= UHCI_TD_LS; if (flags & USBD_SHORT_XFER_OK) status |= UHCI_TD_SPD; for (i = ntd; i >= 0; i--) { p = uhci_alloc_std(sc); if (p == NULL) { - uhci_free_std_chain(sc, lastp, 0); + uhci_free_std_chain(sc, lastp, NULL); return (USBD_NOMEM); } p->link.std = lastp; - if (lastlink == UHCI_PTR_T) - p->td.td_link = LE(lastlink); - else - p->td.td_link = LE(lastlink|UHCI_PTR_VF); + p->td.td_link = htole32(lastlink | UHCI_PTR_VF | UHCI_PTR_TD); lastp = p; lastlink = p->physaddr; - p->td.td_status = LE(status); + p->td.td_status = htole32(status); if (i == ntd) { /* last TD */ l = len % maxp; @@ -1456,14 +1769,14 @@ *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)); + p->td.td_token = + htole32(rd ? UHCI_TD_IN (l, endpt, addr, tog) : + UHCI_TD_OUT(l, endpt, addr, tog)); + p->td.td_buffer = htole32(DMAADDR(dma, i * maxp)); tog ^= 1; } *sp = lastp; - DPRINTFN(10, ("uhci_alloc_std_chain: nexttog=%d\n", + DPRINTFN(10, ("uhci_alloc_std_chain: nexttog=%d\n", upipe->nexttoggle)); return (USBD_NORMAL_COMPLETION); } @@ -1490,8 +1803,9 @@ if (err) return (err); - /* Pipe isn't running (otherwise err would be USBD_INPROG), - * start first + /* + * Pipe isn't running (otherwise err would be USBD_INPROG), + * so start it first. */ return (uhci_device_bulk_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); } @@ -1502,23 +1816,26 @@ struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe; usbd_device_handle dev = upipe->pipe.device; uhci_softc_t *sc = (uhci_softc_t *)dev->bus; - uhci_intr_info_t *ii = upipe->iinfo; + uhci_intr_info_t *ii = &UXFER(xfer)->iinfo; uhci_soft_td_t *data, *dataend; uhci_soft_qh_t *sqh; usbd_status err; int len, isread, endpt; int s; - DPRINTFN(3, ("uhci_device_bulk_transfer: xfer=%p len=%d flags=%d\n", - xfer, xfer->length, xfer->flags)); + DPRINTFN(3, ("uhci_device_bulk_start: xfer=%p len=%d flags=%d ii=%p\n", + xfer, xfer->length, xfer->flags, ii)); + + if (sc->sc_dying) + return (USBD_IOERROR); #ifdef DIAGNOSTIC if (xfer->rqflags & URQ_REQUEST) - panic("uhci_device_bulk_transfer: a request\n"); + panic("uhci_device_bulk_transfer: a request"); #endif len = xfer->length; - endpt = xfer->pipe->endpoint->edesc->bEndpointAddress; + endpt = upipe->pipe.endpoint->edesc->bEndpointAddress; isread = UE_GET_DIR(endpt) == UE_DIR_IN; sqh = upipe->u.bulk.sqh; @@ -1529,7 +1846,7 @@ &xfer->dmabuf, &data, &dataend); if (err) return (err); - dataend->td.td_status |= LE(UHCI_TD_IOC); + dataend->td.td_status |= htole32(UHCI_TD_IOC); #ifdef USB_DEBUG if (uhcidebug > 8) { @@ -1542,9 +1859,6 @@ ii->xfer = xfer; ii->stdstart = data; ii->stdend = dataend; -#if defined(__FreeBSD__) - callout_handle_init(&ii->timeout_handle); -#endif #ifdef DIAGNOSTIC if (!ii->isdone) { printf("uhci_device_bulk_transfer: not done, ii=%p\n", ii); @@ -1553,17 +1867,17 @@ #endif sqh->elink = data; - sqh->qh.qh_elink = LE(data->physaddr); - sqh->intr_info = ii; + sqh->qh.qh_elink = htole32(data->physaddr | UHCI_PTR_TD); s = splusb(); uhci_add_bulk(sc, sqh); - LIST_INSERT_HEAD(&sc->sc_intrhead, ii, list); + uhci_add_intr_info(sc, ii); if (xfer->timeout && !sc->sc_bus.use_polling) { - usb_timeout(uhci_timeout, ii, MS_TO_TICKS(xfer->timeout), - ii->timeout_handle); + usb_callout(xfer->timeout_handle, MS_TO_TICKS(xfer->timeout), + uhci_timeout, ii); } + xfer->status = USBD_IN_PROGRESS; splx(s); #ifdef USB_DEBUG @@ -1587,54 +1901,78 @@ uhci_abort_xfer(xfer, USBD_CANCELLED); } +/* + * 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 uhci_abort_xfer(usbd_xfer_handle xfer, usbd_status status) { + uhci_intr_info_t *ii = &UXFER(xfer)->iinfo; struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe; - uhci_intr_info_t *ii = upipe->iinfo; + uhci_softc_t *sc = (uhci_softc_t *)upipe->pipe.device->bus; uhci_soft_td_t *std; + int s; DPRINTFN(1,("uhci_abort_xfer: xfer=%p, status=%d\n", xfer, status)); - /* Make interrupt routine ignore it, */ - xfer->status = status; - - /* don't timeout, */ - usb_untimeout(uhci_timeout, ii, ii->timeout_handle); + if (sc->sc_dying) { + /* If we're dying, just do the software part. */ + s = splusb(); + xfer->status = status; /* make software ignore it */ + usb_uncallout(xfer->timeout_handle, uhci_timeout, xfer); + usb_transfer_complete(xfer); + splx(s); + return; + } - /* 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)); + if (xfer->device->bus->intr_context || !curproc) + panic("uhci_abort_xfer: not in process context"); - xfer->hcpriv = ii; + /* + * Step 1: Make interrupt routine and hardware ignore xfer. + */ + s = splusb(); + xfer->status = status; /* make software ignore it */ + usb_uncallout(xfer->timeout_handle, uhci_timeout, ii); + DPRINTFN(1,("uhci_abort_xfer: stop ii=%p\n", ii)); + for (std = ii->stdstart; std != NULL; std = std->link.std) + std->td.td_status &= htole32(~(UHCI_TD_ACTIVE | UHCI_TD_IOC)); + splx(s); -#if 1 - /* Make sure hardware has completed. */ - if (xfer->device->bus->intr_context) { - /* We have no process context, so we can't use tsleep(). */ - timeout(uhci_abort_xfer_end, xfer, hz / USB_FRAMES_PER_SECOND); - } else { -#if defined(DIAGNOSTIC) && defined(__i386__) && defined(__FreeBSD__) - KASSERT(intr_nesting_level == 0, - ("ohci_abort_req in interrupt context")); -#endif - usb_delay_ms(xfer->pipe->device->bus, 1); - /* and call final part of interrupt handler. */ - uhci_abort_xfer_end(xfer); - } -#else - delay(1000); - uhci_abort_xfer_end(xfer); -#endif -} + /* + * Step 2: Wait until we know hardware has finished any possible + * use of the xfer. Also make sure the soft interrupt routine + * has run. + */ + usb_delay_ms(upipe->pipe.device->bus, 2); /* Hardware finishes in 1ms */ + s = splusb(); +#ifdef USB_USE_SOFTINTR + sc->sc_softwake = 1; +#endif /* USB_USE_SOFTINTR */ + usb_schedsoftintr(&sc->sc_bus); +#ifdef USB_USE_SOFTINTR + DPRINTFN(1,("uhci_abort_xfer: tsleep\n")); + tsleep(&sc->sc_softwake, PZERO, "uhciab", 0); +#endif /* USB_USE_SOFTINTR */ + splx(s); -void -uhci_abort_xfer_end(void *v) -{ - usbd_xfer_handle xfer = v; - int s; + /* + * Step 3: Execute callback. + */ + xfer->hcpriv = ii; + DPRINTFN(1,("uhci_abort_xfer: callback\n")); s = splusb(); +#ifdef DIAGNOSTIC + ii->isdone = 1; +#endif usb_transfer_complete(xfer); splx(s); } @@ -1648,8 +1986,6 @@ uhci_softc_t *sc = (uhci_softc_t *)dev->bus; uhci_free_sqh(sc, upipe->u.bulk.sqh); - uhci_free_intr_info(upipe->iinfo); - /* XXX free other resources */ } usbd_status @@ -1662,8 +1998,9 @@ if (err) return (err); - /* Pipe isn't running (otherwise err would be USBD_INPROG), - * start first + /* + * Pipe isn't running (otherwise err would be USBD_INPROG), + * so start it first. */ return (uhci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); } @@ -1674,9 +2011,12 @@ uhci_softc_t *sc = (uhci_softc_t *)xfer->pipe->device->bus; usbd_status err; + if (sc->sc_dying) + return (USBD_IOERROR); + #ifdef DIAGNOSTIC if (!(xfer->rqflags & URQ_REQUEST)) - panic("uhci_device_ctrl_transfer: not a request\n"); + panic("uhci_device_ctrl_transfer: not a request"); #endif err = uhci_device_request(xfer); @@ -1698,8 +2038,9 @@ if (err) return (err); - /* Pipe isn't running (otherwise err would be USBD_INPROG), - * start first + /* + * Pipe isn't running (otherwise err would be USBD_INPROG), + * so start it first. */ return (uhci_device_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); } @@ -1710,25 +2051,36 @@ struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe; usbd_device_handle dev = upipe->pipe.device; uhci_softc_t *sc = (uhci_softc_t *)dev->bus; - uhci_intr_info_t *ii = upipe->iinfo; + uhci_intr_info_t *ii = &UXFER(xfer)->iinfo; uhci_soft_td_t *data, *dataend; uhci_soft_qh_t *sqh; usbd_status err; + int isread, endpt; int i, s; + if (sc->sc_dying) + return (USBD_IOERROR); + DPRINTFN(3,("uhci_device_intr_transfer: xfer=%p len=%d flags=%d\n", xfer, xfer->length, xfer->flags)); #ifdef DIAGNOSTIC if (xfer->rqflags & URQ_REQUEST) - panic("uhci_device_intr_transfer: a request\n"); + panic("uhci_device_intr_transfer: a request"); #endif - err = uhci_alloc_std_chain(upipe, sc, xfer->length, 1, xfer->flags, - &xfer->dmabuf, &data, &dataend); + endpt = upipe->pipe.endpoint->edesc->bEndpointAddress; + isread = UE_GET_DIR(endpt) == UE_DIR_IN; + sqh = upipe->u.bulk.sqh; + + upipe->u.intr.isread = isread; + + err = uhci_alloc_std_chain(upipe, sc, xfer->length, isread, + xfer->flags, &xfer->dmabuf, &data, + &dataend); if (err) return (err); - dataend->td.td_status |= LE(UHCI_TD_IOC); + dataend->td.td_status |= htole32(UHCI_TD_IOC); #ifdef USB_DEBUG if (uhcidebug > 10) { @@ -1743,9 +2095,6 @@ ii->xfer = xfer; ii->stdstart = data; ii->stdend = dataend; -#if defined(__FreeBSD__) - callout_handle_init(&ii->timeout_handle); -#endif #ifdef DIAGNOSTIC if (!ii->isdone) { printf("uhci_device_intr_transfer: not done, ii=%p\n", ii); @@ -1753,13 +2102,15 @@ ii->isdone = 0; #endif - DPRINTFN(10,("uhci_device_intr_transfer: 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->elink = data; - sqh->qh.qh_elink = LE(data->physaddr); + sqh->qh.qh_elink = htole32(data->physaddr | UHCI_PTR_TD); } + uhci_add_intr_info(sc, ii); + xfer->status = USBD_IN_PROGRESS; splx(s); #ifdef USB_DEBUG @@ -1785,10 +2136,6 @@ void uhci_device_ctrl_close(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. */ @@ -1798,7 +2145,7 @@ DPRINTFN(1,("uhci_device_intr_abort: xfer=%p\n", xfer)); if (xfer->pipe->intrxfer == xfer) { DPRINTFN(1,("uhci_device_intr_abort: remove\n")); - xfer->pipe->intrxfer = 0; + xfer->pipe->intrxfer = NULL; } uhci_abort_xfer(xfer, USBD_CANCELLED); } @@ -1809,19 +2156,17 @@ { struct uhci_pipe *upipe = (struct uhci_pipe *)pipe; uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus; - int i, s, npoll; - - upipe->iinfo->stdstart = 0; /* inactive */ + int i, npoll; + int s; /* Unlink descriptors from controller data structures. */ npoll = upipe->u.intr.npoll; - uhci_lock_frames(sc); + s = splusb(); for (i = 0; i < npoll; i++) - uhci_remove_intr(sc, upipe->u.intr.qhs[i]->pos, - upipe->u.intr.qhs[i]); - uhci_unlock_frames(sc); + uhci_remove_intr(sc, upipe->u.intr.qhs[i]); + splx(s); - /* + /* * We now have to wait for any activity on the physical * descriptors to stop. */ @@ -1831,11 +2176,6 @@ uhci_free_sqh(sc, upipe->u.intr.qhs[i]); free(upipe->u.intr.qhs, M_USBHC); - s = splusb(); - LIST_REMOVE(upipe->iinfo, list); /* remove from active list */ - splx(s); - uhci_free_intr_info(upipe->iinfo); - /* XXX free other resources */ } @@ -1848,7 +2188,7 @@ 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_intr_info_t *ii = &UXFER(xfer)->iinfo; uhci_soft_td_t *setup, *data, *stat, *next, *dataend; uhci_soft_qh_t *sqh; int len; @@ -1863,7 +2203,7 @@ UGETW(req->wIndex), UGETW(req->wLength), addr, endpt)); - ls = dev->lowspeed ? UHCI_TD_LS : 0; + ls = dev->speed == USB_SPEED_LOW ? UHCI_TD_LS : 0; isread = req->bmRequestType & UT_READ; len = UGETW(req->wLength); @@ -1880,7 +2220,7 @@ return (err); next = data; dataend->link.std = stat; - dataend->td.td_link = LE(stat->physaddr | UHCI_PTR_VF); + dataend->td.td_link = htole32(stat->physaddr | UHCI_PTR_VF | UHCI_PTR_TD); } else { next = stat; } @@ -1889,19 +2229,20 @@ memcpy(KERNADDR(&upipe->u.ctl.reqdma, 0), req, sizeof *req); setup->link.std = next; - setup->td.td_link = LE(next->physaddr | UHCI_PTR_VF); - 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, 0)); - - stat->link.std = 0; - stat->td.td_link = LE(UHCI_PTR_T); - stat->td.td_status = LE(UHCI_TD_SET_ERRCNT(3) | ls | + setup->td.td_link = htole32(next->physaddr | UHCI_PTR_VF | UHCI_PTR_TD); + setup->td.td_status = htole32(UHCI_TD_SET_ERRCNT(3) | ls | + UHCI_TD_ACTIVE); + setup->td.td_token = htole32(UHCI_TD_SETUP(sizeof *req, endpt, addr)); + setup->td.td_buffer = htole32(DMAADDR(&upipe->u.ctl.reqdma, 0)); + + stat->link.std = NULL; + stat->td.td_link = htole32(UHCI_PTR_T); + stat->td.td_status = htole32(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); + stat->td.td_token = + htole32(isread ? UHCI_TD_OUT(0, endpt, addr, 1) : + UHCI_TD_IN (0, endpt, addr, 1)); + stat->td.td_buffer = htole32(0); #ifdef USB_DEBUG if (uhcidebug > 10) { @@ -1914,9 +2255,6 @@ ii->xfer = xfer; ii->stdstart = setup; ii->stdend = stat; -#if defined(__FreeBSD__) - callout_handle_init(&ii->timeout_handle); -#endif #ifdef DIAGNOSTIC if (!ii->isdone) { printf("uhci_device_request: not done, ii=%p\n", ii); @@ -1925,12 +2263,14 @@ #endif sqh->elink = setup; - sqh->qh.qh_elink = LE(setup->physaddr); - sqh->intr_info = ii; + sqh->qh.qh_elink = htole32(setup->physaddr | UHCI_PTR_TD); s = splusb(); - uhci_add_ctrl(sc, sqh); - LIST_INSERT_HEAD(&sc->sc_intrhead, ii, list); + if (dev->speed == USB_SPEED_LOW) + uhci_add_ls_ctrl(sc, sqh); + else + uhci_add_hs_ctrl(sc, sqh); + uhci_add_intr_info(sc, ii); #ifdef USB_DEBUG if (uhcidebug > 12) { uhci_soft_td_t *std; @@ -1940,17 +2280,17 @@ 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; + (link & UHCI_PTR_QH) == 0; std = std->link.std) { - link = LE(std->td.td_link); + link = le32toh(std->td.td_link); uhci_dump_td(std); } sxqh = (uhci_soft_qh_t *)std; uhci_dump_qh(sxqh); for (xqh = sxqh; xqh != NULL; - xqh = (maxqh++ == 5 || xqh->hlink==sxqh || - xqh->hlink==xqh ? NULL : xqh->hlink)) { + xqh = (maxqh++ == 5 || xqh->hlink == sxqh || + xqh->hlink == xqh ? NULL : xqh->hlink)) { uhci_dump_qh(xqh); } DPRINTF(("Enqueued QH:\n")); @@ -1959,9 +2299,10 @@ } #endif if (xfer->timeout && !sc->sc_bus.use_polling) { - usb_timeout(uhci_timeout, ii, - MS_TO_TICKS(xfer->timeout), ii->timeout_handle); + usb_callout(xfer->timeout_handle, MS_TO_TICKS(xfer->timeout), + uhci_timeout, ii); } + xfer->status = USBD_IN_PROGRESS; splx(s); return (USBD_NORMAL_COMPLETION); @@ -1986,7 +2327,7 @@ /* insert into schedule, */ uhci_device_isoc_enter(xfer); - /* and put on interrupt list if the pipe wasn't running */ + /* and start if the pipe wasn't running */ if (!err) uhci_device_isoc_start(SIMPLEQ_FIRST(&xfer->pipe->queue)); @@ -2000,7 +2341,7 @@ 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; + uhci_soft_td_t *std; u_int32_t buf, len, status; int s, i, next, nframes; @@ -2008,8 +2349,12 @@ "nframes=%d\n", iso->inuse, iso->next, xfer, xfer->nframes)); + if (sc->sc_dying) + return; + if (xfer->status == USBD_IN_PROGRESS) { /* This request has already been entered into the frame list */ + printf("uhci_device_isoc_enter: xfer=%p in frame list\n", xfer); /* XXX */ } @@ -2026,12 +2371,12 @@ } xfer->status = USBD_IN_PROGRESS; - xfer->hcprivint = next; + UXFER(xfer)->curframe = next; buf = DMAADDR(&xfer->dmabuf, 0); - status = LE(UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(0) | - UHCI_TD_ACTIVE | - UHCI_TD_IOS)); + status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(0) | + UHCI_TD_ACTIVE | + UHCI_TD_IOS); nframes = xfer->nframes; s = splusb(); for (i = 0; i < nframes; i++) { @@ -2039,12 +2384,12 @@ if (++next >= UHCI_VFRAMELIST_COUNT) next = 0; len = xfer->frlengths[i]; - std->td.td_buffer = LE(buf); + std->td.td_buffer = htole32(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)); + status |= UHCI_TD_IOC; + std->td.td_status = htole32(status); + std->td.td_token &= htole32(~UHCI_TD_MAXLEN_MASK); + std->td.td_token |= htole32(UHCI_TD_SET_MAXLEN(len)); #ifdef USB_DEBUG if (uhcidebug > 5) { DPRINTFN(5,("uhci_device_isoc_enter: TD %d\n", i)); @@ -2064,38 +2409,46 @@ { struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe; uhci_softc_t *sc = (uhci_softc_t *)upipe->pipe.device->bus; - uhci_intr_info_t *ii = upipe->iinfo; + uhci_intr_info_t *ii = &UXFER(xfer)->iinfo; uhci_soft_td_t *end; int s, i; + DPRINTFN(5,("uhci_device_isoc_start: xfer=%p\n", xfer)); + + if (sc->sc_dying) + return (USBD_IOERROR); + #ifdef DIAGNOSTIC if (xfer->status != USBD_IN_PROGRESS) printf("uhci_device_isoc_start: not in progress %p\n", xfer); #endif /* Find the last TD */ - i = xfer->hcprivint + xfer->nframes; + i = UXFER(xfer)->curframe + xfer->nframes; if (i >= UHCI_VFRAMELIST_COUNT) i -= UHCI_VFRAMELIST_COUNT; end = upipe->u.iso.stds[i]; +#ifdef DIAGNOSTIC + if (end == NULL) { + printf("uhci_device_isoc_start: end == NULL\n"); + return (USBD_INVAL); + } +#endif + s = splusb(); - + /* Set up interrupt info. */ ii->xfer = xfer; ii->stdstart = end; ii->stdend = end; -#if defined(__FreeBSD__) - callout_handle_init(&ii->timeout_handle); -#endif #ifdef DIAGNOSTIC - if (!ii->isdone) { + if (!ii->isdone) printf("uhci_device_isoc_start: not done, ii=%p\n", ii); - } ii->isdone = 0; #endif - LIST_INSERT_HEAD(&sc->sc_intrhead, ii, list); - + uhci_add_intr_info(sc, ii); + splx(s); return (USBD_IN_PROGRESS); @@ -2105,35 +2458,46 @@ uhci_device_isoc_abort(usbd_xfer_handle xfer) { struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->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; + int i, n, s, nframes, maxlen, len; + + s = splusb(); + + /* Transfer is already done. */ + if (xfer->status != USBD_NOT_STARTED && + xfer->status != USBD_IN_PROGRESS) { + splx(s); + return; + } - /* Make interrupt routine ignore it, */ + /* Give xfer the requested abort code. */ xfer->status = USBD_CANCELLED; /* make hardware ignore it, */ nframes = xfer->nframes; - n = xfer->hcprivint; + n = UXFER(xfer)->curframe; + maxlen = 0; for (i = 0; i < nframes; i++) { std = stds[n]; - std->td.td_status &= LE(~(UHCI_TD_ACTIVE | UHCI_TD_IOC)); + std->td.td_status &= htole32(~(UHCI_TD_ACTIVE | UHCI_TD_IOC)); + len = UHCI_TD_GET_MAXLEN(le32toh(std->td.td_token)); + if (len > maxlen) + maxlen = len; if (++n >= UHCI_VFRAMELIST_COUNT) n = 0; } - xfer->hcpriv = ii; + /* and wait until we are sure the hardware has finished. */ + delay(maxlen); - /* make sure hardware has completed, */ - if (xfer->device->bus->intr_context) { - /* We have no process context, so we can't use tsleep(). */ - timeout(uhci_abort_xfer_end, xfer, hz / USB_FRAMES_PER_SECOND); - } else { - usb_delay_ms(xfer->pipe->device->bus, 1); - /* and call final part of interrupt handler. */ - uhci_abort_xfer_end(xfer); - } +#ifdef DIAGNOSTIC + UXFER(xfer)->iinfo.isdone = 1; +#endif + /* Run callback and remove from interrupt list. */ + usb_transfer_complete(xfer); + + splx(s); } void @@ -2144,7 +2508,7 @@ uhci_softc_t *sc = (uhci_softc_t *)dev->bus; uhci_soft_td_t *std, *vstd; struct iso *iso; - int i; + int i, s; /* * Make sure all TDs are marked as inactive. @@ -2155,10 +2519,10 @@ iso = &upipe->u.iso; for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) - iso->stds[i]->td.td_status &= LE(~UHCI_TD_ACTIVE); + iso->stds[i]->td.td_status &= htole32(~UHCI_TD_ACTIVE); usb_delay_ms(&sc->sc_bus, 2); /* wait for completion */ - uhci_lock_frames(sc); + s = splusb(); for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) { std = iso->stds[i]; for (vstd = sc->sc_vframes[i].htd; @@ -2168,14 +2532,14 @@ if (vstd == NULL) { /*panic*/ printf("uhci_device_isoc_close: %p not found\n", std); - uhci_unlock_frames(sc); + splx(s); return; } vstd->link = std->link; vstd->td.td_link = std->td.td_link; uhci_free_std(sc, std); } - uhci_unlock_frames(sc); + splx(s); free(iso->stds, M_USBHC); } @@ -2192,36 +2556,36 @@ uhci_soft_td_t *std, *vstd; u_int32_t token; struct iso *iso; - int i; + int i, s; iso = &upipe->u.iso; iso->stds = malloc(UHCI_VFRAMELIST_COUNT * sizeof (uhci_soft_td_t *), M_USBHC, M_WAITOK); - token = LE(rd ? UHCI_TD_IN (0, endpt, addr, 0) : - UHCI_TD_OUT(0, endpt, addr, 0)); + token = rd ? UHCI_TD_IN (0, endpt, addr, 0) : + UHCI_TD_OUT(0, endpt, addr, 0); /* Allocate the TDs and mark as inactive; */ for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) { 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; + std->td.td_status = htole32(UHCI_TD_IOS); /* iso, inactive */ + std->td.td_token = htole32(token); iso->stds[i] = std; } /* Insert TDs into schedule. */ - uhci_lock_frames(sc); + s = splusb(); for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) { std = iso->stds[i]; 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); + vstd->td.td_link = htole32(std->physaddr | UHCI_PTR_TD); } - uhci_unlock_frames(sc); + splx(s); iso->next = -1; iso->inuse = 0; @@ -2238,43 +2602,79 @@ void uhci_device_isoc_done(usbd_xfer_handle xfer) { - uhci_intr_info_t *ii = xfer->hcpriv; + uhci_intr_info_t *ii = &UXFER(xfer)->iinfo; DPRINTFN(4, ("uhci_isoc_done: length=%d\n", xfer->actlen)); + if (ii->xfer != xfer) + /* Not on interrupt list, ignore it. */ + return; + + if (!uhci_active_intr_info(ii)) + return; + +#ifdef DIAGNOSTIC + if (xfer->busy_free != XFER_BUSY) { + printf("uhci_device_isoc_done: xfer=%p not busy 0x%08x\n", + xfer, xfer->busy_free); + return; + } + + if (ii->stdend == NULL) { + printf("uhci_device_isoc_done: xfer=%p stdend==NULL\n", xfer); +#ifdef USB_DEBUG + uhci_dump_ii(ii); +#endif + return; + } +#endif + /* Turn off the interrupt since it is active even if the TD is not. */ - ii->stdend->td.td_status &= LE(~UHCI_TD_IOC); + ii->stdend->td.td_status &= htole32(~UHCI_TD_IOC); + + uhci_del_intr_info(ii); /* remove from active list */ - LIST_REMOVE(ii, list); /* remove from active list */ +#ifdef DIAGNOSTIC + if (ii->stdend == NULL) { + printf("uhci_device_isoc_done: xfer=%p stdend==NULL\n", xfer); +#ifdef USB_DEBUG + uhci_dump_ii(ii); +#endif + return; + } +#endif } void uhci_device_intr_done(usbd_xfer_handle xfer) { - uhci_intr_info_t *ii = xfer->hcpriv; + uhci_intr_info_t *ii = &UXFER(xfer)->iinfo; uhci_softc_t *sc = ii->sc; struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe; uhci_soft_qh_t *sqh; int i, npoll; - DPRINTFN(5, ("uhci_intr_done: length=%d\n", xfer->actlen)); + DPRINTFN(5, ("uhci_device_intr_done: length=%d\n", xfer->actlen)); 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); + sqh->elink = NULL; + sqh->qh.qh_elink = htole32(UHCI_PTR_T); } - uhci_free_std_chain(sc, ii->stdstart, 0); + uhci_free_std_chain(sc, ii->stdstart, NULL); /* XXX Wasteful. */ if (xfer->pipe->repeat) { uhci_soft_td_t *data, *dataend; + DPRINTFN(5,("uhci_device_intr_done: requeing\n")); + /* This alloc cannot fail since we freed the chain above. */ - uhci_alloc_std_chain(upipe, sc, xfer->length, 1, xfer->flags, + uhci_alloc_std_chain(upipe, sc, xfer->length, + upipe->u.intr.isread, xfer->flags, &xfer->dmabuf, &data, &dataend); - dataend->td.td_status |= LE(UHCI_TD_IOC); + dataend->td.td_status |= htole32(UHCI_TD_IOC); #ifdef USB_DEBUG if (uhcidebug > 10) { @@ -2286,9 +2686,6 @@ ii->stdstart = data; ii->stdend = dataend; -#if defined(__FreeBSD__) - callout_handle_init(&ii->timeout_handle); -#endif #ifdef DIAGNOSTIC if (!ii->isdone) { printf("uhci_device_intr_done: not done, ii=%p\n", ii); @@ -2298,10 +2695,14 @@ for (i = 0; i < npoll; i++) { sqh = upipe->u.intr.qhs[i]; sqh->elink = data; - sqh->qh.qh_elink = LE(data->physaddr); + sqh->qh.qh_elink = htole32(data->physaddr | UHCI_PTR_TD); } + xfer->status = USBD_IN_PROGRESS; + /* The ii is already on the examined list, just leave it. */ } else { - ii->stdstart = 0; /* mark as inactive */ + DPRINTFN(5,("uhci_device_intr_done: removing\n")); + if (uhci_active_intr_info(ii)) + uhci_del_intr_info(ii); } } @@ -2309,79 +2710,91 @@ void uhci_device_ctrl_done(usbd_xfer_handle xfer) { - uhci_intr_info_t *ii = xfer->hcpriv; + uhci_intr_info_t *ii = &UXFER(xfer)->iinfo; uhci_softc_t *sc = ii->sc; struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe; #ifdef DIAGNOSTIC if (!(xfer->rqflags & URQ_REQUEST)) - panic("uhci_ctrl_done: not a request\n"); + panic("uhci_device_ctrl_done: not a request"); #endif - LIST_REMOVE(ii, list); /* remove from active list */ + if (!uhci_active_intr_info(ii)) + return; - uhci_remove_ctrl(sc, upipe->u.ctl.sqh); + uhci_del_intr_info(ii); /* remove from active list */ + + if (upipe->pipe.device->speed == USB_SPEED_LOW) + uhci_remove_ls_ctrl(sc, upipe->u.ctl.sqh); + else + uhci_remove_hs_ctrl(sc, upipe->u.ctl.sqh); if (upipe->u.ctl.length != 0) uhci_free_std_chain(sc, ii->stdstart->link.std, ii->stdend); - DPRINTFN(5, ("uhci_ctrl_done: length=%d\n", xfer->actlen)); + DPRINTFN(5, ("uhci_device_ctrl_done: length=%d\n", xfer->actlen)); } /* Deallocate request data structures */ void uhci_device_bulk_done(usbd_xfer_handle xfer) { - uhci_intr_info_t *ii = xfer->hcpriv; + uhci_intr_info_t *ii = &UXFER(xfer)->iinfo; uhci_softc_t *sc = ii->sc; struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe; - LIST_REMOVE(ii, list); /* remove from active list */ + DPRINTFN(5,("uhci_device_bulk_done: xfer=%p ii=%p sc=%p upipe=%p\n", + xfer, ii, sc, upipe)); + + if (!uhci_active_intr_info(ii)) + return; + + uhci_del_intr_info(ii); /* remove from active list */ uhci_remove_bulk(sc, upipe->u.bulk.sqh); - uhci_free_std_chain(sc, ii->stdstart, 0); + uhci_free_std_chain(sc, ii->stdstart, NULL); - DPRINTFN(5, ("uhci_bulk_done: length=%d\n", xfer->actlen)); + DPRINTFN(5, ("uhci_device_bulk_done: length=%d\n", xfer->actlen)); } /* Add interrupt QH, called with vflock. */ void -uhci_add_intr(uhci_softc_t *sc, int n, uhci_soft_qh_t *sqh) +uhci_add_intr(uhci_softc_t *sc, uhci_soft_qh_t *sqh) { - struct uhci_vframe *vf = &sc->sc_vframes[n]; + struct uhci_vframe *vf = &sc->sc_vframes[sqh->pos]; uhci_soft_qh_t *eqh; - DPRINTFN(4, ("uhci_add_intr: n=%d sqh=%p\n", n, sqh)); + DPRINTFN(4, ("uhci_add_intr: n=%d sqh=%p\n", sqh->pos, 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); + eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH); vf->eqh = sqh; vf->bandwidth++; } -/* Remove interrupt QH, called with vflock. */ +/* Remove interrupt QH. */ void -uhci_remove_intr(uhci_softc_t *sc, int n, uhci_soft_qh_t *sqh) +uhci_remove_intr(uhci_softc_t *sc, uhci_soft_qh_t *sqh) { - struct uhci_vframe *vf = &sc->sc_vframes[n]; + struct uhci_vframe *vf = &sc->sc_vframes[sqh->pos]; uhci_soft_qh_t *pqh; - DPRINTFN(4, ("uhci_remove_intr: n=%d sqh=%p\n", n, sqh)); + DPRINTFN(4, ("uhci_remove_intr: n=%d sqh=%p\n", sqh->pos, sqh)); - for (pqh = vf->hqh; pqh->hlink != sqh; pqh = pqh->hlink) -#if defined(DIAGNOSTIC) || defined(USB_DEBUG) - if (LE(pqh->qh.qh_hlink) & UHCI_PTR_T) { - DPRINTF(("uhci_remove_intr: QH not found\n")); - return; - } -#else - ; -#endif + /* See comment in uhci_remove_ctrl() */ + if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) { + sqh->qh.qh_elink = htole32(UHCI_PTR_T); + delay(UHCI_QH_REMOVE_DELAY); + } + + pqh = uhci_find_prev_qh(vf->hqh, sqh); pqh->hlink = sqh->hlink; pqh->qh.qh_hlink = sqh->qh.qh_hlink; + delay(UHCI_QH_REMOVE_DELAY); if (vf->eqh == sqh) vf->eqh = pqh; vf->bandwidth--; @@ -2394,7 +2807,7 @@ int i, npoll, s; u_int bestbw, bw, bestoffs, offs; - DPRINTFN(2, ("uhci_setintr: pipe=%p\n", upipe)); + DPRINTFN(2, ("uhci_device_setintr: pipe=%p\n", upipe)); if (ival == 0) { printf("uhci_setintr: 0 interval\n"); return (USBD_INVAL); @@ -2403,13 +2816,13 @@ 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(2, ("uhci_device_setintr: ival=%d npoll=%d\n", ival, npoll)); upipe->u.intr.npoll = npoll; - upipe->u.intr.qhs = + 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. */ @@ -2422,30 +2835,23 @@ bestoffs = offs; } } - DPRINTFN(1, ("uhci_setintr: bw=%d offs=%d\n", bestbw, bestoffs)); + DPRINTFN(1, ("uhci_device_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->elink = NULL; + sqh->qh.qh_elink = htole32(UHCI_PTR_T); sqh->pos = MOD(i * ival + bestoffs); - sqh->intr_info = upipe->iinfo; } #undef MOD s = splusb(); - LIST_INSERT_HEAD(&sc->sc_intrhead, upipe->iinfo, list); - splx(s); - - 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); + uhci_add_intr(sc, upipe->u.intr.qhs[i]); + splx(s); - DPRINTFN(5, ("uhci_setintr: returns %p\n", upipe)); + DPRINTFN(5, ("uhci_device_setintr: returns %p\n", upipe)); return (USBD_NORMAL_COMPLETION); } @@ -2460,8 +2866,12 @@ int ival; DPRINTFN(1, ("uhci_open: pipe=%p, addr=%d, endpt=%d (%d)\n", - pipe, pipe->device->address, + pipe, pipe->device->address, ed->bEndpointAddress, sc->sc_addr)); + + upipe->aborting = 0; + upipe->nexttoggle = 0; + if (pipe->device->address == sc->sc_addr) { switch (ed->bEndpointAddress) { case USB_CONTROL_ENDPOINT: @@ -2474,9 +2884,6 @@ return (USBD_INVAL); } } 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; @@ -2494,8 +2901,8 @@ uhci_free_std(sc, upipe->u.ctl.setup); goto bad; } - err = usb_allocmem(&sc->sc_bus, - sizeof(usb_device_request_t), + err = usb_allocmem(&sc->sc_bus, + sizeof(usb_device_request_t), 0, &upipe->u.ctl.reqdma); if (err) { uhci_free_sqh(sc, upipe->u.ctl.sqh); @@ -2524,7 +2931,6 @@ return (USBD_NORMAL_COMPLETION); bad: - uhci_free_intr_info(upipe->iinfo); return (USBD_NOMEM); } @@ -2606,6 +3012,101 @@ } /* + * The USB hub protocol requires that SET_FEATURE(PORT_RESET) also + * enables the port, and also states that SET_FEATURE(PORT_ENABLE) + * should not be used by the USB subsystem. As we cannot issue a + * SET_FEATURE(PORT_ENABLE) externally, we must ensure that the port + * will be enabled as part of the reset. + * + * On the VT83C572, the port cannot be successfully enabled until the + * outstanding "port enable change" and "connection status change" + * events have been reset. + */ +Static usbd_status +uhci_portreset(uhci_softc_t *sc, int index) +{ + int lim, port, x; + + if (index == 1) + port = UHCI_PORTSC1; + else if (index == 2) + port = UHCI_PORTSC2; + else + return (USBD_IOERROR); + + x = URWMASK(UREAD2(sc, port)); + UWRITE2(sc, port, x | UHCI_PORTSC_PR); + + usb_delay_ms(&sc->sc_bus, USB_PORT_ROOT_RESET_DELAY); + + DPRINTFN(3,("uhci port %d reset, status0 = 0x%04x\n", + index, UREAD2(sc, port))); + + x = URWMASK(UREAD2(sc, port)); + UWRITE2(sc, port, x & ~UHCI_PORTSC_PR); + + delay(100); + + DPRINTFN(3,("uhci port %d reset, status1 = 0x%04x\n", + index, UREAD2(sc, port))); + + x = URWMASK(UREAD2(sc, port)); + UWRITE2(sc, port, x | UHCI_PORTSC_PE); + + for (lim = 10; --lim > 0;) { + usb_delay_ms(&sc->sc_bus, USB_PORT_RESET_DELAY); + + x = UREAD2(sc, port); + + DPRINTFN(3,("uhci port %d iteration %u, status = 0x%04x\n", + index, lim, x)); + + if (!(x & UHCI_PORTSC_CCS)) { + /* + * No device is connected (or was disconnected + * during reset). Consider the port reset. + * The delay must be long enough to ensure on + * the initial iteration that the device + * connection will have been registered. 50ms + * appears to be sufficient, but 20ms is not. + */ + DPRINTFN(3,("uhci port %d loop %u, device detached\n", + index, lim)); + break; + } + + if (x & (UHCI_PORTSC_POEDC | UHCI_PORTSC_CSC)) { + /* + * Port enabled changed and/or connection + * status changed were set. Reset either or + * both raised flags (by writing a 1 to that + * bit), and wait again for state to settle. + */ + UWRITE2(sc, port, URWMASK(x) | + (x & (UHCI_PORTSC_POEDC | UHCI_PORTSC_CSC))); + continue; + } + + if (x & UHCI_PORTSC_PE) + /* Port is enabled */ + break; + + UWRITE2(sc, port, URWMASK(x) | UHCI_PORTSC_PE); + } + + DPRINTFN(3,("uhci port %d reset, status2 = 0x%04x\n", + index, UREAD2(sc, port))); + + if (lim <= 0) { + DPRINTFN(1,("uhci port %d reset timed out\n", index)); + return (USBD_TIMEOUT); + } + + sc->sc_isreset = 1; + return (USBD_NORMAL_COMPLETION); +} + +/* * Simulate a hardware hub by handling all the necessary requests. */ usbd_status @@ -2618,8 +3119,9 @@ if (err) return (err); - /* Pipe isn't running (otherwise err would be USBD_INPROG), - * start first + /* + * Pipe isn't running (otherwise err would be USBD_INPROG), + * so start it first. */ return (uhci_root_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); } @@ -2635,13 +3137,16 @@ usb_port_status_t ps; usbd_status err; + if (sc->sc_dying) + return (USBD_IOERROR); + #ifdef DIAGNOSTIC if (!(xfer->rqflags & URQ_REQUEST)) - panic("uhci_root_ctrl_transfer: not a request\n"); + panic("uhci_root_ctrl_transfer: not a request"); #endif req = &xfer->request; - DPRINTFN(2,("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)); len = UGETW(req->wLength); @@ -2656,7 +3161,7 @@ case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE): case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE): case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT): - /* + /* * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops * for the integrated root hub. */ @@ -2777,27 +3282,27 @@ } switch(value) { case UHF_PORT_ENABLE: - x = UREAD2(sc, port); + x = URWMASK(UREAD2(sc, port)); UWRITE2(sc, port, x & ~UHCI_PORTSC_PE); break; case UHF_PORT_SUSPEND: - x = UREAD2(sc, port); + x = URWMASK(UREAD2(sc, port)); UWRITE2(sc, port, x & ~UHCI_PORTSC_SUSP); break; case UHF_PORT_RESET: - x = UREAD2(sc, port); + x = URWMASK(UREAD2(sc, port)); UWRITE2(sc, port, x & ~UHCI_PORTSC_PR); break; case UHF_C_PORT_CONNECTION: - x = UREAD2(sc, port); + x = URWMASK(UREAD2(sc, port)); UWRITE2(sc, port, x | UHCI_PORTSC_CSC); break; case UHF_C_PORT_ENABLE: - x = UREAD2(sc, port); + x = URWMASK(UREAD2(sc, port)); UWRITE2(sc, port, x | UHCI_PORTSC_POEDC); break; case UHF_C_PORT_OVER_CURRENT: - x = UREAD2(sc, port); + x = URWMASK(UREAD2(sc, port)); UWRITE2(sc, port, x | UHCI_PORTSC_OCIC); break; case UHF_C_PORT_RESET: @@ -2824,7 +3329,7 @@ goto ret; } if (len > 0) { - *(u_int8_t *)buf = + *(u_int8_t *)buf = (UREAD2(sc, port) & UHCI_PORTSC_LS) >> UHCI_PORTSC_LS_SHIFT; totlen = 1; @@ -2862,21 +3367,21 @@ } x = UREAD2(sc, port); status = change = 0; - if (x & UHCI_PORTSC_CCS ) + if (x & UHCI_PORTSC_CCS) status |= UPS_CURRENT_CONNECT_STATUS; - if (x & UHCI_PORTSC_CSC ) + if (x & UHCI_PORTSC_CSC) change |= UPS_C_CONNECT_STATUS; - if (x & UHCI_PORTSC_PE ) + if (x & UHCI_PORTSC_PE) status |= UPS_PORT_ENABLED; - if (x & UHCI_PORTSC_POEDC) + if (x & UHCI_PORTSC_POEDC) change |= UPS_C_PORT_ENABLED; - if (x & UHCI_PORTSC_OCI ) + if (x & UHCI_PORTSC_OCI) status |= UPS_OVERCURRENT_INDICATOR; - if (x & UHCI_PORTSC_OCIC ) + if (x & UHCI_PORTSC_OCIC) change |= UPS_C_OVERCURRENT_INDICATOR; - if (x & UHCI_PORTSC_SUSP ) + if (x & UHCI_PORTSC_SUSP) status |= UPS_SUSPEND; - if (x & UHCI_PORTSC_LSDA ) + if (x & UHCI_PORTSC_LSDA) status |= UPS_LOW_SPEED; status |= UPS_PORT_POWER; if (sc->sc_isreset) @@ -2903,26 +3408,16 @@ } switch(value) { case UHF_PORT_ENABLE: - x = UREAD2(sc, port); + x = URWMASK(UREAD2(sc, port)); UWRITE2(sc, port, x | UHCI_PORTSC_PE); break; case UHF_PORT_SUSPEND: - x = UREAD2(sc, port); + x = URWMASK(UREAD2(sc, port)); UWRITE2(sc, port, x | UHCI_PORTSC_SUSP); break; case UHF_PORT_RESET: - x = UREAD2(sc, port); - UWRITE2(sc, port, x | UHCI_PORTSC_PR); - usb_delay_ms(&sc->sc_bus, 10); - UWRITE2(sc, port, x & ~UHCI_PORTSC_PR); - delay(100); - x = UREAD2(sc, port); - UWRITE2(sc, port, x | UHCI_PORTSC_PE); - delay(100); - DPRINTFN(3,("uhci port %d reset, status = 0x%04x\n", - index, UREAD2(sc, port))); - sc->sc_isreset = 1; - break; + err = uhci_portreset(sc, index); + goto ret; case UHF_PORT_POWER: /* Pretend we turned on power */ err = USBD_NORMAL_COMPLETION; @@ -2948,7 +3443,6 @@ err = USBD_NORMAL_COMPLETION; ret: xfer->status = err; - xfer->hcpriv = 0; s = splusb(); usb_transfer_complete(xfer); splx(s); @@ -2975,14 +3469,17 @@ { uhci_softc_t *sc = (uhci_softc_t *)xfer->pipe->device->bus; - usb_untimeout(uhci_timo, xfer, xfer->timo_handle); - sc->sc_has_timo = NULL; + usb_uncallout(sc->sc_poll_handle, uhci_poll_hub, xfer); + sc->sc_intr_xfer = NULL; if (xfer->pipe->intrxfer == xfer) { DPRINTF(("uhci_root_intr_abort: remove\n")); xfer->pipe->intrxfer = 0; } xfer->status = USBD_CANCELLED; +#ifdef DIAGNOSTIC + UXFER(xfer)->iinfo.isdone = 1; +#endif usb_transfer_complete(xfer); } @@ -2996,8 +3493,9 @@ if (err) return (err); - /* Pipe isn't running (otherwise err would be USBD_INPROG), - * start first + /* + * Pipe isn't running (otherwise err would be USBD_INPROG), + * so start it first. */ return (uhci_root_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); } @@ -3009,12 +3507,15 @@ usbd_pipe_handle pipe = xfer->pipe; uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus; - DPRINTFN(3, ("uhci_root_intr_transfer: xfer=%p len=%d flags=%d\n", + DPRINTFN(3, ("uhci_root_intr_start: xfer=%p len=%d flags=%d\n", xfer, xfer->length, xfer->flags)); + if (sc->sc_dying) + return (USBD_IOERROR); + sc->sc_ival = MS_TO_TICKS(xfer->pipe->endpoint->edesc->bInterval); - usb_timeout(uhci_timo, xfer, sc->sc_ival, xfer->timo_handle); - sc->sc_has_timo = xfer; + usb_callout(sc->sc_poll_handle, sc->sc_ival, uhci_poll_hub, xfer); + sc->sc_intr_xfer = xfer; return (USBD_IN_PROGRESS); } @@ -3024,7 +3525,7 @@ { uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus; - usb_untimeout(uhci_timo, pipe->intrxfer, pipe->intrxfer->timo_handle); - sc->sc_has_timo = NULL; + usb_uncallout(sc->sc_poll_handle, uhci_poll_hub, sc->sc_intr_xfer); + sc->sc_intr_xfer = NULL; DPRINTF(("uhci_root_intr_close\n")); } Index: sys/dev/usb/uhcireg.h =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/uhcireg.h,v retrieving revision 1.14.2.1 diff -u -r1.14.2.1 uhcireg.h --- sys/dev/usb/uhcireg.h 2 Jul 2000 11:43:59 -0000 1.14.2.1 +++ sys/dev/usb/uhcireg.h 4 Oct 2003 18:54:40 -0000 @@ -1,5 +1,5 @@ -/* $NetBSD: uhcireg.h,v 1.9 1999/11/20 00:57:09 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/uhcireg.h,v 1.14.2.1 2000/07/02 11:43:59 n_hibma Exp $ */ +/* $NetBSD: uhcireg.h,v 1.15 2002/02/11 11:41:30 augustss Exp $ */ +/* $FreeBSD: src/sys/dev/usb/uhcireg.h,v 1.21 2003/07/04 01:50:38 jmg Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -75,6 +75,7 @@ #define UHCI_STS_HSE 0x0008 #define UHCI_STS_HCPE 0x0010 #define UHCI_STS_HCH 0x0020 +#define UHCI_STS_ALLINTRS 0x003f #define UHCI_INTR 0x04 #define UHCI_INTR_TOCRCIE 0x0001 @@ -84,7 +85,6 @@ #define UHCI_FRNUM 0x06 #define UHCI_FRNUM_MASK 0x03ff - #define UHCI_FLBASEADDR 0x08 @@ -106,6 +106,9 @@ #define UHCI_PORTSC_OCIC 0x0800 #define UHCI_PORTSC_SUSP 0x1000 +#define URWMASK(x) \ + ((x) & (UHCI_PORTSC_SUSP | UHCI_PORTSC_PR | UHCI_PORTSC_RD | UHCI_PORTSC_PE)) + #define UHCI_FRAMELIST_COUNT 1024 #define UHCI_FRAMELIST_ALIGN 4096 @@ -114,12 +117,19 @@ typedef u_int32_t uhci_physaddr_t; #define UHCI_PTR_T 0x00000001 -#define UHCI_PTR_Q 0x00000002 +#define UHCI_PTR_TD 0x00000000 +#define UHCI_PTR_QH 0x00000002 #define UHCI_PTR_VF 0x00000004 /* - * The Queue Heads and Transfer Descriptors and accessed - * by both the CPU and the USB controller which runs + * Wait this long after a QH has been removed. This gives that HC a + * chance to stop looking at it before it's recycled. + */ +#define UHCI_QH_REMOVE_DELAY 5 + +/* + * The Queue Heads and Transfer Descriptors are accessed + * by both the CPU and the USB controller which run * concurrently. This means that they have to be accessed * with great care. As long as the data structures are * not linked into the controller's frame list they cannot Index: sys/dev/usb/uhcivar.h =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/uhcivar.h,v retrieving revision 1.16.2.5 diff -u -r1.16.2.5 uhcivar.h --- sys/dev/usb/uhcivar.h 31 Oct 2000 23:23:29 -0000 1.16.2.5 +++ sys/dev/usb/uhcivar.h 4 Oct 2003 18:54:40 -0000 @@ -1,5 +1,5 @@ -/* $NetBSD: uhcivar.h,v 1.21 2000/01/18 20:11:01 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/uhcivar.h,v 1.16.2.5 2000/10/31 23:23:29 n_hibma Exp $ */ +/* $NetBSD: uhcivar.h,v 1.33 2002/02/11 11:41:30 augustss Exp $ */ +/* $FreeBSD: src/sys/dev/usb/uhcivar.h,v 1.36 2003/07/15 23:19:49 jmg Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -41,13 +41,14 @@ /* * To avoid having 1024 TDs for each isochronous transfer we introduce * 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. + * frame list points to a non-active TD. These, in turn, form the + * starts of the virtual frame list. This also has the advantage that it + * simplifies linking in/out of TDs/QHs 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. + * traffic. This QH points at another QH which is the start of the + * bulk traffic. * * UHCI_VFRAMELIST_COUNT should be a power of 2 and <= UHCI_FRAMELIST_COUNT. */ @@ -74,14 +75,20 @@ uhci_soft_td_t *stdstart; uhci_soft_td_t *stdend; LIST_ENTRY(uhci_intr_info) list; -#if defined(__FreeBSD__) - struct callout_handle timeout_handle; -#endif /* defined(__FreeBSD__) */ #ifdef DIAGNOSTIC int isdone; #endif } uhci_intr_info_t; +struct uhci_xfer { + struct usbd_xfer xfer; + uhci_intr_info_t iinfo; + struct usb_task abort_task; + int curframe; +}; + +#define UXFER(xfer) ((struct uhci_xfer *)(xfer)) + /* * Extra information that we need for a TD. */ @@ -90,14 +97,14 @@ uhci_soft_td_qh_t link; /* soft version of the td_link field */ uhci_physaddr_t physaddr; /* TD's physical address. */ }; -/* +/* * 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 TD 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)*/ +#define UHCI_STD_CHUNK (PAGE_SIZE / UHCI_STD_SIZE) /* * Extra information that we need for a QH. @@ -108,12 +115,10 @@ 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 */ }; /* 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)*/ +#define UHCI_SQH_CHUNK (PAGE_SIZE / UHCI_SQH_SIZE) /* * Information about an entry in the virtual frame list. @@ -130,6 +135,7 @@ struct usbd_bus sc_bus; /* base device */ bus_space_tag_t iot; bus_space_handle_t ioh; + bus_size_t sc_size; #if defined(__FreeBSD__) void *ih; @@ -141,10 +147,14 @@ usb_dma_t sc_dma; struct uhci_vframe sc_vframes[UHCI_VFRAMELIST_COUNT]; - uhci_soft_qh_t *sc_ctl_start; /* dummy QH for control */ - uhci_soft_qh_t *sc_ctl_end; /* last control QH */ + uhci_soft_qh_t *sc_lctl_start; /* dummy QH for low speed control */ + uhci_soft_qh_t *sc_lctl_end; /* last control QH */ + uhci_soft_qh_t *sc_hctl_start; /* dummy QH for high speed control */ + uhci_soft_qh_t *sc_hctl_end; /* last control QH */ uhci_soft_qh_t *sc_bulk_start; /* dummy QH for bulk */ uhci_soft_qh_t *sc_bulk_end; /* last bulk transfer */ + uhci_soft_qh_t *sc_last_qh; /* dummy QH at the end */ + u_int32_t sc_loops; /* number of QHs that wants looping */ uhci_soft_td_t *sc_freetds; /* TD free list */ uhci_soft_qh_t *sc_freeqhs; /* QH free list */ @@ -157,18 +167,20 @@ u_int8_t sc_saved_sof; u_int16_t sc_saved_frnum; +#ifdef USB_USE_SOFTINTR + char sc_softwake; +#endif /* USB_USE_SOFTINTR */ + char sc_isreset; char sc_suspend; + char sc_dying; LIST_HEAD(, uhci_intr_info) sc_intrhead; /* Info for the root hub interrupt channel. */ - int sc_ival; /* time between root hug intrs */ - usbd_xfer_handle sc_has_timo; /* root hub interrupt transfer */ - - char sc_vflock; /* for lock virtual frame list */ -#define UHCI_HAS_LOCK 1 -#define UHCI_WANT_LOCK 2 + int sc_ival; /* time between root hub intrs */ + usbd_xfer_handle sc_intr_xfer; /* root hub interrupt transfer */ + usb_callout_t sc_poll_handle; char sc_vendor[16]; /* vendor string for root hub */ int sc_id_vendor; /* vendor ID for root hub */ @@ -178,7 +190,7 @@ void *sc_shutdownhook; /* cookie from shutdown hook */ #endif - device_ptr_t sc_child; /* /dev/usb device */ + device_ptr_t sc_child; /* /dev/usb# device */ } uhci_softc_t; usbd_status uhci_init(uhci_softc_t *); Index: sys/dev/usb/uhid.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/uhid.c,v retrieving revision 1.27.2.12 diff -u -r1.27.2.12 uhid.c --- sys/dev/usb/uhid.c 6 Nov 2002 20:23:50 -0000 1.27.2.12 +++ sys/dev/usb/uhid.c 4 Oct 2003 21:27:28 -0000 @@ -1,5 +1,11 @@ -/* $NetBSD: uhid.c,v 1.38 2000/04/27 15:26:48 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/uhid.c,v 1.27.2.12 2002/11/06 20:23:50 joe Exp $ */ +/* $NetBSD: uhid.c,v 1.46 2001/11/13 06:24:55 lukem Exp $ */ + +/* Also already merged from NetBSD: + * $NetBSD: uhid.c,v 1.54 2002/09/23 05:51:21 simonb Exp $ + */ + +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/uhid.c,v 1.64 2003/10/04 21:41:01 joe Exp $"); /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -45,11 +51,16 @@ #include #include #include +#include #include +#if __FreeBSD_version >= 500000 +#include +#endif #include #if defined(__NetBSD__) || defined(__OpenBSD__) #include #include +#include #elif defined(__FreeBSD__) #include #include @@ -59,8 +70,11 @@ #endif #include #include -#include +#if __FreeBSD_version >= 500014 +#include +#else #include +#endif #include #include #include @@ -69,13 +83,13 @@ #include #include +#include #include #include #include -#if defined(__FreeBSD__) && defined(__i386__) -#include -#endif +/* Report descriptor for broken Wacom Graphire */ +#include #ifdef USB_DEBUG #define DPRINTF(x) if (uhiddebug) logprintf x @@ -143,20 +157,17 @@ #define UHID_CDEV_MAJOR 122 Static struct cdevsw uhid_cdevsw = { - /* open */ uhidopen, - /* close */ uhidclose, - /* read */ uhidread, - /* write */ uhidwrite, - /* ioctl */ uhidioctl, - /* poll */ uhidpoll, - /* mmap */ nommap, - /* strategy */ nostrategy, - /* name */ "uhid", - /* maj */ UHID_CDEV_MAJOR, - /* dump */ nodump, - /* psize */ nopsize, - /* flags */ 0, - /* bmaj */ -1 + .d_open = uhidopen, + .d_close = uhidclose, + .d_read = uhidread, + .d_write = uhidwrite, + .d_ioctl = uhidioctl, + .d_poll = uhidpoll, + .d_name = "uhid", + .d_maj = UHID_CDEV_MAJOR, +#if __FreeBSD_version < 500014 + .d_bmaj -1 +#endif }; #endif @@ -166,7 +177,7 @@ Static int uhid_do_read(struct uhid_softc *, struct uio *uio, int); Static int uhid_do_write(struct uhid_softc *, struct uio *uio, int); Static int uhid_do_ioctl(struct uhid_softc *, u_long, caddr_t, int, - usb_proc_ptr); + usb_proc_ptr); USB_DECLARE_DRIVER(uhid); @@ -174,12 +185,14 @@ { USB_MATCH_START(uhid, uaa); usb_interface_descriptor_t *id; - + if (uaa->iface == NULL) return (UMATCH_NONE); id = usbd_get_interface_descriptor(uaa->iface); if (id == NULL || id->bInterfaceClass != UICLASS_HID) return (UMATCH_NONE); + if (uaa->matchlvl) + return (uaa->matchlvl); return (UMATCH_IFACECLASS_GENERIC); } @@ -193,7 +206,7 @@ void *desc; usbd_status err; char devinfo[1024]; - + sc->sc_udev = uaa->device; sc->sc_iface = iface; id = usbd_get_interface_descriptor(iface); @@ -213,7 +226,7 @@ DPRINTFN(10,("uhid_attach: bLength=%d bDescriptorType=%d " "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d" " bInterval=%d\n", - ed->bLength, ed->bDescriptorType, + ed->bLength, ed->bDescriptorType, ed->bEndpointAddress & UE_ADDR, UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out", ed->bmAttributes & UE_XFERTYPE, @@ -228,14 +241,29 @@ sc->sc_ep_addr = ed->bEndpointAddress; - desc = 0; - err = usbd_alloc_report_desc(uaa->iface, &desc, &size, M_USBDEV); + if (uaa->vendor == USB_VENDOR_WACOM && + uaa->product == USB_PRODUCT_WACOM_GRAPHIRE /* && + uaa->revision == 0x???? */) { /* XXX should use revision */ + /* The report descriptor for the Wacom Graphire is broken. */ + size = sizeof uhid_graphire_report_descr; + desc = malloc(size, M_USBDEV, M_NOWAIT); + if (desc == NULL) + err = USBD_NOMEM; + else { + err = USBD_NORMAL_COMPLETION; + memcpy(desc, uhid_graphire_report_descr, size); + } + } else { + desc = NULL; + err = usbd_read_report_desc(uaa->iface, &desc, &size,M_USBDEV); + } + if (err) { printf("%s: no report descriptor\n", USBDEVNAME(sc->sc_dev)); sc->sc_dying = 1; USB_ATTACH_ERROR_RETURN; } - + (void)usbd_set_idle(iface, 0, 0); sc->sc_isize = hid_report_size(desc, size, hid_input, &sc->sc_iid); @@ -263,7 +291,6 @@ switch (act) { case DVACT_ACTIVATE: return (EOPNOTSUPP); - break; case DVACT_DEACTIVATE: sc->sc_dying = 1; @@ -321,7 +348,8 @@ destroy_dev(sc->dev); #endif - free(sc->sc_repdesc, M_USBDEV); + if (sc->sc_repdesc) + free(sc->sc_repdesc, M_USBDEV); return (0); } @@ -334,7 +362,7 @@ #ifdef USB_DEBUG if (uhiddebug > 5) { u_int32_t cc, i; - + usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL); DPRINTF(("uhid_intr: status=%d cc=%d\n", status, cc)); DPRINTF(("uhid_intr: data =")); @@ -349,21 +377,24 @@ if (status != USBD_NORMAL_COMPLETION) { DPRINTF(("uhid_intr: status=%d\n", status)); - sc->sc_state |= UHID_NEEDCLEAR; + if (status == USBD_STALLED) + sc->sc_state |= UHID_NEEDCLEAR; return; } (void) b_to_q(sc->sc_ibuf, sc->sc_isize, &sc->sc_q); - + if (sc->sc_state & UHID_ASLP) { sc->sc_state &= ~UHID_ASLP; - DPRINTFN(5, ("uhid_intr: waking %p\n", sc)); + DPRINTFN(5, ("uhid_intr: waking %p\n", &sc->sc_q)); wakeup(&sc->sc_q); } selwakeup(&sc->sc_rsel); if (sc->sc_async != NULL) { DPRINTFN(3, ("uhid_intr: sending SIGIO %p\n", sc->sc_async)); + PROC_LOCK(sc->sc_async); psignal(sc->sc_async, SIGIO); + PROC_UNLOCK(sc->sc_async); } } @@ -372,18 +403,6 @@ { struct uhid_softc *sc; usbd_status err; -#if defined(__FreeBSD__) && defined(__i386__) - static int hid_opened; - - if (hid_opened == 0) { - int s; - s = splhigh(); - tty_imask |= bio_imask; - update_intr_masks(); - splx(s); - hid_opened = 1; - } -#endif USB_GET_SC_OPEN(uhid, UHIDUNIT(dev), sc); @@ -405,14 +424,16 @@ sc->sc_obuf = malloc(sc->sc_osize, M_USBDEV, M_WAITOK); /* Set up interrupt pipe. */ - err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ep_addr, - USBD_SHORT_XFER_OK, &sc->sc_intrpipe, sc, sc->sc_ibuf, + err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ep_addr, + USBD_SHORT_XFER_OK, &sc->sc_intrpipe, sc, sc->sc_ibuf, sc->sc_isize, uhid_intr, USBD_DEFAULT_INTERVAL); if (err) { DPRINTF(("uhidopen: usbd_open_pipe_intr failed, " "error=%d\n",err)); free(sc->sc_ibuf, M_USBDEV); free(sc->sc_obuf, M_USBDEV); + sc->sc_ibuf = sc->sc_obuf = NULL; + sc->sc_state &= ~UHID_OPEN; return (EIO); } @@ -443,6 +464,7 @@ free(sc->sc_ibuf, M_USBDEV); free(sc->sc_obuf, M_USBDEV); + sc->sc_ibuf = sc->sc_obuf = NULL; sc->sc_state &= ~UHID_OPEN; @@ -463,7 +485,7 @@ DPRINTFN(1, ("uhidread\n")); if (sc->sc_state & UHID_IMMED) { DPRINTFN(1, ("uhidread immed\n")); - + err = usbd_get_report(sc->sc_iface, UHID_INPUT_REPORT, sc->sc_iid, buffer, sc->sc_isize); if (err) @@ -478,7 +500,7 @@ return (EWOULDBLOCK); } sc->sc_state |= UHID_ASLP; - DPRINTFN(5, ("uhidread: sleep on %p\n", sc)); + DPRINTFN(5, ("uhidread: sleep on %p\n", &sc->sc_q)); error = tsleep(&sc->sc_q, PZERO | PCATCH, "uhidrea", 0); DPRINTFN(5, ("uhidread: woke, error=%d\n", error)); if (sc->sc_dying) @@ -536,7 +558,7 @@ usbd_status err; DPRINTFN(1, ("uhidwrite\n")); - + if (sc->sc_dying) return (EIO); @@ -597,8 +619,12 @@ if (*(int *)addr) { if (sc->sc_async != NULL) return (EBUSY); +#if __FreeBSD_version >= 500000 + sc->sc_async = p->td_proc; +#else sc->sc_async = p; - DPRINTF(("uhid_do_ioctl: FIOASYNC %p\n", p)); +#endif + DPRINTF(("uhid_do_ioctl: FIOASYNC %p\n", sc->sc_async)); } else sc->sc_async = NULL; break; @@ -677,6 +703,10 @@ size); if (err) return (EIO); + break; + + case USB_GET_REPORT_ID: + *(int *)addr = 0; /* XXX: we only support reportid 0? */ break; default: Index: sys/dev/usb/uhub.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/uhub.c,v retrieving revision 1.21.2.7 diff -u -r1.21.2.7 uhub.c --- sys/dev/usb/uhub.c 6 Nov 2002 20:23:50 -0000 1.21.2.7 +++ sys/dev/usb/uhub.c 4 Oct 2003 18:54:40 -0000 @@ -1,5 +1,4 @@ -/* $NetBSD: uhub.c,v 1.47 2000/09/24 02:08:38 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/uhub.c,v 1.21.2.7 2002/11/06 20:23:50 joe Exp $ */ +/* $NetBSD: uhub.c,v 1.64 2003/02/08 03:32:51 ichiro Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -38,8 +37,11 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/uhub.c,v 1.54 2003/08/24 17:55:55 obrien Exp $"); + /* - * USB spec: http://www.usb.org/developers/docs.htm + * USB spec: http://www.usb.org/developers/docs/usbspec.zip */ #include @@ -53,8 +55,8 @@ #include #include #include "bus_if.h" -#include #endif +#include #include @@ -68,10 +70,10 @@ #ifdef USB_DEBUG #define DPRINTF(x) if (uhubdebug) logprintf x #define DPRINTFN(n,x) if (uhubdebug>(n)) logprintf x -static int uhubdebug = 0; +int uhubdebug = 0; SYSCTL_NODE(_hw_usb, OID_AUTO, uhub, CTLFLAG_RW, 0, "USB uhub"); SYSCTL_INT(_hw_usb_uhub, OID_AUTO, debug, CTLFLAG_RW, - &uhubdebug, 0, "uhub debug level"); + &uhubdebug, 0, "uhub debug level"); #else #define DPRINTF(x) #define DPRINTFN(n,x) @@ -89,11 +91,12 @@ Static void uhub_intr(usbd_xfer_handle, usbd_private_handle,usbd_status); #if defined(__FreeBSD__) +Static bus_driver_added_t uhub_driver_added; Static bus_child_detached_t uhub_child_detached; #endif -/* +/* * We need two attachment points: * hub to usb and hub to hub * Every other driver only connects to hubs @@ -103,24 +106,24 @@ USB_DECLARE_DRIVER(uhub); /* 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 -}; +CFATTACH_DECL(uhub_uhub, sizeof(struct uhub_softc), + uhub_match, uhub_attach, uhub_detach, uhub_activate); #elif defined(__FreeBSD__) USB_DECLARE_DRIVER_INIT(uhub, + DEVMETHOD(bus_driver_added, uhub_driver_added), DEVMETHOD(bus_child_detached, uhub_child_detached), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), DEVMETHOD(device_shutdown, bus_generic_shutdown) ); - + /* 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), + /* detach is not allowed for a root hub */ DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), @@ -139,9 +142,9 @@ { USB_MATCH_START(uhub, uaa); usb_device_descriptor_t *dd = usbd_get_device_descriptor(uaa->device); - + DPRINTFN(5,("uhub_match, dd=%p\n", dd)); - /* + /* * The subclass for hubs seems to be 0 for some and 1 for others, * so we just ignore the subclass. */ @@ -154,7 +157,7 @@ { USB_ATTACH_START(uhub, sc, uaa); usbd_device_handle dev = uaa->device; - char devinfo[1024]; + char *devinfo; usbd_status err; struct usbd_hub *hub; usb_device_request_t req; @@ -162,7 +165,11 @@ int p, port, nports, nremov, pwrdly; usbd_interface_handle iface; usb_endpoint_descriptor_t *ed; - + + devinfo = malloc(1024, M_TEMP, M_NOWAIT); + if (devinfo == NULL) { + USB_ATTACH_ERROR_RETURN; + } DPRINTFN(1,("uhub_attach\n")); sc->sc_hub = dev; usbd_devinfo(dev, 1, devinfo); @@ -173,19 +180,21 @@ if (err) { DPRINTF(("%s: configuration failed, error=%s\n", USBDEVNAME(sc->sc_dev), usbd_errstr(err))); + free(devinfo, M_TEMP); USB_ATTACH_ERROR_RETURN; } if (dev->depth > USB_HUB_MAX_DEPTH) { printf("%s: hub depth (%d) exceeded, hub ignored\n", USBDEVNAME(sc->sc_dev), USB_HUB_MAX_DEPTH); + free(devinfo, M_TEMP); USB_ATTACH_ERROR_RETURN; } /* Get hub descriptor. */ req.bmRequestType = UT_READ_CLASS_DEVICE; req.bRequest = UR_GET_DESCRIPTOR; - USETW(req.wValue, 0); + USETW2(req.wValue, (dev->address > 1 ? UDESC_HUB : 0), 0); USETW(req.wIndex, 0); USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE); DPRINTFN(1,("usb_init_hub: getting hub descriptor\n")); @@ -198,6 +207,7 @@ if (err) { DPRINTF(("%s: getting hub descriptor failed, error=%s\n", USBDEVNAME(sc->sc_dev), usbd_errstr(err))); + free(devinfo, M_TEMP); USB_ATTACH_ERROR_RETURN; } @@ -210,17 +220,19 @@ hub = malloc(sizeof(*hub) + (nports-1) * sizeof(struct usbd_port), M_USBDEV, M_NOWAIT); - if (hub == NULL) + if (hub == NULL) { + free(devinfo, M_TEMP); USB_ATTACH_ERROR_RETURN; + } dev->hub = hub; dev->hub->hubsoftc = sc; hub->explore = uhub_explore; hub->hubdesc = hubdesc; - + DPRINTFN(1,("usbhub_init_hub: selfpowered=%d, parent=%p, " "parent->selfpowered=%d\n", dev->self_powered, dev->powersrc->parent, - dev->powersrc->parent ? + dev->powersrc->parent ? dev->powersrc->parent->self_powered : 0)); if (!dev->self_powered && dev->powersrc->parent != NULL && @@ -247,10 +259,10 @@ } err = usbd_open_pipe_intr(iface, ed->bEndpointAddress, - USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_status, + USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_status, sizeof(sc->sc_status), uhub_intr, UHUB_INTR_INTERVAL); if (err) { - printf("%s: cannot open interrupt pipe\n", + printf("%s: cannot open interrupt pipe\n", USBDEVNAME(sc->sc_dev)); goto bad; } @@ -258,6 +270,8 @@ /* Wait with power off for a while. */ usbd_delay_ms(dev, USB_POWER_DOWN_TIME); + usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, dev, USBDEV(sc->sc_dev)); + /* * To have the best chance of success we do things in the exact same * order as Windoze98. This should not be necessary, but some @@ -275,6 +289,7 @@ * For all ports * get port status * if device connected + * wait 100 ms * turn on reset * wait * clear C_PORT_RESET @@ -303,7 +318,7 @@ /* Turn the power on. */ err = usbd_set_port_feature(dev, port, UHF_PORT_POWER); if (err) - printf("%s: port %d power on failed, %s\n", + printf("%s: port %d power on failed, %s\n", USBDEVNAME(sc->sc_dev), port, usbd_errstr(err)); DPRINTF(("usb_init_port: turn on port %d power\n", port)); @@ -319,6 +334,7 @@ bad: free(hub, M_USBDEV); + free(devinfo, M_TEMP); dev->hub = 0; USB_ATTACH_ERROR_RETURN; } @@ -330,6 +346,7 @@ struct uhub_softc *sc = dev->hub->hubsoftc; struct usbd_port *up; usbd_status err; + int speed; int port; int change, status; @@ -352,8 +369,8 @@ } status = UGETW(up->status.wPortStatus); change = UGETW(up->status.wPortChange); - DPRINTFN(3,("uhub_explore: port %d status 0x%04x 0x%04x\n", - port, status, change)); + DPRINTFN(3,("uhub_explore: %s port %d status 0x%04x 0x%04x\n", + USBDEVNAME(sc->sc_dev), port, status, change)); if (change & UPS_C_PORT_ENABLED) { DPRINTF(("uhub_explore: C_PORT_ENABLED\n")); usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE); @@ -379,8 +396,14 @@ DPRINTFN(3,("uhub_explore: port=%d !C_CONNECT_" "STATUS\n", port)); /* No status change, just do recursive explore. */ - if (up->device && up->device->hub) + if (up->device != NULL && up->device->hub != NULL) up->device->hub->explore(up->device); +#if 0 && defined(DIAGNOSTIC) + if (up->device == NULL && + (status & UPS_CURRENT_CONNECT_STATUS)) + printf("%s: connected, no device\n", + USBDEVNAME(sc->sc_dev)); +#endif continue; } @@ -403,7 +426,7 @@ DPRINTF(("uhub_explore: device addr=%d disappeared " "on port %d\n", up->device->address, port)); usb_disconnect_port(up, USBDEV(sc->sc_dev)); - usbd_clear_port_feature(dev, port, + usbd_clear_port_feature(dev, port, UHF_C_PORT_CONNECTION); } if (!(status & UPS_CURRENT_CONNECT_STATUS)) { @@ -424,15 +447,38 @@ /* Reset port, which implies enabling it. */ if (usbd_reset_port(dev, port, &up->status)) { - printf("uhub_explore: port=%d reset failed\n", - port); + printf("%s: port %d reset failed\n", + USBDEVNAME(sc->sc_dev), port); + continue; + } + /* Get port status again, it might have changed during reset */ + err = usbd_get_port_status(dev, port, &up->status); + if (err) { + DPRINTF(("uhub_explore: get port status failed, " + "error=%s\n", usbd_errstr(err))); + continue; + } + status = UGETW(up->status.wPortStatus); + change = UGETW(up->status.wPortChange); + if (!(status & UPS_CURRENT_CONNECT_STATUS)) { + /* Nothing connected, just ignore it. */ +#ifdef DIAGNOSTIC + printf("%s: port %d, device disappeared after reset\n", + USBDEVNAME(sc->sc_dev), port); +#endif continue; } + /* Figure out device speed */ + if (status & UPS_HIGH_SPEED) + speed = USB_SPEED_HIGH; + else if (status & UPS_LOW_SPEED) + speed = USB_SPEED_LOW; + else + speed = USB_SPEED_FULL; /* Get device info and set its address. */ - err = usbd_new_device(USBDEV(sc->sc_dev), dev->bus, - dev->depth + 1, status & UPS_LOW_SPEED, - port, up); + err = usbd_new_device(USBDEV(sc->sc_dev), dev->bus, + dev->depth + 1, speed, port, up); /* XXX retry a few times? */ if (err) { DPRINTFN(-1,("uhub_explore: usb_new_device failed, " @@ -440,7 +486,7 @@ /* Avoid addressing problems by disabling. */ /* usbd_reset_port(dev, port, &up->status); */ - /* + /* * The unit refused to accept a new address, or had * some other serious problem. Since we cannot leave * at 0 we have to disable the port instead. @@ -471,7 +517,6 @@ switch (act) { case DVACT_ACTIVATE: return (EOPNOTSUPP); - break; case DVACT_DEACTIVATE: if (hub == NULL) /* malfunctioning hub */ @@ -519,7 +564,9 @@ if (rup->device) usb_disconnect_port(rup, self); } - + + usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_hub, + USBDEV(sc->sc_dev)); free(hub, M_USBDEV); sc->sc_hub->hub = NULL; @@ -539,7 +586,7 @@ int port; int i; - if (!devhub->hub) + if (!devhub->hub) /* should never happen; children are only created after init */ panic("hub not fully initialised, but child deleted?"); @@ -556,6 +603,19 @@ } } } + +Static void +uhub_driver_added(device_t _dev, driver_t *_driver) +{ + /* Don't do anything, as reprobing does not work currently. We should + * really call through to usbd_new_device or a function along those + * lines that reinitialises the device if it is not owned by any + * driver. But this is complicated. Manual replugging by the user is + * easier. + */ + + ; +} #endif @@ -571,10 +631,10 @@ struct uhub_softc *sc = addr; DPRINTFN(5,("uhub_intr: sc=%p\n", sc)); - if (status != USBD_NORMAL_COMPLETION) + if (status == USBD_STALLED) usbd_clear_endpoint_stall_async(sc->sc_ipipe); - - usb_needs_explore(sc->sc_hub->bus); + else if (status == USBD_NORMAL_COMPLETION) + usb_needs_explore(sc->sc_hub); } #if defined(__FreeBSD__) Index: sys/dev/usb/ukbd.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/ukbd.c,v retrieving revision 1.24.2.6 diff -u -r1.24.2.6 ukbd.c --- sys/dev/usb/ukbd.c 6 Nov 2002 20:23:50 -0000 1.24.2.6 +++ sys/dev/usb/ukbd.c 4 Oct 2003 21:27:28 -0000 @@ -1,4 +1,3 @@ -/* $FreeBSD: src/sys/dev/usb/ukbd.c,v 1.24.2.6 2002/11/06 20:23:50 joe Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -37,8 +36,11 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/ukbd.c,v 1.45 2003/10/04 21:41:01 joe Exp $"); + /* - * HID spec: http://www.usb.org/developers/data/usbhid10.pdf + * HID spec: http://www.usb.org/developers/data/devclass/hid1_1.pdf */ #include "opt_kbd.h" @@ -50,10 +52,17 @@ #include #include #include -#include #include +#if __FreeBSD_version >= 500000 +#include +#else +#include +#endif +#if __FreeBSD_version >= 500014 +#include +#else #include -#include +#endif #include #include @@ -233,8 +242,6 @@ DRIVER_MODULE(ukbd, uhub, ukbd_driver, ukbd_devclass, ukbd_driver_load, 0); -#include -#include #define UKBD_DEFAULT 0 @@ -269,7 +276,7 @@ }; #define NN 0 /* no translation */ -/* +/* * Translate USB keycodes to AT keyboard scancodes. */ /* @@ -426,7 +433,7 @@ Static accentmap_t default_accentmap; Static fkeytab_t default_fkeytab[NUM_FKEYS]; -/* +/* * The back door to the keyboard driver! * This function is called by the console driver, via the kbdio module, * to tickle keyboard drivers when the low-level console is being initialized. @@ -567,7 +574,7 @@ state->ks_uaa = uaa; state->ks_ifstate = 0; callout_handle_init(&state->ks_timeout_handle); - /* + /* * FIXME: set the initial value for lock keys in ks_state * according to the BIOS data? */ @@ -602,12 +609,12 @@ /* Set up interrupt pipe. */ if (state->ks_ifstate & INTRENABLED) return EBUSY; - + state->ks_ifstate |= INTRENABLED; - err = usbd_open_pipe_intr(state->ks_iface, state->ks_ep_addr, + err = usbd_open_pipe_intr(state->ks_iface, state->ks_ep_addr, USBD_SHORT_XFER_OK, &state->ks_intrpipe, kbd, - &state->ks_ndata, + &state->ks_ndata, sizeof(state->ks_ndata), func, USBD_DEFAULT_INTERVAL); if (err) @@ -686,28 +693,25 @@ ukbd_interrupt(keyboard_t *kbd, void *arg) { usbd_status status = (usbd_status)arg; - ukbd_state_t *state = (ukbd_state_t *)kbd->kb_data; - struct ukbd_data *ud = &state->ks_ndata; + ukbd_state_t *state; + struct ukbd_data *ud; struct timeval tv; u_long now; int mod, omod; int key, c; int i, j; -#define ADDKEY1(c) \ - if (state->ks_inputs < INPUTBUFSIZE) { \ - state->ks_input[state->ks_inputtail] = (c); \ - ++state->ks_inputs; \ - state->ks_inputtail = (state->ks_inputtail + 1)%INPUTBUFSIZE; \ - } - DPRINTFN(5, ("ukbd_intr: status=%d\n", status)); if (status == USBD_CANCELLED) return 0; + state = (ukbd_state_t *)kbd->kb_data; + ud = &state->ks_ndata; + if (status != USBD_NORMAL_COMPLETION) { DPRINTF(("ukbd_intr: status=%d\n", status)); - usbd_clear_endpoint_stall_async(state->ks_intrpipe); + if (status == USBD_STALLED) + usbd_clear_endpoint_stall_async(state->ks_intrpipe); return 0; } @@ -717,14 +721,21 @@ getmicrouptime(&tv); now = (u_long)tv.tv_sec*1000 + (u_long)tv.tv_usec/1000; +#define ADDKEY1(c) \ + if (state->ks_inputs < INPUTBUFSIZE) { \ + state->ks_input[state->ks_inputtail] = (c); \ + ++state->ks_inputs; \ + state->ks_inputtail = (state->ks_inputtail + 1)%INPUTBUFSIZE; \ + } + mod = ud->modifiers; omod = state->ks_odata.modifiers; if (mod != omod) { for (i = 0; i < NMOD; i++) - if (( mod & ukbd_mods[i].mask) != + if (( mod & ukbd_mods[i].mask) != (omod & ukbd_mods[i].mask)) - ADDKEY1(ukbd_mods[i].key | - (mod & ukbd_mods[i].mask + ADDKEY1(ukbd_mods[i].key | + (mod & ukbd_mods[i].mask ? KEY_PRESS : KEY_RELEASE)); } @@ -743,7 +754,7 @@ rfound: ; } - + /* Check for pressed keys. */ for (i = 0; i < NKEYCODE; i++) { key = ud->keycode[i]; @@ -836,7 +847,7 @@ return 0; } -/* +/* * Enable the access to the device; until this function is called, * the client cannot read from the keyboard. */ @@ -903,13 +914,13 @@ usbcode & KEY_RELEASE); if (scancode & SCAN_PREFIX) { if (scancode & SCAN_PREFIX_CTL) { - state->ks_buffered_char[0] = + state->ks_buffered_char[0] = 0x1d | (scancode & SCAN_RELEASE); /* Ctrl */ state->ks_buffered_char[1] = scancode & ~SCAN_PREFIX; } else if (scancode & SCAN_PREFIX_SHIFT) { - state->ks_buffered_char[0] = + state->ks_buffered_char[0] = 0x2a | (scancode & SCAN_RELEASE); /* Shift */ - state->ks_buffered_char[1] = + state->ks_buffered_char[1] = scancode & ~SCAN_PREFIX_SHIFT; } else { state->ks_buffered_char[0] = scancode & ~SCAN_PREFIX; @@ -999,12 +1010,12 @@ usbcode & KEY_RELEASE); if (scancode & SCAN_PREFIX) { if (scancode & SCAN_PREFIX_CTL) { - state->ks_buffered_char[0] = + state->ks_buffered_char[0] = 0x1d | (scancode & SCAN_RELEASE); state->ks_buffered_char[1] = scancode & ~SCAN_PREFIX; } else if (scancode & SCAN_PREFIX_SHIFT) { - state->ks_buffered_char[0] = + state->ks_buffered_char[0] = 0x2a | (scancode & SCAN_RELEASE); state->ks_buffered_char[1] = scancode & ~SCAN_PREFIX_SHIFT; @@ -1166,7 +1177,7 @@ state->ks_state &= ~LOCK_MASK; state->ks_state |= KBD_LED_VAL(kbd); } - /* FALL THROUGH */ + /* FALLTHROUGH */ case K_RAW: case K_CODE: if (state->ks_mode != *(int *)arg) { @@ -1241,7 +1252,7 @@ case PIO_KEYMAPENT: /* set keyboard translation table entry */ case PIO_DEADKEYMAP: /* set accent key translation table */ state->ks_accents = 0; - /* FALL THROUGH */ + /* FALLTHROUGH */ default: splx(s); return genkbd_commonioctl(kbd, cmd, arg); @@ -1313,19 +1324,21 @@ ukbd_poll(keyboard_t *kbd, int on) { ukbd_state_t *state; + usbd_device_handle dev; int s; state = (ukbd_state_t *)kbd->kb_data; + usbd_interface2device_handle(state->ks_iface, &dev); s = splusb(); if (on) { if (state->ks_polling == 0) - usbd_set_polling(state->ks_iface, on); + usbd_set_polling(dev, on); ++state->ks_polling; } else { --state->ks_polling; if (state->ks_polling == 0) - usbd_set_polling(state->ks_iface, on); + usbd_set_polling(dev, on); } splx(s); return 0; @@ -1337,7 +1350,7 @@ probe_keyboard(struct usb_attach_arg *uaa, int flags) { usb_interface_descriptor_t *id; - + if (!uaa->iface) /* we attach to ifaces only */ return EINVAL; @@ -1357,7 +1370,7 @@ { usb_endpoint_descriptor_t *ed; usbd_status err; - + *type = KB_OTHER; state->ks_ifstate |= DISCONNECTED; @@ -1430,10 +1443,10 @@ keycode2scancode(int keycode, int shift, int up) { static int scan[] = { - 0x1c, 0x1d, 0x35, + 0x1c, 0x1d, 0x35, 0x37 | SCAN_PREFIX_SHIFT, /* PrintScreen */ - 0x38, 0x47, 0x48, 0x49, 0x4b, 0x4d, 0x4f, - 0x50, 0x51, 0x52, 0x53, + 0x38, 0x47, 0x48, 0x49, 0x4b, 0x4d, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x46, /* XXX Pause/Break */ 0x5b, 0x5c, 0x5d, }; Index: sys/dev/usb/ulpt.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/ulpt.c,v retrieving revision 1.26.2.14 diff -u -r1.26.2.14 ulpt.c --- sys/dev/usb/ulpt.c 22 Jun 2003 13:54:30 -0000 1.26.2.14 +++ sys/dev/usb/ulpt.c 4 Oct 2003 21:27:28 -0000 @@ -1,5 +1,4 @@ -/* $NetBSD: ulpt.c,v 1.29 1999/11/17 23:00:50 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/ulpt.c,v 1.26.2.14 2003/06/22 13:54:30 iedowse Exp $ */ +/* $NetBSD: ulpt.c,v 1.55 2002/10/23 09:14:01 jdolecek Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -38,12 +37,13 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/ulpt.c,v 1.59 2003/09/28 20:48:13 phk Exp $"); + /* - * Printer Class spec: http://www.usb.org/developers/data/usbprn10.pdf + * Printer Class spec: http://www.usb.org/developers/data/devclass/usbprint109.PDF */ -/* XXX Note in the manpage the ULPT_NOPRIME version of the printer */ - #include #include #include @@ -52,6 +52,7 @@ #include #include #elif defined(__FreeBSD__) +#include #include #include #endif @@ -64,6 +65,8 @@ #include #include #include +#include +#include #define TIMEOUT hz*16 /* wait up to 16 seconds for a ready */ #define STEP hz/4 @@ -98,8 +101,15 @@ usbd_device_handle sc_udev; /* device */ usbd_interface_handle sc_iface; /* interface */ int sc_ifaceno; - usbd_pipe_handle sc_bulkpipe; /* bulk pipe */ - int sc_bulk; + + int sc_out; + usbd_pipe_handle sc_out_pipe; /* bulk out pipe */ + + int sc_in; + usbd_pipe_handle sc_in_pipe; /* bulk in pipe */ + usbd_xfer_handle sc_in_xfer1; + usbd_xfer_handle sc_in_xfer2; + u_char sc_junk[64]; /* somewhere to dump input */ u_char sc_state; #define ULPT_OPEN 0x01 /* device is open */ @@ -118,7 +128,17 @@ #endif }; -#if defined(__NetBSD__) || defined(__OpenBSD__) +#if defined(__NetBSD__) +dev_type_open(ulptopen); +dev_type_close(ulptclose); +dev_type_write(ulptwrite); +dev_type_ioctl(ulptioctl); + +const struct cdevsw ulpt_cdevsw = { + ulptopen, ulptclose, noread, ulptwrite, ulptioctl, + nostop, notty, nopoll, nommap, nokqfilter, +}; +#elif defined(__OpenBSD__) cdev_decl(ulpt); #elif defined(__FreeBSD__) Static d_open_t ulptopen; @@ -129,20 +149,15 @@ #define ULPT_CDEV_MAJOR 113 Static struct cdevsw ulpt_cdevsw = { - /* open */ ulptopen, - /* close */ ulptclose, - /* read */ noread, - /* write */ ulptwrite, - /* ioctl */ ulptioctl, - /* poll */ nopoll, - /* mmap */ nommap, - /* strategy */ nostrategy, - /* name */ "ulpt", - /* maj */ ULPT_CDEV_MAJOR, - /* dump */ nodump, - /* psize */ nopsize, - /* flags */ 0, - /* bmaj */ -1 + .d_open = ulptopen, + .d_close = ulptclose, + .d_write = ulptwrite, + .d_ioctl = ulptioctl, + .d_name = "ulpt", + .d_maj = ULPT_CDEV_MAJOR, +#if __FreeBSD_version < 500014 + .d_bmaj -1 +#endif }; #endif @@ -153,7 +168,9 @@ void ulpt_reset(struct ulpt_softc *); int ulpt_statusmsg(u_char, struct ulpt_softc *); +#if 0 void ieee1284_print_id(char *); +#endif #define ULPTUNIT(s) (minor(s) & 0x1f) #define ULPTFLAGS(s) (minor(s) & 0xe0) @@ -165,7 +182,7 @@ { USB_MATCH_START(ulpt, uaa); usb_interface_descriptor_t *id; - + DPRINTFN(10,("ulpt_match\n")); if (uaa->iface == NULL) return (UMATCH_NONE); @@ -174,7 +191,8 @@ id->bInterfaceClass == UICLASS_PRINTER && id->bInterfaceSubClass == UISUBCLASS_PRINTER && (id->bInterfaceProtocol == UIPROTO_PRINTER_UNI || - id->bInterfaceProtocol == UIPROTO_PRINTER_BI)) + id->bInterfaceProtocol == UIPROTO_PRINTER_BI || + id->bInterfaceProtocol == UIPROTO_PRINTER_1284)) return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO); return (UMATCH_NONE); } @@ -184,41 +202,105 @@ USB_ATTACH_START(ulpt, sc, uaa); usbd_device_handle dev = uaa->device; usbd_interface_handle iface = uaa->iface; - usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface); + usb_interface_descriptor_t *ifcd = usbd_get_interface_descriptor(iface); + usb_interface_descriptor_t *id, *iend; + usb_config_descriptor_t *cdesc; + usbd_status err; char devinfo[1024]; usb_endpoint_descriptor_t *ed; - usbd_status err; - + u_int8_t epcount; + int i, altno; + DPRINTFN(10,("ulpt_attach: sc=%p\n", sc)); usbd_devinfo(dev, 0, devinfo); USB_ATTACH_SETUP; printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev), - devinfo, id->bInterfaceClass, id->bInterfaceSubClass); + devinfo, ifcd->bInterfaceClass, ifcd->bInterfaceSubClass); - /* Figure out which endpoint is the bulk out endpoint. */ - ed = usbd_interface2endpoint_descriptor(iface, 0); - if (ed == NULL) - goto nobulk; - 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 == NULL) - goto nobulk; - if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_OUT || - (ed->bmAttributes & UE_XFERTYPE) != UE_BULK) - goto nobulk; + /* XXX + * Stepping through the alternate settings needs to be abstracted out. + */ + cdesc = usbd_get_config_descriptor(dev); + if (cdesc == NULL) { + printf("%s: failed to get configuration descriptor\n", + USBDEVNAME(sc->sc_dev)); + USB_ATTACH_ERROR_RETURN; + } + iend = (usb_interface_descriptor_t *) + ((char *)cdesc + UGETW(cdesc->wTotalLength)); +#ifdef DIAGNOSTIC + if (ifcd < (usb_interface_descriptor_t *)cdesc || + ifcd >= iend) + panic("ulpt: iface desc out of range"); +#endif + /* Step through all the descriptors looking for bidir mode */ + for (id = ifcd, altno = 0; + id < iend; + id = (void *)((char *)id + id->bLength)) { + if (id->bDescriptorType == UDESC_INTERFACE && + id->bInterfaceNumber == ifcd->bInterfaceNumber) { + if (id->bInterfaceClass == UICLASS_PRINTER && + id->bInterfaceSubClass == UISUBCLASS_PRINTER && + (id->bInterfaceProtocol == UIPROTO_PRINTER_BI /* || + id->bInterfaceProtocol == UIPROTO_PRINTER_1284 */)) + goto found; + altno++; + } + } + id = ifcd; /* not found, use original */ + found: + if (id != ifcd) { + /* Found a new bidir setting */ + DPRINTF(("ulpt_attach: set altno = %d\n", altno)); + err = usbd_set_interface(iface, altno); + if (err) { + printf("%s: setting alternate interface failed\n", + USBDEVNAME(sc->sc_dev)); + sc->sc_dying = 1; + USB_ATTACH_ERROR_RETURN; + } } - sc->sc_bulk = ed->bEndpointAddress; - DPRINTFN(10, ("ulpt_attach: bulk=%d\n", sc->sc_bulk)); - sc->sc_iface = iface; - err = usbd_interface2device_handle(iface, &sc->sc_udev); - if (err) { + epcount = 0; + (void)usbd_endpoint_count(iface, &epcount); + + sc->sc_in = -1; + sc->sc_out = -1; + for (i = 0; i < epcount; i++) { + ed = usbd_interface2endpoint_descriptor(iface, i); + if (ed == NULL) { + printf("%s: couldn't get ep %d\n", + USBDEVNAME(sc->sc_dev), i); + USB_ATTACH_ERROR_RETURN; + } + if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && + UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { + sc->sc_in = ed->bEndpointAddress; + } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && + UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { + sc->sc_out = ed->bEndpointAddress; + } + } + if (sc->sc_out == -1) { + printf("%s: could not find bulk out endpoint\n", + USBDEVNAME(sc->sc_dev)); sc->sc_dying = 1; USB_ATTACH_ERROR_RETURN; } + + if (usbd_get_quirks(dev)->uq_flags & UQ_BROKEN_BIDIR) { + /* This device doesn't handle reading properly. */ + sc->sc_in = -1; + } + + printf("%s: using %s-directional mode\n", USBDEVNAME(sc->sc_dev), + sc->sc_in >= 0 ? "bi" : "uni"); + + DPRINTFN(10, ("ulpt_attach: bulk=%d\n", sc->sc_out)); + + sc->sc_iface = iface; sc->sc_ifaceno = id->bInterfaceNumber; + sc->sc_udev = dev; #if 0 /* @@ -237,7 +319,7 @@ USETW2(req.wIndex, id->bInterfaceNumber, id->bAlternateSetting); USETW(req.wLength, sizeof devinfo - 1); err = usbd_do_request_flags(dev, &req, devinfo, USBD_SHORT_XFER_OK, - &alen); + &alen, USBD_DEFAULT_TIMEOUT); if (err) { printf("%s: cannot get device id\n", USBDEVNAME(sc->sc_dev)); } else if (alen <= 2) { @@ -264,12 +346,10 @@ UID_ROOT, GID_OPERATOR, 0644, "unlpt%d", device_get_unit(self)); #endif - USB_ATTACH_SUCCESS_RETURN; + usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, + USBDEV(sc->sc_dev)); - nobulk: - printf("%s: could not find bulk endpoint\n", USBDEVNAME(sc->sc_dev)); - sc->sc_dying = 1; - USB_ATTACH_ERROR_RETURN; + USB_ATTACH_SUCCESS_RETURN; } #if defined(__NetBSD__) || defined(__OpenBSD__) @@ -281,7 +361,6 @@ switch (act) { case DVACT_ACTIVATE: return (EOPNOTSUPP); - break; case DVACT_DEACTIVATE: sc->sc_dying = 1; @@ -308,8 +387,10 @@ #endif sc->sc_dying = 1; - if (sc->sc_bulkpipe != NULL) - usbd_abort_pipe(sc->sc_bulkpipe); + if (sc->sc_out_pipe != NULL) + usbd_abort_pipe(sc->sc_out_pipe); + if (sc->sc_in_pipe != NULL) + usbd_abort_pipe(sc->sc_in_pipe); s = splusb(); if (--sc->sc_refcnt >= 0) { @@ -321,9 +402,13 @@ #if defined(__NetBSD__) || defined(__OpenBSD__) /* locate the major number */ +#if defined(__NetBSD__) + maj = cdevsw_lookup_major(&ulpt_cdevsw); +#elif defined(__OpenBSD__) for (maj = 0; maj < nchrdev; maj++) if (cdevsw[maj].d_open == ulptopen) break; +#endif /* Nuke the vnodes for any open instances (calls close). */ mn = self->dv_unit; @@ -340,6 +425,9 @@ destroy_dev(sc->dev_noprime); #endif + usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, + USBDEV(sc->sc_dev)); + return (0); } @@ -369,14 +457,45 @@ usb_device_request_t req; DPRINTFN(1, ("ulpt_reset\n")); - req.bmRequestType = UT_WRITE_CLASS_OTHER; req.bRequest = UR_SOFT_RESET; USETW(req.wValue, 0); USETW(req.wIndex, sc->sc_ifaceno); USETW(req.wLength, 0); - (void)usbd_do_request(sc->sc_udev, &req, 0); + + /* + * There was a mistake in the USB printer 1.0 spec that gave the + * request type as UT_WRITE_CLASS_OTHER; it should have been + * UT_WRITE_CLASS_INTERFACE. Many printers use the old one, + * so we try both. + */ + req.bmRequestType = UT_WRITE_CLASS_OTHER; + if (usbd_do_request(sc->sc_udev, &req, 0)) { /* 1.0 */ + req.bmRequestType = UT_WRITE_CLASS_INTERFACE; + (void)usbd_do_request(sc->sc_udev, &req, 0); /* 1.1 */ + } } +static void +ulpt_input(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) +{ + struct ulpt_softc *sc = priv; + u_int32_t count; + + /* Don't loop on errors or 0-length input. */ + usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL); + if (status != USBD_NORMAL_COMPLETION || count == 0) + return; + + DPRINTFN(2,("ulpt_input: got some data\n")); + /* Do it again. */ + if (xfer == sc->sc_in_xfer1) + usbd_transfer(sc->sc_in_xfer2); + else + usbd_transfer(sc->sc_in_xfer1); +} + +int ulptusein = 1; + /* * Reset the printer, then wait until it's selected and not busy. */ @@ -408,43 +527,92 @@ #endif + error = 0; + sc->sc_refcnt++; + if ((flags & ULPT_NOPRIME) == 0) { ulpt_reset(sc); if (sc->sc_dying) { + error = ENXIO; sc->sc_state = 0; - return (ENXIO); + goto done; } } for (spin = 0; (ulpt_status(sc) & LPS_SELECT) == 0; spin += STEP) { + DPRINTF(("ulpt_open: waiting a while\n")); if (spin >= TIMEOUT) { + error = EBUSY; sc->sc_state = 0; - return (EBUSY); + goto done; } /* wait 1/4 second, give up if we get a signal */ - error = tsleep((caddr_t)sc, LPTPRI | PCATCH, "ulptop", STEP); + error = tsleep(sc, LPTPRI | PCATCH, "ulptop", STEP); if (error != EWOULDBLOCK) { sc->sc_state = 0; - return (error); + goto done; } if (sc->sc_dying) { + error = ENXIO; sc->sc_state = 0; - return (ENXIO); + goto done; } } - err = usbd_open_pipe(sc->sc_iface, sc->sc_bulk, 0, &sc->sc_bulkpipe); + err = usbd_open_pipe(sc->sc_iface, sc->sc_out, 0, &sc->sc_out_pipe); if (err) { sc->sc_state = 0; - return (EIO); + error = EIO; + goto done; + } + if (ulptusein && sc->sc_in != -1) { + DPRINTF(("ulpt_open: open input pipe\n")); + err = usbd_open_pipe(sc->sc_iface, sc->sc_in,0,&sc->sc_in_pipe); + if (err) { + error = EIO; + usbd_close_pipe(sc->sc_out_pipe); + sc->sc_out_pipe = NULL; + sc->sc_state = 0; + goto done; + } + sc->sc_in_xfer1 = usbd_alloc_xfer(sc->sc_udev); + sc->sc_in_xfer2 = usbd_alloc_xfer(sc->sc_udev); + if (sc->sc_in_xfer1 == NULL || sc->sc_in_xfer2 == NULL) { + error = ENOMEM; + if (sc->sc_in_xfer1 != NULL) { + usbd_free_xfer(sc->sc_in_xfer1); + sc->sc_in_xfer1 = NULL; + } + if (sc->sc_in_xfer2 != NULL) { + usbd_free_xfer(sc->sc_in_xfer2); + sc->sc_in_xfer2 = NULL; + } + usbd_close_pipe(sc->sc_out_pipe); + sc->sc_out_pipe = NULL; + usbd_close_pipe(sc->sc_in_pipe); + sc->sc_in_pipe = NULL; + sc->sc_state = 0; + goto done; + } + usbd_setup_xfer(sc->sc_in_xfer1, sc->sc_in_pipe, sc, + sc->sc_junk, sizeof sc->sc_junk, USBD_SHORT_XFER_OK, + USBD_NO_TIMEOUT, ulpt_input); + usbd_setup_xfer(sc->sc_in_xfer2, sc->sc_in_pipe, sc, + sc->sc_junk, sizeof sc->sc_junk, USBD_SHORT_XFER_OK, + USBD_NO_TIMEOUT, ulpt_input); + usbd_transfer(sc->sc_in_xfer1); /* ignore failed start */ } sc->sc_state = ULPT_OPEN; - DPRINTF(("ulptopen: done\n")); - return (0); + done: + if (--sc->sc_refcnt < 0) + usb_detach_wakeup(USBDEV(sc->sc_dev)); + + DPRINTF(("ulptopen: done, error=%d\n", error)); + return (error); } int @@ -477,8 +645,23 @@ /* We are being forced to close before the open completed. */ return (0); - usbd_close_pipe(sc->sc_bulkpipe); - sc->sc_bulkpipe = 0; + if (sc->sc_out_pipe != NULL) { + usbd_close_pipe(sc->sc_out_pipe); + sc->sc_out_pipe = NULL; + } + if (sc->sc_in_pipe != NULL) { + usbd_abort_pipe(sc->sc_in_pipe); + usbd_close_pipe(sc->sc_in_pipe); + sc->sc_in_pipe = NULL; + if (sc->sc_in_xfer1 != NULL) { + usbd_free_xfer(sc->sc_in_xfer1); + sc->sc_in_xfer1 = NULL; + } + if (sc->sc_in_xfer2 != NULL) { + usbd_free_xfer(sc->sc_in_xfer2); + sc->sc_in_xfer2 = NULL; + } + } sc->sc_state = 0; @@ -510,7 +693,7 @@ if (error) break; DPRINTFN(1, ("ulptwrite: transfer %d bytes\n", n)); - err = usbd_bulk_transfer(xfer, sc->sc_bulkpipe, USBD_NO_COPY, + err = usbd_bulk_transfer(xfer, sc->sc_out_pipe, USBD_NO_COPY, USBD_NO_TIMEOUT, bufp, &n, "ulptwr"); if (err) { DPRINTF(("ulptwrite: error=%d\n", err)); @@ -557,7 +740,7 @@ #if 0 /* XXX This does not belong here. */ /* - * Print select parts of a IEEE 1284 device ID. + * Print select parts of an IEEE 1284 device ID. */ void ieee1284_print_id(char *str) Index: sys/dev/usb/umodem.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/umodem.c,v retrieving revision 1.17.2.9 diff -u -r1.17.2.9 umodem.c --- sys/dev/usb/umodem.c 6 Nov 2002 20:23:50 -0000 1.17.2.9 +++ sys/dev/usb/umodem.c 4 Oct 2003 18:54:40 -0000 @@ -1,5 +1,33 @@ -/* $NetBSD: umodem.c,v 1.5 1999/01/08 11:58:25 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/umodem.c,v 1.17.2.9 2002/11/06 20:23:50 joe Exp $ */ +/* $NetBSD: umodem.c,v 1.45 2002/09/23 05:51:23 simonb Exp $ */ + + +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/umodem.c,v 1.48 2003/08/24 17:55:55 obrien Exp $"); +/*- + * Copyright (c) 2003, M. Warner Losh . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -39,7 +67,8 @@ */ /* - * Comm Class spec: http://www.usb.org/developers/data/usbcdc11.pdf + * Comm Class spec: http://www.usb.org/developers/data/devclass/usbcdc10.pdf + * http://www.usb.org/developers/data/devclass/usbcdc11.pdf */ /* @@ -53,24 +82,16 @@ #include #include #include -#include -#if defined(__NetBSD__) || defined(__OpenBSD__) -#include -#include -#elif defined(__FreeBSD__) -#include #include -#include -#endif #include #include -#include #include #include +#include #include #include +#include #include -#include #include #include @@ -81,35 +102,32 @@ #include #include +#include #ifdef USB_DEBUG -#define DPRINTF(x) if(umodemdebug) logprintf x -#define DPRINTFN(n, x) if(umodemdebug > (n)) logprintf x int umodemdebug = 0; SYSCTL_NODE(_hw_usb, OID_AUTO, umodem, CTLFLAG_RW, 0, "USB umodem"); SYSCTL_INT(_hw_usb_umodem, OID_AUTO, debug, CTLFLAG_RW, &umodemdebug, 0, "umodem debug level"); +#define DPRINTFN(n, x) if (umodemdebug > (n)) logprintf x #else -#define DPRINTF(x) #define DPRINTFN(n, x) #endif +#define DPRINTF(x) DPRINTFN(0, x) -/* Macros to clear/set/test flags. */ -#define SET(t, f) (t) |= (f) -#define CLR(t, f) (t) &= ~((unsigned)(f)) -#define ISSET(t, f) ((t) & (f)) - -#define UMODEMUNIT_MASK 0x3ffff -#define UMODEMDIALOUT_MASK 0x80000 -#define UMODEMCALLUNIT_MASK 0x40000 - -#define UMODEMUNIT(x) (minor(x) & UMODEMUNIT_MASK) -#define UMODEMDIALOUT(x) (minor(x) & UMODEMDIALOUT_MASK) -#define UMODEMCALLUNIT(x) (minor(x) & UMODEMCALLUNIT_MASK) - +/* + * These are the maximum number of bytes transferred per frame. + * If some really high speed devices should use this driver they + * may need to be increased, but this is good enough for normal modems. + */ #define UMODEMIBUFSIZE 64 +#define UMODEMOBUFSIZE 256 + +#define UMODEM_MODVER 1 /* module version */ struct umodem_softc { + struct ucom_softc sc_ucom; + USBBASEDEVICE sc_dev; /* base device */ usbd_device_handle sc_udev; /* USB device */ @@ -119,104 +137,94 @@ int sc_data_iface_no; usbd_interface_handle sc_data_iface; /* data interface */ - int sc_bulkin_no; /* bulk in endpoint address */ - usbd_pipe_handle sc_bulkin_pipe; /* bulk in pipe */ - usbd_xfer_handle sc_ixfer; /* read request */ - u_char *sc_ibuf; /* read buffer */ - - int sc_bulkout_no; /* bulk out endpoint address */ - usbd_pipe_handle sc_bulkout_pipe;/* bulk out pipe */ - usbd_xfer_handle sc_oxfer; /* read request */ - int sc_cm_cap; /* CM capabilities */ int sc_acm_cap; /* ACM capabilities */ int sc_cm_over_data; - struct tty *sc_tty; /* our tty */ - usb_cdc_line_state_t sc_line_state; /* current line state */ u_char sc_dtr; /* current DTR state */ + u_char sc_rts; /* current RTS state */ u_char sc_opening; /* lock during open */ - u_char sc_dying; /* disconnecting */ -#if defined(__FreeBSD__) - dev_t dev; /* special device node */ -#endif + int sc_ctl_notify; /* Notification endpoint */ + usbd_pipe_handle sc_notify_pipe; /* Notification pipe */ + usb_cdc_notification_t sc_notify_buf; /* Notification structure */ + u_char sc_lsr; /* Local status register */ + u_char sc_msr; /* Modem status register */ }; -#if defined(__NetBSD__) || defined(__OpenBSD__) -cdev_decl(umodem); +Static void *umodem_get_desc(usbd_device_handle dev, int type, int subtype); +Static usbd_status umodem_set_comm_feature(struct umodem_softc *sc, + int feature, int state); +Static usbd_status umodem_set_line_coding(struct umodem_softc *sc, + usb_cdc_line_state_t *state); + +Static void umodem_get_caps(usbd_device_handle, int *, int *); + +Static void umodem_get_status(void *, int portno, u_char *lsr, u_char *msr); +Static void umodem_set(void *, int, int, int); +Static void umodem_dtr(struct umodem_softc *, int); +Static void umodem_rts(struct umodem_softc *, int); +Static void umodem_break(struct umodem_softc *, int); +Static void umodem_set_line_state(struct umodem_softc *); +Static int umodem_param(void *, int, struct termios *); +Static int umodem_ioctl(void *, int, u_long, caddr_t, int, usb_proc_ptr ); +Static int umodem_open(void *, int portno); +Static void umodem_close(void *, int portno); +Static void umodem_intr(usbd_xfer_handle, usbd_private_handle, usbd_status); + +Static struct ucom_callback umodem_callback = { + umodem_get_status, + umodem_set, + umodem_param, + umodem_ioctl, + umodem_open, + umodem_close, + NULL, + NULL, +}; -#elif defined(__FreeBSD__) -d_open_t umodemopen; -d_close_t umodemclose; -d_read_t umodemread; -d_write_t umodemwrite; -d_ioctl_t umodemioctl; - -#define UMODEM_CDEV_MAJOR 124 - -static struct cdevsw umodem_cdevsw = { - /* open */ umodemopen, - /* close */ umodemclose, - /* read */ umodemread, - /* write */ umodemwrite, - /* ioctl */ umodemioctl, - /* poll */ ttypoll, - /* mmap */ nommap, - /* strategy */ nostrategy, - /* name */ "umodem", - /* maj */ UMODEM_CDEV_MAJOR, - /* dump */ nodump, - /* psize */ nopsize, - /* flags */ D_TTY | D_KQFILTER, - /* bmaj */ -1, - /* kqfilter */ ttykqfilter, +Static device_probe_t umodem_match; +Static device_attach_t umodem_attach; +Static device_detach_t umodem_detach; + +Static device_method_t umodem_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, umodem_match), + DEVMETHOD(device_attach, umodem_attach), + DEVMETHOD(device_detach, umodem_detach), + { 0, 0 } }; -#endif -void *umodem_get_desc - (usbd_device_handle dev, int type, int subtype); -usbd_status umodem_set_comm_feature - (struct umodem_softc *sc, int feature, int state); -usbd_status umodem_set_line_coding - (struct umodem_softc *sc, usb_cdc_line_state_t *state); - -void umodem_get_caps (usbd_device_handle, int *, int *); -void umodem_cleanup (struct umodem_softc *); -int umodemparam (struct tty *, struct termios *); -void umodemstart (struct tty *); -void umodemstop (struct tty *, int); -struct tty * umodemtty (dev_t dev); -void umodem_shutdown (struct umodem_softc *); -void umodem_modem (struct umodem_softc *, int); -void umodem_break (struct umodem_softc *, int); -usbd_status umodemstartread (struct umodem_softc *); -void umodemreadcb (usbd_xfer_handle, usbd_private_handle, - usbd_status status); -void umodemwritecb (usbd_xfer_handle, usbd_private_handle, - usbd_status status); +Static driver_t umodem_driver = { + "ucom", + umodem_methods, + sizeof (struct umodem_softc) +}; -USB_DECLARE_DRIVER(umodem); +DRIVER_MODULE(umodem, uhub, umodem_driver, ucom_devclass, usbd_driver_load, 0); +MODULE_DEPEND(umodem, usb, 1, 1, 1); +MODULE_DEPEND(umodem, ucom, UCOM_MINVER, UCOM_PREFVER, UCOM_MAXVER); +MODULE_VERSION(umodem, UMODEM_MODVER); USB_MATCH(umodem) { USB_MATCH_START(umodem, uaa); usb_interface_descriptor_t *id; int cm, acm; - - if (!uaa->iface) + + if (uaa->iface == NULL) return (UMATCH_NONE); id = usbd_get_interface_descriptor(uaa->iface); - if (id == 0 || + if (id == NULL || id->bInterfaceClass != UICLASS_CDC || id->bInterfaceSubClass != UISUBCLASS_ABSTRACT_CONTROL_MODEL || id->bInterfaceProtocol != UIPROTO_CDC_AT) return (UMATCH_NONE); - + umodem_get_caps(uaa->device, &cm, &acm); if (!(cm & USB_CDC_CM_DOES_CM) || !(cm & USB_CDC_CM_OVER_DATA) || @@ -233,296 +241,310 @@ usb_interface_descriptor_t *id; usb_endpoint_descriptor_t *ed; usb_cdc_cm_descriptor_t *cmd; - char devinfo[1024]; + char *devinfo = NULL; + const char *devname; usbd_status err; - int data_ifaceno; + int data_ifcno; int i; - struct tty *tp; + struct ucom_softc *ucom; - usbd_devinfo(uaa->device, 0, devinfo); - USB_ATTACH_SETUP; + devinfo = malloc(1024, M_USBDEV, M_WAITOK); + usbd_devinfo(dev, 0, devinfo); + ucom = &sc->sc_ucom; + ucom->sc_dev = self; + sc->sc_dev = self; + device_set_desc_copy(self, devinfo); + ucom->sc_udev = dev; + ucom->sc_iface = uaa->iface; + /*USB_ATTACH_SETUP; */ sc->sc_udev = dev; - sc->sc_ctl_iface = uaa->iface; + + devname = USBDEVNAME(sc->sc_dev); + /* XXX ? use something else ? XXX */ id = usbd_get_interface_descriptor(sc->sc_ctl_iface); - printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev), - devinfo, id->bInterfaceClass, id->bInterfaceSubClass); + printf("%s: %s, iclass %d/%d\n", devname, devinfo, + id->bInterfaceClass, id->bInterfaceSubClass); sc->sc_ctl_iface_no = id->bInterfaceNumber; umodem_get_caps(dev, &sc->sc_cm_cap, &sc->sc_acm_cap); /* Get the data interface no. */ cmd = umodem_get_desc(dev, UDESC_CS_INTERFACE, UDESCSUB_CDC_CM); - if (!cmd) { - DPRINTF(("%s: no CM desc\n", USBDEVNAME(sc->sc_dev))); + if (cmd == NULL) { + printf("%s: no CM descriptor\n", devname); goto bad; } - sc->sc_data_iface_no = data_ifaceno = cmd->bDataInterface; + sc->sc_data_iface_no = data_ifcno = cmd->bDataInterface; printf("%s: data interface %d, has %sCM over data, has %sbreak\n", - USBDEVNAME(sc->sc_dev), data_ifaceno, + devname, data_ifcno, sc->sc_cm_cap & USB_CDC_CM_OVER_DATA ? "" : "no ", sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK ? "" : "no "); - /* Get the data interface too. */ for (i = 0; i < uaa->nifaces; i++) { - if (uaa->ifaces[i]) { + if (uaa->ifaces[i] != NULL) { id = usbd_get_interface_descriptor(uaa->ifaces[i]); - if (id->bInterfaceNumber == data_ifaceno) { + if (id != NULL && id->bInterfaceNumber == data_ifcno) { sc->sc_data_iface = uaa->ifaces[i]; - uaa->ifaces[i] = 0; + uaa->ifaces[i] = NULL; } } } - if (!sc->sc_data_iface) { - printf("%s: no data interface\n", USBDEVNAME(sc->sc_dev)); + if (sc->sc_data_iface == NULL) { + printf("%s: no data interface\n", devname); goto bad; } + ucom->sc_iface = sc->sc_data_iface; - /* - * Find the bulk endpoints. + /* + * Find the bulk endpoints. * Iterate over all endpoints in the data interface and take note. */ - sc->sc_bulkin_no = sc->sc_bulkout_no = -1; + ucom->sc_bulkin_no = ucom->sc_bulkout_no = -1; id = usbd_get_interface_descriptor(sc->sc_data_iface); for (i = 0; i < id->bNumEndpoints; i++) { ed = usbd_interface2endpoint_descriptor(sc->sc_data_iface, i); - if (!ed) { - printf("%s: no endpoint descriptor for %d\n", - USBDEVNAME(sc->sc_dev), i); + if (ed == NULL) { + printf("%s: no endpoint descriptor for %d\n", devname, + i); goto bad; } if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && - (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) { - sc->sc_bulkin_no = ed->bEndpointAddress; + UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { + ucom->sc_bulkin_no = ed->bEndpointAddress; } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && - (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) { - sc->sc_bulkout_no = ed->bEndpointAddress; + UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { + ucom->sc_bulkout_no = ed->bEndpointAddress; } } - if (sc->sc_bulkin_no == -1) { - DPRINTF(("%s: Could not find data bulk in\n", - USBDEVNAME(sc->sc_dev))); + if (ucom->sc_bulkin_no == -1) { + printf("%s: Could not find data bulk in\n", devname); goto bad; } - if (sc->sc_bulkout_no == -1) { - DPRINTF(("%s: Could not find data bulk out\n", - USBDEVNAME(sc->sc_dev))); + if (ucom->sc_bulkout_no == -1) { + printf("%s: Could not find data bulk out\n", devname); goto bad; } if (usbd_get_quirks(sc->sc_udev)->uq_flags & UQ_ASSUME_CM_OVER_DATA) { + DPRINTF(("Quirk says to assume CM over data\n")); sc->sc_cm_over_data = 1; } else { - if (sc->sc_cm_cap & USB_CDC_CM_OVER_DATA) { - err = umodem_set_comm_feature(sc, UCDC_ABSTRACT_STATE, - UCDC_DATA_MULTIPLEXED); - if (err) - goto bad; - sc->sc_cm_over_data = 1; - } + if (sc->sc_cm_cap & USB_CDC_CM_OVER_DATA) { + if (sc->sc_acm_cap & USB_CDC_ACM_HAS_FEATURE) + err = umodem_set_comm_feature(sc, + UCDC_ABSTRACT_STATE, UCDC_DATA_MULTIPLEXED); + else + err = 0; + if (err) { + printf("%s: could not set data multiplex mode\n", + devname); + goto bad; + } + sc->sc_cm_over_data = 1; + } } -#if defined(__NetBSD__) || defined(__OpenBSD__) - sc->sc_tty = tp = ttymalloc(); -#elif defined(__FreeBSD__) - sc->sc_tty = tp = ttymalloc(sc->sc_tty); -#endif - tp->t_oproc = umodemstart; - tp->t_param = umodemparam; - tp->t_stop = umodemstop; - DPRINTF(("umodem_attach: tty_attach %p\n", tp)); -#if defined(__NetBSD__) || defined(__OpenBSD__) - tty_attach(tp); -#endif + /* + * The standard allows for notification messages (to indicate things + * like a modem hangup) to come in via an interrupt endpoint + * off of the control interface. Iterate over the endpoints on + * the control interface and see if there are any interrupt + * endpoints; if there are, then register it. + */ -#if defined(__FreeBSD__) - DPRINTF(("umodem_attach: make_dev: umodem%d\n", device_get_unit(self))); - sc->dev = make_dev(&umodem_cdevsw, device_get_unit(self), - UID_UUCP, GID_DIALER, 0660, - "umodem%d", device_get_unit(self)); - sc->dev->si_tty = tp; -#endif + sc->sc_ctl_notify = -1; + sc->sc_notify_pipe = NULL; + + for (i = 0; i < id->bNumEndpoints; i++) { + ed = usbd_interface2endpoint_descriptor(sc->sc_ctl_iface, i); + if (ed == NULL) + continue; + + if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && + (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) { + printf("%s: status change notification available\n", + devname); + sc->sc_ctl_notify = ed->bEndpointAddress; + } + } sc->sc_dtr = -1; + ucom->sc_parent = sc; + ucom->sc_portno = UCOM_UNK_PORTNO; + /* bulkin, bulkout set above */ + ucom->sc_ibufsize = UMODEMIBUFSIZE; + ucom->sc_obufsize = UMODEMOBUFSIZE; + ucom->sc_ibufsizepad = UMODEMIBUFSIZE; + ucom->sc_opkthdrlen = 0; + ucom->sc_callback = &umodem_callback; + + ucom_attach(&sc->sc_ucom); + + free(devinfo, M_USBDEV); USB_ATTACH_SUCCESS_RETURN; bad: - DPRINTF(("umodem_attach: BAD -> DYING\n")); - sc->sc_dying = 1; + ucom->sc_dying = 1; + free(devinfo, M_USBDEV); USB_ATTACH_ERROR_RETURN; } -void -umodem_get_caps(usbd_device_handle dev, int *cm, int *acm) +Static int +umodem_open(void *addr, int portno) { - usb_cdc_cm_descriptor_t *cmd; - usb_cdc_acm_descriptor_t *cad; + struct umodem_softc *sc = addr; + int err; - *cm = *acm = 0; + DPRINTF(("umodem_open: sc=%p\n", sc)); - cmd = umodem_get_desc(dev, UDESC_CS_INTERFACE, UDESCSUB_CDC_CM); - if (!cmd) { - DPRINTF(("umodem_get_desc: no CM desc\n")); - return; - } - *cm = cmd->bmCapabilities; + if (sc->sc_ctl_notify != -1 && sc->sc_notify_pipe == NULL) { + err = usbd_open_pipe_intr(sc->sc_ctl_iface, sc->sc_ctl_notify, + USBD_SHORT_XFER_OK, &sc->sc_notify_pipe, sc, + &sc->sc_notify_buf, sizeof(sc->sc_notify_buf), + umodem_intr, USBD_DEFAULT_INTERVAL); - cad = umodem_get_desc(dev, UDESC_CS_INTERFACE, UDESCSUB_CDC_ACM); - if (!cad) { - DPRINTF(("umodem_get_desc: no ACM desc\n")); - return; + if (err) { + DPRINTF(("Failed to establish notify pipe: %s\n", + usbd_errstr(err))); + return EIO; + } } - *acm = cad->bmCapabilities; -} -void -umodemstart(struct tty *tp) -{ - struct umodem_softc *sc; - struct cblock *cbp; - int s; - u_char *data; - int cnt; + return 0; +} - USB_GET_SC(umodem, UMODEMUNIT(tp->t_dev), sc); +Static void +umodem_close(void *addr, int portno) +{ + struct umodem_softc *sc = addr; + int err; - if (sc->sc_dying) - return; + DPRINTF(("umodem_close: sc=%p\n", sc)); - s = spltty(); - if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) { - ttwwakeup(tp); - DPRINTFN(4,("umodemstart: stopped\n")); - goto out; + if (sc->sc_notify_pipe != NULL) { + err = usbd_abort_pipe(sc->sc_notify_pipe); + if (err) + printf("%s: abort notify pipe failed: %s\n", + USBDEVNAME(sc->sc_dev), usbd_errstr(err)); + err = usbd_close_pipe(sc->sc_notify_pipe); + if (err) + printf("%s: close notify pipe failed: %s\n", + USBDEVNAME(sc->sc_dev), usbd_errstr(err)); + sc->sc_notify_pipe = NULL; } +} -#if defined(__NetBSD__) || defined(__OpenBSD__) - if (tp->t_outq.c_cc <= tp->t_lowat) { - if (ISSET(tp->t_state, TS_ASLEEP)) { - CLR(tp->t_state, TS_ASLEEP); - wakeup(&tp->t_outq); - } - selwakeup(&tp->t_wsel); - if (tp->t_outq.c_cc == 0) - goto out; - } -#elif defined(__FreeBSD__) - if (tp->t_outq.c_cc <= tp->t_olowat) { - if (ISSET(tp->t_state, TS_SO_OLOWAT)) { - CLR(tp->t_state, TS_SO_OLOWAT); - wakeup(TSA_OLOWAT(tp)); - } - selwakeup(&tp->t_wsel); - if (tp->t_outq.c_cc == 0) { - if (ISSET(tp->t_state, TS_BUSY | TS_SO_OCOMPLETE) == - TS_SO_OCOMPLETE && tp->t_outq.c_cc == 0) { - CLR(tp->t_state, TS_SO_OCOMPLETE); - wakeup(TSA_OCOMPLETE(tp)); - } - goto out; - } - } -#endif +Static void +umodem_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) +{ + struct umodem_softc *sc = priv; + u_char mstatus; - /* Grab the first contiguous region of buffer space. */ - data = tp->t_outq.c_cf; -#if defined(__NetBSD__) || defined(__OpenBSD__) - cnt = ndqb(&tp->t_outq, 0); -#elif defined(__FreeBSD__) - cbp = (struct cblock *) ((intptr_t) tp->t_outq.c_cf & ~CROUND); - cnt = min((char *) (cbp+1) - tp->t_outq.c_cf, tp->t_outq.c_cc); -#endif + if (sc->sc_ucom.sc_dying) + return; - if (cnt == 0) { - DPRINTF(("umodemstart: cnt==0\n")); - splx(s); + if (status != USBD_NORMAL_COMPLETION) { + if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) + return; + printf("%s: abnormal status: %s\n", USBDEVNAME(sc->sc_dev), + usbd_errstr(status)); return; } - SET(tp->t_state, TS_BUSY); + if (sc->sc_notify_buf.bmRequestType != UCDC_NOTIFICATION) { + DPRINTF(("%s: unknown message type (%02x) on notify pipe\n", + USBDEVNAME(sc->sc_dev), + sc->sc_notify_buf.bmRequestType)); + return; + } - DPRINTFN(4,("umodemstart: %d chars\n", cnt)); - /* XXX what can we do on error? */ - usbd_setup_xfer(sc->sc_oxfer, sc->sc_bulkout_pipe, - (usbd_private_handle)sc, data, cnt, - 0, USBD_NO_TIMEOUT, umodemwritecb); - (void)usbd_transfer(sc->sc_oxfer); - - ttwwakeup(tp); -out: - splx(s); + switch (sc->sc_notify_buf.bNotification) { + case UCDC_N_SERIAL_STATE: + /* + * Set the serial state in ucom driver based on + * the bits from the notify message + */ + if (UGETW(sc->sc_notify_buf.wLength) != 2) { + printf("%s: Invalid notification length! (%d)\n", + USBDEVNAME(sc->sc_dev), + UGETW(sc->sc_notify_buf.wLength)); + break; + } + DPRINTF(("%s: notify bytes = %02x%02x\n", + USBDEVNAME(sc->sc_dev), + sc->sc_notify_buf.data[0], + sc->sc_notify_buf.data[1])); + /* Currently, lsr is always zero. */ + sc->sc_lsr = sc->sc_msr = 0; + mstatus = sc->sc_notify_buf.data[0]; + + if (ISSET(mstatus, UCDC_N_SERIAL_RI)) + sc->sc_msr |= UMSR_RI; + if (ISSET(mstatus, UCDC_N_SERIAL_DSR)) + sc->sc_msr |= UMSR_DSR; + if (ISSET(mstatus, UCDC_N_SERIAL_DCD)) + sc->sc_msr |= UMSR_DCD; + ucom_status_change(&sc->sc_ucom); + break; + default: + DPRINTF(("%s: unknown notify message: %02x\n", + USBDEVNAME(sc->sc_dev), + sc->sc_notify_buf.bNotification)); + break; + } } void -umodemwritecb(usbd_xfer_handle xfer, usbd_private_handle priv, - usbd_status status) +umodem_get_caps(usbd_device_handle dev, int *cm, int *acm) { - struct umodem_softc *sc = (struct umodem_softc *)priv; - struct tty *tp = sc->sc_tty; - u_int32_t cc; - int s; + usb_cdc_cm_descriptor_t *cmd; + usb_cdc_acm_descriptor_t *cad; - DPRINTFN(5,("umodemwritecb: status=%d\n", status)); + *cm = *acm = 0; - if (status == USBD_CANCELLED) + cmd = umodem_get_desc(dev, UDESC_CS_INTERFACE, UDESCSUB_CDC_CM); + if (cmd == NULL) { + DPRINTF(("umodem_get_desc: no CM desc\n")); return; + } + *cm = cmd->bmCapabilities; - if (status != USBD_NORMAL_COMPLETION) { - DPRINTF(("umodemwritecb: status=%d\n", status)); - usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe); - /* XXX we should restart after some delay. */ + cad = umodem_get_desc(dev, UDESC_CS_INTERFACE, UDESCSUB_CDC_ACM); + if (cad == NULL) { + DPRINTF(("umodem_get_desc: no ACM desc\n")); return; } + *acm = cad->bmCapabilities; +} - usbd_get_xfer_status(xfer, 0, 0, &cc, 0); - DPRINTFN(5,("umodemwritecb: cc=%d\n", cc)); +void +umodem_get_status(void *addr, int portno, u_char *lsr, u_char *msr) +{ + struct umodem_softc *sc = addr; - s = spltty(); - CLR(tp->t_state, TS_BUSY); - if (ISSET(tp->t_state, TS_FLUSH)) - CLR(tp->t_state, TS_FLUSH); - else - ndflush(&tp->t_outq, cc); - (*linesw[tp->t_line].l_start)(tp); - splx(s); + DPRINTF(("umodem_get_status:\n")); + + if (lsr != NULL) + *lsr = sc->sc_lsr; + if (msr != NULL) + *msr = sc->sc_msr; } int -umodemparam(struct tty *tp, struct termios *t) +umodem_param(void *addr, int portno, struct termios *t) { - struct umodem_softc *sc; + struct umodem_softc *sc = addr; + usbd_status err; usb_cdc_line_state_t ls; - USB_GET_SC(umodem, UMODEMUNIT(tp->t_dev), sc); - - if (sc->sc_dying) - return (EIO); - - /* Check requested parameters. */ - if (t->c_ospeed < 0) - return (EINVAL); - if (t->c_ispeed && t->c_ispeed != t->c_ospeed) - return (EINVAL); - - /* - * If there were no changes, don't do anything. This avoids dropping - * input and improves performance when all we did was frob things like - * VMIN and VTIME. - */ - if (tp->t_ospeed == t->c_ospeed && - tp->t_cflag == t->c_cflag) - return (0); - - /* And copy to tty. */ - tp->t_ispeed = 0; - tp->t_ospeed = t->c_ospeed; - tp->t_cflag = t->c_cflag; + DPRINTF(("umodem_param: sc=%p\n", sc)); USETDW(ls.dwDTERate, t->c_ospeed); if (ISSET(t->c_cflag, CSTOPB)) @@ -550,411 +572,28 @@ ls.bDataBits = 8; break; } - /* XXX what can we if it fails? */ - (void)umodem_set_line_coding(sc, &ls); - - /* - * Update the tty layer's idea of the carrier bit, in case we changed - * CLOCAL or MDMBUF. We don't hang up here; we only do that by - * explicit request. - */ - (void) (*linesw[tp->t_line].l_modem)(tp, 1 /* XXX carrier */ ); - - return (0); -} -int -umodemopen(dev_t dev, int flag, int mode, usb_proc_ptr p) -{ - int unit = UMODEMUNIT(dev); - struct umodem_softc *sc; - usbd_status err; - struct tty *tp; - int s; - int error; - - USB_GET_SC_OPEN(umodem, unit, sc); - - if (sc->sc_dying) - return (EIO); - -#if defined(__NetBSD__) || defined(__OpenBBSD__) - if (ISSET(sc->sc_dev.dv_flags, DVF_ACTIVE) == 0) - return (ENXIO); -#endif - - tp = sc->sc_tty; - - DPRINTF(("%s: umodemopen: tp=%p\n", USBDEVNAME(sc->sc_dev), tp)); - - if (ISSET(tp->t_state, TS_ISOPEN) && - ISSET(tp->t_state, TS_XCLUDE) && - p->p_ucred->cr_uid != 0) - return (EBUSY); - - /* - * Do the following iff this is a first open. - */ - s = spltty(); - while (sc->sc_opening) - tsleep(&sc->sc_opening, PRIBIO, "umdmop", 0); - sc->sc_opening = 1; - -#if defined(__NetBSD__) || defined(__OpenBSD__) - if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { -#elif defined(__FreeBSD__) - if (!ISSET(tp->t_state, TS_ISOPEN)) { -#endif - struct termios t; - - tp->t_dev = dev; - - /* - * Initialize the termios status to the defaults. Add in the - * sticky bits from TIOCSFLAGS. - */ - t.c_ispeed = 0; - t.c_ospeed = TTYDEF_SPEED; - t.c_cflag = TTYDEF_CFLAG; - /* Make sure umodemparam() will do something. */ - tp->t_ospeed = 0; - (void) umodemparam(tp, &t); - tp->t_iflag = TTYDEF_IFLAG; - tp->t_oflag = TTYDEF_OFLAG; - tp->t_lflag = TTYDEF_LFLAG; - ttychars(tp); - ttsetwater(tp); - - /* - * Turn on DTR. We must always do this, even if carrier is not - * present, because otherwise we'd have to use TIOCSDTR - * immediately after setting CLOCAL, which applications do not - * expect. We always assert DTR while the device is open - * unless explicitly requested to deassert it. - */ - umodem_modem(sc, 1); - - DPRINTF(("umodemopen: open pipes\n")); - - /* Open the bulk pipes */ - err = usbd_open_pipe(sc->sc_data_iface, sc->sc_bulkin_no, 0, - &sc->sc_bulkin_pipe); - if (err) { - DPRINTF(("%s: cannot open bulk out pipe (addr %d)\n", - USBDEVNAME(sc->sc_dev), sc->sc_bulkin_no)); - return (EIO); - } - err = usbd_open_pipe(sc->sc_data_iface, sc->sc_bulkout_no, - USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe); - if (err) { - DPRINTF(("%s: cannot open bulk in pipe (addr %d)\n", - USBDEVNAME(sc->sc_dev), sc->sc_bulkout_no)); - usbd_close_pipe(sc->sc_bulkin_pipe); - return (EIO); - } - - /* Allocate a request and an input buffer and start reading. */ - sc->sc_ixfer = usbd_alloc_xfer(sc->sc_udev); - if (sc->sc_ixfer == 0) { - usbd_close_pipe(sc->sc_bulkin_pipe); - usbd_close_pipe(sc->sc_bulkout_pipe); - return (ENOMEM); - } - sc->sc_oxfer = usbd_alloc_xfer(sc->sc_udev); - if (sc->sc_oxfer == 0) { - usbd_close_pipe(sc->sc_bulkin_pipe); - usbd_close_pipe(sc->sc_bulkout_pipe); - usbd_free_xfer(sc->sc_ixfer); - return (ENOMEM); - } - sc->sc_ibuf = malloc(UMODEMIBUFSIZE, M_USBDEV, M_WAITOK); - umodemstartread(sc); - } - sc->sc_opening = 0; - wakeup(&sc->sc_opening); - splx(s); - -#if defined(__NetBSD__) || defined(__OpenBSD__) - error = ttyopen(tp, UMODEMDIALOUT(dev), ISSET(flag, O_NONBLOCK)); - if (error) - goto bad; -#elif defined(__FreeBSD__) - error = ttyopen(dev, tp); - if (error) - goto bad; -#endif - - error = (*linesw[tp->t_line].l_open)(dev, tp); - if (error) - goto bad; - - return (0); - -bad: -#if defined(__NetBSD__) || defined(__OpenBSD__) - if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { -#elif defined(__FreeBSD__) - if (!ISSET(tp->t_state, TS_ISOPEN)) { -#endif - /* - * We failed to open the device, and nobody else had it opened. - * Clean up the state as appropriate. - */ - umodem_cleanup(sc); - } - - return (error); -} - -usbd_status -umodemstartread(struct umodem_softc *sc) -{ - usbd_status err; - - DPRINTFN(5,("umodemstartread: start\n")); - usbd_setup_xfer(sc->sc_ixfer, sc->sc_bulkin_pipe, - (usbd_private_handle)sc, - sc->sc_ibuf, UMODEMIBUFSIZE, USBD_SHORT_XFER_OK, - USBD_NO_TIMEOUT, umodemreadcb); - - err = usbd_transfer(sc->sc_ixfer); - if (err != USBD_IN_PROGRESS) - return (err); - - return (USBD_NORMAL_COMPLETION); -} - -void -umodemreadcb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status) -{ - struct umodem_softc *sc = (struct umodem_softc *)p; - struct tty *tp = sc->sc_tty; - int (*rint) (int c, struct tty *tp) = linesw[tp->t_line].l_rint; - usbd_status err; - u_int32_t cc; - u_char *cp; - int s; - - if (status == USBD_CANCELLED) - return; - - if (status != USBD_NORMAL_COMPLETION) { - DPRINTF(("umodemreadcb: status=%d\n", status)); - usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe); - /* XXX we should restart after some delay. */ - return; - } - - usbd_get_xfer_status(xfer, 0, (void **)&cp, &cc, 0); - DPRINTFN(5,("umodemreadcb: got %d chars, tp=%p\n", cc, tp)); - s = spltty(); - /* Give characters to tty layer. */ - while (cc-- > 0) { - DPRINTFN(7,("umodemreadcb: char=0x%02x\n", *cp)); - if ((*rint)(*cp++, tp) == -1) { - /* XXX what should we do? */ - break; - } - } - splx(s); - - err = umodemstartread(sc); + err = umodem_set_line_coding(sc, &ls); if (err) { - printf("%s: read start failed\n", USBDEVNAME(sc->sc_dev)); - /* XXX what should we dow now? */ + DPRINTF(("umodem_param: err=%s\n", usbd_errstr(err))); + return (ENOTTY); } -} - -int -umodemclose(dev_t dev, int flag, int mode, usb_proc_ptr p) -{ - struct umodem_softc *sc; - struct tty *tp; - int s; - - USB_GET_SC(umodem, UMODEMUNIT(dev), sc); - - tp = sc->sc_tty; - - DPRINTF(("%s: umodemclose sc_tty=%p\n", USBDEVNAME(sc->sc_dev), tp)); - - if (!ISSET(tp->t_state, TS_ISOPEN)) - return (0); - - DPRINTF(("%s: umodemclose lclose(%p,%d)\n", USBDEVNAME(sc->sc_dev), tp,flag)); - - s=spltty(); - DPRINTF(("%s: umodemclose lclose=%p\n", USBDEVNAME(sc->sc_dev), linesw[tp->t_line].l_close)); - (*linesw[tp->t_line].l_close)(tp, flag); - - DPRINTF(("%s: umodemclose ttyclose(%p)\n", USBDEVNAME(sc->sc_dev), tp)); - ttyclose(tp); - splx(s); - - DPRINTF(("%s: umodemclose sc->sc_dying=%d\n", USBDEVNAME(sc->sc_dev), sc->sc_dying)); - if (sc->sc_dying) - return (0); - - DPRINTF(("%s: umodemclose tp->t_state=%d\n", USBDEVNAME(sc->sc_dev), tp->t_state)); -#if defined(__NetBSD__) || defined(__OpenBSD__) - if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { -#elif defined(__FreeBSD__) - if (!ISSET(tp->t_state, TS_ISOPEN)) { -#endif - /* - * Although we got a last close, the device may still be in - * use; e.g. if this was the dialout node, and there are still - * processes waiting for carrier on the non-dialout node. - */ - DPRINTF(("%s: umodemclose umodem_cleanup(%p)\n", USBDEVNAME(sc->sc_dev), sc)); - umodem_cleanup(sc); - } - DPRINTF(("%s: umodemclose return\n", USBDEVNAME(sc->sc_dev))); - return (0); } - -void -umodem_cleanup(struct umodem_softc *sc) -{ - umodem_shutdown(sc); - - DPRINTFN(5, ("%s: umodem_cleanup: closing pipes\n", - USBDEVNAME(sc->sc_dev))); - - usbd_abort_pipe(sc->sc_bulkin_pipe); - usbd_close_pipe(sc->sc_bulkin_pipe); - usbd_abort_pipe(sc->sc_bulkout_pipe); - usbd_close_pipe(sc->sc_bulkout_pipe); - usbd_free_xfer(sc->sc_ixfer); - usbd_free_xfer(sc->sc_oxfer); - free(sc->sc_ibuf, M_USBDEV); -} int -umodemread(dev_t dev, struct uio *uio, int flag) +umodem_ioctl(void *addr, int portno, u_long cmd, caddr_t data, int flag, + usb_proc_ptr p) { - struct umodem_softc *sc; - struct tty *tp; - - USB_GET_SC(umodem, UMODEMUNIT(dev), sc); + struct umodem_softc *sc = addr; + int error = 0; - tp = sc->sc_tty; - - if (sc->sc_dying) + if (sc->sc_ucom.sc_dying) return (EIO); - - return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); -} - -int -umodemwrite(dev_t dev, struct uio *uio, int flag) -{ - struct umodem_softc *sc; - struct tty *tp; - - USB_GET_SC(umodem, UMODEMUNIT(dev), sc); - - tp = sc->sc_tty; - - if (sc->sc_dying) - return (EIO); - - return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); -} - -void -umodemstop(struct tty *tp, int flag) -{ - struct umodem_softc *sc; - int s; - - USB_GET_SC(umodem, UMODEMUNIT(tp->t_dev), sc); - DPRINTF(("umodemstop: %d\n", flag)); - s = spltty(); - if (ISSET(tp->t_state, TS_BUSY)) { - DPRINTF(("umodemstop: XXX\n")); - /* XXX do what? */ - if (!ISSET(tp->t_state, TS_TTSTOP)) - SET(tp->t_state, TS_FLUSH); - } - splx(s); -} - -struct tty * -umodemtty(dev_t dev) -{ - struct umodem_softc *sc; - struct tty *tp; - - USB_GET_SC(umodem, UMODEMUNIT(dev), sc); - - tp = sc->sc_tty; - - return (tp); -} - -int -umodemioctl(dev_t dev, u_long cmd, caddr_t data, int flag, usb_proc_ptr p) -{ - struct umodem_softc *sc; - struct tty *tp; - int error; - int s; - int bits; - - USB_GET_SC(umodem, UMODEMUNIT(dev), sc); - - tp = sc->sc_tty; - - if (sc->sc_dying) - return (EIO); - DPRINTF(("umodemioctl: cmd=0x%08lx\n", cmd)); - error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); - if (error >= 0) - return (error); - -#if defined(__NetBSD__) || defined(__OpenBSD__) - error = ttioctl(tp, cmd, data, flag, p); -#elif defined(__FreeBSD__) - error = ttioctl(tp, cmd, data, flag); -#endif - if (error >= 0) - return (error); - - DPRINTF(("umodemioctl: our cmd=0x%08lx\n", cmd)); - s = spltty(); - switch (cmd) { - case TIOCSBRK: - umodem_break(sc, 1); - break; - - case TIOCCBRK: - umodem_break(sc, 0); - break; - - case TIOCSDTR: - umodem_modem(sc, 1); - break; - - case TIOCCDTR: - umodem_modem(sc, 0); - break; - - case TIOCMGET: - bits = TIOCM_LE; - if(sc->sc_dtr) - bits |= TIOCM_DTR; - *(int *)data = bits; - break; - - case TIOCMSET: - break; - case USB_GET_CM_OVER_DATA: *(int *)data = sc->sc_cm_over_data; break; @@ -968,53 +607,52 @@ default: DPRINTF(("umodemioctl: unknown\n")); error = ENOTTY; - splx(s); - return (error); + break; } - splx(s); - return(0); + return (error); } void -umodem_shutdown(struct umodem_softc *sc) +umodem_dtr(struct umodem_softc *sc, int onoff) { - struct tty *tp = sc->sc_tty; + DPRINTF(("umodem_modem: onoff=%d\n", onoff)); - DPRINTF(("%s: umodem_shutdown\n", USBDEVNAME(sc->sc_dev))); - /* - * Hang up if necessary. Wait a bit, so the other side has time to - * notice even if we immediately open the port again. - */ - if (ISSET(tp->t_cflag, HUPCL)) { - umodem_modem(sc, 0); -#if defined(__NetBSD__) || defined(__OpenBSD__) - (void) tsleep(sc, TTIPRI, ttclos, hz); -#elif defined(__FreeBSD__) - (void) tsleep(sc, TTIPRI, "umdmsd", hz); -#endif - } + if (sc->sc_dtr == onoff) + return; + sc->sc_dtr = onoff; + + umodem_set_line_state(sc); } void -umodem_modem(struct umodem_softc *sc, int onoff) +umodem_rts(struct umodem_softc *sc, int onoff) { - usb_device_request_t req; + DPRINTF(("umodem_modem: onoff=%d\n", onoff)); - DPRINTF(("%s: umodem_modem: onoff=%d\n", USBDEVNAME(sc->sc_dev),onoff)); - - if (sc->sc_dtr == onoff) + if (sc->sc_rts == onoff) return; + sc->sc_rts = onoff; + umodem_set_line_state(sc); +} + +void +umodem_set_line_state(struct umodem_softc *sc) +{ + usb_device_request_t req; + int ls; + + ls = (sc->sc_dtr ? UCDC_LINE_DTR : 0) | + (sc->sc_rts ? UCDC_LINE_RTS : 0); req.bmRequestType = UT_WRITE_CLASS_INTERFACE; req.bRequest = UCDC_SET_CONTROL_LINE_STATE; - USETW(req.wValue, onoff ? UCDC_LINE_DTR : 0); + USETW(req.wValue, ls); USETW(req.wIndex, sc->sc_ctl_iface_no); USETW(req.wLength, 0); (void)usbd_do_request(sc->sc_udev, &req, 0); - sc->sc_dtr = onoff; } void @@ -1022,7 +660,7 @@ { usb_device_request_t req; - DPRINTF(("%s: umodem_break: onoff=%d\n", USBDEVNAME(sc->sc_dev),onoff)); + DPRINTF(("umodem_break: onoff=%d\n", onoff)); if (!(sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK)) return; @@ -1036,6 +674,59 @@ (void)usbd_do_request(sc->sc_udev, &req, 0); } +void +umodem_set(void *addr, int portno, int reg, int onoff) +{ + struct umodem_softc *sc = addr; + + switch (reg) { + case UCOM_SET_DTR: + umodem_dtr(sc, onoff); + break; + case UCOM_SET_RTS: + umodem_rts(sc, onoff); + break; + case UCOM_SET_BREAK: + umodem_break(sc, onoff); + break; + default: + break; + } +} + +usbd_status +umodem_set_line_coding(struct umodem_softc *sc, usb_cdc_line_state_t *state) +{ + usb_device_request_t req; + usbd_status err; + + DPRINTF(("umodem_set_line_coding: rate=%d fmt=%d parity=%d bits=%d\n", + UGETDW(state->dwDTERate), state->bCharFormat, + state->bParityType, state->bDataBits)); + + if (memcmp(state, &sc->sc_line_state, UCDC_LINE_STATE_LENGTH) == 0) { + DPRINTF(("umodem_set_line_coding: already set\n")); + return (USBD_NORMAL_COMPLETION); + } + + req.bmRequestType = UT_WRITE_CLASS_INTERFACE; + req.bRequest = UCDC_SET_LINE_CODING; + USETW(req.wValue, 0); + USETW(req.wIndex, sc->sc_ctl_iface_no); + USETW(req.wLength, UCDC_LINE_STATE_LENGTH); + + err = usbd_do_request(sc->sc_udev, &req, state); + if (err) { + DPRINTF(("umodem_set_line_coding: failed, err=%s\n", + usbd_errstr(err))); + return (err); + } + + sc->sc_line_state = *state; + + return (USBD_NORMAL_COMPLETION); +} + void * umodem_get_desc(usbd_device_handle dev, int type, int subtype) { @@ -1062,6 +753,9 @@ usbd_status err; usb_cdc_abstract_state_t ast; + DPRINTF(("umodem_set_comm_feature: feature=%d state=%d\n", feature, + state)); + req.bmRequestType = UT_WRITE_CLASS_INTERFACE; req.bRequest = UCDC_SET_COMM_FEATURE; USETW(req.wValue, feature); @@ -1071,120 +765,29 @@ err = usbd_do_request(sc->sc_udev, &req, &ast); if (err) { - DPRINTF(("%s: umodem_set_comm_feat: feature=%d failed, err=%d\n", - USBDEVNAME(sc->sc_dev), feature, err)); - return (err); - } - - return (USBD_NORMAL_COMPLETION); -} - -usbd_status -umodem_set_line_coding(struct umodem_softc *sc, usb_cdc_line_state_t *state) -{ - usb_device_request_t req; - usbd_status err; - - DPRINTF(("%s: umodem_set_line_cod: rate=%d fmt=%d parity=%d bits=%d\n", - USBDEVNAME(sc->sc_dev), UGETDW(state->dwDTERate), - state->bCharFormat, state->bParityType, state->bDataBits)); - - if (bcmp(state, &sc->sc_line_state, UCDC_LINE_STATE_LENGTH) == 0) { - DPRINTF(("%s: umodem_set_line_coding: already set\n", - USBDEVNAME(sc->sc_dev))); - return (USBD_NORMAL_COMPLETION); - } - - req.bmRequestType = UT_WRITE_CLASS_INTERFACE; - req.bRequest = UCDC_SET_LINE_CODING; - USETW(req.wValue, 0); - USETW(req.wIndex, sc->sc_ctl_iface_no); - USETW(req.wLength, UCDC_LINE_STATE_LENGTH); - - err = usbd_do_request(sc->sc_udev, &req, state); - if (err) { - DPRINTF(("%s: umodem_set_line_coding: failed, err=%d\n", - USBDEVNAME(sc->sc_dev), err)); + DPRINTF(("umodem_set_comm_feature: feature=%d, err=%s\n", + feature, usbd_errstr(err))); return (err); } - sc->sc_line_state = *state; - return (USBD_NORMAL_COMPLETION); } -#if defined(__NetBSD__) || defined(__OpenBSD__) -int -umodem_activate(device_ptr_t self, enum devact act) -{ - struct umodem_softc *sc = (struct umodem_softc *)self; - - switch (act) { - case DVACT_ACTIVATE: - return (EOPNOTSUPP); - break; - - case DVACT_DEACTIVATE: - sc->sc_dying = 1; - break; - } - return (0); -} -#endif - USB_DETACH(umodem) { USB_DETACH_START(umodem, sc); -#if defined(__NetBSD__) || defined(__OpenBSD__) - int maj, mn; + int rv = 0; - DPRINTF(("umodem_detach: sc=%p flags=%d tp=%p\n", - sc, flags, sc->sc_tty)); -#elif defined(__FreeBSD__) - DPRINTF(("umodem_detach: sc=%p flags=%d, tp=%p\n", - sc, 0, sc->sc_tty)); -#endif - - sc->sc_dying = 1; + DPRINTF(("umodem_detach: sc=%p\n", sc)); -#ifdef DIAGNOSTIC - if (sc->sc_tty == 0) { - DPRINTF(("umodem_detach: no tty\n")); - return (0); + if (sc->sc_notify_pipe != NULL) { + usbd_abort_pipe(sc->sc_notify_pipe); + usbd_close_pipe(sc->sc_notify_pipe); + sc->sc_notify_pipe = NULL; } -#endif - /* use refernce count? XXX */ + sc->sc_ucom.sc_dying = 1; + rv = ucom_detach(&sc->sc_ucom); -#if defined(__NetBSD__) || defined(__OpenBSD__) - /* locate the major number */ - for (maj = 0; maj < nchrdev; maj++) - if (cdevsw[maj].d_open == umodemopen) - break; - - /* Nuke the vnodes for any open instances. */ - mn = self->dv_unit; - vdevgone(maj, mn, mn, VCHR); - vdevgone(maj, mn, mn | UMODEMDIALOUT_MASK, VCHR); - vdevgone(maj, mn, mn | UMODEMCALLUNIT_MASK, VCHR); -#elif defined(__FreeBSD__) - /* XXX not yet implemented */ -#endif - -#if defined(__FreeBSD__) - destroy_dev(sc->dev); -#endif - - /* Detach and free the tty. */ -#if defined(__NetBSD__) || defined(__OpenBSD__) - tty_detach(sc->sc_tty); - ttyfree(sc->sc_tty); - sc->sc_tty = 0; -#endif - - return (0); + return (rv); } - -#if defined(__FreeBSD__) -DRIVER_MODULE(umodem, uhub, umodem_driver, umodem_devclass, usbd_driver_load,0); -#endif Index: sys/dev/usb/ums.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/ums.c,v retrieving revision 1.36.2.6 diff -u -r1.36.2.6 ums.c --- sys/dev/usb/ums.c 6 Nov 2002 20:23:50 -0000 1.36.2.6 +++ sys/dev/usb/ums.c 4 Oct 2003 21:27:29 -0000 @@ -1,4 +1,3 @@ -/* $FreeBSD: src/sys/dev/usb/ums.c,v 1.36.2.6 2002/11/06 20:23:50 joe Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -37,8 +36,11 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/ums.c,v 1.63 2003/10/04 21:41:01 joe Exp $"); + /* - * HID spec: http://www.usb.org/developers/data/usbhid10.pdf + * HID spec: http://www.usb.org/developers/data/devclass/hid1_1.pdf */ #include @@ -51,8 +53,11 @@ #include #include #include +#if __FreeBSD_version >= 500014 +#include +#else #include -#include +#endif #include #include #include @@ -66,7 +71,11 @@ #include #include +#if __FreeBSD_version >= 500000 +#include +#else #include +#endif #ifdef USB_DEBUG #define DPRINTF(x) if (umsdebug) logprintf x @@ -82,7 +91,7 @@ #define UMSUNIT(s) (minor(s)&0x1f) -#define MS_TO_TICKS(ms) ((ms) * hz / 1000) +#define MS_TO_TICKS(ms) ((ms) * hz / 1000) #define QUEUE_BUFSIZE 400 /* MUST be divisible by 5 _and_ 8 */ @@ -98,7 +107,7 @@ struct hid_location sc_loc_x, sc_loc_y, sc_loc_z; struct hid_location *sc_loc_btn; - struct callout_handle timeout_handle; /* for spurious button ups */ + usb_callout_t callout_handle; /* for spurious button ups */ int sc_enabled; int sc_disconnected; /* device is gone */ @@ -146,20 +155,16 @@ #define UMS_CDEV_MAJOR 111 Static struct cdevsw ums_cdevsw = { - /* open */ ums_open, - /* close */ ums_close, - /* read */ ums_read, - /* write */ nowrite, - /* ioctl */ ums_ioctl, - /* poll */ ums_poll, - /* mmap */ nommap, - /* strategy */ nostrategy, - /* name */ "ums", - /* maj */ UMS_CDEV_MAJOR, - /* dump */ nodump, - /* psize */ nopsize, - /* flags */ 0, - /* bmaj */ -1 + .d_open = ums_open, + .d_close = ums_close, + .d_read = ums_read, + .d_ioctl = ums_ioctl, + .d_poll = ums_poll, + .d_name = "ums", + .d_maj = UMS_CDEV_MAJOR, +#if __FreeBSD_version < 500014 + .d_bmaj -1 +#endif }; USB_DECLARE_DRIVER(ums); @@ -171,18 +176,18 @@ int size, ret; void *desc; usbd_status err; - + if (!uaa->iface) return (UMATCH_NONE); id = usbd_get_interface_descriptor(uaa->iface); if (!id || id->bInterfaceClass != UICLASS_HID) return (UMATCH_NONE); - err = usbd_alloc_report_desc(uaa->iface, &desc, &size, M_TEMP); + err = usbd_read_report_desc(uaa->iface, &desc, &size, M_TEMP); if (err) return (UMATCH_NONE); - if (hid_is_collection(desc, size, + if (hid_is_collection(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))) ret = UMATCH_IFACECLASS; else @@ -205,7 +210,7 @@ u_int32_t flags; int i; struct hid_location loc_btn; - + sc->sc_disconnected = 1; sc->sc_iface = iface; id = usbd_get_interface_descriptor(iface); @@ -223,7 +228,7 @@ DPRINTFN(10,("ums_attach: bLength=%d bDescriptorType=%d " "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d" " bInterval=%d\n", - ed->bLength, ed->bDescriptorType, + ed->bLength, ed->bDescriptorType, UE_GET_ADDR(ed->bEndpointAddress), UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN ? "in":"out", UE_GET_XFERTYPE(ed->bmAttributes), @@ -236,7 +241,7 @@ USB_ATTACH_ERROR_RETURN; } - err = usbd_alloc_report_desc(uaa->iface, &desc, &size, M_TEMP); + err = usbd_read_report_desc(uaa->iface, &desc, &size, M_TEMP); if (err) USB_ATTACH_ERROR_RETURN; @@ -280,7 +285,7 @@ hid_input, &loc_btn, 0)) break; sc->nbuttons = i - 1; - sc->sc_loc_btn = malloc(sizeof(struct hid_location)*sc->nbuttons, + sc->sc_loc_btn = malloc(sizeof(struct hid_location)*sc->nbuttons, M_USBDEV, M_NOWAIT); if (!sc->sc_loc_btn) { printf("%s: no memory\n", USBDEVNAME(sc->sc_dev)); @@ -308,12 +313,12 @@ #ifdef USB_DEBUG DPRINTF(("ums_attach: sc=%p\n", sc)); - DPRINTF(("ums_attach: X\t%d/%d\n", + DPRINTF(("ums_attach: X\t%d/%d\n", sc->sc_loc_x.pos, sc->sc_loc_x.size)); - DPRINTF(("ums_attach: Y\t%d/%d\n", + DPRINTF(("ums_attach: Y\t%d/%d\n", sc->sc_loc_y.pos, sc->sc_loc_y.size)); if (sc->flags & UMS_Z) - DPRINTF(("ums_attach: Z\t%d/%d\n", + DPRINTF(("ums_attach: Z\t%d/%d\n", sc->sc_loc_z.pos, sc->sc_loc_z.size)); for (i = 1; i <= sc->nbuttons; i++) { DPRINTF(("ums_attach: B%d\t%d/%d\n", @@ -343,8 +348,10 @@ sc->status.button = sc->status.obutton = 0; sc->status.dx = sc->status.dy = sc->status.dz = 0; +#ifndef __FreeBSD__ sc->rsel.si_flags = 0; sc->rsel.si_pid = 0; +#endif sc->dev = make_dev(&ums_cdevsw, device_get_unit(self), UID_ROOT, GID_OPERATOR, @@ -423,7 +430,8 @@ if (status != USBD_NORMAL_COMPLETION) { DPRINTF(("ums_intr: status=%d\n", status)); - usbd_clear_endpoint_stall_async(sc->sc_intrpipe); + if (status == USBD_STALLED) + usbd_clear_endpoint_stall_async(sc->sc_intrpipe); return; } @@ -466,12 +474,11 @@ */ if (sc->flags & UMS_SPUR_BUT_UP && dx == 0 && dy == 0 && dz == 0 && buttons == 0) { - usb_timeout(ums_add_to_queue_timeout, (void *) sc, - MS_TO_TICKS(50 /*msecs*/), sc->timeout_handle); + usb_callout(sc->callout_handle, MS_TO_TICKS(50 /*msecs*/), + ums_add_to_queue_timeout, (void *) sc); } else { - usb_untimeout(ums_add_to_queue_timeout, (void *) sc, - sc->timeout_handle); - + usb_uncallout(sc->callout_handle, + ums_add_to_queue_timeout, (void *) sc); ums_add_to_queue(sc, dx, dy, dz, buttons); } } @@ -552,11 +559,11 @@ sc->status.button = sc->status.obutton = 0; sc->status.dx = sc->status.dy = sc->status.dz = 0; - callout_handle_init(&sc->timeout_handle); + callout_handle_init((struct callout_handle *)&sc->callout_handle); /* Set up interrupt pipe. */ - err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ep_addr, - USBD_SHORT_XFER_OK, &sc->sc_intrpipe, sc, + err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ep_addr, + USBD_SHORT_XFER_OK, &sc->sc_intrpipe, sc, sc->sc_ibuf, sc->sc_isize, ums_intr, USBD_DEFAULT_INTERVAL); if (err) { @@ -574,7 +581,7 @@ { struct ums_softc *sc = priv; - usb_untimeout(ums_add_to_queue_timeout, sc, sc->timeout_handle); + usb_uncallout(sc->callout_handle, ums_add_to_queue_timeout, sc); /* Disable interrupts. */ usbd_abort_pipe(sc->sc_intrpipe); @@ -634,7 +641,7 @@ splx(s); return EWOULDBLOCK; } - + sc->state |= UMS_ASLEEP; /* blocking I/O */ error = tsleep(sc, PZERO | PCATCH, "umsrea", 0); if (error) { @@ -707,7 +714,7 @@ return revents; } - + int ums_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, usb_proc_ptr p) { Index: sys/dev/usb/uplcom.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/uplcom.c,v retrieving revision 1.8.2.3 diff -u -r1.8.2.3 uplcom.c --- sys/dev/usb/uplcom.c 21 Jul 2003 11:29:43 -0000 1.8.2.3 +++ sys/dev/usb/uplcom.c 4 Oct 2003 18:54:40 -0000 @@ -1,5 +1,4 @@ -/* $NetBSD: uplcom.c,v 1.20 2001/07/31 12:33:11 ichiro Exp $ */ -/* $FreeBSD: src/sys/dev/usb/uplcom.c,v 1.8.2.3 2003/07/21 11:29:43 akiyama Exp $ */ +/* $NetBSD: uplcom.c,v 1.21 2001/11/13 06:24:56 lukem Exp $ */ /*- * Copyright (c) 2001-2002, Shunsuke Akiyama . @@ -27,6 +26,9 @@ * SUCH DAMAGE. */ +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/uplcom.c,v 1.14 2003/08/24 17:55:55 obrien Exp $"); + /* * Copyright (c) 2001 The NetBSD Foundation, Inc. * All rights reserved. @@ -279,7 +281,7 @@ DPRINTF(("uplcom attach: sc = %p\n", sc)); - /* initialize endpoints */ + /* initialize endpoints */ ucom->sc_bulkin_no = ucom->sc_bulkout_no = -1; sc->sc_intr_number = -1; sc->sc_intr_pipe = NULL; @@ -304,7 +306,7 @@ } /* get the (first/common) interface */ - err = usbd_device2interface_handle(dev, UPLCOM_IFACE_INDEX, + err = usbd_device2interface_handle(dev, UPLCOM_IFACE_INDEX, &ucom->sc_iface); if (err) { printf("%s: failed to get interface: %s\n", @@ -331,7 +333,7 @@ UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { sc->sc_intr_number = ed->bEndpointAddress; sc->sc_isize = UGETW(ed->wMaxPacketSize); - } + } } if (sc->sc_intr_number == -1) { @@ -353,11 +355,11 @@ * Interrupt(0x81) | Interrupt(0x81) * -----------------+ BulkIN(0x02) * Interface 1 | BulkOUT(0x83) - * BulkIN(0x02) | + * BulkIN(0x02) | * BulkOUT(0x83) | */ if (cdesc->bNumInterface == 2) { - err = usbd_device2interface_handle(dev, + err = usbd_device2interface_handle(dev, UPLCOM_SECOND_IFACE_INDEX, &ucom->sc_iface); if (err) { @@ -366,7 +368,7 @@ ucom->sc_dying = 1; goto error; } - } + } /* Find the bulk{in,out} endpoints */ @@ -468,9 +470,9 @@ req.bRequest = UPLCOM_SET_REQUEST; USETW(req.wValue, 0); USETW(req.wIndex, sc->sc_iface_number); - USETW(req.wLength, 0); + USETW(req.wLength, 0); - err = usbd_do_request(sc->sc_ucom.sc_udev, &req, 0); + err = usbd_do_request(sc->sc_ucom.sc_udev, &req, 0); if (err) { printf("%s: uplcom_reset: %s\n", USBDEVNAME(sc->sc_ucom.sc_dev), usbd_errstr(err)); @@ -677,7 +679,7 @@ { struct uplcom_softc *sc = addr; int err; - + if (sc->sc_ucom.sc_dying) return (ENXIO); @@ -707,7 +709,7 @@ } Static void -uplcom_close(void *addr, int portno) +uplcom_close(void *addr, int portno) { struct uplcom_softc *sc = addr; int err; Index: sys/dev/usb/urio.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/urio.c,v retrieving revision 1.11.2.4 diff -u -r1.11.2.4 urio.c --- sys/dev/usb/urio.c 6 Nov 2002 14:41:01 -0000 1.11.2.4 +++ sys/dev/usb/urio.c 4 Oct 2003 18:54:40 -0000 @@ -28,7 +28,9 @@ * its contributors. */ -/* $FreeBSD: src/sys/dev/usb/urio.c,v 1.11.2.4 2002/11/06 14:41:01 joe Exp $ */ +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/urio.c,v 1.28 2003/08/25 22:01:06 joe Exp $"); + /* * 2000/3/24 added NetBSD/OpenBSD support (from Alex Nemirovsky) @@ -89,26 +91,18 @@ #endif /* difference of usbd interface */ -#if defined(__FreeBSD__) -#if (__FreeBSD__ >= 4) - #define USBDI 1 -#else - #define USBDI 0 -#endif -#elif defined(__NetBSD__) || defined(__OpenBSD__) - #define USBDI 1 -#endif +#define USBDI 1 #define RIO_OUT 0 #define RIO_IN 1 #define RIO_NODIR 2 #if defined(__NetBSD__) -int urioopen(dev_t, int, int, usb_proc_ptr); -int urioclose(dev_t, int, int, usb_proc_ptr); +int urioopen(dev_t, int, int, struct proc *); +int urioclose(dev_t, int, int, struct proc *p); int urioread(dev_t, struct uio *uio, int); int uriowrite(dev_t, struct uio *uio, int); -int urioioctl(dev_t, u_long, caddr_t, int, usb_proc_ptr); +int urioioctl(dev_t, u_long, caddr_t, int, struct proc *); cdev_decl(urio); #define RIO_UE_GET_DIR(p) ((UE_GET_DIR(p) == UE_DIR_IN) ? RIO_IN :\ @@ -123,30 +117,21 @@ #define URIO_CDEV_MAJOR 143 -#if (__FreeBSD__ >= 4) Static struct cdevsw urio_cdevsw = { - urioopen, urioclose, urioread, uriowrite, - urioioctl, nopoll, nommap, nostrategy, - "urio", URIO_CDEV_MAJOR,nodump, nopsize, - 0, -#if (__FreeBSD__ < 5) - -1 + .d_open = urioopen, + .d_close = urioclose, + .d_read = urioread, + .d_write = uriowrite, + .d_ioctl = urioioctl, + .d_name = "urio", + .d_maj = URIO_CDEV_MAJOR, +#if __FreeBSD_version < 500014 + .d_bmaj = -1 #endif }; #define RIO_UE_GET_DIR(p) ((UE_GET_DIR(p) == UE_DIR_IN) ? RIO_IN :\ ((UE_GET_DIR(p) == UE_DIR_OUT) ? RIO_OUT :\ RIO_NODIR)) -#else -Static struct cdevsw urio_cdevsw = { - urioopen, urioclose, urioread, uriowrite, - urioioctl, nostop, nullreset, nodevtotty, - seltrue, nommap, nostrat, - "urio", NULL, -1 -}; -#define USBBASEDEVICE bdevice -#define RIO_UE_GET_DIR(p) UE_GET_IN(p) -#endif - #endif /*defined(__FreeBSD__)*/ #define URIO_BBSIZE 1024 @@ -162,6 +147,9 @@ int sc_epaddr[2]; int sc_refcnt; +#if defined(__FreeBSD__) + dev_t sc_dev_t; +#endif /* defined(__FreeBSD__) */ #if defined(__NetBSD__) || defined(__OpenBSD__) u_char sc_dying; #endif @@ -209,7 +197,7 @@ char * ermsg = ""; int i; - DPRINTFN(10,("urio_attach: sc=%p\n", sc)); + DPRINTFN(10,("urio_attach: sc=%p\n", sc)); usbd_devinfo(uaa->device, 0, devinfo); USB_ATTACH_SETUP; printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo); @@ -230,12 +218,12 @@ r = usbd_interface_count(udev, &niface); if (r) { ermsg = "iface"; - goto nobulk; + goto nobulk; } r = usbd_device2interface_handle(udev, 0, &iface); if (r) { ermsg = "iface"; - goto nobulk; + goto nobulk; } sc->sc_iface = iface; #endif @@ -245,7 +233,7 @@ sc->sc_refcnt = 0; r = usbd_endpoint_count(iface, &epcount); - if (r != USBD_NORMAL_COMPLETION) { + if (r != USBD_NORMAL_COMPLETION) { ermsg = "endpoints"; goto nobulk; } @@ -254,7 +242,7 @@ sc->sc_epaddr[RIO_IN] = 0x00; for (i = 0; i < epcount; i++) { - usb_endpoint_descriptor_t *edesc = + usb_endpoint_descriptor_t *edesc = usbd_interface2endpoint_descriptor(iface, i); int d; @@ -262,7 +250,7 @@ ermsg = "interface endpoint"; goto nobulk; } - + d = RIO_UE_GET_DIR(edesc->bEndpointAddress); if (d != RIO_NODIR) sc->sc_epaddr[d] = edesc->bEndpointAddress; @@ -274,12 +262,10 @@ } #if defined(__FreeBSD__) - #if (__FreeBSD__ >= 4) /* XXX no error trapping, no storing of dev_t */ - (void) make_dev(&urio_cdevsw, device_get_unit(self), + sc->sc_dev_t = make_dev(&urio_cdevsw, device_get_unit(self), UID_ROOT, GID_OPERATOR, 0644, "urio%d", device_get_unit(self)); - #endif #elif defined(__NetBSD__) || defined(__OpenBSD__) usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, USBDEV(sc->sc_dev)); @@ -304,7 +290,7 @@ int unit = URIOUNIT(dev); USB_GET_SC_OPEN(urio, unit, sc); - DPRINTFN(5, ("urioopen: flag=%d, mode=%d, unit=%d\n", + DPRINTFN(5, ("urioopen: flag=%d, mode=%d, unit=%d\n", flag, mode, unit)); if (sc->sc_opened) @@ -316,18 +302,18 @@ sc->sc_opened = 1; sc->sc_pipeh_in = 0; sc->sc_pipeh_out = 0; - if (usbd_open_pipe(sc->sc_iface, - sc->sc_epaddr[RIO_IN], 0, &sc->sc_pipeh_in) + if (usbd_open_pipe(sc->sc_iface, + sc->sc_epaddr[RIO_IN], 0, &sc->sc_pipeh_in) != USBD_NORMAL_COMPLETION) { sc->sc_pipeh_in = 0; return EIO; }; - if (usbd_open_pipe(sc->sc_iface, - sc->sc_epaddr[RIO_OUT], 0, &sc->sc_pipeh_out) + if (usbd_open_pipe(sc->sc_iface, + sc->sc_epaddr[RIO_OUT], 0, &sc->sc_pipeh_out) != USBD_NORMAL_COMPLETION) { - usbd_close_pipe(sc->sc_pipeh_in); + usbd_close_pipe(sc->sc_pipeh_in); sc->sc_pipeh_in = 0; sc->sc_pipeh_out = 0; return EIO; @@ -345,17 +331,17 @@ USB_GET_SC(urio, unit, sc); DPRINTFN(5, ("urioclose: flag=%d, mode=%d, unit=%d\n", flag, mode, unit)); - if (sc->sc_pipeh_in) - usbd_close_pipe(sc->sc_pipeh_in); + if (sc->sc_pipeh_in) + usbd_close_pipe(sc->sc_pipeh_in); - if (sc->sc_pipeh_out) - usbd_close_pipe(sc->sc_pipeh_out); + if (sc->sc_pipeh_out) + usbd_close_pipe(sc->sc_pipeh_out); sc->sc_pipeh_in = 0; sc->sc_pipeh_out = 0; sc->sc_opened = 0; sc->sc_refcnt = 0; - return 0; + return 0; } int @@ -528,7 +514,7 @@ len = rio_cmd->length; requesttype = rio_cmd->requesttype | UT_READ_VENDOR_DEVICE; - DPRINTFN(1,("sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n", + DPRINTFN(1,("sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n", requesttype, rio_cmd->request, rio_cmd->value, rio_cmd->index, len)); break; @@ -541,7 +527,7 @@ len = rio_cmd->length; requesttype = rio_cmd->requesttype | UT_WRITE_VENDOR_DEVICE; - DPRINTFN(1,("sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n", + DPRINTFN(1,("sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n", requesttype, rio_cmd->request, rio_cmd->value, rio_cmd->index, len)); break; @@ -568,7 +554,7 @@ uio.uio_offset = 0; uio.uio_segflg = UIO_USERSPACE; uio.uio_rw = - req.bmRequestType & UT_READ ? + req.bmRequestType & UT_READ ? UIO_READ : UIO_WRITE; uio.uio_procp = p; ptr = malloc(len, M_TEMP, M_WAITOK); @@ -579,8 +565,9 @@ } } - r = usbd_do_request_flags(sc->sc_udev, &req, - ptr, req_flags, &req_actlen); + r = usbd_do_request_flags(sc->sc_udev, &req, + ptr, req_flags, &req_actlen, + USBD_DEFAULT_TIMEOUT); if (r == USBD_NORMAL_COMPLETION) { error = 0; if (len != 0) { @@ -652,11 +639,11 @@ } splx(s); #else - if (sc->sc_pipeh_in) - usbd_abort_pipe(sc->sc_pipeh_in); + if (sc->sc_pipeh_in) + usbd_abort_pipe(sc->sc_pipeh_in); - if (sc->sc_pipeh_out) - usbd_abort_pipe(sc->sc_pipeh_out); + if (sc->sc_pipeh_out) + usbd_abort_pipe(sc->sc_pipeh_out); s = splusb(); if (--sc->sc_refcnt >= 0) { @@ -675,8 +662,6 @@ /* 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 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, @@ -689,17 +674,15 @@ #if defined(__FreeBSD__) Static int urio_detach(device_t self) -{ +{ + struct urio_softc *sc = device_get_softc(self); + DPRINTF(("%s: disconnected\n", USBDEVNAME(self))); + destroy_dev(sc->sc_dev_t); + /* XXX not implemented yet */ device_set_desc(self, NULL); return 0; } -#if (__FreeBSD__ >= 4) DRIVER_MODULE(urio, uhub, urio_driver, urio_devclass, usbd_driver_load, 0); -#else -CDEV_DRIVER_MODULE(urio, uhub, urio_driver, urio_devclass, - URIO_CDEV_MAJOR, urio_cdevsw, usbd_driver_load, 0); -#endif - #endif Index: sys/dev/usb/usb.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/usb.c,v retrieving revision 1.26.2.9 diff -u -r1.26.2.9 usb.c --- sys/dev/usb/usb.c 13 Nov 2002 15:15:22 -0000 1.26.2.9 +++ sys/dev/usb/usb.c 5 Oct 2003 18:39:11 -0000 @@ -1,5 +1,12 @@ -/* $NetBSD: usb.c,v 1.33 1999/11/22 21:57:09 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/usb.c,v 1.26.2.9 2002/11/13 15:15:22 joe Exp $ */ +/* $NetBSD: usb.c,v 1.68 2002/02/20 20:30:12 christos Exp $ */ + +/* Also already merged from NetBSD: + * $NetBSD: usb.c,v 1.70 2002/05/09 21:54:32 augustss Exp $ + * $NetBSD: usb.c,v 1.73 2002/09/23 05:51:19 simonb Exp $ + */ + +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/usb.c,v 1.93 2003/10/05 06:06:09 bms Exp $"); /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -47,20 +54,29 @@ #include #include #include +#include #include +#if __FreeBSD_version >= 500000 +#include +#endif #if defined(__NetBSD__) || defined(__OpenBSD__) #include -#include -#include #elif defined(__FreeBSD__) +#include #include #include #include #include #endif +#include +#include #include #include +#if __FreeBSD_version >= 500014 +#include +#else #include +#endif #include #include #include @@ -96,13 +112,7 @@ int usbdebug = 0; SYSCTL_INT(_hw_usb, OID_AUTO, debug, CTLFLAG_RW, &usbdebug, 0, "usb debug level"); -#ifdef USB_DEBUG -extern int uhcidebug; -#endif -#ifdef USB_DEBUG -extern int ohcidebug; -#endif -/* +/* * 0 - do usual exploration * 1 - do not use timeout exploration * >1 - do no exploration @@ -118,68 +128,57 @@ usbd_bus_handle sc_bus; /* USB controller */ struct usbd_port sc_port; /* dummy port for root hub */ -#if defined(__FreeBSD__) - /* This part should be deleted when kthreads is available */ - struct selinfo sc_consel; /* waiting for connect change */ -#else - struct proc *sc_event_thread; -#endif + struct proc *sc_event_thread; char sc_dying; }; +TAILQ_HEAD(, usb_task) usb_all_tasks; + #if defined(__NetBSD__) || defined(__OpenBSD__) cdev_decl(usb); #elif defined(__FreeBSD__) -d_open_t usbopen; +d_open_t usbopen; d_close_t usbclose; d_read_t usbread; d_ioctl_t usbioctl; -int usbpoll(dev_t, int, usb_proc_ptr); +d_poll_t usbpoll; struct cdevsw usb_cdevsw = { - /* open */ usbopen, - /* close */ usbclose, - /* read */ usbread, - /* write */ nowrite, - /* ioctl */ usbioctl, - /* poll */ usbpoll, - /* mmap */ nommap, - /* strategy */ nostrategy, - /* name */ "usb", - /* maj */ USB_CDEV_MAJOR, - /* dump */ nodump, - /* psize */ nopsize, - /* flags */ 0, - /* bmaj */ -1 + .d_open = usbopen, + .d_close = usbclose, + .d_read = usbread, + .d_ioctl = usbioctl, + .d_poll = usbpoll, + .d_name = "usb", + .d_maj = USB_CDEV_MAJOR, +#if __FreeBSD_version < 500014 + .d_bmaj = -1 +#endif }; #endif -Static usbd_status usb_discover(struct usb_softc *); -#if defined(__NetBSD__) || defined(__OpenBSD__) +Static void usb_discover(void *); Static void usb_create_event_thread(void *); Static void usb_event_thread(void *); -#endif +Static void usb_task_thread(void *); +Static struct proc *usb_task_thread_proc = NULL; -#define USB_MAX_EVENTS 50 +#define USB_MAX_EVENTS 100 struct usb_event_q { struct usb_event ue; - SIMPLEQ_ENTRY(usb_event_q) next; + TAILQ_ENTRY(usb_event_q) next; }; -Static SIMPLEQ_HEAD(, usb_event_q) usb_events = - SIMPLEQ_HEAD_INITIALIZER(usb_events); +Static TAILQ_HEAD(, usb_event_q) usb_events = + TAILQ_HEAD_INITIALIZER(usb_events); Static int usb_nevents = 0; Static struct selinfo usb_selevent; -Static struct proc *usb_async_proc; /* process who wants USB SIGIO */ +Static struct proc *usb_async_proc; /* process that wants USB SIGIO */ Static int usb_dev_open = 0; +Static void usb_add_event(int, struct usb_event *); Static int usb_get_next_event(struct usb_event *); -#if defined(__NetBSD__) || defined(__OpenBSD__) -/* Flag to see if we are in the cold boot process. */ -extern int cold; -#endif - Static const char *usbrev_str[] = USBREV_STR; USB_DECLARE_DRIVER_INIT(usb, @@ -188,6 +187,10 @@ DEVMETHOD(device_shutdown, bus_generic_shutdown) ); +#if defined(__FreeBSD__) +MODULE_VERSION(usb, 1); +#endif + USB_MATCH(usb) { DPRINTF(("usbd_match\n")); @@ -206,6 +209,8 @@ usbd_device_handle dev; usbd_status err; int usbrev; + int speed; + struct usb_event ue; sc->sc_dev = self; @@ -221,51 +226,90 @@ #endif usbrev = sc->sc_bus->usbrev; printf(": USB revision %s", usbrev_str[usbrev]); - if (usbrev != USBREV_1_0 && usbrev != USBREV_1_1) { + switch (usbrev) { + case USBREV_1_0: + case USBREV_1_1: + speed = USB_SPEED_FULL; + break; + case USBREV_2_0: + speed = USB_SPEED_HIGH; + break; + default: printf(", not supported\n"); + sc->sc_dying = 1; USB_ATTACH_ERROR_RETURN; } printf("\n"); - err = usbd_new_device(USBDEV(sc->sc_dev), sc->sc_bus, 0, 0, 0, + /* Make sure not to use tsleep() if we are cold booting. */ + if (cold) + sc->sc_bus->use_polling++; + + ue.u.ue_ctrlr.ue_bus = USBDEVUNIT(sc->sc_dev); + usb_add_event(USB_EVENT_CTRLR_ATTACH, &ue); + +#ifdef USB_USE_SOFTINTR +#ifdef __HAVE_GENERIC_SOFT_INTERRUPTS + /* XXX we should have our own level */ + sc->sc_bus->soft = softintr_establish(IPL_SOFTNET, + sc->sc_bus->methods->soft_intr, sc->sc_bus); + if (sc->sc_bus->soft == NULL) { + printf("%s: can't register softintr\n", USBDEVNAME(sc->sc_dev)); + sc->sc_dying = 1; + USB_ATTACH_ERROR_RETURN; + } +#else + usb_callout_init(sc->sc_bus->softi); +#endif +#endif + + err = usbd_new_device(USBDEV(sc->sc_dev), sc->sc_bus, 0, speed, 0, &sc->sc_port); if (!err) { dev = sc->sc_port.device; if (dev->hub == NULL) { sc->sc_dying = 1; - printf("%s: root device is not a hub\n", + printf("%s: root device is not a hub\n", USBDEVNAME(sc->sc_dev)); USB_ATTACH_ERROR_RETURN; } sc->sc_bus->root_hub = dev; #if 1 - /* + /* * Turning this code off will delay attachment of USB devices * until the USB event thread is running, which means that * the keyboard will not work until after cold boot. */ - if (cold) { - sc->sc_bus->use_polling++; +#if defined(__FreeBSD__) + if (cold) +#else + if (cold && (sc->sc_dev.dv_cfdata->cf_flags & 1)) +#endif dev->hub->explore(sc->sc_bus->root_hub); - sc->sc_bus->use_polling--; - } #endif } else { - printf("%s: root hub problem, error=%d\n", - USBDEVNAME(sc->sc_dev), err); + printf("%s: root hub problem, error=%d\n", + USBDEVNAME(sc->sc_dev), err); sc->sc_dying = 1; } + if (cold) + sc->sc_bus->use_polling--; - kthread_create(usb_create_event_thread, sc); + config_pending_incr(); +#if defined(__NetBSD__) || defined(__OpenBSD__) + usb_kthread_create(usb_create_event_thread, sc); +#endif #if defined(__FreeBSD__) + usb_create_event_thread(sc); /* The per controller devices (used for usb_discover) */ + /* XXX This is redundant now, but old usbd's will want it */ make_dev(&usb_cdevsw, device_get_unit(self), UID_ROOT, GID_OPERATOR, - 0644, "usb%d", device_get_unit(self)); + 0660, "usb%d", device_get_unit(self)); if (!global_init_done) { /* The device spitting out events */ make_dev(&usb_cdevsw, USB_DEV_MINOR, UID_ROOT, GID_OPERATOR, - 0644, "usb"); + 0660, "usb"); global_init_done = 1; } #endif @@ -273,18 +317,62 @@ USB_ATTACH_SUCCESS_RETURN; } -#if defined(__NetBSD__) || defined(__OpenBSD__) void usb_create_event_thread(void *arg) { struct usb_softc *sc = arg; + static int created = 0; - if (kthread_create1(usb_event_thread, sc, &sc->sc_event_thread, - "%s", sc->sc_dev.dv_xname)) { + if (usb_kthread_create1(usb_event_thread, sc, &sc->sc_event_thread, + "%s", USBDEVNAME(sc->sc_dev))) { printf("%s: unable to create event thread for\n", - sc->sc_dev.dv_xname); + USBDEVNAME(sc->sc_dev)); panic("usb_create_event_thread"); } + if (!created) { + created = 1; + TAILQ_INIT(&usb_all_tasks); + if (usb_kthread_create2(usb_task_thread, NULL, + &usb_task_thread_proc, "usbtask")) { + printf("unable to create task thread\n"); + panic("usb_create_event_thread task"); + } + } +} + +/* + * Add a task to be performed by the task thread. This function can be + * called from any context and the task will be executed in a process + * context ASAP. + */ +void +usb_add_task(usbd_device_handle dev, struct usb_task *task) +{ + int s; + + s = splusb(); + if (!task->onqueue) { + DPRINTFN(2,("usb_add_task: task=%p\n", task)); + TAILQ_INSERT_TAIL(&usb_all_tasks, task, next); + task->onqueue = 1; + } else { + DPRINTFN(3,("usb_add_task: task=%p on q\n", task)); + } + wakeup(&usb_all_tasks); + splx(s); +} + +void +usb_rem_task(usbd_device_handle dev, struct usb_task *task) +{ + int s; + + s = splusb(); + if (task->onqueue) { + TAILQ_REMOVE(&usb_all_tasks, task, next); + task->onqueue = 0; + } + splx(s); } void @@ -292,22 +380,42 @@ { struct usb_softc *sc = arg; +#if defined(__FreeBSD__) && __FreeBSD_version >= 500000 + mtx_lock(&Giant); +#endif + DPRINTF(("usb_event_thread: start\n")); + /* + * In case this controller is a companion controller to an + * EHCI controller we need to wait until the EHCI controller + * has grabbed the port. + * XXX It would be nicer to do this with a tsleep(), but I don't + * know how to synchronize the creation of the threads so it + * will work. + */ + usb_delay_ms(sc->sc_bus, 500); + + /* Make sure first discover does something. */ + sc->sc_bus->needs_explore = 1; + usb_discover(sc); + config_pending_decr(); + while (!sc->sc_dying) { #ifdef USB_DEBUG if (usb_noexplore < 2) #endif usb_discover(sc); - (void)tsleep(&sc->sc_bus->needs_explore, PWAIT, "usbevt", #ifdef USB_DEBUG - usb_noexplore ? 0 : + (void)tsleep(&sc->sc_bus->needs_explore, PWAIT, "usbevt", + usb_noexplore ? 0 : hz * 60); +#else + (void)tsleep(&sc->sc_bus->needs_explore, PWAIT, "usbevt", + hz * 60); #endif - hz*60 - ); DPRINTFN(2,("usb_event_thread: woke up\n")); } - sc->sc_event_thread = 0; + sc->sc_event_thread = NULL; /* In case parent is waiting for us to exit. */ wakeup(sc); @@ -316,6 +424,37 @@ kthread_exit(0); } +void +usb_task_thread(void *arg) +{ + struct usb_task *task; + int s; + +#if defined(__FreeBSD__) && __FreeBSD_version >= 500000 + mtx_lock(&Giant); +#endif + + DPRINTF(("usb_task_thread: start\n")); + + s = splusb(); + for (;;) { + task = TAILQ_FIRST(&usb_all_tasks); + if (task == NULL) { + tsleep(&usb_all_tasks, PWAIT, "usbtsk", 0); + task = TAILQ_FIRST(&usb_all_tasks); + } + DPRINTFN(2,("usb_task_thread: woke up task=%p\n", task)); + if (task != NULL) { + TAILQ_REMOVE(&usb_all_tasks, task, next); + task->onqueue = 0; + splx(s); + task->fun(task->arg); + s = splusb(); + } + } +} + +#if defined(__NetBSD__) || defined(__OpenBSD__) int usbctlprint(void *aux, const char *pnp) { @@ -339,14 +478,14 @@ usb_dev_open = 1; usb_async_proc = 0; return (0); - } else { - USB_GET_SC_OPEN(usb, unit, sc); + } - if (sc->sc_dying) - return (EIO); + USB_GET_SC_OPEN(usb, unit, sc); - return (0); - } + if (sc->sc_dying) + return (EIO); + + return (0); } int @@ -407,10 +546,14 @@ case FIONBIO: /* All handled in the upper FS layer. */ return (0); - + case FIOASYNC: if (*(int *)data) +#if __FreeBSD_version >= 500000 + usb_async_proc = p->td_proc; +#else usb_async_proc = p; +#endif else usb_async_proc = 0; return (0); @@ -426,19 +569,11 @@ return (EIO); switch (cmd) { -#if defined(__FreeBSD__) - /* This part should be deleted when kthreads is available */ +#if defined(__FreeBSD__) + /* This part should be deleted */ case USB_DISCOVER: - usb_discover(sc); break; #endif -#ifdef USB_DEBUG - case USB_SETDEBUG: - usbdebug = ((*(int *)data) & 0x000000ff); - uhcidebug = ((*(int *)data) & 0x0000ff00) >> 8; - ohcidebug = ((*(int *)data) & 0x00ff0000) >> 16; - break; -#endif case USB_REQUEST: { struct usb_ctl_request *ur = (void *)data; @@ -453,7 +588,7 @@ DPRINTF(("usbioctl: USB_REQUEST addr=%d len=%d\n", addr, len)); if (len < 0 || len > 32768) return (EINVAL); - if (addr < 0 || addr >= USB_MAX_DEVICES || + if (addr < 0 || addr >= USB_MAX_DEVICES || sc->sc_bus->devices[addr] == 0) return (EINVAL); if (len != 0) { @@ -465,7 +600,7 @@ uio.uio_offset = 0; uio.uio_segflg = UIO_USERSPACE; uio.uio_rw = - ur->ucr_request.bmRequestType & UT_READ ? + ur->ucr_request.bmRequestType & UT_READ ? UIO_READ : UIO_WRITE; uio.uio_procp = p; ptr = malloc(len, M_TEMP, M_WAITOK); @@ -476,7 +611,8 @@ } } err = usbd_do_request_flags(sc->sc_bus->devices[addr], - &ur->ucr_request, ptr, ur->ucr_flags, &ur->ucr_actlen); + &ur->ucr_request, ptr, ur->ucr_flags, &ur->ucr_actlen, + USBD_DEFAULT_TIMEOUT); if (err) { error = EIO; goto ret; @@ -503,9 +639,9 @@ if (addr < 1 || addr >= USB_MAX_DEVICES) return (EINVAL); dev = sc->sc_bus->devices[addr]; - if (dev == 0) + if (dev == NULL) return (ENXIO); - usbd_fill_deviceinfo(dev, di); + usbd_fill_deviceinfo(dev, di, 1); break; } @@ -530,33 +666,16 @@ mask = POLLIN | POLLRDNORM; s = splusb(); - if ((events & mask) && usb_nevents > 0) + if (events & mask && usb_nevents > 0) revents |= events & mask; - if (revents == 0 && (events & mask)) { - DPRINTFN(2,("usb: sleeping on %p\n", &usb_selevent)); + if (revents == 0 && events & mask) selrecord(p, &usb_selevent); - } splx(s); return (revents); } else { #if defined(__FreeBSD__) - /* This part should be deleted when kthreads is available */ - struct usb_softc *sc; - - USB_GET_SC(usb, unit, sc); - - revents = 0; - mask = POLLOUT | POLLRDNORM; - - s = splusb(); - if ((events & mask) && sc->sc_bus->needs_explore) - revents |= events & mask; - if (revents == 0 && (events & mask)) - selrecord(p, &sc->sc_consel); - splx(s); - - return (revents); + return (0); /* select/poll never wakes up - back compat */ #else return (ENXIO); #endif @@ -564,15 +683,23 @@ } /* Explore device tree from the root. */ -usbd_status -usb_discover(struct usb_softc *sc) +Static void +usb_discover(void *v) { + struct usb_softc *sc = v; + #if defined(__FreeBSD__) - /* The splxxx parts should be deleted when kthreads is available */ + /* splxxx should be changed to mutexes for preemption safety some day */ int s; #endif - /* + DPRINTFN(2,("usb_discover\n")); +#ifdef USB_DEBUG + if (usb_noexplore > 1) + return; +#endif + + /* * We need mutual exclusion while traversing the device tree, * but this is guaranteed since this function is only called * from the event thread for the controller. @@ -593,19 +720,14 @@ #if defined(__FreeBSD__) splx(s); #endif - - return (USBD_NORMAL_COMPLETION); } void -usb_needs_explore(usbd_bus_handle bus) +usb_needs_explore(usbd_device_handle dev) { - bus->needs_explore = 1; -#if defined(__FreeBSD__) - /* This part should be deleted when kthreads is available */ - selwakeup(&bus->usbctl->sc_consel); -#endif - wakeup(&bus->needs_explore); + DPRINTFN(2,("usb_needs_explore\n")); + dev->bus->needs_explore = 1; + wakeup(&dev->bus->needs_explore); } /* Called at splusb() */ @@ -616,51 +738,111 @@ if (usb_nevents <= 0) return (0); - ueq = SIMPLEQ_FIRST(&usb_events); + ueq = TAILQ_FIRST(&usb_events); +#ifdef DIAGNOSTIC + if (ueq == NULL) { + printf("usb: usb_nevents got out of sync! %d\n", usb_nevents); + usb_nevents = 0; + return (0); + } +#endif *ue = ueq->ue; - SIMPLEQ_REMOVE_HEAD(&usb_events, ueq, next); + TAILQ_REMOVE(&usb_events, ueq, next); free(ueq, M_USBDEV); usb_nevents--; return (1); } void -usbd_add_event(int type, usbd_device_handle dev) +usbd_add_dev_event(int type, usbd_device_handle udev) +{ + struct usb_event ue; + + usbd_fill_deviceinfo(udev, &ue.u.ue_device, USB_EVENT_IS_ATTACH(type)); + usb_add_event(type, &ue); +} + +void +usbd_add_drv_event(int type, usbd_device_handle udev, device_ptr_t dev) +{ + struct usb_event ue; + + ue.u.ue_driver.ue_cookie = udev->cookie; + strncpy(ue.u.ue_driver.ue_devname, USBDEVPTRNAME(dev), + sizeof ue.u.ue_driver.ue_devname); + usb_add_event(type, &ue); +} + +void +usb_add_event(int type, struct usb_event *uep) { struct usb_event_q *ueq; struct usb_event ue; struct timeval thetime; int s; + ueq = malloc(sizeof *ueq, M_USBDEV, M_WAITOK); + ueq->ue = *uep; + ueq->ue.ue_type = type; + microtime(&thetime); + TIMEVAL_TO_TIMESPEC(&thetime, &ueq->ue.ue_time); + s = splusb(); - if (++usb_nevents >= USB_MAX_EVENTS) { + if (USB_EVENT_IS_DETACH(type)) { + struct usb_event_q *ueqi, *ueqi_next; + + for (ueqi = TAILQ_FIRST(&usb_events); ueqi; ueqi = ueqi_next) { + ueqi_next = TAILQ_NEXT(ueqi, next); + if (ueqi->ue.u.ue_driver.ue_cookie.cookie == + uep->u.ue_device.udi_cookie.cookie) { + TAILQ_REMOVE(&usb_events, ueqi, next); + free(ueqi, M_USBDEV); + usb_nevents--; + ueqi_next = TAILQ_FIRST(&usb_events); + } + } + } + if (usb_nevents >= USB_MAX_EVENTS) { /* Too many queued events, drop an old one. */ DPRINTF(("usb: event dropped\n")); (void)usb_get_next_event(&ue); } - /* Don't want to wait here inside splusb() */ - ueq = malloc(sizeof *ueq, M_USBDEV, M_NOWAIT); - if (ueq == NULL) { - printf("usb: no memory, event dropped\n"); - splx(s); - return; - } - ueq->ue.ue_type = type; - ueq->ue.u.ue_driver.ue_cookie = dev->cookie; - usbd_fill_deviceinfo(dev, &ueq->ue.u.ue_device); - microtime(&thetime); - TIMEVAL_TO_TIMESPEC(&thetime, &ueq->ue.ue_time); - SIMPLEQ_INSERT_TAIL(&usb_events, ueq, next); + TAILQ_INSERT_TAIL(&usb_events, ueq, next); + usb_nevents++; wakeup(&usb_events); selwakeup(&usb_selevent); - if (usb_async_proc != NULL) + if (usb_async_proc != NULL) { + PROC_LOCK(usb_async_proc); psignal(usb_async_proc, SIGIO); + PROC_UNLOCK(usb_async_proc); + } splx(s); } +void +usb_schedsoftintr(usbd_bus_handle bus) +{ + DPRINTFN(10,("usb_schedsoftintr: polling=%d\n", bus->use_polling)); +#ifdef USB_USE_SOFTINTR + if (bus->use_polling) { + bus->methods->soft_intr(bus); + } else { +#ifdef __HAVE_GENERIC_SOFT_INTERRUPTS + softintr_schedule(bus->soft); +#else + if (!callout_pending(&bus->softi)) + callout_reset(&bus->softi, 0, bus->methods->soft_intr, + bus); +#endif /* __HAVE_GENERIC_SOFT_INTERRUPTS */ + } +#else + bus->methods->soft_intr(bus); +#endif /* USB_USE_SOFTINTR */ +} + #if defined(__NetBSD__) || defined(__OpenBSD__) int -usb_activate(device_ptr_t self, devact act) +usb_activate(device_ptr_t self, enum devact act) { struct usb_softc *sc = (struct usb_softc *)self; usbd_device_handle dev = sc->sc_port.device; @@ -669,11 +851,10 @@ switch (act) { case DVACT_ACTIVATE: return (EOPNOTSUPP); - break; case DVACT_DEACTIVATE: sc->sc_dying = 1; - if (dev && dev->cdesc && dev->subdevs) { + if (dev != NULL && dev->cdesc != NULL && dev->subdevs != NULL) { for (i = 0; dev->subdevs[i]; i++) rv |= config_deactivate(dev->subdevs[i]); } @@ -686,17 +867,18 @@ usb_detach(device_ptr_t self, int flags) { struct usb_softc *sc = (struct usb_softc *)self; + struct usb_event ue; DPRINTF(("usb_detach: start\n")); sc->sc_dying = 1; /* Make all devices disconnect. */ - if (sc->sc_port.device) + if (sc->sc_port.device != NULL) usb_disconnect_port(&sc->sc_port, self); /* Kill off event thread. */ - if (sc->sc_event_thread) { + if (sc->sc_event_thread != NULL) { wakeup(&sc->sc_bus->needs_explore); if (tsleep(sc, PWAIT, "usbdet", hz * 60)) printf("%s: event thread didn't die\n", @@ -705,6 +887,21 @@ } usbd_finish(); + +#ifdef USB_USE_SOFTINTR +#ifdef __HAVE_GENERIC_SOFT_INTERRUPTS + if (sc->sc_bus->soft != NULL) { + softintr_disestablish(sc->sc_bus->soft); + sc->sc_bus->soft = NULL; + } +#else + callout_stop(&sc->sc_bus->softi); +#endif +#endif + + ue.u.ue_ctrlr.ue_bus = USBDEVUNIT(sc->sc_dev); + usb_add_event(USB_EVENT_CTRLR_DETACH, &ue); + return (0); } #elif defined(__FreeBSD__) @@ -721,4 +918,5 @@ #if defined(__FreeBSD__) DRIVER_MODULE(usb, ohci, usb_driver, usb_devclass, 0, 0); DRIVER_MODULE(usb, uhci, usb_driver, usb_devclass, 0, 0); +DRIVER_MODULE(usb, ehci, usb_driver, usb_devclass, 0, 0); #endif Index: sys/dev/usb/usb.h =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/usb.h,v retrieving revision 1.17.2.11 diff -u -r1.17.2.11 usb.h --- sys/dev/usb/usb.h 13 Nov 2002 15:15:22 -0000 1.17.2.11 +++ sys/dev/usb/usb.h 4 Oct 2003 18:54:40 -0000 @@ -1,5 +1,5 @@ -/* $NetBSD: usb.h,v 1.38 1999/10/20 21:02:39 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/usb.h,v 1.17.2.11 2002/11/13 15:15:22 joe Exp $ */ +/* $NetBSD: usb.h,v 1.69 2002/09/22 23:20:50 augustss Exp $ */ +/* $FreeBSD: src/sys/dev/usb/usb.h,v 1.38 2002/11/06 21:37:21 joe Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -47,27 +47,18 @@ #if defined(__NetBSD__) || defined(__OpenBSD__) #include +#endif #if defined(_KERNEL) #include #endif /* _KERNEL */ -#elif defined(__FreeBSD__) -#if defined(_KERNEL) -#include - -MALLOC_DECLARE(M_USB); -MALLOC_DECLARE(M_USBDEV); -MALLOC_DECLARE(M_USBHC); - -#include -#endif /* _KERNEL */ -#endif /* __FreeBSD__ */ - -/* these three defines are used by usbd to autoload the usb kld */ -#define USB_KLD "usb" +/* These two defines are used by usbd to autoload the usb kld */ +#define USB_KLD "usb" /* name of usb module */ #define USB_UHUB "usb/uhub" /* root hub */ +#define USB_STACK_VERSION 2 + #define USB_MAX_DEVICES 128 #define USB_START_ADDR 0 @@ -336,7 +327,7 @@ (((desc)->DeviceRemovable[(i)/8] >> ((i) % 8)) & 1) /* deprecated */ uByte PortPowerCtrlMask[1]; } UPACKED usb_hub_descriptor_t; -#define USB_HUB_DESCRIPTOR_SIZE 8 /* includes deprecated PortPowerCtrlMask */ +#define USB_HUB_DESCRIPTOR_SIZE 9 /* includes deprecated PortPowerCtrlMask */ typedef struct { uByte bLength; @@ -512,18 +503,20 @@ #if 0 /* These are the values from the spec. */ #define USB_PORT_RESET_DELAY 10 /* ms */ -#define USB_PORT_RESET_SETTLE 10 /* ms */ +#define USB_PORT_ROOT_RESET_DELAY 50 /* ms */ +#define USB_PORT_RESET_RECOVERY 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_DELAY (20*5) /* ms */ #define USB_RESUME_WAIT 10 /* ms */ #define USB_RESUME_RECOVERY 10 /* ms */ #define USB_EXTRA_POWER_UP_TIME 0 /* 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_PORT_ROOT_RESET_DELAY 250 /* ms */ +#define USB_PORT_RESET_RECOVERY 250 /* ms */ +#define USB_PORT_POWERUP_DELAY 300 /* ms */ #define USB_SET_ADDRESS_SETTLE 10 /* ms */ #define USB_RESUME_DELAY (50*5) /* ms */ #define USB_RESUME_WAIT 50 /* ms */ @@ -615,7 +608,10 @@ u_int8_t udi_subclass; u_int8_t udi_protocol; u_int8_t udi_config; - u_int8_t udi_lowspeed; + u_int8_t udi_speed; +#define USB_SPEED_LOW 1 +#define USB_SPEED_FULL 2 +#define USB_SPEED_HIGH 3 int udi_power; /* power consumption in mA, 0 if selfpowered */ int udi_nports; char udi_devnames[USB_MAX_DEVNAMES][USB_MAX_DEVNAMELEN]; Index: sys/dev/usb/usb_ethersubr.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/usb_ethersubr.c,v retrieving revision 1.4.2.4 diff -u -r1.4.2.4 usb_ethersubr.c --- sys/dev/usb/usb_ethersubr.c 6 Nov 2002 14:23:20 -0000 1.4.2.4 +++ sys/dev/usb/usb_ethersubr.c 4 Oct 2003 22:37:30 -0000 @@ -28,10 +28,11 @@ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD: src/sys/dev/usb/usb_ethersubr.c,v 1.4.2.4 2002/11/06 14:23:20 joe Exp $ */ +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/usb_ethersubr.c,v 1.15 2003/08/24 17:55:55 obrien Exp $"); + /* * Callbacks in the USB code operate at splusb() (actually splbio() * in FreeBSD). However adding packets to the input queues has to be @@ -50,6 +51,9 @@ * properly. */ +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/usb_ethersubr.c,v 1.15 2003/08/24 17:55:55 obrien Exp $"); + #include #include #include @@ -66,11 +70,6 @@ #include #include - -#ifndef lint -static const char rcsid[] = - "$FreeBSD: src/sys/dev/usb/usb_ethersubr.c,v 1.4.2.4 2002/11/06 14:23:20 joe Exp $"; -#endif Static struct ifqueue usbq_rx; Static struct ifqueue usbq_tx; Index: sys/dev/usb/usb_ethersubr.h =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/usb_ethersubr.h,v retrieving revision 1.4.2.1 diff -u -r1.4.2.1 usb_ethersubr.h --- sys/dev/usb/usb_ethersubr.h 6 Nov 2002 14:23:20 -0000 1.4.2.1 +++ sys/dev/usb/usb_ethersubr.h 4 Oct 2003 18:54:40 -0000 @@ -29,15 +29,11 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/usb/usb_ethersubr.h,v 1.4.2.1 2002/11/06 14:23:20 joe Exp $ + * $FreeBSD: src/sys/dev/usb/usb_ethersubr.h,v 1.6 2003/03/04 23:19:55 jlemon Exp $ */ #ifndef _USB_ETHERSUBR_H_ #define _USB_ETHERSUBR_H_ - -#ifndef NETISR_USB -#define NETISR_USB 25 -#endif struct usb_qdat { struct ifnet *ifp; Index: sys/dev/usb/usb_if.m =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/usb_if.m,v retrieving revision 1.7.2.2 diff -u -r1.7.2.2 usb_if.m --- sys/dev/usb/usb_if.m 7 May 2000 14:58:03 -0000 1.7.2.2 +++ sys/dev/usb/usb_if.m 4 Oct 2003 18:54:40 -0000 @@ -25,7 +25,7 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -# $FreeBSD: src/sys/dev/usb/usb_if.m,v 1.7.2.2 2000/05/07 14:58:03 n_hibma Exp $ +# $FreeBSD: src/sys/dev/usb/usb_if.m,v 1.9 2000/04/08 14:17:05 dfr Exp $ # # USB interface description Index: sys/dev/usb/usb_mem.c =================================================================== RCS file: sys/dev/usb/usb_mem.c diff -N sys/dev/usb/usb_mem.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/dev/usb/usb_mem.c 4 Oct 2003 22:27:21 -0000 @@ -0,0 +1,308 @@ +/* $NetBSD: usb_mem.c,v 1.26 2003/02/01 06:23:40 thorpej Exp $ */ +/* $FreeBSD: src/sys/dev/usb/usb_mem.c,v 1.5 2003/10/04 22:13:21 joe Exp $ */ + +/* + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Lennart Augustsson (lennart@augustsson.net) at + * Carlstedt Research & Technology. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * USB DMA memory allocation. + * We need to allocate a lot of small (many 8 byte, some larger) + * memory blocks that can be used for DMA. Using the bus_dma + * routines directly would incur large overheads in space and time. + */ + +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/usb_mem.c,v 1.5 2003/10/04 22:13:21 joe Exp $"); + +#include +#include +#include +#include +#if defined(__NetBSD__) || defined(__OpenBSD__) +#include /* for usbdivar.h */ +#include +#elif defined(__FreeBSD__) +#include +#include +#include +#endif +#include + +#include +#include + +#ifdef DIAGNOSTIC +#include +#endif + +#include +#include +#include /* just for usb_dma_t */ +#include + +#ifdef USB_DEBUG +#define DPRINTF(x) if (usbdebug) logprintf x +#define DPRINTFN(n,x) if (usbdebug>(n)) logprintf x +extern int usbdebug; +#else +#define DPRINTF(x) +#define DPRINTFN(n,x) +#endif + +#define USB_MEM_SMALL 64 +#define USB_MEM_CHUNKS (PAGE_SIZE / USB_MEM_SMALL) +#define USB_MEM_BLOCK (USB_MEM_SMALL * USB_MEM_CHUNKS) + +/* This struct is overlayed on free fragments. */ +struct usb_frag_dma { + usb_dma_block_t *block; + u_int offs; + LIST_ENTRY(usb_frag_dma) next; +}; + +Static bus_dmamap_callback_t usbmem_callback; +Static usbd_status usb_block_allocmem(bus_dma_tag_t, size_t, size_t, + usb_dma_block_t **); +Static void usb_block_freemem(usb_dma_block_t *); + +Static LIST_HEAD(, usb_dma_block) usb_blk_freelist = + LIST_HEAD_INITIALIZER(usb_blk_freelist); +Static int usb_blk_nfree = 0; +/* XXX should have different free list for different tags (for speed) */ +Static LIST_HEAD(, usb_frag_dma) usb_frag_freelist = + LIST_HEAD_INITIALIZER(usb_frag_freelist); + +Static void +usbmem_callback(void *arg, bus_dma_segment_t *segs, int nseg, int error) +{ + int i; + usb_dma_block_t *p = arg; + + if (error == EFBIG) { + printf("usb: mapping to large\n"); + return; + } + + p->nsegs = nseg; + for (i = 0; i < nseg && i < sizeof p->segs / sizeof *p->segs; i++) + p->segs[i] = segs[i]; +} + +Static usbd_status +usb_block_allocmem(bus_dma_tag_t tag, size_t size, size_t align, + usb_dma_block_t **dmap) +{ + usb_dma_block_t *p; + int s; + + DPRINTFN(5, ("usb_block_allocmem: size=%lu align=%lu\n", + (u_long)size, (u_long)align)); + +#ifdef DIAGNOSTIC + if (!curproc) { + printf("usb_block_allocmem: in interrupt context, size=%lu\n", + (unsigned long) size); + } +#endif + + s = splusb(); + /* First check the free list. */ + for (p = LIST_FIRST(&usb_blk_freelist); p; p = LIST_NEXT(p, next)) { + if (p->tag == tag && p->size >= size && p->align >= align) { + LIST_REMOVE(p, next); + usb_blk_nfree--; + splx(s); + *dmap = p; + DPRINTFN(6,("usb_block_allocmem: free list size=%lu\n", + (u_long)p->size)); + return (USBD_NORMAL_COMPLETION); + } + } + splx(s); + +#ifdef DIAGNOSTIC + if (!curproc) { + printf("usb_block_allocmem: in interrupt context, failed\n"); + return (USBD_NOMEM); + } +#endif + + DPRINTFN(6, ("usb_block_allocmem: no free\n")); + p = malloc(sizeof *p, M_USB, M_NOWAIT); + if (p == NULL) + return (USBD_NOMEM); + +#if __FreeBSD_version >= 500000 + if (bus_dma_tag_create(tag, align, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + size, sizeof(p->segs) / sizeof(p->segs[0]), size, + BUS_DMA_ALLOCNOW, NULL, NULL, &p->tag) == ENOMEM) +#else + if (bus_dma_tag_create(tag, align, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + size, sizeof(p->segs) / sizeof(p->segs[0]), size, + BUS_DMA_ALLOCNOW, &p->tag) == ENOMEM) +#endif + { + goto free; + } + + p->size = size; + p->align = align; + if (bus_dmamem_alloc(p->tag, &p->kaddr, + BUS_DMA_NOWAIT|BUS_DMA_COHERENT, &p->map)) + goto tagfree; + + if (bus_dmamap_load(p->tag, p->map, p->kaddr, p->size, + usbmem_callback, p, 0)) + goto memfree; + + /* XXX - override the tag, ok since we never free it */ + p->tag = tag; + *dmap = p; + return (USBD_NORMAL_COMPLETION); + + /* + * XXX - do we need to _unload? is the order of _free and _destroy + * correct? + */ +memfree: + bus_dmamem_free(p->tag, p->kaddr, p->map); +tagfree: + bus_dma_tag_destroy(p->tag); +free: + free(p, M_USB); + return (USBD_NOMEM); +} + +/* + * Do not free the memory unconditionally since we might be called + * from an interrupt context and that is BAD. + * XXX when should we really free? + */ +Static void +usb_block_freemem(usb_dma_block_t *p) +{ + int s; + + DPRINTFN(6, ("usb_block_freemem: size=%lu\n", (u_long)p->size)); + s = splusb(); + LIST_INSERT_HEAD(&usb_blk_freelist, p, next); + usb_blk_nfree++; + splx(s); +} + +usbd_status +usb_allocmem(usbd_bus_handle bus, size_t size, size_t align, usb_dma_t *p) +{ + bus_dma_tag_t tag = bus->dmatag; + usbd_status err; + struct usb_frag_dma *f; + usb_dma_block_t *b; + int i; + int s; + + /* compat w/ Net/OpenBSD */ + if (align == 0) + align = 1; + + /* If the request is large then just use a full block. */ + if (size > USB_MEM_SMALL || align > USB_MEM_SMALL) { + DPRINTFN(1, ("usb_allocmem: large alloc %d\n", (int)size)); + size = (size + USB_MEM_BLOCK - 1) & ~(USB_MEM_BLOCK - 1); + err = usb_block_allocmem(tag, size, align, &p->block); + if (!err) { + p->block->fullblock = 1; + p->offs = 0; + p->len = size; + } + return (err); + } + + s = splusb(); + /* Check for free fragments. */ + for (f = LIST_FIRST(&usb_frag_freelist); f; f = LIST_NEXT(f, next)) + if (f->block->tag == tag) + break; + if (f == NULL) { + DPRINTFN(1, ("usb_allocmem: adding fragments\n")); + err = usb_block_allocmem(tag, USB_MEM_BLOCK, USB_MEM_SMALL,&b); + if (err) { + splx(s); + return (err); + } + b->fullblock = 0; + /* XXX - override the tag, ok since we never free it */ + b->tag = tag; + KASSERT(sizeof *f <= USB_MEM_SMALL, ("USB_MEM_SMALL(%d) is too small for struct usb_frag_dma(%zd)\n", + USB_MEM_SMALL, sizeof *f)); + for (i = 0; i < USB_MEM_BLOCK; i += USB_MEM_SMALL) { + f = (struct usb_frag_dma *)((char *)b->kaddr + i); + f->block = b; + f->offs = i; + LIST_INSERT_HEAD(&usb_frag_freelist, f, next); + } + f = LIST_FIRST(&usb_frag_freelist); + } + p->block = f->block; + p->offs = f->offs; + p->len = USB_MEM_SMALL; + LIST_REMOVE(f, next); + splx(s); + DPRINTFN(5, ("usb_allocmem: use frag=%p size=%d\n", f, (int)size)); + return (USBD_NORMAL_COMPLETION); +} + +void +usb_freemem(usbd_bus_handle bus, usb_dma_t *p) +{ + struct usb_frag_dma *f; + int s; + + if (p->block->fullblock) { + DPRINTFN(1, ("usb_freemem: large free\n")); + usb_block_freemem(p->block); + return; + } + f = KERNADDR(p, 0); + f->block = p->block; + f->offs = p->offs; + s = splusb(); + LIST_INSERT_HEAD(&usb_frag_freelist, f, next); + splx(s); + DPRINTFN(5, ("usb_freemem: frag=%p\n", f)); +} Index: sys/dev/usb/usb_mem.h =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/usb_mem.h,v retrieving revision 1.10.2.2 diff -u -r1.10.2.2 usb_mem.h --- sys/dev/usb/usb_mem.h 31 Oct 2000 23:23:30 -0000 1.10.2.2 +++ sys/dev/usb/usb_mem.h 4 Oct 2003 21:27:29 -0000 @@ -1,5 +1,5 @@ -/* $NetBSD: usb_mem.h,v 1.9 1999/10/13 08:10:58 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/usb_mem.h,v 1.10.2.2 2000/10/31 23:23:30 n_hibma Exp $ */ +/* $NetBSD: usb_mem.h,v 1.18 2002/05/28 17:45:17 augustss Exp $ */ +/* $FreeBSD: src/sys/dev/usb/usb_mem.h,v 1.20 2003/09/01 01:07:24 jmg Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -38,11 +38,14 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__NetBSD__) || defined(__OpenBSD__) typedef struct usb_dma_block { bus_dma_tag_t tag; bus_dmamap_t map; +#ifdef __FreeBSD__ + void *kaddr; +#else caddr_t kaddr; +#endif bus_dma_segment_t segs[1]; int nsegs; size_t size; @@ -51,39 +54,13 @@ LIST_ENTRY(usb_dma_block) next; } usb_dma_block_t; -#define DMAADDR(dma, offset) ((dma)->block->segs[0].ds_addr + (dma)->offs + (offset)) -#define KERNADDR(dma, offset) ((void *)((dma)->block->kaddr + (dma)->offs) + (offset)) - -usbd_status usb_allocmem(usbd_bus_handle,size_t,size_t, usb_dma_t *); -void usb_freemem(usbd_bus_handle, usb_dma_t *); - -#elif defined(__FreeBSD__) - -/* - * FreeBSD does not have special functions for dma memory, so let's keep it - * simple for now. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include /* for vtophys */ - -#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)) - -#ifdef __alpha__ -#define DMAADDR(dma, offset) (alpha_XXX_dmamap((vm_offset_t) *(dma) + (offset))) +#ifdef __FreeBSD__ +#define DMAADDR(dma, o) ((uint32_t)(uintptr_t)(((char *)(dma)->block->segs[0].ds_addr) + (dma)->offs + (o))) #else -#define DMAADDR(dma, offset) (vtophys(*(dma) + (offset))) -#endif -#define KERNADDR(dma, offset) ((void *) (*(dma) + (offset))) +#define DMAADDR(dma, o) (((char *)(dma)->block->map->dm_segs[0].ds_addr) + (dma)->offs + (o)) #endif +#define KERNADDR(dma, o) \ + ((void *)((char *)((dma)->block->kaddr) + (dma)->offs + (o))) +usbd_status usb_allocmem(usbd_bus_handle,size_t,size_t, usb_dma_t *); +void usb_freemem(usbd_bus_handle, usb_dma_t *); Index: sys/dev/usb/usb_port.h =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/usb_port.h,v retrieving revision 1.25.2.7 diff -u -r1.25.2.7 usb_port.h --- sys/dev/usb/usb_port.h 12 Aug 2002 14:19:49 -0000 1.25.2.7 +++ sys/dev/usb/usb_port.h 4 Oct 2003 21:27:30 -0000 @@ -1,5 +1,11 @@ -/* $NetBSD: usb_port.h,v 1.15 1999/11/16 12:04:28 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/usb_port.h,v 1.25.2.7 2002/08/12 14:19:49 joe Exp $ */ +/* $OpenBSD: usb_port.h,v 1.18 2000/09/06 22:42:10 rahnds Exp $ */ +/* $NetBSD: usb_port.h,v 1.54 2002/03/28 21:49:19 ichiro Exp $ */ +/* $FreeBSD: src/sys/dev/usb/usb_port.h,v 1.64 2003/10/04 21:41:01 joe Exp $ */ + +/* Also already merged from NetBSD: + * $NetBSD: usb_port.h,v 1.57 2002/09/27 20:42:01 thorpej Exp $ + * $NetBSD: usb_port.h,v 1.58 2002/10/01 01:25:26 thorpej Exp $ + */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -38,8 +44,10 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#ifndef _USB_PORT_H +#define _USB_PORT_H -/* +/* * Macro's to cope with the differences between operating systems. */ @@ -50,7 +58,15 @@ #include "opt_usbverbose.h" +#define USB_USE_SOFTINTR + +#ifdef USB_DEBUG +#define Static +#else #define Static static +#endif + +#define SCSI_MODE_SENSE MODE_SENSE typedef struct proc *usb_proc_ptr; @@ -58,8 +74,9 @@ #define USBBASEDEVICE struct device #define USBDEV(bdev) (&(bdev)) #define USBDEVNAME(bdev) ((bdev).dv_xname) -#define USBDEVPTRNAME(bdevptr) ((bdevptr)->dv_xname) #define USBDEVUNIT(bdev) ((bdev).dv_unit) +#define USBDEVPTRNAME(bdevptr) ((bdevptr)->dv_xname) +#define USBGETSOFTC(d) ((void *)(d)) #define DECLARE_USB_DMA_T \ struct usb_dma_block; \ @@ -68,11 +85,22 @@ 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)) +typedef struct callout usb_callout_t; +#define usb_callout_init(h) callout_init(&(h)) +#define usb_callout(h, t, f, d) callout_reset(&(h), (t), (f), (d)) +#define usb_uncallout(h, f, d) callout_stop(&(h)) + +#define usb_kthread_create1 kthread_create1 +#define usb_kthread_create kthread_create + +typedef int usb_malloc_type; + +#define Ether_ifattach ether_ifattach +#define IF_INPUT(ifp, m) (*(ifp)->if_input)((ifp), (m)) #define logprintf printf +#define USB_DNAME(dname) dname #define USB_DECLARE_DRIVER(dname) \ int __CONCAT(dname,_match)(struct device *, struct cfdata *, void *); \ void __CONCAT(dname,_attach)(struct device *, struct device *, void *); \ @@ -81,32 +109,21 @@ \ extern struct cfdriver __CONCAT(dname,_cd); \ \ -struct cfattach __CONCAT(dname,_ca) = { \ - sizeof(struct __CONCAT(dname,_softc)), \ - __CONCAT(dname,_match), \ - __CONCAT(dname,_attach), \ - __CONCAT(dname,_detach), \ - __CONCAT(dname,_activate), \ -} +CFATTACH_DECL(USB_DNAME(dname), \ + 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; \ - struct cfdata *match; \ - void *aux; +int __CONCAT(dname,_match)(struct device *parent, struct cfdata *match, void *aux) #define USB_MATCH_START(dname, uaa) \ struct usb_attach_arg *uaa = aux -#define USB_MATCH_SETUP /* nop */ - #define USB_ATTACH(dname) \ -void \ -__CONCAT(dname,_attach)(parent, self, aux) \ - struct device *parent; \ - struct device *self; \ - void *aux; +void __CONCAT(dname,_attach)(struct device *parent, struct device *self, void *aux) #define USB_ATTACH_START(dname, sc, uaa) \ struct __CONCAT(dname,_softc) *sc = \ @@ -120,10 +137,7 @@ #define USB_ATTACH_SETUP printf("\n") #define USB_DETACH(dname) \ -int \ -__CONCAT(dname,_detach)(self, flags) \ - struct device *self; \ - int flags; +int __CONCAT(dname,_detach)(struct device *self, int flags) #define USB_DETACH_START(dname, sc) \ struct __CONCAT(dname,_softc) *sc = \ @@ -133,7 +147,7 @@ if (unit >= __CONCAT(dname,_cd).cd_ndevs) \ return (ENXIO); \ sc = __CONCAT(dname,_cd).cd_devs[unit]; \ - if (!sc) \ + if (sc == NULL) \ return (ENXIO) #define USB_GET_SC(dname, unit, sc) \ @@ -146,29 +160,90 @@ /* * OpenBSD */ -#define Static static +#define Static typedef struct proc *usb_proc_ptr; +#define UCOMBUSCF_PORTNO -1 +#define UCOMBUSCF_PORTNO_DEFAULT -1 + +#define SCSI_MODE_SENSE MODE_SENSE +#define XS_STS_DONE ITSDONE +#define XS_CTL_POLL SCSI_POLL +#define XS_CTL_DATA_IN SCSI_DATA_IN +#define XS_CTL_DATA_OUT SCSI_DATA_OUT +#define scsipi_adapter scsi_adapter +#define scsipi_cmd scsi_cmd +#define scsipi_device scsi_device +#define scsipi_done scsi_done +#define scsipi_link scsi_link +#define scsipi_minphys scsi_minphys +#define scsipi_sense scsi_sense +#define scsipi_xfer scsi_xfer +#define xs_control flags +#define xs_status status + #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 bswap16(x) swap16(x) + +/* + * The UHCI/OHCI controllers are little endian, so on big endian machines + * the data strored in memory needs to be swapped. + */ + +#if defined(letoh32) +#define le32toh(x) letoh32(x) +#define le16toh(x) letoh16(x) +#endif + +#define usb_kthread_create1 kthread_create +#define usb_kthread_create kthread_create_deferred + +#define config_pending_incr() +#define config_pending_decr() + +typedef int usb_malloc_type; + +#define Ether_ifattach(ifp, eaddr) ether_ifattach(ifp) +#define if_deactivate(x) +#define IF_INPUT(ifp, m) do { \ + struct ether_header *eh; \ + \ + eh = mtod(m, struct ether_header *); \ + m_adj(m, sizeof(struct ether_header)); \ + ether_input((ifp), (eh), (m)); \ +} while (0) #define usbpoll usbselect #define uhidpoll uhidselect #define ugenpoll ugenselect +#define uriopoll urioselect +#define uscannerpoll uscannerselect +#define powerhook_establish(fn, sc) (fn) +#define powerhook_disestablish(hdl) #define PWR_RESUME 0 -#define PWR_SUSPEND 1 -typedef struct device device_ptr_t; +#define logprintf printf + +#define swap_bytes_change_sign16_le swap_bytes_change_sign16 +#define change_sign16_swap_bytes_le change_sign16_swap_bytes +#define change_sign16_le change_sign16 + +#define realloc usb_realloc +void *usb_realloc(void *, u_int, int, int); + +extern int cold; + +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 USBDEVUNIT(bdev) ((bdev).dv_unit) +#define USBDEVPTRNAME(bdevptr) ((bdevptr)->dv_xname) +#define USBGETSOFTC(d) ((void *)(d)) #define DECLARE_USB_DMA_T \ struct usb_dma_block; \ @@ -177,8 +252,10 @@ 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)) +typedef char usb_callout_t; +#define usb_callout_init(h) +#define usb_callout(h, t, f, d) timeout((f), (d), (t)) +#define usb_uncallout(h, f, d) untimeout((f), (d)) #define USB_DECLARE_DRIVER(dname) \ int __CONCAT(dname,_match)(struct device *, void *, void *); \ @@ -190,7 +267,7 @@ NULL, #dname, DV_DULL \ }; \ \ -struct cfattach __CONCAT(dname,_ca) = { \ +const struct cfattach __CONCAT(dname,_ca) = { \ sizeof(struct __CONCAT(dname,_softc)), \ __CONCAT(dname,_match), \ __CONCAT(dname,_attach), \ @@ -208,8 +285,6 @@ #define USB_MATCH_START(dname, uaa) \ struct usb_attach_arg *uaa = aux -#define USB_MATCH_SETUP /* nop */ - #define USB_ATTACH(dname) \ void \ __CONCAT(dname,_attach)(parent, self, aux) \ @@ -242,7 +317,7 @@ if (unit >= __CONCAT(dname,_cd).cd_ndevs) \ return (ENXIO); \ sc = __CONCAT(dname,_cd).cd_devs[unit]; \ - if (!sc) \ + if (sc == NULL) \ return (ENXIO) #define USB_GET_SC(dname, unit, sc) \ @@ -258,31 +333,83 @@ #include "opt_usb.h" +#if defined(_KERNEL) +#include + +MALLOC_DECLARE(M_USB); +MALLOC_DECLARE(M_USBDEV); +MALLOC_DECLARE(M_USBHC); + +#endif + #define USBVERBOSE +/* We don't use the soft interrupt code in FreeBSD. */ +#if 0 +#define USB_USE_SOFTINTR +#endif + #define Static static #define device_ptr_t device_t #define USBBASEDEVICE device_t #define USBDEV(bdev) (bdev) #define USBDEVNAME(bdev) device_get_nameunit(bdev) +#define USBDEVUNIT(bdev) device_get_unit(bdev) #define USBDEVPTRNAME(bdev) device_get_nameunit(bdev) #define USBDEVUNIT(bdev) device_get_unit(bdev) +#define USBGETSOFTC(bdev) (device_get_softc(bdev)) -#define DECLARE_USB_DMA_T typedef char * usb_dma_t +#define DECLARE_USB_DMA_T \ + struct usb_dma_block; \ + typedef struct { \ + struct usb_dma_block *block; \ + u_int offs; \ + u_int len; \ + } usb_dma_t + +#if __FreeBSD_version >= 500000 +typedef struct thread *usb_proc_ptr; + +#define uio_procp uio_td +#define usb_kthread_create1(f, s, p, a0, a1) \ + kthread_create((f), (s), (p), RFHIGHPID, 0, (a0), (a1)) +#define usb_kthread_create2(f, s, p, a0) \ + kthread_create((f), (s), (p), RFHIGHPID, 0, (a0)) +#define usb_kthread_create kthread_create + +#define config_pending_incr() +#define config_pending_decr() + +typedef struct callout usb_callout_t; +#define usb_callout_init(h) callout_init(&(h), 0) +#define usb_callout(h, t, f, d) callout_reset(&(h), (t), (f), (d)) +#define usb_uncallout(h, f, d) callout_stop(&(h)) +#else typedef struct proc *usb_proc_ptr; -/* XXX Change this when FreeBSD has memset */ -#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(function, sc, priv, string, name) -#define kthread_create(create_function, sc) -#define kthread_exit(err) +#define PROC_LOCK(p) +#define PROC_UNLOCK(p) -#define usb_timeout(f, d, t, h) ((h) = timeout((f), (d), (t))) -#define usb_untimeout(f, d, h) untimeout((f), (d), (h)) +#define usb_kthread_create1(f, s, p, a0, a1) \ + kthread_create((f), (s), (p), (a0), (a1)) +#define usb_kthread_create2(f, s, p, a0) \ + kthread_create((f), (s), (p), (a0)) +#define usb_kthread_create kthread_create + +#define config_pending_incr() +#define config_pending_decr() + +typedef struct callout usb_callout_t; +#define usb_callout_init(h) callout_init(&(h)) +#define usb_callout(h, t, f, d) callout_reset(&(h), (t), (f), (d)) +#define usb_uncallout(h, f, d) callout_stop(&(h)) + +#define BUS_DMA_COHERENT 0 +#define ETHER_ALIGN 2 +#define BPF_MTAP(ifp, m) if ((ifp)->if_bpf) bpf_mtap((ifp), (m)); +#endif #define clalloc(p, s, x) (clist_alloc_cblocks((p), (s), (s)), 0) #define clfree(p) clist_free_cblocks((p)) @@ -290,6 +417,10 @@ #define PWR_RESUME 0 #define PWR_SUSPEND 1 +#define config_detach(dev, flag) device_delete_child(device_get_parent(dev), dev) + +typedef struct malloc_type *usb_malloc_type; + #define USB_DECLARE_DRIVER_INIT(dname, init...) \ Static device_probe_t __CONCAT(dname,_match); \ Static device_attach_t __CONCAT(dname,_attach); \ @@ -309,7 +440,10 @@ #dname, \ __CONCAT(dname,_methods), \ sizeof(struct __CONCAT(dname,_softc)) \ -} +}; \ +MODULE_DEPEND(dname, usb, 1, 1, 1) + + #define METHODS_NONE {0,0} #define USB_DECLARE_DRIVER(dname) USB_DECLARE_DRIVER_INIT(dname, METHODS_NONE) @@ -348,7 +482,7 @@ #define USB_GET_SC_OPEN(dname, unit, sc) \ sc = devclass_get_softc(__CONCAT(dname,_devclass), unit); \ - if (!sc) \ + if (sc == NULL) \ return (ENXIO) #define USB_GET_SC(dname, unit, sc) \ @@ -370,6 +504,8 @@ #define SIMPLEQ_NEXT STAILQ_NEXT #define SIMPLEQ_FIRST STAILQ_FIRST #define SIMPLEQ_HEAD STAILQ_HEAD +#define SIMPLEQ_EMPTY STAILQ_EMPTY +#define SIMPLEQ_FOREACH STAILQ_FOREACH #define SIMPLEQ_INIT STAILQ_INIT #define SIMPLEQ_HEAD_INITIALIZER STAILQ_HEAD_INITIALIZER #define SIMPLEQ_ENTRY STAILQ_ENTRY @@ -385,3 +521,6 @@ #endif #endif /* __FreeBSD__ */ + +#endif /* _USB_PORT_H */ + Index: sys/dev/usb/usb_quirks.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/usb_quirks.c,v retrieving revision 1.21.2.8 diff -u -r1.21.2.8 usb_quirks.c --- sys/dev/usb/usb_quirks.c 12 Feb 2003 14:05:57 -0000 1.21.2.8 +++ sys/dev/usb/usb_quirks.c 4 Oct 2003 18:54:40 -0000 @@ -1,5 +1,4 @@ -/* $NetBSD: usb_quirks.c,v 1.26 2000/04/27 15:26:50 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/usb_quirks.c,v 1.21.2.8 2003/02/12 14:05:57 sanpei Exp $ */ +/* $NetBSD: usb_quirks.c,v 1.42 2003/01/02 04:19:00 imp Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -38,9 +37,12 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/usb_quirks.c,v 1.34 2003/08/24 17:55:55 obrien Exp $"); + #include #include - + #include #include @@ -52,14 +54,14 @@ #define ANY 0xffff -Static struct usbd_quirk_entry { +Static const struct usbd_quirk_entry { u_int16_t idVendor; u_int16_t idProduct; u_int16_t bcdDevice; struct usbd_quirks quirks; } usb_quirks[] = { { USB_VENDOR_KYE, USB_PRODUCT_KYE_NICHE, 0x100, { UQ_NO_SET_PROTO}}, - { USB_VENDOR_INSIDEOUT,USB_PRODUCT_INSIDEOUT_EDGEPORT4, + { USB_VENDOR_INSIDEOUT, USB_PRODUCT_INSIDEOUT_EDGEPORT4, 0x094, { UQ_SWAP_UNICODE}}, { USB_VENDOR_BTC, USB_PRODUCT_BTC_BTC7932, 0x100, { UQ_NO_STRINGS }}, { USB_VENDOR_ADS, USB_PRODUCT_ADS_UBS10BT, 0x002, { UQ_NO_STRINGS }}, @@ -75,14 +77,22 @@ { USB_VENDOR_MCT, USB_PRODUCT_MCT_USB232, 0x102, { UQ_BUS_POWERED }}, { USB_VENDOR_METRICOM, USB_PRODUCT_METRICOM_RICOCHET_GS, 0x100, { UQ_ASSUME_CM_OVER_DATA | UQ_NO_STRINGS }}, + { USB_VENDOR_SANYO, USB_PRODUCT_SANYO_SCP4900, + 0x000, { UQ_ASSUME_CM_OVER_DATA | UQ_NO_STRINGS }}, + { USB_VENDOR_TI, USB_PRODUCT_TI_UTUSB41, 0x110, { UQ_POWER_CLAIM }}, { USB_VENDOR_ACERP, USB_PRODUCT_ACERP_ACERSCAN_320U, - 0x000, { UQ_NO_STRINGS }}, + 0x000, { UQ_NO_STRINGS }}, + { USB_VENDOR_TELEX, USB_PRODUCT_TELEX_MIC1, 0x009, { UQ_AU_NO_FRAC }}, + { USB_VENDOR_SILICONPORTALS, USB_PRODUCT_SILICONPORTALS_YAPPHONE, + 0x100, { UQ_AU_INP_ASYNC }}, + { USB_VENDOR_NEODIO, USB_PRODUCT_NEODIO_ND5010, 0x100, { UQ_NO_STRINGS }}, /* XXX These should have a revision number, but I don't know what they are. */ { USB_VENDOR_HP, USB_PRODUCT_HP_895C, ANY, { UQ_BROKEN_BIDIR }}, { USB_VENDOR_HP, USB_PRODUCT_HP_880C, ANY, { UQ_BROKEN_BIDIR }}, { USB_VENDOR_HP, USB_PRODUCT_HP_815C, ANY, { UQ_BROKEN_BIDIR }}, { USB_VENDOR_HP, USB_PRODUCT_HP_810C, ANY, { UQ_BROKEN_BIDIR }}, { USB_VENDOR_HP, USB_PRODUCT_HP_830C, ANY, { UQ_BROKEN_BIDIR }}, + { USB_VENDOR_HP, USB_PRODUCT_HP_1220C, ANY, { UQ_BROKEN_BIDIR }}, /* YAMAHA router's ucdDevice is the version of farmware and often changes. */ { USB_VENDOR_YAMAHA, USB_PRODUCT_YAMAHA_RTA54I, ANY, { UQ_ASSUME_CM_OVER_DATA }}, @@ -92,26 +102,30 @@ ANY, { UQ_ASSUME_CM_OVER_DATA }}, { USB_VENDOR_YAMAHA, USB_PRODUCT_YAMAHA_RTW65I, ANY, { UQ_ASSUME_CM_OVER_DATA }}, + { USB_VENDOR_LOGITECH, USB_PRODUCT_LOGITECH_WMRPAD, ANY, { UQ_NO_STRINGS }}, { 0, 0, 0, { 0 } } }; -struct usbd_quirks usbd_no_quirk = { 0 }; +const struct usbd_quirks usbd_no_quirk = { 0 }; -struct usbd_quirks * +const struct usbd_quirks * usbd_find_quirk(usb_device_descriptor_t *d) { - struct usbd_quirk_entry *t; + const struct usbd_quirk_entry *t; + u_int16_t vendor = UGETW(d->idVendor); + u_int16_t product = UGETW(d->idProduct); + u_int16_t revision = UGETW(d->bcdDevice); for (t = usb_quirks; t->idVendor != 0; t++) { - if (t->idVendor == UGETW(d->idVendor) && - t->idProduct == UGETW(d->idProduct) && - (t->bcdDevice == ANY || t->bcdDevice == UGETW(d->bcdDevice))) + if (t->idVendor == vendor && + t->idProduct == product && + (t->bcdDevice == ANY || t->bcdDevice == revision)) break; } #ifdef USB_DEBUG if (usbdebug && t->quirks.uq_flags) - logprintf("usbd_find_quirk 0x%04x/0x%04x/%x: %d\n", + 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 Index: sys/dev/usb/usb_quirks.h =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/usb_quirks.h,v retrieving revision 1.11.2.6 diff -u -r1.11.2.6 usb_quirks.h --- sys/dev/usb/usb_quirks.h 24 Aug 2002 08:00:32 -0000 1.11.2.6 +++ sys/dev/usb/usb_quirks.h 4 Oct 2003 18:54:40 -0000 @@ -1,5 +1,5 @@ -/* $NetBSD: usb_quirks.h,v 1.11 2000/04/27 15:26:50 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/usb_quirks.h,v 1.11.2.6 2002/08/24 08:00:32 nsayer Exp $ */ +/* $NetBSD: usb_quirks.h,v 1.20 2001/04/15 09:38:01 augustss Exp $ */ +/* $FreeBSD: src/sys/dev/usb/usb_quirks.h,v 1.16 2001/07/05 10:12:59 n_hibma Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -49,12 +49,13 @@ #define UQ_BAD_AUDIO 0x0040 /* device claims audio class, but isn't */ #define UQ_SPUR_BUT_UP 0x0080 /* spurious mouse button up events */ #define UQ_AU_NO_XU 0x0100 /* audio device has broken extension unit */ -#define UQ_AU_NO_FRAC 0x0400 /* audio don't adjust for fractional samples */ +#define UQ_POWER_CLAIM 0x0200 /* hub lies about power status */ +#define UQ_AU_NO_FRAC 0x0400 /* don't adjust for fractional samples */ #define UQ_AU_INP_ASYNC 0x0800 /* input is async despite claim of adaptive */ #define UQ_ASSUME_CM_OVER_DATA 0x1000 /* modem device breaks on cm over data */ #define UQ_BROKEN_BIDIR 0x2000 /* printer has broken bidir mode */ }; -extern struct usbd_quirks usbd_no_quirk; +extern const struct usbd_quirks usbd_no_quirk; -struct usbd_quirks *usbd_find_quirk(usb_device_descriptor_t *); +const struct usbd_quirks *usbd_find_quirk(usb_device_descriptor_t *); Index: sys/dev/usb/usb_subr.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/usb_subr.c,v retrieving revision 1.23.2.8 diff -u -r1.23.2.8 usb_subr.c --- sys/dev/usb/usb_subr.c 17 Jan 2003 17:46:24 -0000 1.23.2.8 +++ sys/dev/usb/usb_subr.c 4 Oct 2003 22:30:49 -0000 @@ -1,5 +1,12 @@ -/* $NetBSD: usb_subr.c,v 1.76 2000/04/27 15:26:50 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/usb_subr.c,v 1.23.2.8 2003/01/17 17:46:24 joe Exp $ */ +/* $NetBSD: usb_subr.c,v 1.99 2002/07/11 21:14:34 augustss Exp $ */ + +/* Also already have from NetBSD: + * $NetBSD: usb_subr.c,v 1.102 2003/01/01 16:21:50 augustss Exp $ + * $NetBSD: usb_subr.c,v 1.103 2003/01/10 11:19:13 augustss Exp $ + */ + +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/usb_subr.c,v 1.58 2003/09/01 07:47:42 ticso Exp $"); /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -75,19 +82,21 @@ #define DPRINTFN(n,x) #endif -Static usbd_status usbd_set_config(usbd_device_handle, int); +Static usbd_status usbd_set_config(usbd_device_handle, int); +Static void usbd_devinfo_vp(usbd_device_handle, char *, char *, int); Static char *usbd_get_string(usbd_device_handle, int, char *); Static int usbd_getnewaddr(usbd_bus_handle bus); #if defined(__NetBSD__) Static int usbd_print(void *aux, const char *pnp); Static int usbd_submatch(device_ptr_t, struct cfdata *cf, void *); #elif defined(__OpenBSD__) +Static int usbd_print(void *aux, const char *pnp); Static int usbd_submatch(device_ptr_t, void *, void *); #endif Static void usbd_free_iface_data(usbd_device_handle dev, int ifcno); Static void usbd_kill_pipe(usbd_pipe_handle); -Static usbd_status usbd_probe_and_attach - (device_ptr_t parent, usbd_device_handle dev, int port, int addr); +Static usbd_status usbd_probe_and_attach(device_ptr_t parent, + usbd_device_handle dev, int port, int addr); Static u_int32_t usb_cookie_no = 0; @@ -109,7 +118,7 @@ #include #endif /* USBVERBOSE */ -Static const char *usbd_error_strs[] = { +Static const char * const usbd_error_strs[] = { "NORMAL_COMPLETION", "IN_PROGRESS", "PENDING_REQUESTS", @@ -159,7 +168,7 @@ USETW(req.wIndex, langid); USETW(req.wLength, 2); /* only size byte first */ err = usbd_do_request_flags(dev, &req, sdesc, USBD_SHORT_XFER_OK, - &actlen); + &actlen, USBD_DEFAULT_TIMEOUT); if (err) return (err); @@ -188,7 +197,7 @@ /* Set up default language */ err = usbd_get_string_desc(dev, USB_LANGUAGE_TABLE, 0, &us); if (err || us.bLength < 4) { - dev->langid = 0; /* Well, just pick English then */ + dev->langid = 0; /* Well, just pick something then */ } else { /* Pick the first language as the default. */ dev->langid = UGETW(us.bString[0]); @@ -206,20 +215,36 @@ *s++ = c; else if ((c & 0x00ff) == 0 && swap) *s++ = c >> 8; - else + else *s++ = '?'; } *s++ = 0; return (buf); } -void -usbd_devinfo_vp(usbd_device_handle dev, char *v, char *p) +Static void +usbd_trim_spaces(char *p) +{ + char *q, *e; + + if (p == NULL) + return; + q = e = p; + while (*q == ' ') /* skip leading spaces */ + q++; + while ((*p = *q++)) /* copy string */ + if (*p++ != ' ') /* remember last non-space */ + e = p; + *e = 0; /* kill trailing spaces */ +} + +Static void +usbd_devinfo_vp(usbd_device_handle dev, char *v, char *p, int usedev) { usb_device_descriptor_t *udd = &dev->ddesc; char *vendor = 0, *product = 0; #ifdef USBVERBOSE - struct usb_knowndev *kdp; + const struct usb_knowndev *kdp; #endif if (dev == NULL) { @@ -227,32 +252,39 @@ return; } - vendor = usbd_get_string(dev, udd->iManufacturer, v); - product = usbd_get_string(dev, udd->iProduct, p); + if (usedev) { + vendor = usbd_get_string(dev, udd->iManufacturer, v); + usbd_trim_spaces(vendor); + product = usbd_get_string(dev, udd->iProduct, p); + usbd_trim_spaces(product); + } else { + vendor = NULL; + product = NULL; + } #ifdef USBVERBOSE if (vendor == NULL || product == NULL) { for(kdp = usb_knowndevs; kdp->vendorname != NULL; kdp++) { - if (kdp->vendor == UGETW(udd->idVendor) && + if (kdp->vendor == UGETW(udd->idVendor) && (kdp->product == UGETW(udd->idProduct) || (kdp->flags & USB_KNOWNDEV_NOPROD) != 0)) break; } if (kdp->vendorname != NULL) { - if (!vendor) - vendor = kdp->vendorname; - if (!product) - product = (kdp->flags & USB_KNOWNDEV_NOPROD) == 0 ? + if (vendor == NULL) + vendor = kdp->vendorname; + if (product == NULL) + product = (kdp->flags & USB_KNOWNDEV_NOPROD) == 0 ? kdp->productname : NULL; } } #endif - if (vendor != NULL) + if (vendor != NULL && *vendor) strcpy(v, vendor); else sprintf(v, "vendor 0x%04x", UGETW(udd->idVendor)); - if (product != NULL) + if (product != NULL && *product) strcpy(p, product); else sprintf(p, "product 0x%04x", UGETW(udd->idProduct)); @@ -272,7 +304,7 @@ char product[USB_MAX_STRING_LEN]; int bcdDevice, bcdUSB; - usbd_devinfo_vp(dev, vendor, product); + usbd_devinfo_vp(dev, vendor, product, 1); cp += sprintf(cp, "%s %s", vendor, product); if (showclass) cp += sprintf(cp, ", class %d/%d", @@ -311,7 +343,7 @@ usb_device_request_t req; usbd_status err; int n; - + req.bmRequestType = UT_WRITE_CLASS_OTHER; req.bRequest = UR_SET_FEATURE; USETW(req.wValue, UHF_PORT_RESET); @@ -332,6 +364,9 @@ err)); return (err); } + /* If the device disappeared, just give up. */ + if (!(UGETW(ps->wPortStatus) & UPS_CURRENT_CONNECT_STATUS)) + return (USBD_NORMAL_COMPLETION); } while ((UGETW(ps->wPortChange) & UPS_C_PORT_RESET) == 0 && --n > 0); if (n == 0) return (USBD_TIMEOUT); @@ -358,7 +393,7 @@ for (curidx = lastidx = -1; p < end; ) { d = (usb_interface_descriptor_t *)p; DPRINTFN(4,("usbd_find_idesc: idx=%d(%d) altidx=%d(%d) len=%d " - "type=%d\n", + "type=%d\n", ifaceidx, curidx, altidx, curaidx, d->bLength, d->bDescriptorType)); if (d->bLength == 0) /* bad descriptor */ @@ -379,7 +414,7 @@ } usb_endpoint_descriptor_t * -usbd_find_edesc(usb_config_descriptor_t *cd, int ifaceidx, int altidx, +usbd_find_edesc(usb_config_descriptor_t *cd, int ifaceidx, int altidx, int endptidx) { char *p = (char *)cd; @@ -415,15 +450,17 @@ usbd_fill_iface_data(usbd_device_handle dev, int ifaceidx, int altidx) { usbd_interface_handle ifc = &dev->ifaces[ifaceidx]; + usb_interface_descriptor_t *idesc; char *p, *end; int endpt, nendpt; DPRINTFN(4,("usbd_fill_iface_data: ifaceidx=%d altidx=%d\n", ifaceidx, altidx)); - ifc->device = dev; - ifc->idesc = usbd_find_idesc(dev->cdesc, ifaceidx, altidx); - if (ifc->idesc == 0) + idesc = usbd_find_idesc(dev->cdesc, ifaceidx, altidx); + if (idesc == NULL) return (USBD_INVAL); + ifc->device = dev; + ifc->idesc = idesc; ifc->index = ifaceidx; ifc->altindex = altidx; nendpt = ifc->idesc->bNumEndpoints; @@ -442,7 +479,6 @@ for (endpt = 0; endpt < nendpt; endpt++) { DPRINTFN(10,("usbd_fill_iface_data: endpt=%d\n", endpt)); for (; p < end; p += ed->bLength) { - ed = (usb_endpoint_descriptor_t *)p; DPRINTFN(10,("usbd_fill_iface_data: p=%p end=%p " "len=%d type=%d\n", p, end, ed->bLength, ed->bDescriptorType)); @@ -454,13 +490,35 @@ break; } /* passed end, or bad desc */ - DPRINTF(("usbd_fill_iface_data: bad descriptor(s): %s\n", - ed->bLength == 0 ? "0 length" : - ed->bDescriptorType == UDESC_INTERFACE ? "iface desc": - "out of data")); + printf("usbd_fill_iface_data: bad descriptor(s): %s\n", + ed->bLength == 0 ? "0 length" : + ed->bDescriptorType == UDESC_INTERFACE ? "iface desc": + "out of data"); goto bad; found: ifc->endpoints[endpt].edesc = ed; + if (dev->speed == USB_SPEED_HIGH) { + u_int mps; + /* Control and bulk endpoints have max packet limits. */ + switch (UE_GET_XFERTYPE(ed->bmAttributes)) { + case UE_CONTROL: + mps = USB_2_MAX_CTRL_PACKET; + goto check; + case UE_BULK: + mps = USB_2_MAX_BULK_PACKET; + check: + if (UGETW(ed->wMaxPacketSize) != mps) { + USETW(ed->wMaxPacketSize, mps); +#ifdef DIAGNOSTIC + printf("usbd_fill_iface_data: bad max " + "packet size\n"); +#endif + } + break; + default: + break; + } + } ifc->endpoints[endpt].refcnt = 0; p += ed->bLength; } @@ -469,8 +527,10 @@ return (USBD_NORMAL_COMPLETION); bad: - if (ifc->endpoints != NULL) + if (ifc->endpoints != NULL) { free(ifc->endpoints, M_USB); + ifc->endpoints = NULL; + } return (USBD_INVAL); } @@ -577,18 +637,43 @@ /* May be self powered. */ if (cdp->bmAttributes & UC_BUS_POWERED) { /* Must ask device. */ - err = usbd_get_device_status(dev, &ds); - if (!err && (UGETW(ds.wStatus) & UDS_SELF_POWERED)) - selfpowered = 1; - DPRINTF(("usbd_set_config_index: status=0x%04x, " - "error=%s\n", - UGETW(ds.wStatus), usbd_errstr(err))); + if (dev->quirks->uq_flags & UQ_POWER_CLAIM) { + /* + * Hub claims to be self powered, but isn't. + * It seems that the power status can be + * determined by the hub characteristics. + */ + usb_hub_descriptor_t hd; + usb_device_request_t req; + req.bmRequestType = UT_READ_CLASS_DEVICE; + req.bRequest = UR_GET_DESCRIPTOR; + USETW(req.wValue, 0); + USETW(req.wIndex, 0); + USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE); + err = usbd_do_request(dev, &req, &hd); + if (!err && + (UGETW(hd.wHubCharacteristics) & + UHD_PWR_INDIVIDUAL)) + selfpowered = 1; + DPRINTF(("usbd_set_config_index: charac=0x%04x" + ", error=%s\n", + UGETW(hd.wHubCharacteristics), + usbd_errstr(err))); + } else { + err = usbd_get_device_status(dev, &ds); + if (!err && + (UGETW(ds.wStatus) & UDS_SELF_POWERED)) + selfpowered = 1; + DPRINTF(("usbd_set_config_index: status=0x%04x" + ", error=%s\n", + UGETW(ds.wStatus), usbd_errstr(err))); + } } else selfpowered = 1; } - DPRINTF(("usbd_set_config_index: (addr %d) attr=0x%02x, " - "selfpowered=%d, power=%d\n", - dev->address, cdp->bmAttributes, + DPRINTF(("usbd_set_config_index: (addr %d) cno=%d attr=0x%02x, " + "selfpowered=%d, power=%d\n", + cdp->bConfigurationValue, dev->address, cdp->bmAttributes, selfpowered, cdp->bMaxPower * 2)); /* Check if we have enough power. */ @@ -600,12 +685,13 @@ #endif power = cdp->bMaxPower * 2; if (power > dev->powersrc->power) { + DPRINTF(("power exceeded %d %d\n", power,dev->powersrc->power)); /* XXX print nicer message. */ if (msg) printf("%s: device addr %d (config %d) exceeds power " "budget, %d mA > %d mA\n", - USBDEVNAME(dev->bus->bdev), dev->address, - cdp->bConfigurationValue, + USBDEVNAME(dev->bus->bdev), dev->address, + cdp->bConfigurationValue, power, dev->powersrc->power); err = USBD_NO_POWER; goto bad; @@ -626,7 +712,7 @@ /* Allocate and fill interface data. */ nifc = cdp->bNumInterface; - dev->ifaces = malloc(nifc * sizeof(struct usbd_interface), + dev->ifaces = malloc(nifc * sizeof(struct usbd_interface), M_USB, M_NOWAIT); if (dev->ifaces == NULL) { err = USBD_NOMEM; @@ -672,6 +758,7 @@ p->refcnt = 1; p->intrxfer = 0; p->running = 0; + p->aborting = 0; p->repeat = 0; p->interval = ival; SIMPLEQ_INIT(&p->queue); @@ -694,6 +781,7 @@ void usbd_kill_pipe(usbd_pipe_handle pipe) { + usbd_abort_pipe(pipe); pipe->methods->close(pipe); pipe->endpoint->refcnt--; free(pipe, M_USB); @@ -723,17 +811,17 @@ 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. */ device_t bdev; bdev = device_add_child(parent, NULL, -1); - device_set_ivars(bdev, &uaa); if (!bdev) { printf("%s: Device creation failed\n", USBDEVNAME(dev->bus->bdev)); return (USBD_INVAL); } + device_set_ivars(bdev, &uaa); device_quiet(bdev); #endif @@ -815,12 +903,12 @@ #if defined(__FreeBSD__) /* create another child for the next iface */ bdev = device_add_child(parent, NULL, -1); - device_set_ivars(bdev, &uaa); if (!bdev) { printf("%s: Device creation failed\n", USBDEVNAME(dev->bus->bdev)); return (USBD_NORMAL_COMPLETION); } + device_set_ivars(bdev, &uaa); device_quiet(bdev); #endif } @@ -847,9 +935,6 @@ uaa.usegeneric = 1; uaa.configno = UHUB_UNK_CONFIGURATION; uaa.ifaceno = UHUB_UNK_INTERFACE; - 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 != NULL) { dev->subdevs = malloc(2 * sizeof dv, M_USB, M_NOWAIT); @@ -860,7 +945,7 @@ return (USBD_NORMAL_COMPLETION); } - /* + /* * The generic attach failed, but leave the device as it is. * We just did not find any drivers, that's all. The device is * fully operational and not harming anyone. @@ -881,27 +966,28 @@ */ usbd_status usbd_new_device(device_ptr_t parent, usbd_bus_handle bus, int depth, - int lowspeed, int port, struct usbd_port *up) + int speed, int port, struct usbd_port *up) { usbd_device_handle dev; + struct usbd_device *hub; usb_device_descriptor_t *dd; + usb_port_status_t ps; usbd_status err; int addr; int i; - DPRINTF(("usbd_new_device bus=%p port=%d depth=%d lowspeed=%d\n", - bus, port, depth, lowspeed)); + DPRINTF(("usbd_new_device bus=%p port=%d depth=%d speed=%d\n", + bus, port, depth, speed)); addr = usbd_getnewaddr(bus); if (addr < 0) { - printf("%s: No free USB addresses, new device ignored.\n", + printf("%s: No free USB addresses, new device ignored.\n", USBDEVNAME(bus->bdev)); return (USBD_NO_ADDR); } - dev = malloc(sizeof *dev, M_USB, M_NOWAIT); + dev = malloc(sizeof *dev, M_USB, M_NOWAIT|M_ZERO); if (dev == NULL) return (USBD_NOMEM); - memset(dev, 0, sizeof(*dev)); dev->bus = bus; @@ -919,9 +1005,15 @@ dev->quirks = &usbd_no_quirk; dev->address = USB_START_ADDR; dev->ddesc.bMaxPacketSize = 0; - dev->lowspeed = lowspeed != 0; dev->depth = depth; dev->powersrc = up; + dev->myhub = up->parent; + for (hub = up->parent; + hub != NULL && hub->speed != USB_SPEED_HIGH; + hub = hub->myhub) + ; + dev->myhighhub = hub; + dev->speed = speed; dev->langid = USBD_NOLANG; dev->cookie.cookie = ++usb_cookie_no; @@ -936,12 +1028,14 @@ up->device = dev; dd = &dev->ddesc; /* Try a few times in case the device is slow (i.e. outside specs.) */ - for (i = 0; i < 3; i++) { + for (i = 0; i < 15; i++) { /* Get the first 8 bytes of the device descriptor. */ err = usbd_get_desc(dev, UDESC_DEVICE, 0, USB_MAX_IPACKET, dd); if (!err) break; usbd_delay_ms(dev, 200); + if ((i & 3) == 3) + usbd_reset_port(up->parent, port, &ps); } if (err) { DPRINTFN(-1, ("usbd_new_device: addr=%d, getting first desc " @@ -950,11 +1044,22 @@ return (err); } + if (speed == USB_SPEED_HIGH) { + /* Max packet size must be 64 (sec 5.5.3). */ + if (dd->bMaxPacketSize != USB_2_MAX_CTRL_PACKET) { +#ifdef DIAGNOSTIC + printf("usbd_new_device: addr=%d bad max packet size\n", + addr); +#endif + dd->bMaxPacketSize = USB_2_MAX_CTRL_PACKET; + } + } + DPRINTF(("usbd_new_device: adding unit addr=%d, rev=%02x, class=%d, " - "subclass=%d, protocol=%d, maxpacket=%d, len=%d, ls=%d\n", + "subclass=%d, protocol=%d, maxpacket=%d, len=%d, speed=%d\n", addr,UGETW(dd->bcdUSB), dd->bDeviceClass, dd->bDeviceSubClass, - dd->bDeviceProtocol, dd->bMaxPacketSize, dd->bLength, - dev->lowspeed)); + dd->bDeviceProtocol, dd->bMaxPacketSize, dd->bLength, + dev->speed)); if (dd->bDescriptorType != UDESC_DEVICE) { /* Illegal device descriptor */ @@ -999,7 +1104,7 @@ dev->power = USB_MIN_POWER; dev->self_powered = 0; - DPRINTF(("usbd_new_device: new dev (addr %d), dev=%p, parent=%p\n", + 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); @@ -1007,8 +1112,9 @@ usbd_remove_device(dev, up); return (err); } - - usbd_add_event(USB_EVENT_DEVICE_ATTACH, dev); + + usbd_add_dev_event(USB_EVENT_DEVICE_ATTACH, dev); + return (USBD_NORMAL_COMPLETION); } @@ -1038,7 +1144,7 @@ usbd_remove_device(usbd_device_handle dev, struct usbd_port *up) { DPRINTF(("usbd_remove_device: %p\n", dev)); - + if (dev->default_pipe != NULL) usbd_kill_pipe(dev->default_pipe); up->device = 0; @@ -1068,7 +1174,7 @@ 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. @@ -1105,54 +1211,54 @@ uaa->release, cf->uhubcf_release)); if (uaa->port != 0 && /* root hub has port 0, it should match */ ((uaa->port != 0 && - cf->uhubcf_port != UHUB_UNK_PORT && - cf->uhubcf_port != uaa->port) || - (uaa->configno != UHUB_UNK_CONFIGURATION && - cf->uhubcf_configuration != UHUB_UNK_CONFIGURATION && - cf->uhubcf_configuration != uaa->configno) || - (uaa->ifaceno != UHUB_UNK_INTERFACE && - cf->uhubcf_interface != UHUB_UNK_INTERFACE && - 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) - ) + cf->uhubcf_port != UHUB_UNK_PORT && + cf->uhubcf_port != uaa->port) || + (uaa->configno != UHUB_UNK_CONFIGURATION && + cf->uhubcf_configuration != UHUB_UNK_CONFIGURATION && + cf->uhubcf_configuration != uaa->configno) || + (uaa->ifaceno != UHUB_UNK_INTERFACE && + cf->uhubcf_interface != UHUB_UNK_INTERFACE && + 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; + if (cf->uhubcf_vendor != UHUB_UNK_VENDOR && + cf->uhubcf_vendor == uaa->vendor && + cf->uhubcf_product != UHUB_UNK_PRODUCT && + cf->uhubcf_product == uaa->product) { + /* We have a vendor&product locator match */ + if (cf->uhubcf_release != UHUB_UNK_RELEASE && + cf->uhubcf_release == uaa->release) + uaa->matchlvl = UMATCH_VENDOR_PRODUCT_REV; + else + uaa->matchlvl = UMATCH_VENDOR_PRODUCT; + } else + uaa->matchlvl = 0; return ((*cf->cf_attach->ca_match)(parent, cf, aux)); } #endif void -usbd_fill_deviceinfo(usbd_device_handle dev, struct usb_device_info *di) +usbd_fill_deviceinfo(usbd_device_handle dev, struct usb_device_info *di, + int usedev) { struct usbd_port *p; int i, err, s; di->udi_bus = USBDEVUNIT(dev->bus->bdev); di->udi_addr = dev->address; - - if (dev->subdevs) { - for (i = 0; dev->subdevs[i] && - i < USB_MAX_DEVNAMES; i++) { - strncpy(di->udi_devnames[i], USBDEVPTRNAME(dev->subdevs[i]), - USB_MAX_DEVNAMELEN); - di->udi_devnames[i][USB_MAX_DEVNAMELEN-1] = '\0'; /* terminate */ - } - } else { - i = 0; - } - for (/*i is set */; i < USB_MAX_DEVNAMES; i++) - di->udi_devnames[i][0] = 0; /* empty */ - - usbd_devinfo_vp(dev, di->udi_vendor, di->udi_product); + di->udi_cookie = dev->cookie; + usbd_devinfo_vp(dev, di->udi_vendor, di->udi_product, usedev); usbd_printBCD(di->udi_release, UGETW(dev->ddesc.bcdDevice)); di->udi_vendorNo = UGETW(dev->ddesc.idVendor); di->udi_productNo = UGETW(dev->ddesc.idProduct); @@ -1162,10 +1268,23 @@ di->udi_protocol = dev->ddesc.bDeviceProtocol; di->udi_config = dev->config; di->udi_power = dev->self_powered ? 0 : dev->power; - di->udi_lowspeed = dev->lowspeed; + di->udi_speed = dev->speed; + + if (dev->subdevs != NULL) { + for (i = 0; dev->subdevs[i] && + i < USB_MAX_DEVNAMES; i++) { + strncpy(di->udi_devnames[i], USBDEVPTRNAME(dev->subdevs[i]), + USB_MAX_DEVNAMELEN); + di->udi_devnames[i][USB_MAX_DEVNAMELEN-1] = '\0'; + } + } else { + i = 0; + } + for (/*i is set */; i < USB_MAX_DEVNAMES; i++) + di->udi_devnames[i][0] = 0; /* empty */ if (dev->hub) { - for (i = 0; + for (i = 0; i < sizeof(di->udi_ports) / sizeof(di->udi_ports[0]) && i < dev->hub->hubdesc.bNbrPorts; i++) { @@ -1234,7 +1353,7 @@ const char *hubname = USBDEVPTRNAME(parent); int i; - DPRINTFN(3,("uhub_disconnect: up=%p dev=%p port=%d\n", + DPRINTFN(3,("uhub_disconnect: up=%p dev=%p port=%d\n", up, dev, up->portno)); #ifdef DIAGNOSTIC @@ -1244,34 +1363,19 @@ } #endif - if (dev->cdesc == NULL) { - /* Partially attached device, just drop it. */ - dev->bus->devices[dev->address] = 0; - up->device = 0; - return; - } - - usbd_add_event(USB_EVENT_DEVICE_DETACH, dev); - if (dev->subdevs != NULL) { DPRINTFN(3,("usb_disconnect_port: disconnect subdevs\n")); for (i = 0; dev->subdevs[i]; i++) { - printf("%s: at %s", USBDEVPTRNAME(dev->subdevs[i]), + printf("%s: at %s", USBDEVPTRNAME(dev->subdevs[i]), hubname); if (up->portno != 0) printf(" port %d", up->portno); printf(" (addr %d) disconnected\n", 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 - } } - /*usbd_add_event(USB_EVENT_DEVICE_DETACH, dev);*/ + /*usbd_add_dev_event(USB_EVENT_DEVICE_DETACH, dev);*/ dev->bus->devices[dev->address] = NULL; up->device = NULL; usb_free_device(dev); Index: sys/dev/usb/usbcdc.h =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/usbcdc.h,v retrieving revision 1.7.2.2 diff -u -r1.7.2.2 usbcdc.h --- sys/dev/usb/usbcdc.h 31 Oct 2000 23:01:16 -0000 1.7.2.2 +++ sys/dev/usb/usbcdc.h 4 Oct 2003 18:54:40 -0000 @@ -1,5 +1,5 @@ -/* $NetBSD: usbcdc.h,v 1.3 1999/01/03 01:09:18 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/usbcdc.h,v 1.7.2.2 2000/10/31 23:01:16 n_hibma Exp $ */ +/* $NetBSD: usbcdc.h,v 1.6 2000/04/27 15:26:50 augustss Exp $ */ +/* $FreeBSD: src/sys/dev/usb/usbcdc.h,v 1.10 2003/01/09 04:24:28 imp Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -145,6 +145,18 @@ uByte data[16]; } usb_cdc_notification_t; #define UCDC_NOTIFICATION_LENGTH 8 + +/* + * Bits set in the SERIAL STATE notifcation (first byte of data) + */ + +#define UCDC_N_SERIAL_OVERRUN 0x40 +#define UCDC_N_SERIAL_PARITY 0x20 +#define UCDC_N_SERIAL_FRAMING 0x10 +#define UCDC_N_SERIAL_RI 0x08 +#define UCDC_N_SERIAL_BREAK 0x04 +#define UCDC_N_SERIAL_DSR 0x02 +#define UCDC_N_SERIAL_DCD 0x01 /* Serial state bit masks */ #define UCDC_MDM_RXCARRIER 0x01 Index: sys/dev/usb/usbdevs =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/usbdevs,v retrieving revision 1.11.2.48 diff -u -r1.11.2.48 usbdevs --- sys/dev/usb/usbdevs 2 Sep 2003 14:35:17 -0000 1.11.2.48 +++ sys/dev/usb/usbdevs 4 Oct 2003 22:28:08 -0000 @@ -1,4 +1,4 @@ -$FreeBSD: src/sys/dev/usb/usbdevs,v 1.11.2.48 2003/09/02 14:35:17 joe Exp $ +$FreeBSD: src/sys/dev/usb/usbdevs,v 1.139 2003/09/24 02:02:41 jb Exp $ /* * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc. @@ -146,7 +146,9 @@ vendor PANASONIC 0x04da Panasonic (Matsushita) vendor IIYAMA 0x04e1 Iiyama vendor SHUTTLE 0x04e6 Shuttle Technology +vendor SAMSUNG 0x04e8 Samsung Electronics vendor ANNABOOKS 0x04ed Annabooks +vendor JVC 0x04f1 JVC vendor CHICONY 0x04f2 Chicony Electronics vendor BROTHER 0x04f9 Brother Industries vendor DALLAS 0x04fa Dallas Semiconductor @@ -253,7 +255,7 @@ vendor DIGITALSTREAM 0x074e Digital Stream vendor AUREAL 0x0755 Aureal Semiconductor vendor MIDIMAN 0x0763 Midiman -vendor LINKSYS2 0x077b Linksys +vendor LINKSYS2 0x077b Linksys vendor GRIFFIN 0x077d Griffin Technology vendor SANDISK 0x0781 SanDisk Corp vendor BRIMAX 0x078e Brimax @@ -308,6 +310,7 @@ vendor ALATION 0x0910 Alation Systems vendor GOHUBS 0x0921 GoHubs vendor BIOMETRIC 0x0929 American Biometric Company +vendor TOSHIBA 0x0930 Toshiba Corporation vendor YANO 0x094f Yano vendor KINGSTON 0x0951 Kingston Technology vendor BLUEWATER 0x0956 BlueWater Systems @@ -341,6 +344,7 @@ vendor AGATE 0x0c08 Agate Technologies vendor DMI 0x0c0b DMI vendor LUWEN 0x0c76 Luwen +vendor HAWKING 0x0e66 Hawking Technologies vendor MOTOROLA 0x1063 Motorola vendor PLX 0x10b5 PLX vendor ASANTE 0x10bd Asante @@ -356,6 +360,7 @@ vendor ENTREGA 0x1645 Entrega vendor ACTIONTEC 0x1668 Actiontec Electronics vendor DLINK 0x2001 D-Link +vendor VIDZMEDIA 0x3275 VidzMedia Pte Ltd vendor DAISY 0x3579 Daisy Technology vendor INTEL 0x8086 Intel vendor HP2 0xf003 Hewlett Packard @@ -481,6 +486,7 @@ product BELKIN F5U103 0x0103 F5U103 Serial adapter product BELKIN F5U109 0x0109 F5U109 Serial adapter product BELKIN F5U120 0x1203 F5U120-PC Hub +product BELKIN F5U208 0x0208 F5U208 VideoBus II /* Billionton products */ product BILLIONTON USB100 0x0986 USB100N 10/100 FastEthernet Adapter @@ -542,6 +548,7 @@ product CYPRESS MOUSE 0x0001 mouse product CYPRESS THERMO 0x0002 thermometer product CYPRESS FMRADIO 0x1002 FM Radio +product CYPRESS SLIM_HUB 0x6560 Slim Hub /* Daisy Technology products */ product DAISY DMC 0x6901 USB MultiMedia Reader @@ -669,6 +676,9 @@ /* Hauppauge Computer Works */ product HAUPPAUGE WINTV_USB_FM 0x4d12 WinTV USB FM +/* Hawking Technologies products */ +product HAWKING UF100 0x400c 10/100 USB Ethernet + /* Hitachi, Ltd. products */ product HITACHI DVDCAM_USB 0x001e DVDCAM USB HS Interface @@ -697,6 +707,7 @@ product HP 840C 0x0604 DeskJet 840c product HP 2200C 0x0605 ScanJet 2200C product HP 5300C 0x0701 Scanjet 5300C +product HP 4400C 0x0705 Scanjet 4400C product HP 970CSE 0x1004 Deskjet 970Cse product HP 5400C 0x1005 Scanjet 5400C product HP 930C 0x1204 DeskJet 930c @@ -734,6 +745,9 @@ product IOMEGA ZIP100 0x0001 Zip 100 product IOMEGA ZIP250 0x0030 Zip 250 +/* JVC products */ +product JVC GR_DX95 0x000a GR-DX95 + /* JRC products */ product JRC AH_J3001V_J3002V 0x0001 AirH\" PHONE AH-J3001V/J3002V @@ -820,7 +834,7 @@ product LOGITECH BB13 0xc401 USB-PS/2 Trackball product LOGITECH WMPAD 0xc208 WingMan GamePad Extreme product LOGITECH WMRPAD 0xc20a WingMan RumblePad -product LOGITECH WMJOY 0xc281 WingMan Force joystick +product LOGITECH WMJOY 0xc281 WingMan Force joystick product LOGITECH RK53 0xc501 Cordless mouse product LOGITECH RB6 0xc503 Cordless keyboard product LOGITECH MX700 0xc506 Cordless optical mouse @@ -860,6 +874,7 @@ product MICROSOFT INETPRO 0x001c Internet Keyboard Pro product MICROSOFT INTELLIEYE 0x0025 IntelliEye mouse product MICROSOFT INETPRO2 0x002b Internet Keyboard Pro +product MICROSOFT MN110 0x007a 10/100 USB NIC /* Microtech products */ product MICROTECH SCSIDB25 0x0004 USB-SCSI-DB25 @@ -1013,7 +1028,7 @@ product QUICKSHOT STRIKEPAD 0x6238 USB StrikePad /* Rainbow Technologies products */ -product RAINBOW IKEY2000 0x1200 i-Key 2000 +product RAINBOW IKEY2000 0x1200 i-Key 2000 /* ReakTek products */ product REALTEK USBKR100 0x8150 USBKR100 USB Ethernet (GREEN HOUSE) @@ -1029,6 +1044,9 @@ /* RATOC Systems products */ product RATOC REXUSB60 0xb000 USB serial adapter REX-USB60 +/* Samsung products */ +product SAMSUNG ML6060 0x3008 ML-6060 laser printer + /* SanDisk products */ product SANDISK SDDR05A 0x0001 ImageMate SDDR-05a product SANDISK SDDR05 0x0005 ImageMate SDDR-05 @@ -1126,7 +1144,7 @@ /* Taugagreining products */ product TAUGA CAMERAMATE 0x0005 CameraMate (DPCM_USB) - + /* TDK products */ product TDK UPA9664 0x0115 USB-PDC Adapter UPA9664 product TDK UCA1464 0x0116 USB-cdmaOne Adapter UCA1464 @@ -1146,6 +1164,9 @@ /* Thrustmaster products */ product THRUST FUSION_PAD 0xa0a3 Fusion Digital Gamepad +/* Toshiba Corporation products */ +product TOSHIBA POCKETPC_E740 0x0706 PocketPC e740 + /* Trek Technology products */ product TREK THUMBDRIVE 0x1111 ThumbDrive product TREK THUMBDRIVE_8MB 0x9988 ThumbDrive_8MB @@ -1164,6 +1185,9 @@ /* Universal Access products */ product UNIACCESS PANACHE 0x0101 Panache Surf USB ISDN Adapter +/* VidzMedia products */ +product VIDZMEDIA MONSTERTV 0x4fb1 MonsterTV P2H + /* Vision products */ product VISION VC6452V002 0x0002 CPiA Camera @@ -1175,13 +1199,13 @@ product VISIONEER 6200 0x0311 OneTouch 6200 product VISIONEER 8100 0x0321 OneTouch 8100 product VISIONEER 8600 0x0331 OneTouch 8600 - + /* Wacom products */ product WACOM CT0405U 0x0000 CT-0405-U Tablet product WACOM GRAPHIRE 0x0010 Graphire product WACOM INTUOSA5 0x0021 Intuos A5 product WACOM GD0912U 0x0022 Intuos 9x12 Graphics Tablet - + /* Xirlink products */ product XIRLINK PCCAM 0x8080 IBM PC Camera Index: sys/dev/usb/usbdevs.h =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/usbdevs.h,v retrieving revision 1.32.2.45 diff -u -r1.32.2.45 usbdevs.h --- sys/dev/usb/usbdevs.h 2 Sep 2003 14:35:57 -0000 1.32.2.45 +++ sys/dev/usb/usbdevs.h 4 Oct 2003 22:28:33 -0000 @@ -1,10 +1,10 @@ -/* $FreeBSD: src/sys/dev/usb/usbdevs.h,v 1.32.2.45 2003/09/02 14:35:57 joe Exp $ */ +/* $FreeBSD: src/sys/dev/usb/usbdevs.h,v 1.147 2003/09/24 02:02:41 jb Exp $ */ /* * THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. * * generated from: - * FreeBSD: src/sys/dev/usb/usbdevs,v 1.11.2.48 2003/09/02 14:35:17 joe Exp + * FreeBSD: src/sys/dev/usb/usbdevs,v 1.138 2003/09/20 20:01:08 se Exp */ /* @@ -153,7 +153,9 @@ #define USB_VENDOR_PANASONIC 0x04da /* Panasonic (Matsushita) */ #define USB_VENDOR_IIYAMA 0x04e1 /* Iiyama */ #define USB_VENDOR_SHUTTLE 0x04e6 /* Shuttle Technology */ +#define USB_VENDOR_SAMSUNG 0x04e8 /* Samsung Electronics */ #define USB_VENDOR_ANNABOOKS 0x04ed /* Annabooks */ +#define USB_VENDOR_JVC 0x04f1 /* JVC */ #define USB_VENDOR_CHICONY 0x04f2 /* Chicony Electronics */ #define USB_VENDOR_BROTHER 0x04f9 /* Brother Industries */ #define USB_VENDOR_DALLAS 0x04fa /* Dallas Semiconductor */ @@ -315,6 +317,7 @@ #define USB_VENDOR_ALATION 0x0910 /* Alation Systems */ #define USB_VENDOR_GOHUBS 0x0921 /* GoHubs */ #define USB_VENDOR_BIOMETRIC 0x0929 /* American Biometric Company */ +#define USB_VENDOR_TOSHIBA 0x0930 /* Toshiba Corporation */ #define USB_VENDOR_YANO 0x094f /* Yano */ #define USB_VENDOR_KINGSTON 0x0951 /* Kingston Technology */ #define USB_VENDOR_BLUEWATER 0x0956 /* BlueWater Systems */ @@ -348,6 +351,7 @@ #define USB_VENDOR_AGATE 0x0c08 /* Agate Technologies */ #define USB_VENDOR_DMI 0x0c0b /* DMI */ #define USB_VENDOR_LUWEN 0x0c76 /* Luwen */ +#define USB_VENDOR_HAWKING 0x0e66 /* Hawking Technologies */ #define USB_VENDOR_MOTOROLA 0x1063 /* Motorola */ #define USB_VENDOR_PLX 0x10b5 /* PLX */ #define USB_VENDOR_ASANTE 0x10bd /* Asante */ @@ -363,6 +367,7 @@ #define USB_VENDOR_ENTREGA 0x1645 /* Entrega */ #define USB_VENDOR_ACTIONTEC 0x1668 /* Actiontec Electronics */ #define USB_VENDOR_DLINK 0x2001 /* D-Link */ +#define USB_VENDOR_VIDZMEDIA 0x3275 /* VidzMedia Pte Ltd */ #define USB_VENDOR_DAISY 0x3579 /* Daisy Technology */ #define USB_VENDOR_INTEL 0x8086 /* Intel */ #define USB_VENDOR_HP2 0xf003 /* Hewlett Packard */ @@ -488,6 +493,7 @@ #define USB_PRODUCT_BELKIN_F5U103 0x0103 /* F5U103 Serial adapter */ #define USB_PRODUCT_BELKIN_F5U109 0x0109 /* F5U109 Serial adapter */ #define USB_PRODUCT_BELKIN_F5U120 0x1203 /* F5U120-PC Hub */ +#define USB_PRODUCT_BELKIN_F5U208 0x0208 /* F5U208 VideoBus II */ /* Billionton products */ #define USB_PRODUCT_BILLIONTON_USB100 0x0986 /* USB100N 10/100 FastEthernet Adapter */ @@ -549,6 +555,7 @@ #define USB_PRODUCT_CYPRESS_MOUSE 0x0001 /* mouse */ #define USB_PRODUCT_CYPRESS_THERMO 0x0002 /* thermometer */ #define USB_PRODUCT_CYPRESS_FMRADIO 0x1002 /* FM Radio */ +#define USB_PRODUCT_CYPRESS_SLIM_HUB 0x6560 /* Slim Hub */ /* Daisy Technology products */ #define USB_PRODUCT_DAISY_DMC 0x6901 /* USB MultiMedia Reader */ @@ -676,6 +683,9 @@ /* Hauppauge Computer Works */ #define USB_PRODUCT_HAUPPAUGE_WINTV_USB_FM 0x4d12 /* WinTV USB FM */ +/* Hawking Technologies products */ +#define USB_PRODUCT_HAWKING_UF100 0x400c /* 10/100 USB Ethernet */ + /* Hitachi, Ltd. products */ #define USB_PRODUCT_HITACHI_DVDCAM_USB 0x001e /* DVDCAM USB HS Interface */ @@ -704,6 +714,7 @@ #define USB_PRODUCT_HP_840C 0x0604 /* DeskJet 840c */ #define USB_PRODUCT_HP_2200C 0x0605 /* ScanJet 2200C */ #define USB_PRODUCT_HP_5300C 0x0701 /* Scanjet 5300C */ +#define USB_PRODUCT_HP_4400C 0x0705 /* Scanjet 4400C */ #define USB_PRODUCT_HP_970CSE 0x1004 /* Deskjet 970Cse */ #define USB_PRODUCT_HP_5400C 0x1005 /* Scanjet 5400C */ #define USB_PRODUCT_HP_930C 0x1204 /* DeskJet 930c */ @@ -741,6 +752,9 @@ #define USB_PRODUCT_IOMEGA_ZIP100 0x0001 /* Zip 100 */ #define USB_PRODUCT_IOMEGA_ZIP250 0x0030 /* Zip 250 */ +/* JVC products */ +#define USB_PRODUCT_JVC_GR_DX95 0x000a /* GR-DX95 */ + /* JRC products */ #define USB_PRODUCT_JRC_AH_J3001V_J3002V 0x0001 /* AirH\" PHONE AH-J3001V/J3002V */ @@ -867,6 +881,7 @@ #define USB_PRODUCT_MICROSOFT_INETPRO 0x001c /* Internet Keyboard Pro */ #define USB_PRODUCT_MICROSOFT_INTELLIEYE 0x0025 /* IntelliEye mouse */ #define USB_PRODUCT_MICROSOFT_INETPRO2 0x002b /* Internet Keyboard Pro */ +#define USB_PRODUCT_MICROSOFT_MN110 0x007a /* 10/100 USB NIC */ /* Microtech products */ #define USB_PRODUCT_MICROTECH_SCSIDB25 0x0004 /* USB-SCSI-DB25 */ @@ -1036,6 +1051,9 @@ /* RATOC Systems products */ #define USB_PRODUCT_RATOC_REXUSB60 0xb000 /* USB serial adapter REX-USB60 */ +/* Samsung products */ +#define USB_PRODUCT_SAMSUNG_ML6060 0x3008 /* ML-6060 laser printer */ + /* SanDisk products */ #define USB_PRODUCT_SANDISK_SDDR05A 0x0001 /* ImageMate SDDR-05a */ #define USB_PRODUCT_SANDISK_SDDR05 0x0005 /* ImageMate SDDR-05 */ @@ -1133,7 +1151,7 @@ /* Taugagreining products */ #define USB_PRODUCT_TAUGA_CAMERAMATE 0x0005 /* CameraMate (DPCM_USB) */ - + /* TDK products */ #define USB_PRODUCT_TDK_UPA9664 0x0115 /* USB-PDC Adapter UPA9664 */ #define USB_PRODUCT_TDK_UCA1464 0x0116 /* USB-cdmaOne Adapter UCA1464 */ @@ -1153,6 +1171,9 @@ /* Thrustmaster products */ #define USB_PRODUCT_THRUST_FUSION_PAD 0xa0a3 /* Fusion Digital Gamepad */ +/* Toshiba Corporation products */ +#define USB_PRODUCT_TOSHIBA_POCKETPC_E740 0x0706 /* PocketPC e740 */ + /* Trek Technology products */ #define USB_PRODUCT_TREK_THUMBDRIVE 0x1111 /* ThumbDrive */ #define USB_PRODUCT_TREK_THUMBDRIVE_8MB 0x9988 /* ThumbDrive_8MB */ @@ -1171,6 +1192,9 @@ /* Universal Access products */ #define USB_PRODUCT_UNIACCESS_PANACHE 0x0101 /* Panache Surf USB ISDN Adapter */ +/* VidzMedia products */ +#define USB_PRODUCT_VIDZMEDIA_MONSTERTV 0x4fb1 /* MonsterTV P2H */ + /* Vision products */ #define USB_PRODUCT_VISION_VC6452V002 0x0002 /* CPiA Camera */ @@ -1182,13 +1206,13 @@ #define USB_PRODUCT_VISIONEER_6200 0x0311 /* OneTouch 6200 */ #define USB_PRODUCT_VISIONEER_8100 0x0321 /* OneTouch 8100 */ #define USB_PRODUCT_VISIONEER_8600 0x0331 /* OneTouch 8600 */ - + /* Wacom products */ #define USB_PRODUCT_WACOM_CT0405U 0x0000 /* CT-0405-U Tablet */ #define USB_PRODUCT_WACOM_GRAPHIRE 0x0010 /* Graphire */ #define USB_PRODUCT_WACOM_INTUOSA5 0x0021 /* Intuos A5 */ #define USB_PRODUCT_WACOM_GD0912U 0x0022 /* Intuos 9x12 Graphics Tablet */ - + /* Xirlink products */ #define USB_PRODUCT_XIRLINK_PCCAM 0x8080 /* IBM PC Camera */ Index: sys/dev/usb/usbdevs_data.h =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/usbdevs_data.h,v retrieving revision 1.32.2.45 diff -u -r1.32.2.45 usbdevs_data.h --- sys/dev/usb/usbdevs_data.h 2 Sep 2003 14:35:57 -0000 1.32.2.45 +++ sys/dev/usb/usbdevs_data.h 4 Oct 2003 22:28:33 -0000 @@ -1,10 +1,10 @@ -/* $FreeBSD: src/sys/dev/usb/usbdevs_data.h,v 1.32.2.45 2003/09/02 14:35:57 joe Exp $ */ +/* $FreeBSD: src/sys/dev/usb/usbdevs_data.h,v 1.147 2003/09/24 02:02:41 jb Exp $ */ /* * THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. * * generated from: - * FreeBSD: src/sys/dev/usb/usbdevs,v 1.11.2.48 2003/09/02 14:35:17 joe Exp + * FreeBSD: src/sys/dev/usb/usbdevs,v 1.138 2003/09/20 20:01:08 se Exp */ /* @@ -44,7 +44,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -struct usb_knowndev usb_knowndevs[] = { +const struct usb_knowndev usb_knowndevs[] = { { USB_VENDOR_3COM, USB_PRODUCT_3COM_HOMECONN, 0, @@ -472,6 +472,12 @@ "F5U120-PC Hub", }, { + USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U208, + 0, + "Belkin Components", + "F5U208 VideoBus II", + }, + { USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USB100, 0, "Billionton Systems", @@ -658,6 +664,12 @@ "FM Radio", }, { + USB_VENDOR_CYPRESS, USB_PRODUCT_CYPRESS_SLIM_HUB, + 0, + "Cypress Semiconductor", + "Slim Hub", + }, + { USB_VENDOR_DAISY, USB_PRODUCT_DAISY_DMC, 0, "Daisy Technology", @@ -1096,6 +1108,12 @@ "WinTV USB FM", }, { + USB_VENDOR_HAWKING, USB_PRODUCT_HAWKING_UF100, + 0, + "Hawking Technologies", + "10/100 USB Ethernet", + }, + { USB_VENDOR_HITACHI, USB_PRODUCT_HITACHI_DVDCAM_USB, 0, "Hitachi, Ltd.", @@ -1246,6 +1264,12 @@ "Scanjet 5300C", }, { + USB_VENDOR_HP, USB_PRODUCT_HP_4400C, + 0, + "Hewlett Packard", + "Scanjet 4400C", + }, + { USB_VENDOR_HP, USB_PRODUCT_HP_970CSE, 0, "Hewlett Packard", @@ -1378,6 +1402,12 @@ "Zip 250", }, { + USB_VENDOR_JVC, USB_PRODUCT_JVC_GR_DX95, + 0, + "JVC", + "GR-DX95", + }, + { USB_VENDOR_JRC, USB_PRODUCT_JRC_AH_J3001V_J3002V, 0, "Japan Radio Company", @@ -1864,6 +1894,12 @@ "Internet Keyboard Pro", }, { + USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_MN110, + 0, + "Microsoft", + "10/100 USB NIC", + }, + { USB_VENDOR_MICROTECH, USB_PRODUCT_MICROTECH_SCSIDB25, 0, "Microtech", @@ -2464,6 +2500,12 @@ "USB serial adapter REX-USB60", }, { + USB_VENDOR_SAMSUNG, USB_PRODUCT_SAMSUNG_ML6060, + 0, + "Samsung Electronics", + "ML-6060 laser printer", + }, + { USB_VENDOR_SANDISK, USB_PRODUCT_SANDISK_SDDR05A, 0, "SanDisk Corp", @@ -2860,6 +2902,12 @@ "Fusion Digital Gamepad", }, { + USB_VENDOR_TOSHIBA, USB_PRODUCT_TOSHIBA_POCKETPC_E740, + 0, + "Toshiba Corporation", + "PocketPC e740", + }, + { USB_VENDOR_TREK, USB_PRODUCT_TREK_THUMBDRIVE, 0, "Trek Technology", @@ -2920,6 +2968,12 @@ "Panache Surf USB ISDN Adapter", }, { + USB_VENDOR_VIDZMEDIA, USB_PRODUCT_VIDZMEDIA_MONSTERTV, + 0, + "VidzMedia Pte Ltd", + "MonsterTV P2H", + }, + { USB_VENDOR_VISION, USB_PRODUCT_VISION_VC6452V002, 0, "VLSI Vision", @@ -3502,12 +3556,24 @@ NULL, }, { + USB_VENDOR_SAMSUNG, 0, + USB_KNOWNDEV_NOPROD, + "Samsung Electronics", + NULL, + }, + { USB_VENDOR_ANNABOOKS, 0, USB_KNOWNDEV_NOPROD, "Annabooks", NULL, }, { + USB_VENDOR_JVC, 0, + USB_KNOWNDEV_NOPROD, + "JVC", + NULL, + }, + { USB_VENDOR_CHICONY, 0, USB_KNOWNDEV_NOPROD, "Chicony Electronics", @@ -4474,6 +4540,12 @@ NULL, }, { + USB_VENDOR_TOSHIBA, 0, + USB_KNOWNDEV_NOPROD, + "Toshiba Corporation", + NULL, + }, + { USB_VENDOR_YANO, 0, USB_KNOWNDEV_NOPROD, "Yano", @@ -4672,6 +4744,12 @@ NULL, }, { + USB_VENDOR_HAWKING, 0, + USB_KNOWNDEV_NOPROD, + "Hawking Technologies", + NULL, + }, + { USB_VENDOR_MOTOROLA, 0, USB_KNOWNDEV_NOPROD, "Motorola", @@ -4759,6 +4837,12 @@ USB_VENDOR_DLINK, 0, USB_KNOWNDEV_NOPROD, "D-Link", + NULL, + }, + { + USB_VENDOR_VIDZMEDIA, 0, + USB_KNOWNDEV_NOPROD, + "VidzMedia Pte Ltd", NULL, }, { Index: sys/dev/usb/usbdi.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/usbdi.c,v retrieving revision 1.34.2.7 diff -u -r1.34.2.7 usbdi.c --- sys/dev/usb/usbdi.c 6 Nov 2002 14:03:37 -0000 1.34.2.7 +++ sys/dev/usb/usbdi.c 4 Oct 2003 18:54:41 -0000 @@ -1,5 +1,12 @@ -/* $NetBSD: usbdi.c,v 1.60 2000/01/19 00:23:58 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/usbdi.c,v 1.34.2.7 2002/11/06 14:03:37 joe Exp $ */ +/* $NetBSD: usbdi.c,v 1.100 2002/05/19 06:24:33 augustss Exp $ */ + +/* Also already have from NetBSD: + * $NetBSD: usbdi.c,v 1.102 2002/07/11 21:14:35 augustss Exp $ + * $NetBSD: usbdi.c,v 1.103 2002/09/27 15:37:38 provos Exp $ + */ + +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/usbdi.c,v 1.82 2003/08/24 17:55:55 obrien Exp $"); /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -77,11 +84,12 @@ #endif Static usbd_status usbd_ar_pipe(usbd_pipe_handle pipe); -Static void usbd_do_request_async_cb - (usbd_xfer_handle, usbd_private_handle, usbd_status); +Static void usbd_do_request_async_cb + (usbd_xfer_handle, usbd_private_handle, usbd_status); Static void usbd_start_next(usbd_pipe_handle pipe); Static usbd_status usbd_open_pipe_ival - (usbd_interface_handle, u_int8_t, u_int8_t, usbd_pipe_handle *, int); + (usbd_interface_handle, u_int8_t, u_int8_t, usbd_pipe_handle *, int); +Static int usbd_xfer_isread(usbd_xfer_handle xfer); Static int usbd_nbuses = 0; @@ -97,10 +105,8 @@ --usbd_nbuses; } -Static __inline int usbd_xfer_isread(usbd_xfer_handle xfer); -Static __inline int -usbd_xfer_isread(xfer) - usbd_xfer_handle xfer; +static __inline int +usbd_xfer_isread(usbd_xfer_handle xfer) { if (xfer->rqflags & URQ_REQUEST) return (xfer->request.bmRequestType & UT_READ); @@ -111,7 +117,40 @@ #ifdef USB_DEBUG void -usbd_dump_queue(usbd_pipe_handle); +usbd_dump_iface(struct usbd_interface *iface) +{ + printf("usbd_dump_iface: iface=%p\n", iface); + if (iface == NULL) + return; + printf(" device=%p idesc=%p index=%d altindex=%d priv=%p\n", + iface->device, iface->idesc, iface->index, iface->altindex, + iface->priv); +} + +void +usbd_dump_device(struct usbd_device *dev) +{ + printf("usbd_dump_device: dev=%p\n", dev); + if (dev == NULL) + return; + printf(" bus=%p default_pipe=%p\n", dev->bus, dev->default_pipe); + printf(" address=%d config=%d depth=%d speed=%d self_powered=%d " + "power=%d langid=%d\n", + dev->address, dev->config, dev->depth, dev->speed, + dev->self_powered, dev->power, dev->langid); +} + +void +usbd_dump_endpoint(struct usbd_endpoint *endp) +{ + printf("usbd_dump_endpoint: endp=%p\n", endp); + if (endp == NULL) + return; + printf(" edesc=%p refcnt=%d\n", endp->edesc, endp->refcnt); + if (endp->edesc) + printf(" bEndpointAddress=0x%02x\n", + endp->edesc->bEndpointAddress); +} void usbd_dump_queue(usbd_pipe_handle pipe) @@ -119,26 +158,39 @@ usbd_xfer_handle xfer; printf("usbd_dump_queue: pipe=%p\n", pipe); - for (xfer = SIMPLEQ_FIRST(&pipe->queue); - xfer; - xfer = SIMPLEQ_NEXT(xfer, next)) { + SIMPLEQ_FOREACH(xfer, &pipe->queue, next) { printf(" xfer=%p\n", xfer); } } + +void +usbd_dump_pipe(usbd_pipe_handle pipe) +{ + printf("usbd_dump_pipe: pipe=%p\n", pipe); + if (pipe == NULL) + return; + usbd_dump_iface(pipe->iface); + usbd_dump_device(pipe->device); + usbd_dump_endpoint(pipe->endpoint); + printf(" (usbd_dump_pipe:)\n refcnt=%d running=%d aborting=%d\n", + pipe->refcnt, pipe->running, pipe->aborting); + printf(" intrxfer=%p, repeat=%d, interval=%d\n", + pipe->intrxfer, pipe->repeat, pipe->interval); +} #endif -usbd_status +usbd_status usbd_open_pipe(usbd_interface_handle iface, u_int8_t address, u_int8_t flags, usbd_pipe_handle *pipe) -{ - return (usbd_open_pipe_ival(iface, address, flags, pipe, +{ + return (usbd_open_pipe_ival(iface, address, flags, pipe, USBD_DEFAULT_INTERVAL)); } -usbd_status +usbd_status usbd_open_pipe_ival(usbd_interface_handle iface, u_int8_t address, u_int8_t flags, usbd_pipe_handle *pipe, int ival) -{ +{ usbd_pipe_handle p; struct usbd_endpoint *ep; usbd_status err; @@ -166,7 +218,7 @@ return (USBD_NORMAL_COMPLETION); } -usbd_status +usbd_status usbd_open_pipe_intr(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 len, @@ -179,7 +231,7 @@ DPRINTFN(3,("usbd_open_pipe_intr: address=0x%x flags=0x%x len=%d\n", address, flags, len)); - err = usbd_open_pipe_ival(iface, address, USBD_EXCLUSIVE_USE, + err = usbd_open_pipe_ival(iface, address, USBD_EXCLUSIVE_USE, &ipipe, ival); if (err) return (err); @@ -219,7 +271,7 @@ if (--pipe->refcnt != 0) return (USBD_NORMAL_COMPLETION); - if (SIMPLEQ_FIRST(&pipe->queue) != 0) + if (! SIMPLEQ_EMPTY(&pipe->queue)) return (USBD_PENDING_REQUESTS); LIST_REMOVE(pipe, next); pipe->endpoint->refcnt--; @@ -247,6 +299,9 @@ #endif xfer->done = 0; + if (pipe->aborting) + return (USBD_CANCELLED); + size = xfer->length; /* If there is no buffer, allocate one. */ if (!(xfer->rqflags & URQ_DEV_DMABUF) && size != 0) { @@ -263,7 +318,7 @@ } /* Copy data if going out. */ - if (!(xfer->flags & USBD_NO_COPY) && size != 0 && + if (!(xfer->flags & USBD_NO_COPY) && size != 0 && !usbd_xfer_isread(xfer)) memcpy(KERNADDR(dmap, 0), xfer->buffer, size); @@ -288,23 +343,8 @@ s = splusb(); if (!xfer->done) { if (pipe->device->bus->use_polling) - panic("usbd_transfer: not done\n"); - /* XXX Temporary hack XXX */ - if (xfer->flags & USBD_NO_TSLEEP) { - int i; - usbd_bus_handle bus = pipe->device->bus; - int to = xfer->timeout * 1000; - for (i = 0; i < to; i += 10) { - delay(10); - bus->methods->do_poll(bus); - if (xfer->done) - break; - } - if (!xfer->done) - pipe->methods->abort(xfer); - } else - /* XXX End hack XXX */ - tsleep(xfer, PRIBIO, "usbsyn", 0); + panic("usbd_transfer: not done"); + tsleep(xfer, PRIBIO, "usbsyn", 0); } splx(s); return (xfer->status); @@ -324,9 +364,13 @@ struct usbd_bus *bus = xfer->device->bus; usbd_status err; +#ifdef DIAGNOSTIC + if (xfer->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF)) + printf("usbd_alloc_buffer: xfer already has a buffer\n"); +#endif err = bus->methods->allocm(bus, &xfer->dmabuf, size); if (err) - return (0); + return (NULL); xfer->rqflags |= URQ_DEV_DMABUF; return (KERNADDR(&xfer->dmabuf, 0)); } @@ -352,7 +396,7 @@ return (KERNADDR(&xfer->dmabuf, 0)); } -usbd_xfer_handle +usbd_xfer_handle usbd_alloc_xfer(usbd_device_handle dev) { usbd_xfer_handle xfer; @@ -361,16 +405,23 @@ if (xfer == NULL) return (NULL); xfer->device = dev; + usb_callout_init(xfer->timeout_handle); DPRINTFN(5,("usbd_alloc_xfer() = %p\n", xfer)); return (xfer); } -usbd_status +usbd_status usbd_free_xfer(usbd_xfer_handle xfer) { DPRINTFN(5,("usbd_free_xfer: %p\n", xfer)); if (xfer->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF)) usbd_free_buffer(xfer); +#if defined(__NetBSD__) && defined(DIAGNOSTIC) + if (callout_pending(&xfer->timeout_handle)) { + callout_stop(&xfer->timeout_handle); + printf("usbd_free_xfer: timout_handle pending"); + } +#endif xfer->device->bus->methods->freex(xfer->device->bus, xfer); return (USBD_NORMAL_COMPLETION); } @@ -486,7 +537,7 @@ return (iface->endpoints[index].edesc); } -usbd_status +usbd_status usbd_abort_pipe(usbd_pipe_handle pipe) { usbd_status err; @@ -503,8 +554,8 @@ splx(s); return (err); } - -usbd_status + +usbd_status usbd_clear_endpoint_stall(usbd_pipe_handle pipe) { usbd_device_handle dev = pipe->device; @@ -513,8 +564,8 @@ DPRINTFN(8, ("usbd_clear_endpoint_stall\n")); - /* - * Clearing en endpoint stall resets the enpoint toggle, so + /* + * Clearing en endpoint stall resets the endpoint toggle, so * do the same to the HC toggle. */ pipe->methods->cleartoggle(pipe); @@ -535,7 +586,7 @@ return (err); } -usbd_status +usbd_status usbd_clear_endpoint_stall_async(usbd_pipe_handle pipe) { usbd_device_handle dev = pipe->device; @@ -559,15 +610,20 @@ pipe->methods->cleartoggle(pipe); } - -usbd_status +usbd_status usbd_endpoint_count(usbd_interface_handle iface, u_int8_t *count) { +#ifdef DIAGNOSTIC + if (iface == NULL || iface->idesc == NULL) { + printf("usbd_endpoint_count: NULL pointer\n"); + return (USBD_INVAL); + } +#endif *count = iface->idesc->bNumEndpoints; return (USBD_NORMAL_COMPLETION); } -usbd_status +usbd_status usbd_interface_count(usbd_device_handle dev, u_int8_t *count) { if (dev->cdesc == NULL) @@ -576,15 +632,14 @@ return (USBD_NORMAL_COMPLETION); } -usbd_status +void usbd_interface2device_handle(usbd_interface_handle iface, usbd_device_handle *dev) { *dev = iface->device; - return (USBD_NORMAL_COMPLETION); } -usbd_status +usbd_status usbd_device2interface_handle(usbd_device_handle dev, u_int8_t ifaceno, usbd_interface_handle *iface) { @@ -608,19 +663,27 @@ { usb_device_request_t req; usbd_status err; + void *endpoints; if (LIST_FIRST(&iface->pipes) != 0) return (USBD_IN_USE); - if (iface->endpoints) - free(iface->endpoints, M_USB); - iface->endpoints = 0; - iface->idesc = 0; - + endpoints = iface->endpoints; err = usbd_fill_iface_data(iface->device, iface->index, altidx); if (err) return (err); + /* new setting works, we can free old endpoints */ + if (endpoints != NULL) + free(endpoints, M_USB); + +#ifdef DIAGNOSTIC + if (iface->idesc == NULL) { + printf("usbd_set_interface: NULL pointer\n"); + return (USBD_INVAL); + } +#endif + req.bmRequestType = UT_WRITE_INTERFACE; req.bRequest = UR_SET_INTERFACE; USETW(req.wValue, iface->idesc->bAlternateSetting); @@ -639,7 +702,7 @@ for (n = 0; p < end; p += d->bLength) { d = (usb_interface_descriptor_t *)p; - if (p + d->bLength <= end && + if (p + d->bLength <= end && d->bDescriptorType == UDESC_INTERFACE && d->bInterfaceNumber == ifaceno) n++; @@ -682,13 +745,15 @@ usbd_dump_queue(pipe); #endif pipe->repeat = 0; + pipe->aborting = 1; while ((xfer = SIMPLEQ_FIRST(&pipe->queue)) != NULL) { - DPRINTFN(2,("usbd_ar_pipe: pipe=%p xfer=%p (methods=%p)\n", + DPRINTFN(2,("usbd_ar_pipe: pipe=%p xfer=%p (methods=%p)\n", pipe, xfer, pipe->methods)); /* Make the HC abort it (and invoke the callback). */ pipe->methods->abort(xfer); /* XXX only for non-0 usbd_clear_endpoint_stall(pipe); */ } + pipe->aborting = 0; return (USBD_NORMAL_COMPLETION); } @@ -705,6 +770,13 @@ DPRINTFN(5, ("usb_transfer_complete: pipe=%p xfer=%p status=%d " "actlen=%d\n", pipe, xfer, xfer->status, xfer->actlen)); +#ifdef DIAGNOSTIC + if (xfer->busy_free != XFER_ONQU) { + printf("usb_transfer_complete: xfer=%p not busy 0x%08x\n", + xfer, xfer->busy_free); + return; + } +#endif #ifdef DIAGNOSTIC if (pipe == NULL) { @@ -738,18 +810,18 @@ } } - if (pipe->methods->done != NULL) - pipe->methods->done(xfer); - if (!repeat) { /* Remove request from queue. */ #ifdef DIAGNOSTIC if (xfer != SIMPLEQ_FIRST(&pipe->queue)) printf("usb_transfer_complete: bad dequeue %p != %p\n", xfer, SIMPLEQ_FIRST(&pipe->queue)); + xfer->busy_free = XFER_BUSY; #endif SIMPLEQ_REMOVE_HEAD(&pipe->queue, xfer, next); } + DPRINTFN(5,("usb_transfer_complete: repeat=%d new head=%p\n", + repeat, SIMPLEQ_FIRST(&pipe->queue))); /* Count completed transfers. */ ++pipe->device->bus->stats.uds_requests @@ -766,14 +838,23 @@ if (xfer->callback) xfer->callback(xfer, xfer->priv, xfer->status); +#ifdef DIAGNOSTIC + if (pipe->methods->done != NULL) + pipe->methods->done(xfer); + else + printf("usb_transfer_complete: pipe->methods->done == NULL\n"); +#else + pipe->methods->done(xfer); +#endif + if ((xfer->flags & USBD_SYNCHRONOUS) && !polling) wakeup(xfer); if (!repeat) { /* XXX should we stop the queue on all errors? */ - if ((xfer->status == USBD_CANCELLED - || xfer->status == USBD_TIMEOUT) - && pipe->iface != NULL) /* not control pipe */ + if ((xfer->status == USBD_CANCELLED || + xfer->status == USBD_TIMEOUT) && + pipe->iface != NULL) /* not control pipe */ pipe->running = 0; else usbd_start_next(pipe); @@ -787,8 +868,16 @@ usbd_status err; int s; - DPRINTFN(5,("usb_insert_transfer: pipe=%p running=%d timeout=%d\n", + DPRINTFN(5,("usb_insert_transfer: pipe=%p running=%d timeout=%d\n", pipe, pipe->running, xfer->timeout)); +#ifdef DIAGNOSTIC + if (xfer->busy_free != XFER_BUSY) { + printf("usb_insert_transfer: xfer=%p not busy 0x%08x\n", + xfer, xfer->busy_free); + return (USBD_INVAL); + } + xfer->busy_free = XFER_ONQU; +#endif s = splusb(); SIMPLEQ_INSERT_TAIL(&pipe->queue, xfer, next); if (pipe->running) @@ -839,19 +928,29 @@ usbd_status usbd_do_request(usbd_device_handle dev, usb_device_request_t *req, void *data) { - return (usbd_do_request_flags(dev, req, data, 0, 0)); + return (usbd_do_request_flags(dev, req, data, 0, 0, + USBD_DEFAULT_TIMEOUT)); +} + +usbd_status +usbd_do_request_flags(usbd_device_handle dev, usb_device_request_t *req, + void *data, u_int16_t flags, int *actlen, u_int32_t timo) +{ + return (usbd_do_request_flags_pipe(dev, dev->default_pipe, req, + data, flags, actlen, timo)); } usbd_status -usbd_do_request_flags(usbd_device_handle dev, - usb_device_request_t *req, void *data, u_int16_t flags, int *actlen) +usbd_do_request_flags_pipe(usbd_device_handle dev, usbd_pipe_handle pipe, + usb_device_request_t *req, void *data, u_int16_t flags, int *actlen, + u_int32_t timeout) { usbd_xfer_handle xfer; usbd_status err; #ifdef DIAGNOSTIC #if defined(__i386__) && defined(__FreeBSD__) - KASSERT(intr_nesting_level == 0, + KASSERT(curthread->td_intr_nesting_level == 0, ("usbd_do_request: in interrupt context")); #endif if (dev->bus->intr_context) { @@ -863,8 +962,9 @@ xfer = usbd_alloc_xfer(dev); if (xfer == NULL) return (USBD_NOMEM); - usbd_setup_default_xfer(xfer, dev, 0, USBD_DEFAULT_TIMEOUT, req, - data, UGETW(req->wLength), flags, 0); + usbd_setup_default_xfer(xfer, dev, 0, timeout, req, + data, UGETW(req->wLength), flags, 0); + xfer->pipe = pipe; err = usbd_sync_transfer(xfer); #if defined(USB_DEBUG) || defined(DIAGNOSTIC) if (xfer->actlen > xfer->length) @@ -872,14 +972,14 @@ "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n", dev->address, xfer->request.bmRequestType, xfer->request.bRequest, UGETW(xfer->request.wValue), - UGETW(xfer->request.wIndex), - UGETW(xfer->request.wLength), + UGETW(xfer->request.wIndex), + UGETW(xfer->request.wLength), xfer->length, xfer->actlen)); #endif if (actlen != NULL) *actlen = xfer->actlen; if (err == USBD_STALLED) { - /* + /* * The control endpoint has stalled. Control endpoints * should not halt, but some may do so anyway so clear * any halt condition. @@ -929,11 +1029,11 @@ if (xfer->actlen > xfer->length) DPRINTF(("usbd_do_request: overrun addr=%d type=0x%02x req=0x" "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n", - xfer->pipe->device->address, + xfer->pipe->device->address, xfer->request.bmRequestType, xfer->request.bRequest, UGETW(xfer->request.wValue), - UGETW(xfer->request.wIndex), - UGETW(xfer->request.wLength), + UGETW(xfer->request.wIndex), + UGETW(xfer->request.wLength), xfer->length, xfer->actlen)); #endif usbd_free_xfer(xfer); @@ -963,9 +1063,15 @@ return (USBD_NORMAL_COMPLETION); } -struct usbd_quirks * +const struct usbd_quirks * usbd_get_quirks(usbd_device_handle dev) { +#ifdef DIAGNOSTIC + if (dev == NULL) { + printf("usbd_get_quirks: dev == NULL\n"); + return 0; + } +#endif return (dev->quirks); } @@ -981,12 +1087,15 @@ } void -usbd_set_polling(usbd_interface_handle iface, int on) +usbd_set_polling(usbd_device_handle dev, int on) { if (on) - iface->device->bus->use_polling++; + dev->bus->use_polling++; else - iface->device->bus->use_polling--; + dev->bus->use_polling--; + /* When polling we need to make sure there is nothing pending to do. */ + if (dev->bus->use_polling) + dev->bus->methods->soft_intr(dev->bus); } @@ -1005,6 +1114,23 @@ } /* + * usbd_ratecheck() can limit the number of error messages that occurs. + * When a device is unplugged it may take up to 0.25s for the hub driver + * to notice it. If the driver continuosly tries to do I/O operations + * this can generate a large number of messages. + */ +int +usbd_ratecheck(struct timeval *last) +{ +#if 0 + static struct timeval errinterval = { 0, 250000 }; /* 0.25 s*/ + + return (ratecheck(last, &errinterval)); +#endif + return (1); +} + +/* * Search for a vendor/product pair in an array. The item size is * given as an argument. */ @@ -1013,7 +1139,9 @@ u_int16_t vendor, u_int16_t product) { while (nentries-- > 0) { - if (tbl->ud_vendor == vendor && tbl->ud_product == product) + u_int16_t tproduct = tbl->ud_product; + if (tbl->ud_vendor == vendor && + (tproduct == product || tproduct == USB_PRODUCT_ANY)) return (tbl); tbl = (const struct usb_devno *)((const char *)tbl + sz); } @@ -1025,7 +1153,7 @@ usbd_driver_load(module_t mod, int what, void *arg) { /* XXX should implement something like a function that removes all generic devices */ - + return (0); } Index: sys/dev/usb/usbdi.h =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/usbdi.h,v retrieving revision 1.21.2.3 diff -u -r1.21.2.3 usbdi.h --- sys/dev/usb/usbdi.h 14 Feb 2002 02:30:47 -0000 1.21.2.3 +++ sys/dev/usb/usbdi.h 4 Oct 2003 18:54:41 -0000 @@ -1,5 +1,5 @@ -/* $NetBSD: usbdi.h,v 1.39 2000/01/19 00:23:59 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/usbdi.h,v 1.21.2.3 2002/02/14 02:30:47 joe Exp $ */ +/* $NetBSD: usbdi.h,v 1.62 2002/07/11 21:14:35 augustss Exp $ */ +/* $FreeBSD: src/sys/dev/usb/usbdi.h,v 1.48 2003/07/14 20:31:03 joe Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -45,33 +45,33 @@ typedef struct usbd_xfer *usbd_xfer_handle; typedef void *usbd_private_handle; -typedef enum { /* keep in sync with usbd_status_msgs */ +typedef enum { /* keep in sync with usbd_status_msgs */ USBD_NORMAL_COMPLETION = 0, /* must be 0 */ - USBD_IN_PROGRESS, + USBD_IN_PROGRESS, /* 1 */ /* errors */ - USBD_PENDING_REQUESTS, - USBD_NOT_STARTED, - USBD_INVAL, - USBD_NOMEM, - USBD_CANCELLED, - USBD_BAD_ADDRESS, - USBD_IN_USE, - USBD_NO_ADDR, - USBD_SET_ADDR_FAILED, - USBD_NO_POWER, - USBD_TOO_DEEP, - USBD_IOERROR, - USBD_NOT_CONFIGURED, - USBD_TIMEOUT, - USBD_SHORT_XFER, - USBD_STALLED, - USBD_INTERRUPTED, + USBD_PENDING_REQUESTS, /* 2 */ + USBD_NOT_STARTED, /* 3 */ + USBD_INVAL, /* 4 */ + USBD_NOMEM, /* 5 */ + USBD_CANCELLED, /* 6 */ + USBD_BAD_ADDRESS, /* 7 */ + USBD_IN_USE, /* 8 */ + USBD_NO_ADDR, /* 9 */ + USBD_SET_ADDR_FAILED, /* 10 */ + USBD_NO_POWER, /* 11 */ + USBD_TOO_DEEP, /* 12 */ + USBD_IOERROR, /* 13 */ + USBD_NOT_CONFIGURED, /* 14 */ + USBD_TIMEOUT, /* 15 */ + USBD_SHORT_XFER, /* 16 */ + USBD_STALLED, /* 17 */ + USBD_INTERRUPTED, /* 18 */ - USBD_ERROR_MAX, /* must be last */ + USBD_ERROR_MAX /* must be last */ } usbd_status; typedef void (*usbd_callback)(usbd_xfer_handle, usbd_private_handle, - usbd_status); + usbd_status); /* Open flags */ #define USBD_EXCLUSIVE_USE 0x01 @@ -85,9 +85,6 @@ /* in usb.h #define USBD_SHORT_XFER_OK 0x04*/ /* allow short reads */ #define USBD_FORCE_SHORT_XFER 0x08 /* force last short packet on write */ -/* XXX Temporary hack XXX */ -#define USBD_NO_TSLEEP 0x80 /* XXX use busy wait */ - #define USBD_NO_TIMEOUT 0 #define USBD_DEFAULT_TIMEOUT 5000 /* ms = 5 s */ @@ -95,96 +92,108 @@ #define USB_CDEV_MAJOR 108 #endif -usbd_status usbd_open_pipe - (usbd_interface_handle iface, u_int8_t address, - u_int8_t flags, usbd_pipe_handle *pipe); -usbd_status usbd_close_pipe (usbd_pipe_handle pipe); -usbd_status usbd_transfer (usbd_xfer_handle req); -usbd_xfer_handle usbd_alloc_xfer (usbd_device_handle); -usbd_status usbd_free_xfer (usbd_xfer_handle xfer); -void usbd_setup_xfer - (usbd_xfer_handle xfer, usbd_pipe_handle pipe, - usbd_private_handle priv, void *buffer, - u_int32_t length, u_int16_t flags, u_int32_t timeout, - usbd_callback); -void usbd_setup_default_xfer - (usbd_xfer_handle xfer, 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); -void usbd_setup_isoc_xfer - (usbd_xfer_handle xfer, usbd_pipe_handle pipe, - usbd_private_handle priv, u_int16_t *frlengths, - u_int32_t nframes, u_int16_t flags, usbd_callback); -void usbd_get_xfer_status - (usbd_xfer_handle xfer, usbd_private_handle *priv, - void **buffer, u_int32_t *count, usbd_status *status); +usbd_status usbd_open_pipe(usbd_interface_handle iface, u_int8_t address, + u_int8_t flags, usbd_pipe_handle *pipe); +usbd_status usbd_close_pipe(usbd_pipe_handle pipe); +usbd_status usbd_transfer(usbd_xfer_handle req); +usbd_xfer_handle usbd_alloc_xfer(usbd_device_handle); +usbd_status usbd_free_xfer(usbd_xfer_handle xfer); +void usbd_setup_xfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe, + usbd_private_handle priv, void *buffer, + u_int32_t length, u_int16_t flags, u_int32_t timeout, + usbd_callback); +void usbd_setup_default_xfer(usbd_xfer_handle xfer, 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); +void usbd_setup_isoc_xfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe, + usbd_private_handle priv, u_int16_t *frlengths, + u_int32_t nframes, u_int16_t flags, usbd_callback); +void usbd_get_xfer_status(usbd_xfer_handle xfer, usbd_private_handle *priv, + void **buffer, u_int32_t *count, usbd_status *status); usb_endpoint_descriptor_t *usbd_interface2endpoint_descriptor - (usbd_interface_handle iface, u_int8_t address); + (usbd_interface_handle iface, u_int8_t address); usbd_status usbd_abort_pipe(usbd_pipe_handle pipe); usbd_status usbd_clear_endpoint_stall(usbd_pipe_handle pipe); usbd_status usbd_clear_endpoint_stall_async(usbd_pipe_handle pipe); void usbd_clear_endpoint_toggle(usbd_pipe_handle pipe); -usbd_status usbd_endpoint_count - (usbd_interface_handle dev, u_int8_t *count); -usbd_status usbd_interface_count - (usbd_device_handle dev, u_int8_t *count); -usbd_status usbd_interface2device_handle - (usbd_interface_handle iface, usbd_device_handle *dev); -usbd_status usbd_device2interface_handle - (usbd_device_handle dev, u_int8_t ifaceno, usbd_interface_handle *iface); +usbd_status usbd_endpoint_count(usbd_interface_handle dev, u_int8_t *count); +usbd_status usbd_interface_count(usbd_device_handle dev, u_int8_t *count); +void usbd_interface2device_handle(usbd_interface_handle iface, + usbd_device_handle *dev); +usbd_status usbd_device2interface_handle(usbd_device_handle dev, + u_int8_t ifaceno, usbd_interface_handle *iface); usbd_device_handle usbd_pipe2device_handle(usbd_pipe_handle); -void *usbd_alloc_buffer(usbd_xfer_handle req, u_int32_t size); -void usbd_free_buffer(usbd_xfer_handle req); +void *usbd_alloc_buffer(usbd_xfer_handle xfer, u_int32_t size); +void usbd_free_buffer(usbd_xfer_handle xfer); void *usbd_get_buffer(usbd_xfer_handle xfer); usbd_status usbd_sync_transfer(usbd_xfer_handle req); -usbd_status usbd_open_pipe_intr - (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, int); -usbd_status usbd_do_request - (usbd_device_handle pipe, usb_device_request_t *req, void *data); -usbd_status usbd_do_request_async - (usbd_device_handle pipe, usb_device_request_t *req, void *data); -usbd_status usbd_do_request_flags - (usbd_device_handle pipe, usb_device_request_t *req, - void *data, u_int16_t flags, int *); +usbd_status usbd_open_pipe_intr(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, int); +usbd_status usbd_do_request(usbd_device_handle pipe, usb_device_request_t *req, + void *data); +usbd_status usbd_do_request_async(usbd_device_handle pipe, + usb_device_request_t *req, void *data); +usbd_status usbd_do_request_flags(usbd_device_handle pipe, + usb_device_request_t *req, + void *data, u_int16_t flags, int*, u_int32_t); +usbd_status usbd_do_request_flags_pipe( + usbd_device_handle dev, usbd_pipe_handle pipe, + usb_device_request_t *req, void *data, u_int16_t flags, int *actlen, + u_int32_t); usb_interface_descriptor_t *usbd_get_interface_descriptor - (usbd_interface_handle iface); -usb_config_descriptor_t *usbd_get_config_descriptor - (usbd_device_handle dev); -usb_device_descriptor_t *usbd_get_device_descriptor - (usbd_device_handle dev); + (usbd_interface_handle iface); +usb_config_descriptor_t *usbd_get_config_descriptor(usbd_device_handle dev); +usb_device_descriptor_t *usbd_get_device_descriptor(usbd_device_handle dev); usbd_status usbd_set_interface(usbd_interface_handle, int); int usbd_get_no_alts(usb_config_descriptor_t *, int); -usbd_status usbd_get_interface - (usbd_interface_handle iface, u_int8_t *aiface); -void usbd_fill_deviceinfo - (usbd_device_handle dev, struct usb_device_info *di); +usbd_status usbd_get_interface(usbd_interface_handle iface, u_int8_t *aiface); +void usbd_fill_deviceinfo(usbd_device_handle, struct usb_device_info *, int); int usbd_get_interface_altindex(usbd_interface_handle iface); -usb_interface_descriptor_t *usbd_find_idesc - (usb_config_descriptor_t *cd, int iindex, int ano); -usb_endpoint_descriptor_t *usbd_find_edesc - (usb_config_descriptor_t *cd, int ifaceidx, int altidx, - int endptidx); +usb_interface_descriptor_t *usbd_find_idesc(usb_config_descriptor_t *cd, + int iindex, int ano); +usb_endpoint_descriptor_t *usbd_find_edesc(usb_config_descriptor_t *cd, + int ifaceidx, int altidx, + int endptidx); void usbd_dopoll(usbd_interface_handle); -void usbd_set_polling(usbd_interface_handle iface, int on); +void usbd_set_polling(usbd_device_handle dev, int on); const char *usbd_errstr(usbd_status err); -void usbd_add_event(int, usbd_device_handle); +void usbd_add_dev_event(int, usbd_device_handle); +void usbd_add_drv_event(int, usbd_device_handle, device_ptr_t); void usbd_devinfo(usbd_device_handle, int, char *); -struct usbd_quirks *usbd_get_quirks(usbd_device_handle); +const struct usbd_quirks *usbd_get_quirks(usbd_device_handle); usb_endpoint_descriptor_t *usbd_get_endpoint_descriptor - (usbd_interface_handle iface, u_int8_t address); + (usbd_interface_handle iface, u_int8_t address); usbd_status usbd_reload_device_desc(usbd_device_handle); +int usbd_ratecheck(struct timeval *last); + +/* + * The usb_task structs form a queue of things to run in the USB event + * thread. Normally this is just device discovery when a connect/disconnect + * has been detected. But it may also be used by drivers that need to + * perform (short) tasks that must have a process context. + */ +struct usb_task { + TAILQ_ENTRY(usb_task) next; + void (*fun)(void *); + void *arg; + char onqueue; +}; + +void usb_add_task(usbd_device_handle dev, struct usb_task *task); +void usb_rem_task(usbd_device_handle dev, struct usb_task *task); +#define usb_init_task(t, f, a) ((t)->fun = (f), (t)->arg = (a), (t)->onqueue = 0) + struct usb_devno { u_int16_t ud_vendor; u_int16_t ud_product; @@ -193,6 +202,7 @@ u_int nentries, u_int sz, u_int16_t vendor, u_int16_t product); #define usb_lookup(tbl, vendor, product) \ usb_match_device((const struct usb_devno *)(tbl), sizeof (tbl) / sizeof ((tbl)[0]), sizeof ((tbl)[0]), (vendor), (product)) +#define USB_PRODUCT_ANY 0xffff /* NetBSD attachment information */ @@ -204,6 +214,7 @@ int vendor; int product; int release; + int matchlvl; usbd_device_handle device; /* current device */ usbd_interface_handle iface; /* current interface */ int usegeneric; @@ -257,13 +268,15 @@ int usbd_driver_load(module_t mod, int what, void *arg); #endif -/* - * XXX - * splusb MUST be the lowest level interrupt so that within USB callbacks - * the level can be raised the appropriate level. - * XXX Should probably use a softsplusb. - */ -/* XXX */ +/* XXX Perhaps USB should have its own levels? */ +#ifdef USB_USE_SOFTINTR +#ifdef __HAVE_GENERIC_SOFT_INTERRUPTS +#define splusb splsoftnet +#else +#define splusb splsoftclock +#endif /* __HAVE_GENERIC_SOFT_INTERRUPTS */ +#else #define splusb splbio +#endif /* USB_USE_SOFTINTR */ +#define splhardusb splbio #define IPL_USB IPL_BIO -/* XXX */ Index: sys/dev/usb/usbdi_util.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/usbdi_util.c,v retrieving revision 1.15.2.5 diff -u -r1.15.2.5 usbdi_util.c --- sys/dev/usb/usbdi_util.c 6 Nov 2002 14:03:37 -0000 1.15.2.5 +++ sys/dev/usb/usbdi_util.c 4 Oct 2003 18:54:41 -0000 @@ -1,5 +1,4 @@ -/* $NetBSD: usbdi_util.c,v 1.24 1999/11/17 23:00:50 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/usbdi_util.c,v 1.15.2.5 2002/11/06 14:03:37 joe Exp $ */ +/* $NetBSD: usbdi_util.c,v 1.36 2001/11/13 06:24:57 lukem Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -38,6 +37,9 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/usbdi_util.c,v 1.31 2003/08/24 17:55:55 obrien Exp $"); + #include #include #include @@ -69,6 +71,9 @@ { usb_device_request_t req; + DPRINTFN(3,("usbd_get_desc: type=%d, index=%d, len=%d\n", + type, index, len)); + req.bmRequestType = UT_READ_DEVICE; req.bRequest = UR_GET_DESCRIPTOR; USETW2(req.wValue, type, index); @@ -78,19 +83,20 @@ } usbd_status -usbd_get_config_desc(usbd_device_handle dev, int conf, +usbd_get_config_desc(usbd_device_handle dev, int confidx, usb_config_descriptor_t *d) { usbd_status err; - DPRINTFN(3,("usbd_get_config_desc: conf=%d\n", conf)); - err = usbd_get_desc(dev, UDESC_CONFIG, conf, - USB_CONFIG_DESCRIPTOR_SIZE, d); + DPRINTFN(3,("usbd_get_config_desc: confidx=%d\n", confidx)); + err = usbd_get_desc(dev, UDESC_CONFIG, confidx, + USB_CONFIG_DESCRIPTOR_SIZE, d); if (err) return (err); if (d->bDescriptorType != UDESC_CONFIG) { - DPRINTFN(-1,("usbd_get_config_desc: conf %d, bad desc %d\n", - conf, d->bDescriptorType)); + DPRINTFN(-1,("usbd_get_config_desc: confidx=%d, bad desc " + "len=%d type=%d\n", + confidx, d->bLength, d->bDescriptorType)); return (USBD_INVAL); } return (USBD_NORMAL_COMPLETION); @@ -107,7 +113,7 @@ usbd_get_device_desc(usbd_device_handle dev, usb_device_descriptor_t *d) { DPRINTFN(3,("usbd_get_device_desc:\n")); - return (usbd_get_desc(dev, UDESC_DEVICE, + return (usbd_get_desc(dev, UDESC_DEVICE, 0, USB_DEVICE_DESCRIPTOR_SIZE, d)); } @@ -122,7 +128,7 @@ USETW(req.wIndex, 0); USETW(req.wLength, sizeof(usb_status_t)); return (usbd_do_request(dev, &req, st)); -} +} usbd_status usbd_get_hub_status(usbd_device_handle dev, usb_hub_status_t *st) @@ -135,7 +141,7 @@ USETW(req.wIndex, 0); USETW(req.wLength, sizeof(usb_hub_status_t)); return (usbd_do_request(dev, &req, st)); -} +} usbd_status usbd_set_address(usbd_device_handle dev, int addr) @@ -222,15 +228,12 @@ usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface); usbd_device_handle dev; usb_device_request_t req; - usbd_status err; DPRINTFN(4, ("usbd_set_protocol: iface=%p, report=%d, endpt=%d\n", iface, report, id->bInterfaceNumber)); if (id == NULL) return (USBD_IOERROR); - err = usbd_interface2device_handle(iface, &dev); - if (err) - return (err); + usbd_interface2device_handle(iface, &dev); req.bmRequestType = UT_WRITE_CLASS_INTERFACE; req.bRequest = UR_SET_PROTOCOL; USETW(req.wValue, report); @@ -246,14 +249,11 @@ usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface); usbd_device_handle dev; usb_device_request_t req; - usbd_status err; DPRINTFN(4, ("usbd_set_report: len=%d\n", len)); if (ifd == NULL) return (USBD_IOERROR); - err = usbd_interface2device_handle(iface, &dev); - if (err) - return (err); + usbd_interface2device_handle(iface, &dev); req.bmRequestType = UT_WRITE_CLASS_INTERFACE; req.bRequest = UR_SET_REPORT; USETW2(req.wValue, type, id); @@ -269,14 +269,11 @@ usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface); usbd_device_handle dev; usb_device_request_t req; - usbd_status err; DPRINTFN(4, ("usbd_set_report_async: len=%d\n", len)); if (ifd == NULL) return (USBD_IOERROR); - err = usbd_interface2device_handle(iface, &dev); - if (err) - return (err); + usbd_interface2device_handle(iface, &dev); req.bmRequestType = UT_WRITE_CLASS_INTERFACE; req.bRequest = UR_SET_REPORT; USETW2(req.wValue, type, id); @@ -292,14 +289,11 @@ usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface); usbd_device_handle dev; usb_device_request_t req; - usbd_status err; DPRINTFN(4, ("usbd_set_report: len=%d\n", len)); - if (id == NULL) + if (id == 0) return (USBD_IOERROR); - err = usbd_interface2device_handle(iface, &dev); - if (err) - return (err); + usbd_interface2device_handle(iface, &dev); req.bmRequestType = UT_READ_CLASS_INTERFACE; req.bRequest = UR_GET_REPORT; USETW2(req.wValue, type, id); @@ -314,14 +308,11 @@ usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface); usbd_device_handle dev; usb_device_request_t req; - usbd_status err; DPRINTFN(4, ("usbd_set_idle: %d %d\n", duration, id)); if (ifd == NULL) return (USBD_IOERROR); - err = usbd_interface2device_handle(iface, &dev); - if (err) - return (err); + usbd_interface2device_handle(iface, &dev); req.bmRequestType = UT_WRITE_CLASS_INTERFACE; req.bRequest = UR_SET_IDLE; USETW2(req.wValue, duration, id); @@ -331,14 +322,14 @@ } usbd_status -usbd_get_report_descriptor(usbd_device_handle dev, int ifcno, int repid, +usbd_get_report_descriptor(usbd_device_handle dev, int ifcno, int size, void *d) { usb_device_request_t req; req.bmRequestType = UT_READ_INTERFACE; req.bRequest = UR_GET_DESCRIPTOR; - USETW2(req.wValue, UDESC_REPORT, repid); + USETW2(req.wValue, UDESC_REPORT, 0); /* report id should be 0 */ USETW(req.wIndex, ifcno); USETW(req.wLength, size); return (usbd_do_request(dev, &req, d)); @@ -352,13 +343,10 @@ usb_config_descriptor_t *cdesc; usb_hid_descriptor_t *hd; char *p, *end; - usbd_status err; if (idesc == NULL) return (0); - err = usbd_interface2device_handle(ifc, &dev); - if (err) - return (0); + usbd_interface2device_handle(ifc, &dev); cdesc = usbd_get_config_descriptor(dev); p = (char *)idesc + idesc->bLength; @@ -375,17 +363,15 @@ } usbd_status -usbd_alloc_report_desc(usbd_interface_handle ifc, void **descp, int *sizep, - struct malloc_type *mem) +usbd_read_report_desc(usbd_interface_handle ifc, void **descp, int *sizep, + usb_malloc_type mem) { usb_interface_descriptor_t *id; usb_hid_descriptor_t *hid; usbd_device_handle dev; usbd_status err; - err = usbd_interface2device_handle(ifc, &dev); - if (err) - return (err); + usbd_interface2device_handle(ifc, &dev); id = usbd_get_interface_descriptor(ifc); if (id == NULL) return (USBD_INVAL); @@ -396,9 +382,8 @@ *descp = malloc(*sizep, mem, M_NOWAIT); if (*descp == NULL) return (USBD_NOMEM); - /* XXX should not use 0 Report ID */ - err = usbd_get_report_descriptor(dev, id->bInterfaceNumber, 0, - *sizep, *descp); + err = usbd_get_report_descriptor(dev, id->bInterfaceNumber, + *sizep, *descp); if (err) { free(*descp, mem); *descp = NULL; @@ -407,7 +392,7 @@ return (USBD_NORMAL_COMPLETION); } -usbd_status +usbd_status usbd_get_config(usbd_device_handle dev, u_int8_t *conf) { usb_device_request_t req; @@ -420,9 +405,8 @@ return (usbd_do_request(dev, &req, conf)); } -Static void -usbd_bulk_transfer_cb(usbd_xfer_handle xfer, - usbd_private_handle priv, usbd_status status); +Static void usbd_bulk_transfer_cb(usbd_xfer_handle xfer, + usbd_private_handle priv, usbd_status status); Static void usbd_bulk_transfer_cb(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) @@ -447,14 +431,14 @@ splx(s); return (err); } - error = tsleep((caddr_t)xfer, PZERO | PCATCH, lbl, 0); + error = tsleep(xfer, PZERO | PCATCH, lbl, 0); splx(s); if (error) { DPRINTF(("usbd_bulk_transfer: tsleep=%d\n", error)); usbd_abort_pipe(pipe); return (USBD_INTERRUPTED); } - usbd_get_xfer_status(xfer, 0, 0, size, &err); + usbd_get_xfer_status(xfer, NULL, NULL, size, &err); DPRINTFN(1,("usbd_bulk_transfer: transferred %d\n", *size)); if (err) { DPRINTF(("usbd_bulk_transfer: error=%d\n", err)); @@ -463,6 +447,48 @@ return (err); } +Static void usbd_intr_transfer_cb(usbd_xfer_handle xfer, + usbd_private_handle priv, usbd_status status); +Static void +usbd_intr_transfer_cb(usbd_xfer_handle xfer, usbd_private_handle priv, + usbd_status status) +{ + wakeup(xfer); +} + +usbd_status +usbd_intr_transfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe, + u_int16_t flags, u_int32_t timeout, void *buf, + u_int32_t *size, char *lbl) +{ + usbd_status err; + int s, error; + + usbd_setup_xfer(xfer, pipe, 0, buf, *size, + flags, timeout, usbd_intr_transfer_cb); + DPRINTFN(1, ("usbd_intr_transfer: start transfer %d bytes\n", *size)); + s = splusb(); /* don't want callback until tsleep() */ + err = usbd_transfer(xfer); + if (err != USBD_IN_PROGRESS) { + splx(s); + return (err); + } + error = tsleep(xfer, PZERO | PCATCH, lbl, 0); + splx(s); + if (error) { + DPRINTF(("usbd_intr_transfer: tsleep=%d\n", error)); + usbd_abort_pipe(pipe); + return (USBD_INTERRUPTED); + } + usbd_get_xfer_status(xfer, NULL, NULL, size, &err); + DPRINTFN(1,("usbd_intr_transfer: transferred %d\n", *size)); + if (err) { + DPRINTF(("usbd_intr_transfer: error=%d\n", err)); + usbd_clear_endpoint_stall(pipe); + } + return (err); +} + void usb_detach_wait(device_ptr_t dv) { @@ -471,11 +497,11 @@ printf("usb_detach_wait: %s didn't detach\n", USBDEVPTRNAME(dv)); DPRINTF(("usb_detach_wait: %s done\n", USBDEVPTRNAME(dv))); -} +} void usb_detach_wakeup(device_ptr_t dv) { DPRINTF(("usb_detach_wakeup: for %s\n", USBDEVPTRNAME(dv))); wakeup(dv); -} +} Index: sys/dev/usb/usbdi_util.h =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/usbdi_util.h,v retrieving revision 1.9.2.2 diff -u -r1.9.2.2 usbdi_util.h --- sys/dev/usb/usbdi_util.h 31 Oct 2000 23:23:30 -0000 1.9.2.2 +++ sys/dev/usb/usbdi_util.h 4 Oct 2003 18:54:41 -0000 @@ -1,5 +1,5 @@ -/* $NetBSD: usbdi_util.h,v 1.17 1999/09/05 19:32:19 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/usbdi_util.h,v 1.9.2.2 2000/10/31 23:23:30 n_hibma Exp $ */ +/* $NetBSD: usbdi_util.h,v 1.23 2001/10/26 17:58:22 augustss Exp $ */ +/* $FreeBSD: src/sys/dev/usb/usbdi_util.h,v 1.16 2003/07/04 01:50:39 jmg Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -38,60 +38,51 @@ * POSSIBILITY OF SUCH DAMAGE. */ -usbd_status usbd_get_desc(usbd_device_handle dev, int type, - int index, int len, void *desc); -usbd_status usbd_get_config_desc(usbd_device_handle, int, - usb_config_descriptor_t *); -usbd_status usbd_get_config_desc_full(usbd_device_handle, int, - void *, int); +usbd_status usbd_get_desc(usbd_device_handle dev, int type, + int index, int len, void *desc); +usbd_status usbd_get_config_desc(usbd_device_handle, int, + usb_config_descriptor_t *); +usbd_status usbd_get_config_desc_full(usbd_device_handle, int, void *, int); usbd_status usbd_get_device_desc(usbd_device_handle dev, - usb_device_descriptor_t *d); + usb_device_descriptor_t *d); usbd_status usbd_set_address(usbd_device_handle dev, int addr); -usbd_status usbd_get_port_status(usbd_device_handle, - int, usb_port_status_t *); +usbd_status usbd_get_port_status(usbd_device_handle, + int, usb_port_status_t *); usbd_status usbd_set_hub_feature(usbd_device_handle dev, int); usbd_status usbd_clear_hub_feature(usbd_device_handle, int); usbd_status usbd_set_port_feature(usbd_device_handle dev, int, int); usbd_status usbd_clear_port_feature(usbd_device_handle, int, int); -usbd_status usbd_get_device_status(usbd_device_handle,usb_status_t*); -usbd_status usbd_get_hub_status(usbd_device_handle dev, - usb_hub_status_t *st); +usbd_status usbd_get_device_status(usbd_device_handle, usb_status_t *); +usbd_status usbd_get_hub_status(usbd_device_handle, usb_hub_status_t *); usbd_status usbd_set_protocol(usbd_interface_handle dev, int report); -usbd_status usbd_get_report_descriptor - (usbd_device_handle dev, int ifcno, int repid, int size, void *d); -struct usb_hid_descriptor *usbd_get_hid_descriptor - (usbd_interface_handle ifc); -usbd_status usbd_set_report - (usbd_interface_handle iface,int type,int id,void *data,int len); -usbd_status usbd_set_report_async - (usbd_interface_handle iface,int type,int id,void *data,int len); -usbd_status usbd_get_report - (usbd_interface_handle iface,int type,int id,void *data,int len); -usbd_status usbd_set_idle - (usbd_interface_handle iface, int duration, int id); -#if defined(__NetBSD__) || defined(__OpenBSD__) -usbd_status usbd_alloc_report_desc - (usbd_interface_handle ifc, void **descp, int *sizep, int mem); -#elif defined(__FreeBSD__) -usbd_status usbd_alloc_report_desc - (usbd_interface_handle ifc, void **descp, int *sizep, struct malloc_type * mem); -#endif -usbd_status usbd_get_config - (usbd_device_handle dev, u_int8_t *conf); -usbd_status usbd_get_string_desc - (usbd_device_handle dev, int sindex, int langid, - usb_string_descriptor_t *sdesc); -void usbd_delay_ms (usbd_device_handle, u_int); - - -usbd_status usbd_set_config_no - (usbd_device_handle dev, int no, int msg); -usbd_status usbd_set_config_index - (usbd_device_handle dev, int index, int msg); - -usbd_status usbd_bulk_transfer - (usbd_xfer_handle xfer, usbd_pipe_handle pipe, u_int16_t flags, - u_int32_t timeout, void *buf, u_int32_t *size, char *lbl); +usbd_status usbd_get_report_descriptor(usbd_device_handle dev, int ifcno, + int size, void *d); +struct usb_hid_descriptor *usbd_get_hid_descriptor(usbd_interface_handle ifc); +usbd_status usbd_set_report(usbd_interface_handle iface, int type, int id, + void *data,int len); +usbd_status usbd_set_report_async(usbd_interface_handle iface, int type, + int id, void *data, int len); +usbd_status usbd_get_report(usbd_interface_handle iface, int type, int id, + void *data, int len); +usbd_status usbd_set_idle(usbd_interface_handle iface, int duration, int id); +usbd_status usbd_read_report_desc(usbd_interface_handle ifc, void **descp, + int *sizep, usb_malloc_type mem); +usbd_status usbd_get_config(usbd_device_handle dev, u_int8_t *conf); +usbd_status usbd_get_string_desc(usbd_device_handle dev, int sindex, + int langid, usb_string_descriptor_t *sdesc); +void usbd_delay_ms(usbd_device_handle, u_int); + + +usbd_status usbd_set_config_no(usbd_device_handle dev, int no, int msg); +usbd_status usbd_set_config_index(usbd_device_handle dev, int index, int msg); + +usbd_status usbd_bulk_transfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe, + u_int16_t flags, u_int32_t timeout, void *buf, + u_int32_t *size, char *lbl); + +usbd_status usbd_intr_transfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe, + u_int16_t flags, u_int32_t timeout, void *buf, + u_int32_t *size, char *lbl); void usb_detach_wait(device_ptr_t); void usb_detach_wakeup(device_ptr_t); Index: sys/dev/usb/usbdivar.h =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/usbdivar.h,v retrieving revision 1.14.2.2 diff -u -r1.14.2.2 usbdivar.h --- sys/dev/usb/usbdivar.h 31 Oct 2000 23:23:30 -0000 1.14.2.2 +++ sys/dev/usb/usbdivar.h 4 Oct 2003 18:54:41 -0000 @@ -1,5 +1,5 @@ -/* $NetBSD: usbdivar.h,v 1.46 2000/01/19 01:16:40 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/usbdivar.h,v 1.14.2.2 2000/10/31 23:23:30 n_hibma Exp $ */ +/* $NetBSD: usbdivar.h,v 1.70 2002/07/11 21:14:36 augustss Exp $ */ +/* $FreeBSD: src/sys/dev/usb/usbdivar.h,v 1.40 2003/07/15 22:42:37 jmg Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -38,6 +38,10 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#if defined(__NetBSD__) +#include +#endif + /* From usb_mem.h */ DECLARE_USB_DMA_T; @@ -51,13 +55,13 @@ struct usbd_bus_methods { usbd_status (*open_pipe)(struct usbd_pipe *pipe); + void (*soft_intr)(void *); void (*do_poll)(struct usbd_bus *); usbd_status (*allocm)(struct usbd_bus *, usb_dma_t *, - u_int32_t bufsize); + u_int32_t bufsize); void (*freem)(struct usbd_bus *, usb_dma_t *); struct usbd_xfer * (*allocx)(struct usbd_bus *); - void (*freex)(struct usbd_bus *, - struct usbd_xfer *); + void (*freex)(struct usbd_bus *, struct usbd_xfer *); }; struct usbd_pipe_methods { @@ -75,7 +79,7 @@ u_int8_t portno; u_int8_t restartcnt; #define USBD_RESTART_MAX 5 - struct usbd_device *device; + struct usbd_device *device; /* Connected device */ struct usbd_device *parent; /* The ports hub */ }; @@ -109,11 +113,18 @@ #define USBREV_PRE_1_0 1 #define USBREV_1_0 2 #define USBREV_1_1 3 -#define USBREV_STR { "unknown", "pre 1.0", "1.0", "1.1" } +#define USBREV_2_0 4 +#define USBREV_STR { "unknown", "pre 1.0", "1.0", "1.1", "2.0" } -#if defined(__NetBSD__) || defined(__OpenBSD__) - bus_dma_tag_t dmatag; /* DMA tag */ +#ifdef USB_USE_SOFTINTR +#ifdef __HAVE_GENERIC_SOFT_INTERRUPTS + void *soft; /* soft interrupt cookie */ +#else + struct callout softi; #endif +#endif + + bus_dma_tag_t dmatag; /* DMA tag */ }; struct usbd_device { @@ -122,19 +133,21 @@ u_int8_t address; /* device addess */ u_int8_t config; /* current configuration # */ u_int8_t depth; /* distance from root hub */ - u_int8_t lowspeed; /* lowspeed flag */ + u_int8_t speed; /* low/full/high speed */ u_int8_t self_powered; /* flag for self powered */ u_int16_t power; /* mA the device uses */ int16_t langid; /* language for strings */ #define USBD_NOLANG (-1) usb_event_cookie_t cookie; /* unique connection id */ struct usbd_port *powersrc; /* upstream hub port, or 0 */ + struct usbd_device *myhub; /* upstream hub */ + struct usbd_device *myhighhub; /* closest high speed hub */ struct usbd_endpoint def_ep; /* for pipe 0 */ usb_endpoint_descriptor_t def_ep_desc; /* for pipe 0 */ struct usbd_interface *ifaces; /* array of all interfaces */ usb_device_descriptor_t ddesc; /* device descriptor */ usb_config_descriptor_t *cdesc; /* full config descr */ - struct usbd_quirks *quirks; /* device quirks, always set */ + const struct usbd_quirks *quirks; /* device quirks, always set */ struct usbd_hub *hub; /* only if this is a hub */ device_ptr_t *subdevs; /* sub-devices, 0 terminated */ }; @@ -155,6 +168,7 @@ struct usbd_endpoint *endpoint; int refcnt; char running; + char aborting; SIMPLEQ_HEAD(, usbd_xfer) queue; LIST_ENTRY(usbd_pipe) next; @@ -177,6 +191,12 @@ usbd_status status; usbd_callback callback; __volatile char done; +#ifdef DIAGNOSTIC + u_int32_t busy_free; +#define XFER_FREE 0x46524545 +#define XFER_BUSY 0x42555359 +#define XFER_ONQU 0x4f4e5155 +#endif /* For control pipe */ usb_device_request_t request; @@ -197,35 +217,37 @@ SIMPLEQ_ENTRY(usbd_xfer) next; void *hcpriv; /* private use by the HC driver */ - int hcprivint; -#if defined(__FreeBSD__) - struct callout_handle timo_handle; -#endif + usb_callout_t timeout_handle; }; void usbd_init(void); void usbd_finish(void); +#ifdef USB_DEBUG +void usbd_dump_iface(struct usbd_interface *iface); +void usbd_dump_device(struct usbd_device *dev); +void usbd_dump_endpoint(struct usbd_endpoint *endp); +void usbd_dump_queue(usbd_pipe_handle pipe); +void usbd_dump_pipe(usbd_pipe_handle pipe); +#endif + /* Routines from usb_subr.c */ int usbctlprint(void *, const char *); void usb_delay_ms(usbd_bus_handle, u_int); -void usbd_devinfo_vp(usbd_device_handle, char *, char *); usbd_status usbd_reset_port(usbd_device_handle dev, - int port, usb_port_status_t *ps); + int port, usb_port_status_t *ps); usbd_status usbd_setup_pipe(usbd_device_handle dev, - usbd_interface_handle iface, - struct usbd_endpoint *, int, - usbd_pipe_handle *pipe); -usbd_status usbd_new_device(device_ptr_t parent, - usbd_bus_handle bus, int depth, - int lowspeed, int port, - struct usbd_port *); -void usbd_remove_device(usbd_device_handle, - struct usbd_port *); + usbd_interface_handle iface, + struct usbd_endpoint *, int, + usbd_pipe_handle *pipe); +usbd_status usbd_new_device(device_ptr_t parent, + usbd_bus_handle bus, int depth, + int lowspeed, int port, + struct usbd_port *); +void usbd_remove_device(usbd_device_handle, struct usbd_port *); int usbd_printBCD(char *cp, int bcd); -usbd_status usbd_fill_iface_data(usbd_device_handle dev, - int i, int a); +usbd_status usbd_fill_iface_data(usbd_device_handle dev, int i, int a); void usb_free_device(usbd_device_handle); usbd_status usb_insert_transfer(usbd_xfer_handle xfer); @@ -233,10 +255,13 @@ void usb_disconnect_port(struct usbd_port *up, device_ptr_t); /* Routines from usb.c */ -int usb_bus_count(void); -void usb_needs_explore(usbd_bus_handle); +void usb_needs_explore(usbd_device_handle); +void usb_schedsoftintr(struct usbd_bus *); -#ifdef DIAGNOSTIC +/* + * XXX This check is extremely bogus. Bad Bad Bad. + */ +#if defined(DIAGNOSTIC) && 0 #define SPLUSBCHECK \ do { int _s = splusb(), _su = splusb(); \ if (!cold && _s != _su) printf("SPLUSBCHECK failed 0x%x!=0x%x, %s:%d\n", \ Index: sys/dev/usb/usbhid.h =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/usbhid.h,v retrieving revision 1.7.2.2 diff -u -r1.7.2.2 usbhid.h --- sys/dev/usb/usbhid.h 31 Oct 2000 23:03:00 -0000 1.7.2.2 +++ sys/dev/usb/usbhid.h 4 Oct 2003 18:54:41 -0000 @@ -1,5 +1,5 @@ /* $NetBSD: usbhid.h,v 1.9 2000/09/03 19:09:14 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/usbhid.h,v 1.7.2.2 2000/10/31 23:03:00 n_hibma Exp $ */ +/* $FreeBSD: src/sys/dev/usb/usbhid.h,v 1.13 2002/01/02 20:16:53 joe Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -53,10 +53,6 @@ #define UR_SET_IDLE 0x0a #define UR_GET_PROTOCOL 0x03 #define UR_SET_PROTOCOL 0x0b - -#if defined(__FreeBSD__) -#define UPACKED __attribute__ ((packed)) -#endif typedef struct usb_hid_descriptor { uByte bLength; Index: sys/dev/usb/uscanner.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/uscanner.c,v retrieving revision 1.2.2.15 diff -u -r1.2.2.15 uscanner.c --- sys/dev/usb/uscanner.c 1 Jul 2003 12:22:36 -0000 1.2.2.15 +++ sys/dev/usb/uscanner.c 4 Oct 2003 21:27:30 -0000 @@ -1,5 +1,11 @@ -/* $NetBSD: uscanner.c,v 1.26 2001/12/31 12:15:22 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/uscanner.c,v 1.2.2.15 2003/07/01 12:22:36 joe Exp $ */ +/* $NetBSD: uscanner.c,v 1.30 2002/07/11 21:14:36 augustss Exp$ */ + +/* Also already merged from NetBSD: + * $NetBSD: uscanner.c,v 1.33 2002/09/23 05:51:24 simonb Exp $ + */ + +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/uscanner.c,v 1.46 2003/10/01 13:53:51 ticso Exp $"); /* * Copyright (c) 2000 The NetBSD Foundation, Inc. @@ -55,7 +61,11 @@ #endif #include #include +#if __FreeBSD_version >= 500014 +#include +#else #include +#endif #include #include #include @@ -188,6 +198,7 @@ {{ USB_VENDOR_UMAX, USB_PRODUCT_UMAX_ASTRA1220U }, 0 }, {{ USB_VENDOR_UMAX, USB_PRODUCT_UMAX_ASTRA1236U }, 0 }, {{ USB_VENDOR_UMAX, USB_PRODUCT_UMAX_ASTRA2000U }, 0 }, + {{ USB_VENDOR_UMAX, USB_PRODUCT_UMAX_ASTRA2100U }, 0 }, {{ USB_VENDOR_UMAX, USB_PRODUCT_UMAX_ASTRA2200U }, 0 }, {{ USB_VENDOR_UMAX, USB_PRODUCT_UMAX_ASTRA3400 }, 0 }, @@ -243,26 +254,21 @@ d_close_t uscannerclose; d_read_t uscannerread; d_write_t uscannerwrite; -d_ioctl_t uscannerioctl; d_poll_t uscannerpoll; #define USCANNER_CDEV_MAJOR 156 Static struct cdevsw uscanner_cdevsw = { - /* open */ uscanneropen, - /* close */ uscannerclose, - /* read */ uscannerread, - /* write */ uscannerwrite, - /* ioctl */ uscannerioctl, - /* poll */ uscannerpoll, - /* mmap */ nommap, - /* strategy */ nostrategy, - /* name */ "uscanner", - /* maj */ USCANNER_CDEV_MAJOR, - /* dump */ nodump, - /* psize */ nopsize, - /* flags */ 0, - /* bmaj */ -1 + .d_open = uscanneropen, + .d_close = uscannerclose, + .d_read = uscannerread, + .d_write = uscannerwrite, + .d_poll = uscannerpoll, + .d_name = "uscanner", + .d_maj = USCANNER_CDEV_MAJOR, +#if __FreeBSD_version < 500014 + .d_bmaj -1 +#endif }; #endif @@ -356,6 +362,9 @@ UID_ROOT, GID_OPERATOR, 0644, "%s", USBDEVNAME(sc->sc_dev)); #endif + usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, + USBDEV(sc->sc_dev)); + USB_ATTACH_SUCCESS_RETURN; } @@ -368,7 +377,7 @@ USB_GET_SC_OPEN(uscanner, unit, sc); - DPRINTFN(5, ("uscanneropen: flag=%d, mode=%d, unit=%d\n", + DPRINTFN(5, ("uscanneropen: flag=%d, mode=%d, unit=%d\n", flag, mode, unit)); if (sc->sc_dying) @@ -594,7 +603,6 @@ switch (act) { case DVACT_ACTIVATE: return (EOPNOTSUPP); - break; case DVACT_DEACTIVATE: sc->sc_dying = 1; @@ -655,6 +663,9 @@ destroy_dev(dev); #endif + usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, + USBDEV(sc->sc_dev)); + return (0); } @@ -669,21 +680,15 @@ if (sc->sc_dying) return (EIO); - /* + /* * We have no easy way of determining if a read will * yield any data or a write will happen. * Pretend they will. */ - revents |= events & + revents |= events & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM); return (revents); -} - -int -uscannerioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, usb_proc_ptr p) -{ - return (EINVAL); } #if defined(__FreeBSD__) Index: sys/dev/usb/uvisor.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/uvisor.c,v retrieving revision 1.7.2.6 diff -u -r1.7.2.6 uvisor.c --- sys/dev/usb/uvisor.c 2 Sep 2003 14:35:17 -0000 1.7.2.6 +++ sys/dev/usb/uvisor.c 4 Oct 2003 22:19:45 -0000 @@ -1,18 +1,19 @@ /* $NetBSD: uvisor.c,v 1.9 2001/01/23 14:04:14 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/uvisor.c,v 1.7.2.6 2003/09/02 14:35:17 joe Exp $ */ +/* $FreeBSD: src/sys/dev/usb/uvisor.c,v 1.15 2003/08/14 00:15:23 joe Exp $ */ -/* This version of uvisor is heavily based upon the version in NetBSD - * but is missing the following patches: - * - * 1.10 needed? connect a ucom to each of the uvisor ports - * 1.11 needed ucom has an "info" attach message - use it - * 1.12 not needed rcsids - * 1.13 already merged extra arg to usbd_do_request_flags - * 1.14 already merged sony and palm support - * 1.15 already merged sony clie - * 1.16 already merged trailing whites +/* Also already merged from NetBSD: + * $NetBSD: uvisor.c,v 1.12 2001/11/13 06:24:57 lukem Exp $ + * $NetBSD: uvisor.c,v 1.13 2002/02/11 15:11:49 augustss Exp $ + * $NetBSD: uvisor.c,v 1.14 2002/02/27 23:00:03 augustss Exp $ + * $NetBSD: uvisor.c,v 1.15 2002/06/16 15:01:31 augustss Exp $ + * $NetBSD: uvisor.c,v 1.16 2002/07/11 21:14:36 augustss Exp $ + * $NetBSD: uvisor.c,v 1.17 2002/08/13 11:38:15 augustss Exp $ + * $NetBSD: uvisor.c,v 1.18 2003/02/05 00:50:14 augustss Exp $ + * $NetBSD: uvisor.c,v 1.19 2003/02/07 18:12:37 augustss Exp $ + * $NetBSD: uvisor.c,v 1.20 2003/04/11 01:30:10 simonb Exp $ */ + /* * Copyright (c) 2000 The NetBSD Foundation, Inc. * All rights reserved. @@ -228,7 +229,7 @@ USB_MATCH(uvisor) { USB_MATCH_START(uvisor, uaa); - + if (uaa->iface != NULL) return (UMATCH_NONE); @@ -302,7 +303,7 @@ ": %s\n", devname, usbd_errstr(err)); goto bad; } - + addr = ed->bEndpointAddress; dir = UE_GET_DIR(ed->bEndpointAddress); attr = ed->bmAttributes & UE_XFERTYPE; @@ -325,7 +326,7 @@ USBDEVNAME(ucom->sc_dev)); goto bad; } - + ucom->sc_parent = sc; ucom->sc_portno = UCOM_UNK_PORTNO; /* bulkin, bulkout set above */ @@ -342,6 +343,9 @@ goto bad; } + usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, ucom->sc_udev, + USBDEV(ucom->sc_dev)); + DPRINTF(("uvisor: in=0x%x out=0x%x\n", ucom->sc_bulkin_no, ucom->sc_bulkout_no)); ucom_attach(&sc->sc_ucom); @@ -386,6 +390,9 @@ sc->sc_ucom.sc_dying = 1; rv = ucom_detach(&sc->sc_ucom); + usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_ucom.sc_udev, + USBDEV(sc->sc_ucom.sc_dev)); + return (rv); } @@ -406,7 +413,8 @@ USETW(req.wIndex, 0); USETW(req.wLength, UVISOR_CONNECTION_INFO_SIZE); err = usbd_do_request_flags(sc->sc_ucom.sc_udev, &req, &coninfo, - USBD_SHORT_XFER_OK, &actlen); + USBD_SHORT_XFER_OK, &actlen, + USBD_DEFAULT_TIMEOUT); if (err) return (err); @@ -433,7 +441,7 @@ break; default: string = "unknown"; - break; + break; } printf("%s: port %d, is for %s\n", USBDEVNAME(sc->sc_ucom.sc_dev), coninfo.connections[i].port, @@ -494,5 +502,6 @@ USETW(req.wIndex, 0); USETW(req.wLength, UVISOR_CONNECTION_INFO_SIZE); (void)usbd_do_request_flags(sc->sc_ucom.sc_udev, &req, &coninfo, - USBD_SHORT_XFER_OK, &actlen); + USBD_SHORT_XFER_OK, &actlen, + USBD_DEFAULT_TIMEOUT); } Index: sys/dev/usb/uvscom.c =================================================================== RCS file: /home/ncvs/src/sys/dev/usb/uvscom.c,v retrieving revision 1.9.2.7 diff -u -r1.9.2.7 uvscom.c --- sys/dev/usb/uvscom.c 21 Jul 2003 12:19:22 -0000 1.9.2.7 +++ sys/dev/usb/uvscom.c 4 Oct 2003 18:54:41 -0000 @@ -24,9 +24,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/usb/uvscom.c,v 1.9.2.7 2003/07/21 12:19:22 akiyama Exp $ */ +#include +__FBSDID("$FreeBSD: src/sys/dev/usb/uvscom.c,v 1.18 2003/08/24 17:55:55 obrien Exp $"); + /* * uvscom: SUNTAC Slipper U VS-10U driver. * Slipper U is a PC card to USB converter for data communication card @@ -690,7 +692,7 @@ default: return (EIO); } - + if (ISSET(t->c_cflag, CSTOPB)) SET(ls, UVSCOM_STOP_BIT_2); else @@ -740,7 +742,7 @@ struct uvscom_softc *sc = addr; int err; int i; - + if (sc->sc_ucom.sc_dying) return (ENXIO);