summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/usb/FILES21
-rw-r--r--sys/dev/usb/TODO2
-rw-r--r--sys/dev/usb/ehci.c2757
-rw-r--r--sys/dev/usb/ehcireg.h288
-rw-r--r--sys/dev/usb/ehcivar.h138
-rw-r--r--sys/dev/usb/files.usb113
-rw-r--r--sys/dev/usb/hid.c143
-rw-r--r--sys/dev/usb/hid.h21
-rw-r--r--sys/dev/usb/if_upl.c28
-rw-r--r--sys/dev/usb/if_url.c1609
-rw-r--r--sys/dev/usb/if_urlreg.h195
-rw-r--r--sys/dev/usb/ohci.c483
-rw-r--r--sys/dev/usb/ohcivar.h14
-rw-r--r--sys/dev/usb/ucom.c49
-rw-r--r--sys/dev/usb/ucomvar.h15
-rw-r--r--sys/dev/usb/udsbr.c279
-rw-r--r--sys/dev/usb/uftdi.c38
-rw-r--r--sys/dev/usb/uftdireg.h5
-rw-r--r--sys/dev/usb/ugen.c168
-rw-r--r--sys/dev/usb/uhci.c297
-rw-r--r--sys/dev/usb/uhcireg.h5
-rw-r--r--sys/dev/usb/uhcivar.h6
-rw-r--r--sys/dev/usb/uhid.c349
-rw-r--r--sys/dev/usb/uhidev.c513
-rw-r--r--sys/dev/usb/uhidev.h91
-rw-r--r--sys/dev/usb/uhub.c37
-rw-r--r--sys/dev/usb/ukbd.c492
-rw-r--r--sys/dev/usb/ukbdmap.c11
-rw-r--r--sys/dev/usb/ulpt.c44
-rw-r--r--sys/dev/usb/umass.c2576
-rw-r--r--sys/dev/usb/umass_isdata.c589
-rw-r--r--sys/dev/usb/umass_isdata.h40
-rw-r--r--sys/dev/usb/umass_quirks.c333
-rw-r--r--sys/dev/usb/umass_quirks.h62
-rw-r--r--sys/dev/usb/umass_scsi.c488
-rw-r--r--sys/dev/usb/umass_scsi.h31
-rw-r--r--sys/dev/usb/umass_scsipi.c636
-rw-r--r--sys/dev/usb/umass_scsipi.h41
-rw-r--r--sys/dev/usb/umassvar.h271
-rw-r--r--sys/dev/usb/umct.c631
-rw-r--r--sys/dev/usb/umct.h109
-rw-r--r--sys/dev/usb/umidi.c1374
-rw-r--r--sys/dev/usb/umidi_quirks.c215
-rw-r--r--sys/dev/usb/umidi_quirks.h120
-rw-r--r--sys/dev/usb/umidireg.h80
-rw-r--r--sys/dev/usb/umidivar.h138
-rw-r--r--sys/dev/usb/umodem.c8
-rw-r--r--sys/dev/usb/ums.c197
-rw-r--r--sys/dev/usb/uplcom.c33
-rw-r--r--sys/dev/usb/urio.c36
-rw-r--r--sys/dev/usb/usb.c236
-rw-r--r--sys/dev/usb/usb.h117
-rw-r--r--sys/dev/usb/usb_port.h121
-rw-r--r--sys/dev/usb/usb_quirks.c6
-rw-r--r--sys/dev/usb/usb_subr.c80
-rw-r--r--sys/dev/usb/usbdevs.h2
-rw-r--r--sys/dev/usb/usbdevs_data.h2
-rw-r--r--sys/dev/usb/usbdi.c111
-rw-r--r--sys/dev/usb/usbdi.h73
-rw-r--r--sys/dev/usb/usbdi_util.c79
-rw-r--r--sys/dev/usb/usbdi_util.h8
-rw-r--r--sys/dev/usb/usbdivar.h27
-rw-r--r--sys/dev/usb/usbhid.h19
-rw-r--r--sys/dev/usb/uscanner.c334
-rw-r--r--sys/dev/usb/usscanner.c18
-rw-r--r--sys/dev/usb/uvisor.c62
66 files changed, 13599 insertions, 3915 deletions
diff --git a/sys/dev/usb/FILES b/sys/dev/usb/FILES
index ed7b4094b13..166fecb2dcd 100644
--- a/sys/dev/usb/FILES
+++ b/sys/dev/usb/FILES
@@ -5,6 +5,9 @@ Makefile to install .h files
Makefile.usbdevs to run devlist2h.awk
TODO just a list of things to do
devlist2h.awk script to generate usbdevs*.h
+ehci.c Host controller driver for EHCI (just a stub now)
+ehcireg.h Hardware definitions for EHCI (just a stub now)
+ehcivar.h API for ehci.c
ezload.c EZ-USB firmware download subroutines
ezload.h API for ezload.c
files.usb config include file
@@ -31,13 +34,27 @@ ugen.c generic driver that can handle access to any USB device
uhci.c Host controller driver for UHCI
uhcireg.h Hardware definitions for UHCI
uhcivar.h API for uhci.c
-uhid.c USB HID class driver
+uhid.c USB generic HID driver
+uhidev.c USB HID class driver
+uhidev.h and definitions for it
uhub.c USB hub driver
ukbd.c USB keyboard driver
ukbdmap.c wscons key mapping for ukbd
ukbdvar.h API for ukbd.c
ulpt.c USB printer class driver
-umass.c USB mass storage driver (bulk only for now)
+umass.c USB mass storage wire protocol driver
+umass_isdata.c In-System Design ATA over bulk-only driver
+umass_isdata.h and definitions for it
+umass_quirks.c Table of strange umass devices
+umass_quirks.h and definitions for it
+umass_scsipi.c umass command protocol driver
+umass_scsipi.h and definitions for it
+umassvar.h definitions for umass.c
+umidi.c USB MIDI driver
+umidi_quirks.c Strange MIDI devices
+umidi_quirks.h and definitions for it
+umidireg.h Protocol definitions for umidi.c
+umidivar.h definitions for umidi.c
umodem.c USB modem (CDC ACM) driver
ums.c USB mouse driver
urio.c USB Diamond Rio500 driver
diff --git a/sys/dev/usb/TODO b/sys/dev/usb/TODO
index 28088a69fb3..2bc3497628a 100644
--- a/sys/dev/usb/TODO
+++ b/sys/dev/usb/TODO
@@ -85,6 +85,8 @@ Get rid of hcpriv.
Keyspan serial driver
+Clean up umass driver
+
Documentation:
--------------
diff --git a/sys/dev/usb/ehci.c b/sys/dev/usb/ehci.c
new file mode 100644
index 00000000000..ea68e25be57
--- /dev/null
+++ b/sys/dev/usb/ehci.c
@@ -0,0 +1,2757 @@
+/* $OpenBSD: ehci.c,v 1.1 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: ehci.c,v 1.29 2001/12/31 12:16:57 augustss Exp $ */
+
+/*
+ * TODO
+ * hold off explorations by companion controllers until ehci has started.
+ */
+
+/*
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (lennart@augustsson.net).
+ *
+ * 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 Enhanced Host Controller Driver, a.k.a. USB 2.0 controller.
+ *
+ * The EHCI 0.96 spec can be found at
+ * http://developer.intel.com/technology/usb/download/ehci-r096.pdf
+ * and the USB 2.0 spec at
+ * http://www.usb.org/developers/data/usb_20.zip
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/select.h>
+#include <sys/proc.h>
+#include <sys/queue.h>
+
+#include <machine/bus.h>
+#include <machine/endian.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdivar.h>
+#include <dev/usb/usb_mem.h>
+#include <dev/usb/usb_quirks.h>
+
+#include <dev/usb/ehcireg.h>
+#include <dev/usb/ehcivar.h>
+
+#if defined(__OpenBSD__)
+struct cfdriver ehci_cd = {
+ NULL, "ehci", DV_DULL
+};
+#endif
+
+#ifdef EHCI_DEBUG
+#define DPRINTF(x) if (ehcidebug) printf x
+#define DPRINTFN(n,x) if (ehcidebug>(n)) printf x
+int ehcidebug = 0;
+#ifndef __NetBSD__
+#define bitmask_snprintf(q,f,b,l) snprintf((b), (l), "%b", (q), (f))
+#endif
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n,x)
+#endif
+
+struct ehci_pipe {
+ struct usbd_pipe pipe;
+ ehci_soft_qh_t *sqh;
+ union {
+ ehci_soft_qtd_t *qtd;
+ /* ehci_soft_itd_t *itd; */
+ } tail;
+ union {
+ /* Control pipe */
+ struct {
+ usb_dma_t reqdma;
+ u_int length;
+ /*ehci_soft_qtd_t *setup, *data, *stat;*/
+ } ctl;
+ /* Interrupt pipe */
+ /* XXX */
+ /* Bulk pipe */
+ struct {
+ u_int length;
+ } bulk;
+ /* Iso pipe */
+ /* XXX */
+ } u;
+};
+
+Static void ehci_shutdown(void *);
+Static void ehci_power(int, void *);
+
+Static usbd_status ehci_open(usbd_pipe_handle);
+Static void ehci_poll(struct usbd_bus *);
+Static void ehci_softintr(void *);
+Static int ehci_intr1(ehci_softc_t *);
+Static void ehci_waitintr(ehci_softc_t *, usbd_xfer_handle);
+Static void ehci_check_intr(ehci_softc_t *, struct ehci_xfer *);
+Static void ehci_idone(struct ehci_xfer *);
+Static void ehci_timeout(void *);
+Static void ehci_timeout_task(void *);
+
+Static usbd_status ehci_allocm(struct usbd_bus *, usb_dma_t *, u_int32_t);
+Static void ehci_freem(struct usbd_bus *, usb_dma_t *);
+
+Static usbd_xfer_handle ehci_allocx(struct usbd_bus *);
+Static void ehci_freex(struct usbd_bus *, usbd_xfer_handle);
+
+Static usbd_status ehci_root_ctrl_transfer(usbd_xfer_handle);
+Static usbd_status ehci_root_ctrl_start(usbd_xfer_handle);
+Static void ehci_root_ctrl_abort(usbd_xfer_handle);
+Static void ehci_root_ctrl_close(usbd_pipe_handle);
+Static void ehci_root_ctrl_done(usbd_xfer_handle);
+
+Static usbd_status ehci_root_intr_transfer(usbd_xfer_handle);
+Static usbd_status ehci_root_intr_start(usbd_xfer_handle);
+Static void ehci_root_intr_abort(usbd_xfer_handle);
+Static void ehci_root_intr_close(usbd_pipe_handle);
+Static void ehci_root_intr_done(usbd_xfer_handle);
+
+Static usbd_status ehci_device_ctrl_transfer(usbd_xfer_handle);
+Static usbd_status ehci_device_ctrl_start(usbd_xfer_handle);
+Static void ehci_device_ctrl_abort(usbd_xfer_handle);
+Static void ehci_device_ctrl_close(usbd_pipe_handle);
+Static void ehci_device_ctrl_done(usbd_xfer_handle);
+
+Static usbd_status ehci_device_bulk_transfer(usbd_xfer_handle);
+Static usbd_status ehci_device_bulk_start(usbd_xfer_handle);
+Static void ehci_device_bulk_abort(usbd_xfer_handle);
+Static void ehci_device_bulk_close(usbd_pipe_handle);
+Static void ehci_device_bulk_done(usbd_xfer_handle);
+
+Static usbd_status ehci_device_intr_transfer(usbd_xfer_handle);
+Static usbd_status ehci_device_intr_start(usbd_xfer_handle);
+Static void ehci_device_intr_abort(usbd_xfer_handle);
+Static void ehci_device_intr_close(usbd_pipe_handle);
+Static void ehci_device_intr_done(usbd_xfer_handle);
+
+Static usbd_status ehci_device_isoc_transfer(usbd_xfer_handle);
+Static usbd_status ehci_device_isoc_start(usbd_xfer_handle);
+Static void ehci_device_isoc_abort(usbd_xfer_handle);
+Static void ehci_device_isoc_close(usbd_pipe_handle);
+Static void ehci_device_isoc_done(usbd_xfer_handle);
+
+Static void ehci_device_clear_toggle(usbd_pipe_handle pipe);
+Static void ehci_noop(usbd_pipe_handle pipe);
+
+Static int ehci_str(usb_string_descriptor_t *, int, char *);
+Static void ehci_pcd(ehci_softc_t *, usbd_xfer_handle);
+Static void ehci_pcd_able(ehci_softc_t *, int);
+Static void ehci_pcd_enable(void *);
+Static void ehci_disown(ehci_softc_t *, int, int);
+
+Static ehci_soft_qh_t *ehci_alloc_sqh(ehci_softc_t *);
+Static void ehci_free_sqh(ehci_softc_t *, ehci_soft_qh_t *);
+
+Static ehci_soft_qtd_t *ehci_alloc_sqtd(ehci_softc_t *);
+Static void ehci_free_sqtd(ehci_softc_t *, ehci_soft_qtd_t *);
+Static usbd_status ehci_alloc_sqtd_chain(struct ehci_pipe *,
+ ehci_softc_t *, int, int, usbd_xfer_handle,
+ ehci_soft_qtd_t **, ehci_soft_qtd_t **);
+Static void ehci_free_sqtd_chain(ehci_softc_t *, ehci_soft_qtd_t *,
+ ehci_soft_qtd_t *);
+
+Static usbd_status ehci_device_request(usbd_xfer_handle xfer);
+
+Static void ehci_add_qh(ehci_soft_qh_t *, ehci_soft_qh_t *);
+Static void ehci_rem_qh(ehci_softc_t *, ehci_soft_qh_t *,
+ ehci_soft_qh_t *);
+Static void ehci_set_qh_qtd(ehci_soft_qh_t *, ehci_soft_qtd_t *);
+Static void ehci_sync_hc(ehci_softc_t *);
+
+Static void ehci_close_pipe(usbd_pipe_handle, ehci_soft_qh_t *);
+Static void ehci_abort_xfer(usbd_xfer_handle, usbd_status);
+
+#ifdef EHCI_DEBUG
+Static void ehci_dump_regs(ehci_softc_t *);
+Static void ehci_dump(void);
+Static ehci_softc_t *theehci;
+Static void ehci_dump_link(ehci_link_t, int);
+Static void ehci_dump_sqtds(ehci_soft_qtd_t *);
+Static void ehci_dump_sqtd(ehci_soft_qtd_t *);
+Static void ehci_dump_qtd(ehci_qtd_t *);
+Static void ehci_dump_sqh(ehci_soft_qh_t *);
+Static void ehci_dump_exfer(struct ehci_xfer *);
+#endif
+
+#define MS_TO_TICKS(ms) ((ms) * hz / 1000)
+
+#define EHCI_NULL htole32(EHCI_LINK_TERMINATE)
+
+#define EHCI_INTR_ENDPT 1
+
+#define ehci_add_intr_list(sc, ex) \
+ LIST_INSERT_HEAD(&(sc)->sc_intrhead, (ex), inext);
+#define ehci_del_intr_list(ex) \
+ LIST_REMOVE((ex), inext)
+
+Static struct usbd_bus_methods ehci_bus_methods = {
+ ehci_open,
+ ehci_softintr,
+ ehci_poll,
+ ehci_allocm,
+ ehci_freem,
+ ehci_allocx,
+ ehci_freex,
+};
+
+Static struct usbd_pipe_methods ehci_root_ctrl_methods = {
+ ehci_root_ctrl_transfer,
+ ehci_root_ctrl_start,
+ ehci_root_ctrl_abort,
+ ehci_root_ctrl_close,
+ ehci_noop,
+ ehci_root_ctrl_done,
+};
+
+Static struct usbd_pipe_methods ehci_root_intr_methods = {
+ ehci_root_intr_transfer,
+ ehci_root_intr_start,
+ ehci_root_intr_abort,
+ ehci_root_intr_close,
+ ehci_noop,
+ ehci_root_intr_done,
+};
+
+Static struct usbd_pipe_methods ehci_device_ctrl_methods = {
+ ehci_device_ctrl_transfer,
+ ehci_device_ctrl_start,
+ ehci_device_ctrl_abort,
+ ehci_device_ctrl_close,
+ ehci_noop,
+ ehci_device_ctrl_done,
+};
+
+Static struct usbd_pipe_methods ehci_device_intr_methods = {
+ ehci_device_intr_transfer,
+ ehci_device_intr_start,
+ ehci_device_intr_abort,
+ ehci_device_intr_close,
+ ehci_device_clear_toggle,
+ ehci_device_intr_done,
+};
+
+Static struct usbd_pipe_methods ehci_device_bulk_methods = {
+ ehci_device_bulk_transfer,
+ ehci_device_bulk_start,
+ ehci_device_bulk_abort,
+ ehci_device_bulk_close,
+ ehci_device_clear_toggle,
+ ehci_device_bulk_done,
+};
+
+Static struct usbd_pipe_methods ehci_device_isoc_methods = {
+ ehci_device_isoc_transfer,
+ ehci_device_isoc_start,
+ ehci_device_isoc_abort,
+ ehci_device_isoc_close,
+ ehci_noop,
+ ehci_device_isoc_done,
+};
+
+usbd_status
+ehci_init(ehci_softc_t *sc)
+{
+ u_int32_t version, sparams, cparams, hcr;
+ u_int i;
+ usbd_status err;
+ ehci_soft_qh_t *sqh;
+
+ DPRINTF(("ehci_init: start\n"));
+#ifdef EHCI_DEBUG
+ theehci = sc;
+#endif
+
+ sc->sc_offs = EREAD1(sc, EHCI_CAPLENGTH);
+
+ version = EREAD2(sc, EHCI_HCIVERSION);
+ printf("%s: EHCI version %x.%x\n", USBDEVNAME(sc->sc_bus.bdev),
+ version >> 8, version & 0xff);
+
+ sparams = EREAD4(sc, EHCI_HCSPARAMS);
+ DPRINTF(("ehci_init: sparams=0x%x\n", sparams));
+ sc->sc_npcomp = EHCI_HCS_N_PCC(sparams);
+ if (EHCI_HCS_N_CC(sparams) != sc->sc_ncomp) {
+ printf("%s: wrong number of companions (%d != %d)\n",
+ USBDEVNAME(sc->sc_bus.bdev),
+ EHCI_HCS_N_CC(sparams), sc->sc_ncomp);
+ return (USBD_IOERROR);
+ }
+ if (sc->sc_ncomp > 0) {
+ printf("%s: companion controller%s, %d port%s each:",
+ USBDEVNAME(sc->sc_bus.bdev), sc->sc_ncomp!=1 ? "s" : "",
+ EHCI_HCS_N_PCC(sparams),
+ EHCI_HCS_N_PCC(sparams)!=1 ? "s" : "");
+ for (i = 0; i < sc->sc_ncomp; i++)
+ printf(" %s", USBDEVNAME(sc->sc_comps[i]->bdev));
+ printf("\n");
+ }
+ sc->sc_noport = EHCI_HCS_N_PORTS(sparams);
+ cparams = EREAD4(sc, EHCI_HCCPARAMS);
+ DPRINTF(("ehci_init: cparams=0x%x\n", cparams));
+
+ sc->sc_bus.usbrev = USBREV_2_0;
+
+ /* Reset the controller */
+ DPRINTF(("%s: resetting\n", USBDEVNAME(sc->sc_bus.bdev)));
+ EOWRITE4(sc, EHCI_USBCMD, 0); /* Halt controller */
+ usb_delay_ms(&sc->sc_bus, 1);
+ EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET);
+ for (i = 0; i < 100; i++) {
+ delay(10);
+ hcr = EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_HCRESET;
+ if (!hcr)
+ break;
+ }
+ if (hcr) {
+ printf("%s: reset timeout\n", USBDEVNAME(sc->sc_bus.bdev));
+ return (USBD_IOERROR);
+ }
+
+ /* frame list size at default, read back what we got and use that */
+ switch (EHCI_CMD_FLS(EOREAD4(sc, EHCI_USBCMD))) {
+ case 0: sc->sc_flsize = 1024*4; break;
+ case 1: sc->sc_flsize = 512*4; break;
+ case 2: sc->sc_flsize = 256*4; break;
+ case 3: return (USBD_IOERROR);
+ }
+ err = usb_allocmem(&sc->sc_bus, sc->sc_flsize,
+ EHCI_FLALIGN_ALIGN, &sc->sc_fldma);
+ if (err)
+ return (err);
+ DPRINTF(("%s: flsize=%d\n", USBDEVNAME(sc->sc_bus.bdev),sc->sc_flsize));
+
+ /* Set up the bus struct. */
+ sc->sc_bus.methods = &ehci_bus_methods;
+ sc->sc_bus.pipe_size = sizeof(struct ehci_pipe);
+
+ sc->sc_powerhook = powerhook_establish(ehci_power, sc);
+ sc->sc_shutdownhook = shutdownhook_establish(ehci_shutdown, sc);
+
+ sc->sc_eintrs = EHCI_NORMAL_INTRS;
+
+ /* Allocate dummy QH that starts the async list. */
+ sqh = ehci_alloc_sqh(sc);
+ if (sqh == NULL) {
+ err = USBD_NOMEM;
+ goto bad1;
+ }
+ /* Fill the QH */
+ sqh->qh.qh_endp =
+ htole32(EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH) | EHCI_QH_HRECL);
+ sqh->qh.qh_link =
+ htole32(sqh->physaddr | EHCI_LINK_QH);
+ sqh->qh.qh_curqtd = EHCI_NULL;
+ sqh->next = NULL;
+ /* Fill the overlay qTD */
+ sqh->qh.qh_qtd.qtd_next = EHCI_NULL;
+ sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL;
+ sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED);
+ sqh->sqtd = NULL;
+#ifdef EHCI_DEBUG
+ if (ehcidebug) {
+ ehci_dump_sqh(sqh);
+ }
+#endif
+
+ /* Point to async list */
+ sc->sc_async_head = sqh;
+ EOWRITE4(sc, EHCI_ASYNCLISTADDR, sqh->physaddr | EHCI_LINK_QH);
+
+ usb_callout_init(sc->sc_tmo_pcd);
+
+ lockinit(&sc->sc_doorbell_lock, PZERO, "ehcidb", 0, 0);
+
+ /* Enable interrupts */
+ EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);
+
+ /* Turn on controller */
+ EOWRITE4(sc, EHCI_USBCMD,
+ EHCI_CMD_ITC_8 | /* 8 microframes */
+ (EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_FLS_M) |
+ EHCI_CMD_ASE |
+ /* EHCI_CMD_PSE | */
+ EHCI_CMD_RS);
+
+ /* Take over port ownership */
+ EOWRITE4(sc, EHCI_CONFIGFLAG, EHCI_CONF_CF);
+
+ for (i = 0; i < 100; i++) {
+ delay(10);
+ hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH;
+ if (!hcr)
+ break;
+ }
+ if (hcr) {
+ printf("%s: run timeout\n", USBDEVNAME(sc->sc_bus.bdev));
+ return (USBD_IOERROR);
+ }
+
+ return (USBD_NORMAL_COMPLETION);
+
+#if 0
+ bad2:
+ ehci_free_sqh(sc, sc->sc_async_head);
+#endif
+ bad1:
+ usb_freemem(&sc->sc_bus, &sc->sc_fldma);
+ return (err);
+}
+
+int
+ehci_intr(void *v)
+{
+ ehci_softc_t *sc = v;
+
+ 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
+ printf("ehci_intr: ignored interrupt while polling\n");
+#endif
+ return (0);
+ }
+
+ return (ehci_intr1(sc));
+}
+
+Static int
+ehci_intr1(ehci_softc_t *sc)
+{
+ u_int32_t intrs, eintrs;
+
+ DPRINTFN(20,("ehci_intr1: enter\n"));
+
+ /* In case the interrupt occurs before initialization has completed. */
+ if (sc == NULL) {
+#ifdef DIAGNOSTIC
+ printf("ehci_intr: sc == NULL\n");
+#endif
+ return (0);
+ }
+
+ intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS));
+
+ if (!intrs)
+ return (0);
+
+ EOWRITE4(sc, EHCI_USBSTS, intrs); /* Acknowledge */
+ eintrs = intrs & sc->sc_eintrs;
+ DPRINTFN(7, ("ehci_intr: sc=%p intrs=0x%x(0x%x) eintrs=0x%x\n",
+ sc, (u_int)intrs, EOREAD4(sc, EHCI_USBSTS),
+ (u_int)eintrs));
+ if (!eintrs)
+ return (0);
+
+ sc->sc_bus.intr_context++;
+ sc->sc_bus.no_intrs++;
+ if (eintrs & EHCI_STS_IAA) {
+ DPRINTF(("ehci_intr1: door bell\n"));
+ wakeup(&sc->sc_async_head);
+ eintrs &= ~EHCI_STS_IAA;
+ }
+ if (eintrs & (EHCI_STS_INT | EHCI_STS_ERRINT)) {
+ DPRINTF(("ehci_intr1: %s %s\n",
+ eintrs & EHCI_STS_INT ? "INT" : "",
+ eintrs & EHCI_STS_ERRINT ? "ERRINT" : ""));
+ usb_schedsoftintr(&sc->sc_bus);
+ eintrs &= ~(EHCI_STS_INT | EHCI_STS_ERRINT);
+ }
+ if (eintrs & EHCI_STS_HSE) {
+ printf("%s: unrecoverable error, controller halted\n",
+ USBDEVNAME(sc->sc_bus.bdev));
+ /* XXX what else */
+ }
+ if (eintrs & EHCI_STS_PCD) {
+ ehci_pcd(sc, sc->sc_intrxfer);
+ /*
+ * Disable PCD interrupt for now, because it will be
+ * on until the port has been reset.
+ */
+ ehci_pcd_able(sc, 0);
+ /* Do not allow RHSC interrupts > 1 per second */
+ usb_callout(sc->sc_tmo_pcd, hz, ehci_pcd_enable, sc);
+ eintrs &= ~EHCI_STS_PCD;
+ }
+
+ sc->sc_bus.intr_context--;
+
+ if (eintrs != 0) {
+ /* Block unprocessed interrupts. */
+ sc->sc_eintrs &= ~eintrs;
+ EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);
+ printf("%s: blocking intrs 0x%x\n",
+ USBDEVNAME(sc->sc_bus.bdev), eintrs);
+ }
+
+ return (1);
+}
+
+void
+ehci_pcd_able(ehci_softc_t *sc, int on)
+{
+ DPRINTFN(4, ("ehci_pcd_able: on=%d\n", on));
+ if (on)
+ sc->sc_eintrs |= EHCI_STS_PCD;
+ else
+ sc->sc_eintrs &= ~EHCI_STS_PCD;
+ EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);
+}
+
+void
+ehci_pcd_enable(void *v_sc)
+{
+ ehci_softc_t *sc = v_sc;
+
+ ehci_pcd_able(sc, 1);
+}
+
+void
+ehci_pcd(ehci_softc_t *sc, usbd_xfer_handle xfer)
+{
+ usbd_pipe_handle pipe;
+ struct ehci_pipe *epipe;
+ u_char *p;
+ int i, m;
+
+ if (xfer == NULL) {
+ /* Just ignore the change. */
+ return;
+ }
+
+ pipe = xfer->pipe;
+ epipe = (struct ehci_pipe *)pipe;
+
+ p = KERNADDR(&xfer->dmabuf);
+ 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 (EOREAD4(sc, EHCI_PORTSC(i)) & EHCI_PS_CLEAR)
+ p[i/8] |= 1 << (i%8);
+ }
+ DPRINTF(("ehci_pcd: change=0x%02x\n", *p));
+ xfer->actlen = xfer->length;
+ xfer->status = USBD_NORMAL_COMPLETION;
+
+ usb_transfer_complete(xfer);
+}
+
+void
+ehci_softintr(void *v)
+{
+ ehci_softc_t *sc = v;
+ struct ehci_xfer *ex;
+
+ DPRINTFN(10,("%s: ehci_softintr (%d)\n", USBDEVNAME(sc->sc_bus.bdev),
+ sc->sc_bus.intr_context));
+
+ sc->sc_bus.intr_context++;
+
+ /*
+ * The only explanation I can think of for why EHCI is as brain dead
+ * as UHCI interrupt-wise is that Intel was involved in both.
+ * An interrupt just tells us that something is done, we have no
+ * clue what, so we need to scan through all active transfers. :-(
+ */
+ for (ex = LIST_FIRST(&sc->sc_intrhead); ex; ex = LIST_NEXT(ex, inext))
+ ehci_check_intr(sc, ex);
+
+ if (sc->sc_softwake) {
+ sc->sc_softwake = 0;
+ wakeup(&sc->sc_softwake);
+ }
+
+ sc->sc_bus.intr_context--;
+}
+
+/* Check for an interrupt. */
+void
+ehci_check_intr(ehci_softc_t *sc, struct ehci_xfer *ex)
+{
+ ehci_soft_qtd_t *sqtd, *lsqtd;
+ u_int32_t status;
+
+ DPRINTFN(/*15*/2, ("ehci_check_intr: ex=%p\n", ex));
+
+ if (ex->sqtdstart == NULL) {
+ printf("ehci_check_intr: sqtdstart=NULL\n");
+ return;
+ }
+ lsqtd = ex->sqtdend;
+#ifdef DIAGNOSTIC
+ if (lsqtd == NULL) {
+ printf("ehci_check_intr: sqtd==0\n");
+ return;
+ }
+#endif
+ /*
+ * If the last TD is still active we need to check whether there
+ * is a an error somewhere in the middle, or whether there was a
+ * short packet (SPD and not ACTIVE).
+ */
+ if (le32toh(lsqtd->qtd.qtd_status) & EHCI_QTD_ACTIVE) {
+ DPRINTFN(12, ("ehci_check_intr: active ex=%p\n", ex));
+ for (sqtd = ex->sqtdstart; sqtd != lsqtd; sqtd=sqtd->nextqtd) {
+ status = le32toh(sqtd->qtd.qtd_status);
+ /* If there's an active QTD the xfer isn't done. */
+ if (status & EHCI_QTD_ACTIVE)
+ break;
+ /* Any kind of error makes the xfer done. */
+ if (status & EHCI_QTD_HALTED)
+ goto done;
+ /* We want short packets, and it is short: it's done */
+ if (EHCI_QTD_SET_BYTES(status) != 0)
+ goto done;
+ }
+ DPRINTFN(12, ("ehci_check_intr: ex=%p std=%p still active\n",
+ ex, ex->sqtdstart));
+ return;
+ }
+ done:
+ DPRINTFN(12, ("ehci_check_intr: ex=%p done\n", ex));
+ usb_uncallout(ex->xfer.timeout_handle, ehci_timeout, ex);
+ ehci_idone(ex);
+}
+
+void
+ehci_idone(struct ehci_xfer *ex)
+{
+ usbd_xfer_handle xfer = &ex->xfer;
+#ifdef EHCI_DEBUG
+ struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
+#endif
+ ehci_soft_qtd_t *sqtd;
+ u_int32_t status = 0, nstatus;
+ int actlen;
+
+ DPRINTFN(/*12*/2, ("ehci_idone: ex=%p\n", ex));
+#ifdef DIAGNOSTIC
+ {
+ int s = splhigh();
+ if (ex->isdone) {
+ splx(s);
+#ifdef EHCI_DEBUG
+ printf("ehci_idone: ex is done!\n ");
+ ehci_dump_exfer(ex);
+#else
+ printf("ehci_idone: ex=%p is done!\n", ex);
+#endif
+ return;
+ }
+ ex->isdone = 1;
+ splx(s);
+ }
+#endif
+
+ if (xfer->status == USBD_CANCELLED ||
+ xfer->status == USBD_TIMEOUT) {
+ DPRINTF(("ehci_idone: aborted xfer=%p\n", xfer));
+ return;
+ }
+
+#ifdef EHCI_DEBUG
+ DPRINTFN(/*10*/2, ("ehci_idone: xfer=%p, pipe=%p ready\n", xfer, epipe));
+ if (ehcidebug > 10)
+ ehci_dump_sqtds(ex->sqtdstart);
+#endif
+
+ /* The transfer is done, compute actual length and status. */
+ actlen = 0;
+ for (sqtd = ex->sqtdstart; sqtd != NULL; sqtd = sqtd->nextqtd) {
+ nstatus = le32toh(sqtd->qtd.qtd_status);
+ if (nstatus & EHCI_QTD_ACTIVE)
+ break;
+
+ status = nstatus;
+ if (EHCI_QTD_GET_PID(status) != EHCI_QTD_PID_SETUP)
+ actlen += sqtd->len - EHCI_QTD_GET_BYTES(status);
+ }
+
+ /* If there are left over TDs we need to update the toggle. */
+ if (sqtd != NULL) {
+ if (!(xfer->rqflags & URQ_REQUEST))
+ printf("ehci_idone: need toggle update\n");
+#if 0
+ epipe->nexttoggle = EHCI_TD_GET_DT(le32toh(std->td.td_token));
+#endif
+ }
+
+ status &= EHCI_QTD_STATERRS;
+ DPRINTFN(/*10*/2, ("ehci_idone: len=%d, actlen=%d, status=0x%x\n",
+ xfer->length, actlen, status));
+ xfer->actlen = actlen;
+ if (status != 0) {
+#ifdef EHCI_DEBUG
+ char sbuf[128];
+
+ bitmask_snprintf((u_int32_t)status,
+ "\20\3MISSEDMICRO\4XACT\5BABBLE\6BABBLE"
+ "\7HALTED",
+ sbuf, sizeof(sbuf));
+
+ DPRINTFN((status == EHCI_QTD_HALTED)*/*10*/2,
+ ("ehci_idone: error, addr=%d, endpt=0x%02x, "
+ "status 0x%s\n",
+ xfer->pipe->device->address,
+ xfer->pipe->endpoint->edesc->bEndpointAddress,
+ sbuf));
+ if (ehcidebug > 2) {
+ ehci_dump_sqh(epipe->sqh);
+ ehci_dump_sqtds(ex->sqtdstart);
+ }
+#endif
+ if (status == EHCI_QTD_HALTED)
+ xfer->status = USBD_STALLED;
+ else
+ xfer->status = USBD_IOERROR; /* more info XXX */
+ } else {
+ xfer->status = USBD_NORMAL_COMPLETION;
+ }
+
+ usb_transfer_complete(xfer);
+ DPRINTFN(/*12*/2, ("ehci_idone: ex=%p done\n", ex));
+}
+
+/*
+ * Wait here until controller claims to have an interrupt.
+ * Then call ehci_intr and return. Use timeout to avoid waiting
+ * too long.
+ */
+void
+ehci_waitintr(ehci_softc_t *sc, usbd_xfer_handle xfer)
+{
+ int timo = xfer->timeout;
+ int usecs;
+ u_int32_t intrs;
+
+ 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 = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS)) &
+ sc->sc_eintrs;
+ DPRINTFN(15,("ehci_waitintr: 0x%04x\n", intrs));
+#ifdef EHCI_DEBUG
+ if (ehcidebug > 15)
+ ehci_dump_regs(sc);
+#endif
+ if (intrs) {
+ ehci_intr1(sc);
+ if (xfer->status != USBD_IN_PROGRESS)
+ return;
+ }
+ }
+
+ /* Timeout */
+ DPRINTF(("ehci_waitintr: timeout\n"));
+ xfer->status = USBD_TIMEOUT;
+ usb_transfer_complete(xfer);
+ /* XXX should free TD */
+}
+
+void
+ehci_poll(struct usbd_bus *bus)
+{
+ ehci_softc_t *sc = (ehci_softc_t *)bus;
+#ifdef EHCI_DEBUG
+ static int last;
+ int new;
+ new = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS));
+ if (new != last) {
+ DPRINTFN(10,("ehci_poll: intrs=0x%04x\n", new));
+ last = new;
+ }
+#endif
+
+ if (EOREAD4(sc, EHCI_USBSTS) & sc->sc_eintrs)
+ ehci_intr1(sc);
+}
+
+int
+ehci_detach(struct ehci_softc *sc, int flags)
+{
+ int rv = 0;
+
+ if (sc->sc_child != NULL)
+ rv = config_detach(sc->sc_child, flags);
+
+ if (rv != 0)
+ return (rv);
+
+ usb_uncallout(sc->sc_tmo_pcd, ehci_pcd_enable, sc);
+
+ if (sc->sc_powerhook != NULL)
+ powerhook_disestablish(sc->sc_powerhook);
+ if (sc->sc_shutdownhook != NULL)
+ shutdownhook_disestablish(sc->sc_shutdownhook);
+
+ usb_delay_ms(&sc->sc_bus, 300); /* XXX let stray task complete */
+
+ /* XXX free other data structures XXX */
+
+ return (rv);
+}
+
+
+int
+ehci_activate(device_ptr_t self, enum devact act)
+{
+ struct ehci_softc *sc = (struct ehci_softc *)self;
+ int rv = 0;
+
+ switch (act) {
+ case DVACT_ACTIVATE:
+ return (EOPNOTSUPP);
+ break;
+
+ case DVACT_DEACTIVATE:
+ if (sc->sc_child != NULL)
+ rv = config_deactivate(sc->sc_child);
+ sc->sc_dying = 1;
+ break;
+ }
+ return (rv);
+}
+
+/*
+ * Handle suspend/resume.
+ *
+ * We need to switch to polling mode here, because this routine is
+ * called from an intterupt context. This is all right since we
+ * are almost suspended anyway.
+ */
+void
+ehci_power(int why, void *v)
+{
+ ehci_softc_t *sc = v;
+ //u_int32_t ctl;
+ int s;
+
+#ifdef EHCI_DEBUG
+ DPRINTF(("ehci_power: sc=%p, why=%d\n", sc, why));
+ ehci_dump_regs(sc);
+#endif
+
+ s = splhardusb();
+ switch (why) {
+ case PWR_SUSPEND:
+ case PWR_STANDBY:
+ sc->sc_bus.use_polling++;
+#if 0
+OOO
+ ctl = OREAD4(sc, EHCI_CONTROL) & ~EHCI_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, EHCI_INTERRUPT_ENABLE);
+ }
+ ctl |= EHCI_HCFS_SUSPEND;
+ OWRITE4(sc, EHCI_CONTROL, ctl);
+#endif
+ usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT);
+ sc->sc_bus.use_polling--;
+ break;
+ case PWR_RESUME:
+ sc->sc_bus.use_polling++;
+#if 0
+OOO
+ /* Some broken BIOSes do not recover these values */
+ OWRITE4(sc, EHCI_HCCA, DMAADDR(&sc->sc_hccadma));
+ OWRITE4(sc, EHCI_CONTROL_HEAD_ED, sc->sc_ctrl_head->physaddr);
+ OWRITE4(sc, EHCI_BULK_HEAD_ED, sc->sc_bulk_head->physaddr);
+ if (sc->sc_intre)
+ OWRITE4(sc, EHCI_INTERRUPT_ENABLE,
+ sc->sc_intre & (EHCI_ALL_INTRS | EHCI_MIE));
+ if (sc->sc_control)
+ ctl = sc->sc_control;
+ else
+ ctl = OREAD4(sc, EHCI_CONTROL);
+ ctl |= EHCI_HCFS_RESUME;
+ OWRITE4(sc, EHCI_CONTROL, ctl);
+ usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY);
+ ctl = (ctl & ~EHCI_HCFS_MASK) | EHCI_HCFS_OPERATIONAL;
+ OWRITE4(sc, EHCI_CONTROL, ctl);
+ usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY);
+ sc->sc_control = sc->sc_intre = 0;
+#endif
+ sc->sc_bus.use_polling--;
+ break;
+#if defined(__NetBSD__)
+ case PWR_SOFTSUSPEND:
+ case PWR_SOFTSTANDBY:
+ case PWR_SOFTRESUME:
+ break;
+#endif
+ }
+ splx(s);
+}
+
+/*
+ * Shut down the controller when the system is going down.
+ */
+void
+ehci_shutdown(void *v)
+{
+ ehci_softc_t *sc = v;
+
+ DPRINTF(("ehci_shutdown: stopping the HC\n"));
+ EOWRITE4(sc, EHCI_USBCMD, 0); /* Halt controller */
+ EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET);
+}
+
+usbd_status
+ehci_allocm(struct usbd_bus *bus, usb_dma_t *dma, u_int32_t size)
+{
+ struct ehci_softc *sc = (struct ehci_softc *)bus;
+ usbd_status err;
+
+ err = usb_allocmem(&sc->sc_bus, size, 0, dma);
+#ifdef EHCI_DEBUG
+ if (err)
+ printf("ehci_allocm: usb_allocmem()=%d\n", err);
+#endif
+ return (err);
+}
+
+void
+ehci_freem(struct usbd_bus *bus, usb_dma_t *dma)
+{
+ struct ehci_softc *sc = (struct ehci_softc *)bus;
+
+ usb_freemem(&sc->sc_bus, dma);
+}
+
+usbd_xfer_handle
+ehci_allocx(struct usbd_bus *bus)
+{
+ struct ehci_softc *sc = (struct ehci_softc *)bus;
+ usbd_xfer_handle xfer;
+
+ xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers);
+ if (xfer != NULL) {
+ SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, xfer, next);
+#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 ehci_xfer), M_USB, M_NOWAIT);
+ }
+ if (xfer != NULL) {
+ memset(xfer, 0, sizeof (struct ehci_xfer));
+#ifdef DIAGNOSTIC
+ EXFER(xfer)->isdone = 1;
+ xfer->busy_free = XFER_BUSY;
+#endif
+ }
+ return (xfer);
+}
+
+void
+ehci_freex(struct usbd_bus *bus, usbd_xfer_handle xfer)
+{
+ struct ehci_softc *sc = (struct ehci_softc *)bus;
+
+#ifdef DIAGNOSTIC
+ if (xfer->busy_free != XFER_BUSY) {
+ printf("ehci_freex: xfer=%p not busy, 0x%08x\n", xfer,
+ xfer->busy_free);
+ return;
+ }
+ xfer->busy_free = XFER_FREE;
+ if (!EXFER(xfer)->isdone) {
+ printf("ehci_freex: !isdone\n");
+ return;
+ }
+#endif
+ SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next);
+}
+
+Static void
+ehci_device_clear_toggle(usbd_pipe_handle pipe)
+{
+ struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
+
+ DPRINTF(("ehci_device_clear_toggle: epipe=%p status=0x%x\n",
+ epipe, epipe->sqh->qh.qh_qtd.qtd_status));
+#ifdef USB_DEBUG
+ if (ehcidebug)
+ usbd_dump_pipe(pipe);
+#endif
+ epipe->sqh->qh.qh_qtd.qtd_status &= htole32(~EHCI_QTD_TOGGLE);
+}
+
+Static void
+ehci_noop(usbd_pipe_handle pipe)
+{
+}
+
+#ifdef EHCI_DEBUG
+void
+ehci_dump_regs(ehci_softc_t *sc)
+{
+ int i;
+ printf("cmd=0x%08x, sts=0x%08x, ien=0x%08x\n",
+ EOREAD4(sc, EHCI_USBCMD),
+ EOREAD4(sc, EHCI_USBSTS),
+ EOREAD4(sc, EHCI_USBINTR));
+ printf("frindex=0x%08x ctrdsegm=0x%08x periodic=0x%08x async=0x%08x\n",
+ EOREAD4(sc, EHCI_FRINDEX),
+ EOREAD4(sc, EHCI_CTRLDSSEGMENT),
+ EOREAD4(sc, EHCI_PERIODICLISTBASE),
+ EOREAD4(sc, EHCI_ASYNCLISTADDR));
+ for (i = 1; i <= sc->sc_noport; i++)
+ printf("port %d status=0x%08x\n", i,
+ EOREAD4(sc, EHCI_PORTSC(i)));
+}
+
+void
+ehci_dump()
+{
+ ehci_dump_regs(theehci);
+}
+
+void
+ehci_dump_link(ehci_link_t link, int type)
+{
+ link = le32toh(link);
+ printf("0x%08x", link);
+ if (link & EHCI_LINK_TERMINATE)
+ printf("<T>");
+ else {
+ printf("<");
+ if (type) {
+ switch (EHCI_LINK_TYPE(link)) {
+ case EHCI_LINK_ITD: printf("ITD"); break;
+ case EHCI_LINK_QH: printf("QH"); break;
+ case EHCI_LINK_SITD: printf("SITD"); break;
+ case EHCI_LINK_FSTN: printf("FSTN"); break;
+ }
+ }
+ printf(">");
+ }
+}
+
+void
+ehci_dump_sqtds(ehci_soft_qtd_t *sqtd)
+{
+ int i;
+ u_int32_t stop;
+
+ stop = 0;
+ for (i = 0; sqtd && i < 20 && !stop; sqtd = sqtd->nextqtd, i++) {
+ ehci_dump_sqtd(sqtd);
+ stop = sqtd->qtd.qtd_next & EHCI_LINK_TERMINATE;
+ }
+ if (sqtd)
+ printf("dump aborted, too many TDs\n");
+}
+
+void
+ehci_dump_sqtd(ehci_soft_qtd_t *sqtd)
+{
+ printf("QTD(%p) at 0x%08x:\n", sqtd, sqtd->physaddr);
+ ehci_dump_qtd(&sqtd->qtd);
+}
+
+void
+ehci_dump_qtd(ehci_qtd_t *qtd)
+{
+ u_int32_t s;
+ char sbuf[128];
+
+ printf(" next="); ehci_dump_link(qtd->qtd_next, 0);
+ printf(" altnext="); ehci_dump_link(qtd->qtd_altnext, 0);
+ printf("\n");
+ s = le32toh(qtd->qtd_status);
+ bitmask_snprintf(EHCI_QTD_GET_STATUS(s),
+ "\20\10ACTIVE\7HALTED\6BUFERR\5BABBLE\4XACTERR"
+ "\3MISSED\2SPLIT\1PING", sbuf, sizeof(sbuf));
+ printf(" status=0x%08x: toggle=%d bytes=0x%x ioc=%d c_page=0x%x\n",
+ s, EHCI_QTD_GET_TOGGLE(s), EHCI_QTD_GET_BYTES(s),
+ EHCI_QTD_GET_IOC(s), EHCI_QTD_GET_C_PAGE(s));
+ printf(" cerr=%d pid=%d stat=0x%s\n", EHCI_QTD_GET_CERR(s),
+ EHCI_QTD_GET_PID(s), sbuf);
+ for (s = 0; s < 5; s++)
+ printf(" buffer[%d]=0x%08x\n", s, le32toh(qtd->qtd_buffer[s]));
+}
+
+void
+ehci_dump_sqh(ehci_soft_qh_t *sqh)
+{
+ ehci_qh_t *qh = &sqh->qh;
+ u_int32_t endp, endphub;
+
+ printf("QH(%p) at 0x%08x:\n", sqh, sqh->physaddr);
+ printf(" link="); ehci_dump_link(qh->qh_link, 1); printf("\n");
+ endp = le32toh(qh->qh_endp);
+ printf(" endp=0x%08x\n", endp);
+ printf(" addr=0x%02x inact=%d endpt=%d eps=%d dtc=%d hrecl=%d\n",
+ EHCI_QH_GET_ADDR(endp), EHCI_QH_GET_INACT(endp),
+ EHCI_QH_GET_ENDPT(endp), EHCI_QH_GET_EPS(endp),
+ EHCI_QH_GET_DTC(endp), EHCI_QH_GET_HRECL(endp));
+ printf(" mpl=0x%x ctl=%d nrl=%d\n",
+ EHCI_QH_GET_MPL(endp), EHCI_QH_GET_CTL(endp),
+ EHCI_QH_GET_NRL(endp));
+ endphub = le32toh(qh->qh_endphub);
+ printf(" endphub=0x%08x\n", endphub);
+ printf(" smask=0x%02x cmask=0x%02x huba=0x%02x port=%d mult=%d\n",
+ EHCI_QH_GET_SMASK(endphub), EHCI_QH_GET_CMASK(endphub),
+ EHCI_QH_GET_HUBA(endphub), EHCI_QH_GET_PORT(endphub),
+ EHCI_QH_GET_MULT(endphub));
+ printf(" curqtd="); ehci_dump_link(qh->qh_curqtd, 0); printf("\n");
+ printf("Overlay qTD:\n");
+ ehci_dump_qtd(&qh->qh_qtd);
+}
+
+Static void
+ehci_dump_exfer(struct ehci_xfer *ex)
+{
+ printf("ehci_dump_exfer: ex=%p\n", ex);
+}
+#endif
+
+usbd_status
+ehci_open(usbd_pipe_handle pipe)
+{
+ usbd_device_handle dev = pipe->device;
+ ehci_softc_t *sc = (ehci_softc_t *)dev->bus;
+ usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc;
+ u_int8_t addr = dev->address;
+ u_int8_t xfertype = ed->bmAttributes & UE_XFERTYPE;
+ struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
+ ehci_soft_qh_t *sqh;
+ usbd_status err;
+ int s;
+ int speed, naks;
+
+ DPRINTFN(1, ("ehci_open: pipe=%p, addr=%d, endpt=%d (%d)\n",
+ pipe, addr, ed->bEndpointAddress, sc->sc_addr));
+
+ if (sc->sc_dying)
+ return (USBD_IOERROR);
+
+ if (addr == sc->sc_addr) {
+ switch (ed->bEndpointAddress) {
+ case USB_CONTROL_ENDPOINT:
+ pipe->methods = &ehci_root_ctrl_methods;
+ break;
+ case UE_DIR_IN | EHCI_INTR_ENDPT:
+ pipe->methods = &ehci_root_intr_methods;
+ break;
+ default:
+ return (USBD_INVAL);
+ }
+ return (USBD_NORMAL_COMPLETION);
+ }
+
+ /* XXX All this stuff is only valid for async. */
+ switch (dev->speed) {
+ case USB_SPEED_LOW: speed = EHCI_QH_SPEED_LOW; break;
+ case USB_SPEED_FULL: speed = EHCI_QH_SPEED_FULL; break;
+ case USB_SPEED_HIGH: speed = EHCI_QH_SPEED_HIGH; break;
+ default: panic("ehci_open: bad device speed %d\n", dev->speed);
+ }
+ naks = 8; /* XXX */
+ sqh = ehci_alloc_sqh(sc);
+ if (sqh == NULL)
+ goto bad0;
+ /* qh_link filled when the QH is added */
+ sqh->qh.qh_endp = htole32(
+ EHCI_QH_SET_ADDR(addr) |
+ EHCI_QH_SET_ENDPT(ed->bEndpointAddress) |
+ EHCI_QH_SET_EPS(speed) | /* XXX */
+ /* XXX EHCI_QH_DTC ? */
+ EHCI_QH_SET_MPL(UGETW(ed->wMaxPacketSize)) |
+ (speed != EHCI_QH_SPEED_HIGH && xfertype == UE_CONTROL ?
+ EHCI_QH_CTL : 0) |
+ EHCI_QH_SET_NRL(naks)
+ );
+ sqh->qh.qh_endphub = htole32(
+ EHCI_QH_SET_MULT(1)
+ /* XXX TT stuff */
+ /* XXX interrupt mask */
+ );
+ sqh->qh.qh_curqtd = EHCI_NULL;
+ /* Fill the overlay qTD */
+ sqh->qh.qh_qtd.qtd_next = EHCI_NULL;
+ sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL;
+ sqh->qh.qh_qtd.qtd_status = htole32(0);
+
+ epipe->sqh = sqh;
+
+ switch (xfertype) {
+ case UE_CONTROL:
+ err = usb_allocmem(&sc->sc_bus, sizeof(usb_device_request_t),
+ 0, &epipe->u.ctl.reqdma);
+#ifdef EHCI_DEBUG
+ if (err)
+ printf("ehci_open: usb_allocmem()=%d\n", err);
+#endif
+ if (err)
+ goto bad1;
+ pipe->methods = &ehci_device_ctrl_methods;
+ s = splusb();
+ ehci_add_qh(sqh, sc->sc_async_head);
+ splx(s);
+ break;
+ case UE_BULK:
+ pipe->methods = &ehci_device_bulk_methods;
+ s = splusb();
+ ehci_add_qh(sqh, sc->sc_async_head);
+ splx(s);
+ break;
+ case UE_INTERRUPT:
+ pipe->methods = &ehci_device_intr_methods;
+ return (USBD_INVAL);
+ case UE_ISOCHRONOUS:
+ pipe->methods = &ehci_device_isoc_methods;
+ return (USBD_INVAL);
+ default:
+ return (USBD_INVAL);
+ }
+ return (USBD_NORMAL_COMPLETION);
+
+ bad1:
+ ehci_free_sqh(sc, sqh);
+ bad0:
+ return (USBD_NOMEM);
+}
+
+/*
+ * Add an ED to the schedule. Called at splusb().
+ */
+void
+ehci_add_qh(ehci_soft_qh_t *sqh, ehci_soft_qh_t *head)
+{
+ SPLUSBCHECK;
+
+ sqh->next = head->next;
+ sqh->qh.qh_link = head->qh.qh_link;
+ head->next = sqh;
+ head->qh.qh_link = htole32(sqh->physaddr | EHCI_LINK_QH);
+
+#ifdef EHCI_DEBUG
+ if (ehcidebug > 5) {
+ printf("ehci_add_qh:\n");
+ ehci_dump_sqh(sqh);
+ }
+#endif
+}
+
+/*
+ * Remove an ED from the schedule. Called at splusb().
+ */
+void
+ehci_rem_qh(ehci_softc_t *sc, ehci_soft_qh_t *sqh, ehci_soft_qh_t *head)
+{
+ ehci_soft_qh_t *p;
+
+ SPLUSBCHECK;
+ /* XXX */
+ for (p = head; p == NULL && p->next != sqh; p = p->next)
+ ;
+ if (p == NULL)
+ panic("ehci_rem_qh: ED not found\n");
+ p->next = sqh->next;
+ p->qh.qh_link = sqh->qh.qh_link;
+
+ ehci_sync_hc(sc);
+}
+
+void
+ehci_set_qh_qtd(ehci_soft_qh_t *sqh, ehci_soft_qtd_t *sqtd)
+{
+ /* Halt while we are messing. */
+ sqh->qh.qh_qtd.qtd_status |= htole32(EHCI_QTD_HALTED);
+ sqh->qh.qh_curqtd = 0;
+ sqh->qh.qh_qtd.qtd_next = htole32(sqtd->physaddr);
+ sqh->sqtd = sqtd;
+ /* Keep toggle, clear the rest, including length. */
+ sqh->qh.qh_qtd.qtd_status &= htole32(EHCI_QTD_TOGGLE);
+}
+
+/*
+ * Ensure that the HC has released all references to the QH. We do this
+ * by asking for a Async Advance Doorbell interrupt and then we wait for
+ * the interrupt.
+ * To make this easier we first obtain exclusive use of the doorbell.
+ */
+void
+ehci_sync_hc(ehci_softc_t *sc)
+{
+ int s, error;
+
+ if (sc->sc_dying) {
+ DPRINTFN(2,("ehci_sync_hc: dying\n"));
+ return;
+ }
+ DPRINTFN(2,("ehci_sync_hc: enter\n"));
+
+ /* get doorbell */
+ usb_lockmgr(&sc->sc_doorbell_lock, LK_EXCLUSIVE, NULL, curproc);
+
+ s = splhardusb();
+ /* ask for doorbell */
+ EOWRITE4(sc, EHCI_USBCMD, EOREAD4(sc, EHCI_USBCMD) | EHCI_CMD_IAAD);
+ DPRINTFN(1,("ehci_sync_hc: cmd=0x%08x sts=0x%08x\n",
+ EOREAD4(sc, EHCI_USBCMD), EOREAD4(sc, EHCI_USBSTS)));
+ error = tsleep(&sc->sc_async_head, PZERO, "ehcidi", hz); /* bell wait */
+ DPRINTFN(1,("ehci_sync_hc: cmd=0x%08x sts=0x%08x\n",
+ EOREAD4(sc, EHCI_USBCMD), EOREAD4(sc, EHCI_USBSTS)));
+ splx(s);
+
+ /* release doorbell */
+ usb_lockmgr(&sc->sc_doorbell_lock, LK_RELEASE, NULL, curproc);
+
+#ifdef DIAGNOSTIC
+ if (error)
+ printf("ehci_sync_hc: tsleep() = %d\n", error);
+#endif
+ DPRINTFN(2,("ehci_sync_hc: exit\n"));
+}
+
+/***********/
+
+/*
+ * Data structures and routines to emulate the root hub.
+ */
+Static usb_device_descriptor_t ehci_devd = {
+ USB_DEVICE_DESCRIPTOR_SIZE,
+ UDESC_DEVICE, /* type */
+ {0x00, 0x02}, /* USB version */
+ UDCLASS_HUB, /* class */
+ UDSUBCLASS_HUB, /* subclass */
+ UDPROTO_HSHUBSTT, /* protocol */
+ 64, /* max packet */
+ {0},{0},{0x00,0x01}, /* device id */
+ 1,2,0, /* string indicies */
+ 1 /* # of configurations */
+};
+
+Static usb_device_qualifier_t ehci_odevd = {
+ USB_DEVICE_DESCRIPTOR_SIZE,
+ UDESC_DEVICE_QUALIFIER, /* type */
+ {0x00, 0x02}, /* USB version */
+ UDCLASS_HUB, /* class */
+ UDSUBCLASS_HUB, /* subclass */
+ UDPROTO_FSHUB, /* protocol */
+ 64, /* max packet */
+ 1, /* # of configurations */
+ 0
+};
+
+Static usb_config_descriptor_t ehci_confd = {
+ USB_CONFIG_DESCRIPTOR_SIZE,
+ UDESC_CONFIG,
+ {USB_CONFIG_DESCRIPTOR_SIZE +
+ USB_INTERFACE_DESCRIPTOR_SIZE +
+ USB_ENDPOINT_DESCRIPTOR_SIZE},
+ 1,
+ 1,
+ 0,
+ UC_SELF_POWERED,
+ 0 /* max power */
+};
+
+Static usb_interface_descriptor_t ehci_ifcd = {
+ USB_INTERFACE_DESCRIPTOR_SIZE,
+ UDESC_INTERFACE,
+ 0,
+ 0,
+ 1,
+ UICLASS_HUB,
+ UISUBCLASS_HUB,
+ UIPROTO_HSHUBSTT,
+ 0
+};
+
+Static usb_endpoint_descriptor_t ehci_endpd = {
+ USB_ENDPOINT_DESCRIPTOR_SIZE,
+ UDESC_ENDPOINT,
+ UE_DIR_IN | EHCI_INTR_ENDPT,
+ UE_INTERRUPT,
+ {8, 0}, /* max packet */
+ 255
+};
+
+Static usb_hub_descriptor_t ehci_hubd = {
+ USB_HUB_DESCRIPTOR_SIZE,
+ UDESC_HUB,
+ 0,
+ {0,0},
+ 0,
+ 0,
+ {0},
+};
+
+Static int
+ehci_str(p, l, s)
+ usb_string_descriptor_t *p;
+ int l;
+ char *s;
+{
+ int i;
+
+ if (l == 0)
+ return (0);
+ p->bLength = 2 * strlen(s) + 2;
+ if (l == 1)
+ return (1);
+ p->bDescriptorType = UDESC_STRING;
+ l -= 2;
+ for (i = 0; s[i] && l > 1; i++, l -= 2)
+ USETW2(p->bString[i], 0, s[i]);
+ return (2*i+2);
+}
+
+/*
+ * Simulate a hardware hub by handling all the necessary requests.
+ */
+Static usbd_status
+ehci_root_ctrl_transfer(usbd_xfer_handle xfer)
+{
+ usbd_status err;
+
+ /* Insert last in queue. */
+ err = usb_insert_transfer(xfer);
+ if (err)
+ return (err);
+
+ /* Pipe isn't running, start first */
+ return (ehci_root_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
+}
+
+Static usbd_status
+ehci_root_ctrl_start(usbd_xfer_handle xfer)
+{
+ ehci_softc_t *sc = (ehci_softc_t *)xfer->pipe->device->bus;
+ usb_device_request_t *req;
+ void *buf = NULL;
+ int port, i;
+ int s, len, value, index, l, totlen = 0;
+ usb_port_status_t ps;
+ usb_hub_descriptor_t hubd;
+ usbd_status err;
+ u_int32_t v;
+
+ if (sc->sc_dying)
+ return (USBD_IOERROR);
+
+#ifdef DIAGNOSTIC
+ if (!(xfer->rqflags & URQ_REQUEST))
+ /* XXX panic */
+ return (USBD_INVAL);
+#endif
+ req = &xfer->request;
+
+ DPRINTFN(4,("ehci_root_ctrl_control type=0x%02x request=%02x\n",
+ req->bmRequestType, req->bRequest));
+
+ len = UGETW(req->wLength);
+ value = UGETW(req->wValue);
+ index = UGETW(req->wIndex);
+
+ if (len != 0)
+ buf = KERNADDR(&xfer->dmabuf);
+
+#define C(x,y) ((x) | ((y) << 8))
+ switch(C(req->bRequest, req->bmRequestType)) {
+ 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.
+ */
+ break;
+ case C(UR_GET_CONFIG, UT_READ_DEVICE):
+ if (len > 0) {
+ *(u_int8_t *)buf = sc->sc_conf;
+ totlen = 1;
+ }
+ break;
+ case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
+ DPRINTFN(8,("ehci_root_ctrl_control wValue=0x%04x\n", value));
+ switch(value >> 8) {
+ case UDESC_DEVICE:
+ if ((value & 0xff) != 0) {
+ err = USBD_IOERROR;
+ goto ret;
+ }
+ totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
+ USETW(ehci_devd.idVendor, sc->sc_id_vendor);
+ memcpy(buf, &ehci_devd, l);
+ break;
+ /*
+ * We can't really operate at another speed, but the spec says
+ * we need this descriptor.
+ */
+ case UDESC_DEVICE_QUALIFIER:
+ if ((value & 0xff) != 0) {
+ err = USBD_IOERROR;
+ goto ret;
+ }
+ totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
+ memcpy(buf, &ehci_odevd, l);
+ break;
+ /*
+ * We can't really operate at another speed, but the spec says
+ * we need this descriptor.
+ */
+ case UDESC_OTHER_SPEED_CONFIGURATION:
+ case UDESC_CONFIG:
+ if ((value & 0xff) != 0) {
+ err = USBD_IOERROR;
+ goto ret;
+ }
+ totlen = l = min(len, USB_CONFIG_DESCRIPTOR_SIZE);
+ memcpy(buf, &ehci_confd, l);
+ ((usb_config_descriptor_t *)buf)->bDescriptorType =
+ value >> 8;
+ buf = (char *)buf + l;
+ len -= l;
+ l = min(len, USB_INTERFACE_DESCRIPTOR_SIZE);
+ totlen += l;
+ memcpy(buf, &ehci_ifcd, l);
+ buf = (char *)buf + l;
+ len -= l;
+ l = min(len, USB_ENDPOINT_DESCRIPTOR_SIZE);
+ totlen += l;
+ memcpy(buf, &ehci_endpd, l);
+ break;
+ case UDESC_STRING:
+ if (len == 0)
+ break;
+ *(u_int8_t *)buf = 0;
+ totlen = 1;
+ switch (value & 0xff) {
+ case 1: /* Vendor */
+ totlen = ehci_str(buf, len, sc->sc_vendor);
+ break;
+ case 2: /* Product */
+ totlen = ehci_str(buf, len, "EHCI root hub");
+ break;
+ }
+ break;
+ default:
+ err = USBD_IOERROR;
+ goto ret;
+ }
+ break;
+ case C(UR_GET_INTERFACE, UT_READ_INTERFACE):
+ if (len > 0) {
+ *(u_int8_t *)buf = 0;
+ totlen = 1;
+ }
+ break;
+ case C(UR_GET_STATUS, UT_READ_DEVICE):
+ if (len > 1) {
+ USETW(((usb_status_t *)buf)->wStatus,UDS_SELF_POWERED);
+ totlen = 2;
+ }
+ break;
+ case C(UR_GET_STATUS, UT_READ_INTERFACE):
+ case C(UR_GET_STATUS, UT_READ_ENDPOINT):
+ if (len > 1) {
+ USETW(((usb_status_t *)buf)->wStatus, 0);
+ totlen = 2;
+ }
+ break;
+ case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
+ if (value >= USB_MAX_DEVICES) {
+ err = USBD_IOERROR;
+ goto ret;
+ }
+ sc->sc_addr = value;
+ break;
+ case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
+ if (value != 0 && value != 1) {
+ err = USBD_IOERROR;
+ goto ret;
+ }
+ sc->sc_conf = value;
+ break;
+ case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
+ break;
+ case C(UR_SET_FEATURE, UT_WRITE_DEVICE):
+ case C(UR_SET_FEATURE, UT_WRITE_INTERFACE):
+ case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
+ err = USBD_IOERROR;
+ goto ret;
+ case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
+ break;
+ case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
+ break;
+ /* Hub requests */
+ case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE):
+ break;
+ case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):
+ DPRINTFN(8, ("ehci_root_ctrl_control: UR_CLEAR_PORT_FEATURE "
+ "port=%d feature=%d\n",
+ index, value));
+ if (index < 1 || index > sc->sc_noport) {
+ err = USBD_IOERROR;
+ goto ret;
+ }
+ port = EHCI_PORTSC(index);
+ v = EOREAD4(sc, port) &~ EHCI_PS_CLEAR;
+ switch(value) {
+ case UHF_PORT_ENABLE:
+ EOWRITE4(sc, port, v &~ EHCI_PS_PE);
+ break;
+ case UHF_PORT_SUSPEND:
+ EOWRITE4(sc, port, v &~ EHCI_PS_SUSP);
+ break;
+ case UHF_PORT_POWER:
+ EOWRITE4(sc, port, v &~ EHCI_PS_PP);
+ break;
+ case UHF_PORT_TEST:
+ DPRINTFN(2,("ehci_root_ctrl_transfer: clear port test "
+ "%d\n", index));
+ break;
+ case UHF_PORT_INDICATOR:
+ DPRINTFN(2,("ehci_root_ctrl_transfer: clear port ind "
+ "%d\n", index));
+ EOWRITE4(sc, port, v &~ EHCI_PS_PIC);
+ break;
+ case UHF_C_PORT_CONNECTION:
+ EOWRITE4(sc, port, v | EHCI_PS_CSC);
+ break;
+ case UHF_C_PORT_ENABLE:
+ EOWRITE4(sc, port, v | EHCI_PS_PEC);
+ break;
+ case UHF_C_PORT_SUSPEND:
+ /* how? */
+ break;
+ case UHF_C_PORT_OVER_CURRENT:
+ EOWRITE4(sc, port, v | EHCI_PS_OCC);
+ break;
+ case UHF_C_PORT_RESET:
+ sc->sc_isreset = 0;
+ break;
+ default:
+ err = USBD_IOERROR;
+ goto ret;
+ }
+#if 0
+ switch(value) {
+ case UHF_C_PORT_CONNECTION:
+ case UHF_C_PORT_ENABLE:
+ case UHF_C_PORT_SUSPEND:
+ case UHF_C_PORT_OVER_CURRENT:
+ case UHF_C_PORT_RESET:
+ /* Enable RHSC interrupt if condition is cleared. */
+ if ((OREAD4(sc, port) >> 16) == 0)
+ ehci_pcd_able(sc, 1);
+ break;
+ default:
+ break;
+ }
+#endif
+ break;
+ case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
+ if (value != 0) {
+ err = USBD_IOERROR;
+ goto ret;
+ }
+ hubd = ehci_hubd;
+ hubd.bNbrPorts = sc->sc_noport;
+ v = EOREAD4(sc, EHCI_HCSPARAMS);
+ USETW(hubd.wHubCharacteristics,
+ EHCI_HCS_PPC(v) ? UHD_PWR_INDIVIDUAL : UHD_PWR_NO_SWITCH |
+ EHCI_HCS_P_INCICATOR(EREAD4(sc, EHCI_HCSPARAMS))
+ ? UHD_PORT_IND : 0);
+ hubd.bPwrOn2PwrGood = 200; /* XXX can't find out? */
+ for (i = 0, l = sc->sc_noport; l > 0; i++, l -= 8, v >>= 8)
+ hubd.DeviceRemovable[i++] = 0; /* XXX can't find out? */
+ hubd.bDescLength = USB_HUB_DESCRIPTOR_SIZE + i;
+ l = min(len, hubd.bDescLength);
+ totlen = l;
+ memcpy(buf, &hubd, l);
+ break;
+ case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
+ if (len != 4) {
+ err = USBD_IOERROR;
+ goto ret;
+ }
+ memset(buf, 0, len); /* ? XXX */
+ totlen = len;
+ break;
+ case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):
+ DPRINTFN(8,("ehci_root_ctrl_transfer: get port status i=%d\n",
+ index));
+ if (index < 1 || index > sc->sc_noport) {
+ err = USBD_IOERROR;
+ goto ret;
+ }
+ if (len != 4) {
+ err = USBD_IOERROR;
+ goto ret;
+ }
+ v = EOREAD4(sc, EHCI_PORTSC(index));
+ DPRINTFN(8,("ehci_root_ctrl_transfer: port status=0x%04x\n",
+ v));
+ i = UPS_HIGH_SPEED;
+ if (v & EHCI_PS_CS) i |= UPS_CURRENT_CONNECT_STATUS;
+ if (v & EHCI_PS_PE) i |= UPS_PORT_ENABLED;
+ if (v & EHCI_PS_SUSP) i |= UPS_SUSPEND;
+ if (v & EHCI_PS_OCA) i |= UPS_OVERCURRENT_INDICATOR;
+ if (v & EHCI_PS_PR) i |= UPS_RESET;
+ if (v & EHCI_PS_PP) i |= UPS_PORT_POWER;
+ USETW(ps.wPortStatus, i);
+ i = 0;
+ if (v & EHCI_PS_CSC) i |= UPS_C_CONNECT_STATUS;
+ if (v & EHCI_PS_PEC) i |= UPS_C_PORT_ENABLED;
+ if (v & EHCI_PS_OCC) i |= UPS_C_OVERCURRENT_INDICATOR;
+ if (sc->sc_isreset) i |= UPS_C_PORT_RESET;
+ USETW(ps.wPortChange, i);
+ l = min(len, sizeof ps);
+ memcpy(buf, &ps, l);
+ totlen = l;
+ break;
+ case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE):
+ err = USBD_IOERROR;
+ goto ret;
+ case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE):
+ break;
+ case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):
+ if (index < 1 || index > sc->sc_noport) {
+ err = USBD_IOERROR;
+ goto ret;
+ }
+ port = EHCI_PORTSC(index);
+ v = EOREAD4(sc, port) &~ EHCI_PS_CLEAR;
+ switch(value) {
+ case UHF_PORT_ENABLE:
+ EOWRITE4(sc, port, v | EHCI_PS_PE);
+ break;
+ case UHF_PORT_SUSPEND:
+ EOWRITE4(sc, port, v | EHCI_PS_SUSP);
+ break;
+ case UHF_PORT_RESET:
+ DPRINTFN(5,("ehci_root_ctrl_transfer: reset port %d\n",
+ index));
+ if (EHCI_PS_IS_LOWSPEED(v)) {
+ /* Low speed device, give up ownership. */
+ ehci_disown(sc, index, 1);
+ break;
+ }
+ /* Start reset sequence. */
+ v &= ~ (EHCI_PS_PE | EHCI_PS_PR);
+ EOWRITE4(sc, port, v | EHCI_PS_PR);
+ /* Wait for reset to complete. */
+ usb_delay_ms(&sc->sc_bus, USB_PORT_ROOT_RESET_DELAY);
+ if (sc->sc_dying) {
+ err = USBD_IOERROR;
+ goto ret;
+ }
+ /* Terminate reset sequence. */
+ EOWRITE4(sc, port, v);
+ /* Wait for HC to complete reset. */
+ usb_delay_ms(&sc->sc_bus, EHCI_PORT_RESET_COMPLETE);
+ if (sc->sc_dying) {
+ err = USBD_IOERROR;
+ goto ret;
+ }
+ v = EOREAD4(sc, port);
+ DPRINTF(("ehci after reset, status=0x%08x\n", v));
+ if (v & EHCI_PS_PR) {
+ printf("%s: port reset timeout\n",
+ USBDEVNAME(sc->sc_bus.bdev));
+ return (USBD_TIMEOUT);
+ }
+ if (!(v & EHCI_PS_PE)) {
+ /* Not a high speed device, give up ownership.*/
+ ehci_disown(sc, index, 0);
+ break;
+ }
+ sc->sc_isreset = 1;
+ DPRINTF(("ehci port %d reset, status = 0x%08x\n",
+ index, v));
+ break;
+ case UHF_PORT_POWER:
+ DPRINTFN(2,("ehci_root_ctrl_transfer: set port power "
+ "%d\n", index));
+ EOWRITE4(sc, port, v | EHCI_PS_PP);
+ break;
+ case UHF_PORT_TEST:
+ DPRINTFN(2,("ehci_root_ctrl_transfer: set port test "
+ "%d\n", index));
+ break;
+ case UHF_PORT_INDICATOR:
+ DPRINTFN(2,("ehci_root_ctrl_transfer: set port ind "
+ "%d\n", index));
+ EOWRITE4(sc, port, v | EHCI_PS_PIC);
+ break;
+ default:
+ err = USBD_IOERROR;
+ goto ret;
+ }
+ break;
+ case C(UR_CLEAR_TT_BUFFER, UT_WRITE_CLASS_OTHER):
+ case C(UR_RESET_TT, UT_WRITE_CLASS_OTHER):
+ case C(UR_GET_TT_STATE, UT_READ_CLASS_OTHER):
+ case C(UR_STOP_TT, UT_WRITE_CLASS_OTHER):
+ break;
+ default:
+ err = USBD_IOERROR;
+ goto ret;
+ }
+ xfer->actlen = totlen;
+ err = USBD_NORMAL_COMPLETION;
+ ret:
+ xfer->status = err;
+ s = splusb();
+ usb_transfer_complete(xfer);
+ splx(s);
+ return (USBD_IN_PROGRESS);
+}
+
+void
+ehci_disown(ehci_softc_t *sc, int index, int lowspeed)
+{
+ int port;
+ u_int32_t v;
+
+ DPRINTF(("ehci_disown: index=%d lowspeed=%d\n", index, lowspeed));
+#ifdef DIAGNOSTIC
+ if (sc->sc_npcomp != 0) {
+ int i = (index-1) / sc->sc_npcomp;
+ if (i >= sc->sc_ncomp)
+ printf("%s: strange port\n",
+ USBDEVNAME(sc->sc_bus.bdev));
+ else
+ printf("%s: handing over %s speed device on "
+ "port %d to %s\n",
+ USBDEVNAME(sc->sc_bus.bdev),
+ lowspeed ? "low" : "full",
+ index, USBDEVNAME(sc->sc_comps[i]->bdev));
+ } else {
+ printf("%s: npcomp == 0\n", USBDEVNAME(sc->sc_bus.bdev));
+ }
+#endif
+ port = EHCI_PORTSC(index);
+ v = EOREAD4(sc, port) &~ EHCI_PS_CLEAR;
+ EOWRITE4(sc, port, v | EHCI_PS_PO);
+}
+
+/* Abort a root control request. */
+Static void
+ehci_root_ctrl_abort(usbd_xfer_handle xfer)
+{
+ /* Nothing to do, all transfers are synchronous. */
+}
+
+/* Close the root pipe. */
+Static void
+ehci_root_ctrl_close(usbd_pipe_handle pipe)
+{
+ DPRINTF(("ehci_root_ctrl_close\n"));
+ /* Nothing to do. */
+}
+
+void
+ehci_root_intr_done(usbd_xfer_handle xfer)
+{
+ xfer->hcpriv = NULL;
+}
+
+Static usbd_status
+ehci_root_intr_transfer(usbd_xfer_handle xfer)
+{
+ usbd_status err;
+
+ /* Insert last in queue. */
+ err = usb_insert_transfer(xfer);
+ if (err)
+ return (err);
+
+ /* Pipe isn't running, start first */
+ return (ehci_root_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
+}
+
+Static usbd_status
+ehci_root_intr_start(usbd_xfer_handle xfer)
+{
+ usbd_pipe_handle pipe = xfer->pipe;
+ ehci_softc_t *sc = (ehci_softc_t *)pipe->device->bus;
+
+ if (sc->sc_dying)
+ return (USBD_IOERROR);
+
+ sc->sc_intrxfer = xfer;
+
+ return (USBD_IN_PROGRESS);
+}
+
+/* Abort a root interrupt request. */
+Static void
+ehci_root_intr_abort(usbd_xfer_handle xfer)
+{
+ int s;
+
+ if (xfer->pipe->intrxfer == xfer) {
+ DPRINTF(("ehci_root_intr_abort: remove\n"));
+ xfer->pipe->intrxfer = NULL;
+ }
+ xfer->status = USBD_CANCELLED;
+ s = splusb();
+ usb_transfer_complete(xfer);
+ splx(s);
+}
+
+/* Close the root pipe. */
+Static void
+ehci_root_intr_close(usbd_pipe_handle pipe)
+{
+ ehci_softc_t *sc = (ehci_softc_t *)pipe->device->bus;
+
+ DPRINTF(("ehci_root_intr_close\n"));
+
+ sc->sc_intrxfer = NULL;
+}
+
+void
+ehci_root_ctrl_done(usbd_xfer_handle xfer)
+{
+ xfer->hcpriv = NULL;
+}
+
+/************************/
+
+ehci_soft_qh_t *
+ehci_alloc_sqh(ehci_softc_t *sc)
+{
+ ehci_soft_qh_t *sqh;
+ usbd_status err;
+ int i, offs;
+ usb_dma_t dma;
+
+ if (sc->sc_freeqhs == NULL) {
+ DPRINTFN(2, ("ehci_alloc_sqh: allocating chunk\n"));
+ err = usb_allocmem(&sc->sc_bus, EHCI_SQH_SIZE * EHCI_SQH_CHUNK,
+ EHCI_PAGE_SIZE, &dma);
+#ifdef EHCI_DEBUG
+ if (err)
+ printf("ehci_alloc_sqh: usb_allocmem()=%d\n", err);
+#endif
+ if (err)
+ return (NULL);
+ for(i = 0; i < EHCI_SQH_CHUNK; i++) {
+ offs = i * EHCI_SQH_SIZE;
+ sqh = (ehci_soft_qh_t *)((char *)KERNADDR(&dma) + offs);
+ sqh->physaddr = DMAADDR(&dma) + offs;
+ sqh->next = sc->sc_freeqhs;
+ sc->sc_freeqhs = sqh;
+ }
+ }
+ sqh = sc->sc_freeqhs;
+ sc->sc_freeqhs = sqh->next;
+ memset(&sqh->qh, 0, sizeof(ehci_qh_t));
+ sqh->next = NULL;
+ return (sqh);
+}
+
+void
+ehci_free_sqh(ehci_softc_t *sc, ehci_soft_qh_t *sqh)
+{
+ sqh->next = sc->sc_freeqhs;
+ sc->sc_freeqhs = sqh;
+}
+
+ehci_soft_qtd_t *
+ehci_alloc_sqtd(ehci_softc_t *sc)
+{
+ ehci_soft_qtd_t *sqtd;
+ usbd_status err;
+ int i, offs;
+ usb_dma_t dma;
+ int s;
+
+ if (sc->sc_freeqtds == NULL) {
+ DPRINTFN(2, ("ehci_alloc_sqtd: allocating chunk\n"));
+ err = usb_allocmem(&sc->sc_bus, EHCI_SQTD_SIZE*EHCI_SQTD_CHUNK,
+ EHCI_PAGE_SIZE, &dma);
+#ifdef EHCI_DEBUG
+ if (err)
+ printf("ehci_alloc_sqtd: usb_allocmem()=%d\n", err);
+#endif
+ if (err)
+ return (NULL);
+ s = splusb();
+ for(i = 0; i < EHCI_SQTD_CHUNK; i++) {
+ offs = i * EHCI_SQTD_SIZE;
+ sqtd = (ehci_soft_qtd_t *)((char *)KERNADDR(&dma)+offs);
+ sqtd->physaddr = DMAADDR(&dma) + offs;
+ sqtd->nextqtd = sc->sc_freeqtds;
+ sc->sc_freeqtds = sqtd;
+ }
+ splx(s);
+ }
+
+ s = splusb();
+ sqtd = sc->sc_freeqtds;
+ sc->sc_freeqtds = sqtd->nextqtd;
+ memset(&sqtd->qtd, 0, sizeof(ehci_qtd_t));
+ sqtd->nextqtd = NULL;
+ sqtd->xfer = NULL;
+ splx(s);
+
+ return (sqtd);
+}
+
+void
+ehci_free_sqtd(ehci_softc_t *sc, ehci_soft_qtd_t *sqtd)
+{
+ int s;
+
+ s = splusb();
+ sqtd->nextqtd = sc->sc_freeqtds;
+ sc->sc_freeqtds = sqtd;
+ splx(s);
+}
+
+usbd_status
+ehci_alloc_sqtd_chain(struct ehci_pipe *epipe, ehci_softc_t *sc,
+ int alen, int rd, usbd_xfer_handle xfer,
+ ehci_soft_qtd_t **sp, ehci_soft_qtd_t **ep)
+{
+ ehci_soft_qtd_t *next, *cur;
+ ehci_physaddr_t dataphys, dataphyspage, dataphyslastpage, nextphys;
+ u_int32_t qtdstatus;
+ int len, curlen;
+ int i;
+ usb_dma_t *dma = &xfer->dmabuf;
+
+ DPRINTFN(alen<4*4096,("ehci_alloc_sqtd_chain: start len=%d\n", alen));
+
+ len = alen;
+ dataphys = DMAADDR(dma);
+ dataphyslastpage = EHCI_PAGE(dataphys + len - 1);
+ qtdstatus = htole32(
+ EHCI_QTD_ACTIVE |
+ EHCI_QTD_SET_PID(rd ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT) |
+ EHCI_QTD_SET_CERR(3)
+ /* IOC set below */
+ /* BYTES set below */
+ /* XXX Data toggle */
+ );
+
+ cur = ehci_alloc_sqtd(sc);
+ *sp = cur;
+ if (cur == NULL)
+ goto nomem;
+ for (;;) {
+ dataphyspage = EHCI_PAGE(dataphys);
+ /* The EHCI hardware can handle at most 5 pages. */
+ if (dataphyslastpage - dataphyspage <
+ EHCI_QTD_NBUFFERS * EHCI_PAGE_SIZE) {
+ /* we can handle it in this QTD */
+ curlen = len;
+ } else {
+ /* must use multiple TDs, fill as much as possible. */
+ curlen = EHCI_QTD_NBUFFERS * EHCI_PAGE_SIZE -
+ EHCI_PAGE_OFFSET(dataphys);
+#ifdef DIAGNOSTIC
+ if (curlen > len) {
+ printf("ehci_alloc_sqtd_chain: curlen=0x%x "
+ "len=0x%x offs=0x%x\n", curlen, len,
+ EHCI_PAGE_OFFSET(dataphys));
+ printf("lastpage=0x%x page=0x%x phys=0x%x\n",
+ dataphyslastpage, dataphyspage,
+ dataphys);
+ curlen = len;
+ }
+#endif
+
+ /* XXX true for EHCI? */
+ /* the length must be a multiple of the max size */
+ curlen -= curlen % UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize);
+ DPRINTFN(1,("ehci_alloc_sqtd_chain: multiple QTDs, "
+ "curlen=%d\n", curlen));
+#ifdef DIAGNOSTIC
+ if (curlen == 0)
+ panic("ehci_alloc_std: curlen == 0\n");
+#endif
+ }
+ DPRINTFN(4,("ehci_alloc_sqtd_chain: dataphys=0x%08x "
+ "dataphyslastpage=0x%08x len=%d curlen=%d\n",
+ dataphys, dataphyslastpage,
+ len, curlen));
+ len -= curlen;
+
+ if (len != 0) {
+ next = ehci_alloc_sqtd(sc);
+ if (next == NULL)
+ goto nomem;
+ nextphys = next->physaddr;
+ } else {
+ next = NULL;
+ nextphys = EHCI_NULL;
+ }
+
+ for (i = 0; i * EHCI_PAGE_SIZE < curlen; i++) {
+ ehci_physaddr_t a = dataphys + i * EHCI_PAGE_SIZE;
+ if (i != 0) /* use offset only in first buffer */
+ a = EHCI_PAGE(a);
+ cur->qtd.qtd_buffer[i] = htole32(a);
+#ifdef DIAGNOSTIC
+ if (i >= EHCI_QTD_NBUFFERS) {
+ printf("ehci_alloc_sqtd_chain: i=%d\n", i);
+ goto nomem;
+ }
+#endif
+ }
+ cur->nextqtd = next;
+ cur->qtd.qtd_next = cur->qtd.qtd_altnext = htole32(nextphys);
+ cur->qtd.qtd_status =
+ qtdstatus | htole32(EHCI_QTD_SET_BYTES(curlen));
+ cur->xfer = xfer;
+ cur->len = curlen;
+ DPRINTFN(10,("ehci_alloc_sqtd_chain: cbp=0x%08x end=0x%08x\n",
+ dataphys, dataphys + curlen));
+ if (len == 0)
+ break;
+ DPRINTFN(10,("ehci_alloc_sqtd_chain: extend chain\n"));
+ dataphys += curlen;
+ cur = next;
+ }
+ cur->qtd.qtd_status |= htole32(EHCI_QTD_IOC);
+ *ep = cur;
+
+ DPRINTFN(10,("ehci_alloc_sqtd_chain: return sqtd=%p sqtdend=%p\n",
+ *sp, *ep));
+
+ return (USBD_NORMAL_COMPLETION);
+
+ nomem:
+ /* XXX free chain */
+ DPRINTFN(-1,("ehci_alloc_sqtd_chain: no memory\n"));
+ return (USBD_NOMEM);
+}
+
+Static void
+ehci_free_sqtd_chain(ehci_softc_t *sc, ehci_soft_qtd_t *sqtd,
+ ehci_soft_qtd_t *sqtdend)
+{
+ ehci_soft_qtd_t *p;
+ int i;
+
+ DPRINTFN(10,("ehci_free_sqtd_chain: sqtd=%p sqtdend=%p\n",
+ sqtd, sqtdend));
+
+ for (i = 0; sqtd != sqtdend; sqtd = p, i++) {
+ p = sqtd->nextqtd;
+ ehci_free_sqtd(sc, sqtd);
+ }
+}
+
+/****************/
+
+/*
+ * Close a reqular pipe.
+ * Assumes that there are no pending transactions.
+ */
+void
+ehci_close_pipe(usbd_pipe_handle pipe, ehci_soft_qh_t *head)
+{
+ struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
+ ehci_softc_t *sc = (ehci_softc_t *)pipe->device->bus;
+ ehci_soft_qh_t *sqh = epipe->sqh;
+ int s;
+
+ s = splusb();
+ ehci_rem_qh(sc, sqh, head);
+ splx(s);
+ ehci_free_sqh(sc, epipe->sqh);
+}
+
+/*
+ * 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.
+ * XXX This is most probably wrong.
+ */
+void
+ehci_abort_xfer(usbd_xfer_handle xfer, usbd_status status)
+{
+#define exfer EXFER(xfer)
+ struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
+ ehci_softc_t *sc = (ehci_softc_t *)epipe->pipe.device->bus;
+ ehci_soft_qh_t *sqh = epipe->sqh;
+ ehci_soft_qtd_t *sqtd;
+ ehci_physaddr_t cur;
+ u_int32_t qhstatus;
+ int s;
+ int hit;
+
+ DPRINTF(("ehci_abort_xfer: xfer=%p pipe=%p\n", xfer, epipe));
+
+ 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, ehci_timeout, xfer);
+ usb_transfer_complete(xfer);
+ splx(s);
+ return;
+ }
+
+ if (xfer->device->bus->intr_context || !curproc)
+ panic("ehci_abort_xfer: not in process context\n");
+
+ /*
+ * Step 1: Make interrupt routine and hardware ignore xfer.
+ */
+ s = splusb();
+ xfer->status = status; /* make software ignore it */
+ usb_uncallout(xfer->timeout_handle, ehci_timeout, xfer);
+ qhstatus = sqh->qh.qh_qtd.qtd_status;
+ sqh->qh.qh_qtd.qtd_status = qhstatus | htole32(EHCI_QTD_HALTED);
+ for (sqtd = exfer->sqtdstart; ; sqtd = sqtd->nextqtd) {
+ sqtd->qtd.qtd_status |= htole32(EHCI_QTD_HALTED);
+ if (sqtd == exfer->sqtdend)
+ break;
+ }
+ splx(s);
+
+ /*
+ * Step 2: Wait until we know hardware has finished any possible
+ * use of the xfer. Also make sure the soft interrupt routine
+ * has run.
+ */
+ ehci_sync_hc(sc);
+ s = splusb();
+ sc->sc_softwake = 1;
+ usb_schedsoftintr(&sc->sc_bus);
+ tsleep(&sc->sc_softwake, PZERO, "ehciab", 0);
+ 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? */
+ cur = EHCI_LINK_ADDR(le32toh(sqh->qh.qh_curqtd));
+ hit = 0;
+ for (sqtd = exfer->sqtdstart; ; sqtd = sqtd->nextqtd) {
+ hit |= cur == sqtd->physaddr;
+ if (sqtd == exfer->sqtdend)
+ break;
+ }
+ sqtd = sqtd->nextqtd;
+ /* Zap curqtd register if hardware pointed inside the xfer. */
+ if (hit && sqtd != NULL) {
+ DPRINTFN(1,("ehci_abort_xfer: cur=0x%08x\n", sqtd->physaddr));
+ sqh->qh.qh_curqtd = htole32(sqtd->physaddr); /* unlink qTDs */
+ sqh->qh.qh_qtd.qtd_status = qhstatus;
+ } else {
+ DPRINTFN(1,("ehci_abort_xfer: no hit\n"));
+ }
+
+ /*
+ * Step 4: Execute callback.
+ */
+#ifdef DIAGNOSTIC
+ exfer->isdone = 1;
+#endif
+ usb_transfer_complete(xfer);
+
+ splx(s);
+#undef exfer
+}
+
+void
+ehci_timeout(void *addr)
+{
+ struct ehci_xfer *exfer = addr;
+ struct ehci_pipe *epipe = (struct ehci_pipe *)exfer->xfer.pipe;
+ ehci_softc_t *sc = (ehci_softc_t *)epipe->pipe.device->bus;
+
+ DPRINTF(("ehci_timeout: exfer=%p\n", exfer));
+#ifdef USB_DEBUG
+ if (ehcidebug > 1)
+ usbd_dump_pipe(exfer->xfer.pipe);
+#endif
+
+ if (sc->sc_dying) {
+ ehci_abort_xfer(&exfer->xfer, USBD_TIMEOUT);
+ return;
+ }
+
+ /* Execute the abort in a process context. */
+ usb_init_task(&exfer->abort_task, ehci_timeout_task, addr);
+ usb_add_task(exfer->xfer.pipe->device, &exfer->abort_task);
+}
+
+void
+ehci_timeout_task(void *addr)
+{
+ usbd_xfer_handle xfer = addr;
+ int s;
+
+ DPRINTF(("ehci_timeout_task: xfer=%p\n", xfer));
+
+ s = splusb();
+ ehci_abort_xfer(xfer, USBD_TIMEOUT);
+ splx(s);
+}
+
+/************************/
+
+Static usbd_status
+ehci_device_ctrl_transfer(usbd_xfer_handle xfer)
+{
+ usbd_status err;
+
+ /* Insert last in queue. */
+ err = usb_insert_transfer(xfer);
+ if (err)
+ return (err);
+
+ /* Pipe isn't running, start first */
+ return (ehci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
+}
+
+Static usbd_status
+ehci_device_ctrl_start(usbd_xfer_handle xfer)
+{
+ ehci_softc_t *sc = (ehci_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 */
+ printf("ehci_device_ctrl_transfer: not a request\n");
+ return (USBD_INVAL);
+ }
+#endif
+
+ err = ehci_device_request(xfer);
+ if (err)
+ return (err);
+
+ if (sc->sc_bus.use_polling)
+ ehci_waitintr(sc, xfer);
+ return (USBD_IN_PROGRESS);
+}
+
+void
+ehci_device_ctrl_done(usbd_xfer_handle xfer)
+{
+ struct ehci_xfer *ex = EXFER(xfer);
+ ehci_softc_t *sc = (ehci_softc_t *)xfer->pipe->device->bus;
+ /*struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;*/
+
+ DPRINTFN(10,("ehci_ctrl_done: xfer=%p\n", xfer));
+
+#ifdef DIAGNOSTIC
+ if (!(xfer->rqflags & URQ_REQUEST)) {
+ panic("ehci_ctrl_done: not a request\n");
+ }
+#endif
+
+ if (xfer->status != USBD_NOMEM) {
+ ehci_del_intr_list(ex); /* remove from active list */
+ ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL);
+ }
+
+ DPRINTFN(5, ("ehci_ctrl_done: length=%d\n", xfer->actlen));
+}
+
+/* Abort a device control request. */
+Static void
+ehci_device_ctrl_abort(usbd_xfer_handle xfer)
+{
+ DPRINTF(("ehci_device_ctrl_abort: xfer=%p\n", xfer));
+ ehci_abort_xfer(xfer, USBD_CANCELLED);
+}
+
+/* Close a device control pipe. */
+Static void
+ehci_device_ctrl_close(usbd_pipe_handle pipe)
+{
+ ehci_softc_t *sc = (ehci_softc_t *)pipe->device->bus;
+ /*struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;*/
+
+ DPRINTF(("ehci_device_ctrl_close: pipe=%p\n", pipe));
+ ehci_close_pipe(pipe, sc->sc_async_head);
+}
+
+usbd_status
+ehci_device_request(usbd_xfer_handle xfer)
+{
+#define exfer EXFER(xfer)
+ struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
+ usb_device_request_t *req = &xfer->request;
+ usbd_device_handle dev = epipe->pipe.device;
+ ehci_softc_t *sc = (ehci_softc_t *)dev->bus;
+ int addr = dev->address;
+ ehci_soft_qtd_t *setup, *stat, *next;
+ ehci_soft_qh_t *sqh;
+ int isread;
+ int len;
+ usbd_status err;
+ int s;
+
+ isread = req->bmRequestType & UT_READ;
+ len = UGETW(req->wLength);
+
+ DPRINTFN(3,("ehci_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,
+ epipe->pipe.endpoint->edesc->bEndpointAddress));
+
+ setup = ehci_alloc_sqtd(sc);
+ if (setup == NULL) {
+ err = USBD_NOMEM;
+ goto bad1;
+ }
+ stat = ehci_alloc_sqtd(sc);
+ if (stat == NULL) {
+ err = USBD_NOMEM;
+ goto bad2;
+ }
+
+ sqh = epipe->sqh;
+ epipe->u.ctl.length = len;
+
+ /* XXX
+ * Since we're messing with the QH we must know the HC is in sync.
+ * This needs to go away since it slows down control transfers.
+ * Removing it entails:
+ * - fill the QH only once with addr & wMaxPacketSize
+ * - put the correct data toggles in the qtds and set DTC
+ */
+ /* ehci_sync_hc(sc); */
+ /* 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. */
+ /* XXXX Should not touch ED here! */
+ sqh->qh.qh_endp =
+ (sqh->qh.qh_endp & htole32(~(EHCI_QH_ADDRMASK | EHCI_QG_MPLMASK))) |
+ htole32(
+ EHCI_QH_SET_ADDR(addr) |
+ /* EHCI_QH_DTC | */
+ EHCI_QH_SET_MPL(UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize))
+ );
+ /* Clear toggle */
+ sqh->qh.qh_qtd.qtd_status &= htole32(~EHCI_QTD_TOGGLE);
+
+ /* Set up data transaction */
+ if (len != 0) {
+ ehci_soft_qtd_t *end;
+
+ err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer,
+ &next, &end);
+ if (err)
+ goto bad3;
+ end->nextqtd = stat;
+ end->qtd.qtd_next =
+ end->qtd.qtd_altnext = htole32(stat->physaddr);
+ /* Start toggle at 1. */
+ /*next->qtd.td_flags |= htole32(EHCI_QTD_TOGGLE);*/
+ } else {
+ next = stat;
+ }
+
+ memcpy(KERNADDR(&epipe->u.ctl.reqdma), req, sizeof *req);
+
+ setup->qtd.qtd_status = htole32(
+ EHCI_QTD_ACTIVE |
+ EHCI_QTD_SET_PID(EHCI_QTD_PID_SETUP) |
+ EHCI_QTD_SET_CERR(3) |
+ EHCI_QTD_SET_BYTES(sizeof *req)
+ );
+ setup->qtd.qtd_buffer[0] = htole32(DMAADDR(&epipe->u.ctl.reqdma));
+ setup->nextqtd = next;
+ setup->qtd.qtd_next = setup->qtd.qtd_altnext = htole32(next->physaddr);
+ setup->xfer = xfer;
+ setup->len = sizeof *req;
+
+ stat->qtd.qtd_status = htole32(
+ EHCI_QTD_ACTIVE |
+ EHCI_QTD_SET_PID(isread ? EHCI_QTD_PID_OUT : EHCI_QTD_PID_IN) |
+ EHCI_QTD_SET_CERR(3) |
+ EHCI_QTD_IOC
+ );
+ stat->qtd.qtd_buffer[0] = 0; /* XXX not needed? */
+ stat->nextqtd = NULL;
+ stat->qtd.qtd_next = stat->qtd.qtd_altnext = EHCI_NULL;
+ stat->xfer = xfer;
+ stat->len = 0;
+
+#ifdef EHCI_DEBUG
+ if (ehcidebug > 5) {
+ DPRINTF(("ehci_device_request:\n"));
+ ehci_dump_sqh(sqh);
+ ehci_dump_sqtds(setup);
+ }
+#endif
+
+ exfer->sqtdstart = setup;
+ exfer->sqtdend = stat;
+#ifdef DIAGNOSTIC
+ if (!exfer->isdone) {
+ printf("ehci_device_request: not done, exfer=%p\n", exfer);
+ }
+ exfer->isdone = 0;
+#endif
+
+ /* Insert qTD in QH list. */
+ s = splusb();
+ ehci_set_qh_qtd(sqh, setup);
+ if (xfer->timeout && !sc->sc_bus.use_polling) {
+ usb_callout(xfer->timeout_handle, MS_TO_TICKS(xfer->timeout),
+ ehci_timeout, xfer);
+ }
+ ehci_add_intr_list(sc, exfer);
+ xfer->status = USBD_IN_PROGRESS;
+ splx(s);
+
+#ifdef EHCI_DEBUG
+ if (ehcidebug > 10) {
+ DPRINTF(("ehci_device_request: status=%x\n",
+ EOREAD4(sc, EHCI_USBSTS)));
+ delay(10000);
+ ehci_dump_regs(sc);
+ ehci_dump_sqh(sc->sc_async_head);
+ ehci_dump_sqh(sqh);
+ ehci_dump_sqtds(setup);
+ }
+#endif
+
+ return (USBD_NORMAL_COMPLETION);
+
+ bad3:
+ ehci_free_sqtd(sc, stat);
+ bad2:
+ ehci_free_sqtd(sc, setup);
+ bad1:
+ DPRINTFN(-1,("ehci_device_request: no memory\n"));
+ xfer->status = err;
+ usb_transfer_complete(xfer);
+ return (err);
+#undef exfer
+}
+
+/************************/
+
+Static usbd_status
+ehci_device_bulk_transfer(usbd_xfer_handle xfer)
+{
+ usbd_status err;
+
+ /* Insert last in queue. */
+ err = usb_insert_transfer(xfer);
+ if (err)
+ return (err);
+
+ /* Pipe isn't running, start first */
+ return (ehci_device_bulk_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
+}
+
+usbd_status
+ehci_device_bulk_start(usbd_xfer_handle xfer)
+{
+#define exfer EXFER(xfer)
+ struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
+ usbd_device_handle dev = epipe->pipe.device;
+ ehci_softc_t *sc = (ehci_softc_t *)dev->bus;
+ ehci_soft_qtd_t *data, *dataend;
+ ehci_soft_qh_t *sqh;
+ usbd_status err;
+ int len, isread, endpt;
+ int s;
+
+ DPRINTFN(2, ("ehci_device_bulk_transfer: xfer=%p len=%d flags=%d\n",
+ xfer, xfer->length, xfer->flags));
+
+ if (sc->sc_dying)
+ return (USBD_IOERROR);
+
+#ifdef DIAGNOSTIC
+ if (xfer->rqflags & URQ_REQUEST)
+ panic("ehci_device_bulk_transfer: a request\n");
+#endif
+
+ len = xfer->length;
+ endpt = epipe->pipe.endpoint->edesc->bEndpointAddress;
+ isread = UE_GET_DIR(endpt) == UE_DIR_IN;
+ sqh = epipe->sqh;
+
+ epipe->u.bulk.length = len;
+
+ err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer, &data,
+ &dataend);
+ if (err) {
+ DPRINTFN(-1,("ehci_device_bulk_transfer: no memory\n"));
+ xfer->status = err;
+ usb_transfer_complete(xfer);
+ return (err);
+ }
+
+#ifdef EHCI_DEBUG
+ if (ehcidebug > 5) {
+ DPRINTF(("ehci_device_bulk_transfer: data(1)\n"));
+ ehci_dump_sqh(sqh);
+ ehci_dump_sqtds(data);
+ }
+#endif
+
+ /* Set up interrupt info. */
+ exfer->sqtdstart = data;
+ exfer->sqtdend = dataend;
+#ifdef DIAGNOSTIC
+ if (!exfer->isdone) {
+ printf("ehci_device_bulk_transfer: not done, ex=%p\n", exfer);
+ }
+ exfer->isdone = 0;
+#endif
+
+ s = splusb();
+ ehci_set_qh_qtd(sqh, data);
+ if (xfer->timeout && !sc->sc_bus.use_polling) {
+ usb_callout(xfer->timeout_handle, MS_TO_TICKS(xfer->timeout),
+ ehci_timeout, xfer);
+ }
+ ehci_add_intr_list(sc, exfer);
+ xfer->status = USBD_IN_PROGRESS;
+ splx(s);
+
+#ifdef EHCI_DEBUG
+ if (ehcidebug > 10) {
+ DPRINTF(("ehci_device_bulk_transfer: data(2)\n"));
+ delay(10000);
+ DPRINTF(("ehci_device_bulk_transfer: data(3)\n"));
+ ehci_dump_regs(sc);
+#if 0
+ printf("async_head:\n");
+ ehci_dump_sqh(sc->sc_async_head);
+#endif
+ printf("sqh:\n");
+ ehci_dump_sqh(sqh);
+ ehci_dump_sqtds(data);
+ }
+#endif
+
+ if (sc->sc_bus.use_polling)
+ ehci_waitintr(sc, xfer);
+
+ return (USBD_IN_PROGRESS);
+#undef exfer
+}
+
+Static void
+ehci_device_bulk_abort(usbd_xfer_handle xfer)
+{
+ DPRINTF(("ehci_device_bulk_abort: xfer=%p\n", xfer));
+ ehci_abort_xfer(xfer, USBD_CANCELLED);
+}
+
+/*
+ * Close a device bulk pipe.
+ */
+Static void
+ehci_device_bulk_close(usbd_pipe_handle pipe)
+{
+ ehci_softc_t *sc = (ehci_softc_t *)pipe->device->bus;
+
+ DPRINTF(("ehci_device_bulk_close: pipe=%p\n", pipe));
+ ehci_close_pipe(pipe, sc->sc_async_head);
+}
+
+void
+ehci_device_bulk_done(usbd_xfer_handle xfer)
+{
+ struct ehci_xfer *ex = EXFER(xfer);
+ ehci_softc_t *sc = (ehci_softc_t *)xfer->pipe->device->bus;
+ /*struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;*/
+
+ DPRINTFN(10,("ehci_bulk_done: xfer=%p, actlen=%d\n",
+ xfer, xfer->actlen));
+
+ if (xfer->status != USBD_NOMEM) {
+ ehci_del_intr_list(ex); /* remove from active list */
+ ehci_free_sqtd_chain(sc, ex->sqtdstart, 0);
+ }
+
+ DPRINTFN(5, ("ehci_bulk_done: length=%d\n", xfer->actlen));
+}
+
+/************************/
+
+Static usbd_status ehci_device_intr_transfer(usbd_xfer_handle xfer) { return USBD_IOERROR; }
+Static usbd_status ehci_device_intr_start(usbd_xfer_handle xfer) { return USBD_IOERROR; }
+Static void ehci_device_intr_abort(usbd_xfer_handle xfer) { }
+Static void ehci_device_intr_close(usbd_pipe_handle pipe) { }
+Static void ehci_device_intr_done(usbd_xfer_handle xfer) { }
+
+/************************/
+
+Static usbd_status ehci_device_isoc_transfer(usbd_xfer_handle xfer) { return USBD_IOERROR; }
+Static usbd_status ehci_device_isoc_start(usbd_xfer_handle xfer) { return USBD_IOERROR; }
+Static void ehci_device_isoc_abort(usbd_xfer_handle xfer) { }
+Static void ehci_device_isoc_close(usbd_pipe_handle pipe) { }
+Static void ehci_device_isoc_done(usbd_xfer_handle xfer) { }
diff --git a/sys/dev/usb/ehcireg.h b/sys/dev/usb/ehcireg.h
new file mode 100644
index 00000000000..341644210b1
--- /dev/null
+++ b/sys/dev/usb/ehcireg.h
@@ -0,0 +1,288 @@
+/* $OpenBSD: ehcireg.h,v 1.1 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: ehcireg.h,v 1.13 2001/11/23 01:16:27 augustss Exp $ */
+
+/*
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (lennart@augustsson.net).
+ *
+ * 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.
+ */
+
+/*
+ * The EHCI 0.96 spec can be found at
+ * http://developer.intel.com/technology/usb/download/ehci-r096.pdf
+ * and the USB 2.0 spec at
+ * http://www.usb.org/developers/data/usb_20.zip
+ */
+
+#ifndef _DEV_PCI_EHCIREG_H_
+#define _DEV_PCI_EHCIREG_H_
+
+/*** PCI config registers ***/
+
+#define PCI_CBMEM 0x10 /* configuration base MEM */
+
+#define PCI_INTERFACE_EHCI 0x20
+
+#define PCI_USBREV 0x60 /* RO USB protocol revision */
+#define PCI_USBREV_MASK 0xff
+#define PCI_USBREV_PRE_1_0 0x00
+#define PCI_USBREV_1_0 0x10
+#define PCI_USBREV_1_1 0x11
+#define PCI_USBREV_2_0 0x20
+
+#define PCI_EHCI_FLADJ 0x61 /*RW Frame len adj, SOF=59488+6*fladj */
+
+#define PCI_EHCI_PORTWAKECAP 0x62 /* RW Port wake caps (opt) */
+
+/* Regs ar EECP + offset */
+#define PCI_EHCI_USBLEGSUP 0x00
+#define PCI_EHCI_USBLEGCTLSTS 0x04
+
+/*** EHCI capability registers ***/
+
+#define EHCI_CAPLENGTH 0x00 /*RO Capability register length field */
+/* reserved 0x01 */
+#define EHCI_HCIVERSION 0x02 /* RO Interface version number */
+
+#define EHCI_HCSPARAMS 0x04 /* RO Structural parameters */
+#define EHCI_HCS_DEBUGPORT(x) (((x) >> 20) & 0xf)
+#define EHCI_HCS_P_INCICATOR(x) ((x) & 0x10000)
+#define EHCI_HCS_N_CC(x) (((x) >> 12) & 0xf) /* # of companion ctlrs */
+#define EHCI_HCS_N_PCC(x) (((x) >> 8) & 0xf) /* # of ports per comp. */
+#define EHCI_HCS_PPC(x) ((x) & 0x10) /* port power control */
+#define EHCI_HCS_N_PORTS(x) ((x) & 0xf) /* # of ports */
+
+#define EHCI_HCCPARAMS 0x08 /* RO Capability parameters */
+#define EHCI_HCC_EECP(x) (((x) >> 8) & 0xff) /* extended ports caps */
+#define EHCI_HCC_IST(x) (((x) >> 4) & 0xf) /* isoc sched threshold */
+#define EHCI_HCC_ASPC(x) ((x) & 0x4) /* async sched park cap */
+#define EHCI_HCC_PFLF(x) ((x) & 0x2) /* prog frame list flag */
+#define EHCI_HCC_64BIT(x) ((x) & 0x1) /* 64 bit address cap */
+
+#define EHCI_HCSP_PORTROUTE 0x0c /*RO Companion port route description */
+
+/* EHCI operational registers. Offset given by EHCI_CAPLENGTH register */
+#define EHCI_USBCMD 0x00 /* RO, RW, WO Command register */
+#define EHCI_CMD_ITC_M 0x00ff0000 /* RW interrupt threshold ctrl */
+#define EHCI_CMD_ITC_1 0x00010000
+#define EHCI_CMD_ITC_2 0x00020000
+#define EHCI_CMD_ITC_4 0x00040000
+#define EHCI_CMD_ITC_8 0x00080000
+#define EHCI_CMD_ITC_16 0x00100000
+#define EHCI_CMD_ITC_32 0x00200000
+#define EHCI_CMD_ITC_64 0x00400000
+#define EHCI_CMD_ASPME 0x00000800 /* RW/RO async park enable */
+#define EHCI_CMD_ASPMC 0x00000300 /* RW/RO async park count */
+#define EHCI_CMD_LHCR 0x00000080 /* RW light host ctrl reset */
+#define EHCI_CMD_IAAD 0x00000040 /* RW intr on async adv door bell */
+#define EHCI_CMD_ASE 0x00000020 /* RW async sched enable */
+#define EHCI_CMD_PSE 0x00000010 /* RW periodic sched enable */
+#define EHCI_CMD_FLS_M 0x0000000c /* RW/RO frame list size */
+#define EHCI_CMD_FLS(x) (((x) >> 2) & 3) /* RW/RO frame list size */
+#define EHCI_CMD_HCRESET 0x00000002 /* RW reset */
+#define EHCI_CMD_RS 0x00000001 /* RW run/stop */
+
+#define EHCI_USBSTS 0x04 /* RO, RW, RWC Status register */
+#define EHCI_STS_ASS 0x00008000 /* RO async sched status */
+#define EHCI_STS_PSS 0x00004000 /* RO periodic sched status */
+#define EHCI_STS_REC 0x00002000 /* RO reclamation */
+#define EHCI_STS_HCH 0x00001000 /* RO host controller halted */
+#define EHCI_STS_IAA 0x00000020 /* RWC interrupt on async adv */
+#define EHCI_STS_HSE 0x00000010 /* RWC host system error */
+#define EHCI_STS_FLR 0x00000008 /* RWC frame list rollover */
+#define EHCI_STS_PCD 0x00000004 /* RWC port change detect */
+#define EHCI_STS_ERRINT 0x00000002 /* RWC error interrupt */
+#define EHCI_STS_INT 0x00000001 /* RWC interrupt */
+#define EHCI_STS_INTRS(x) ((x) & 0x3f)
+
+#define EHCI_NORMAL_INTRS (EHCI_STS_IAA | EHCI_STS_HSE | EHCI_STS_PCD | EHCI_STS_ERRINT | EHCI_STS_INT)
+
+#define EHCI_USBINTR 0x08 /* RW Interrupt register */
+#define EHCI_INTR_IAAE 0x00000020 /* interrupt on async advance ena */
+#define EHCI_INTR_HSEE 0x00000010 /* host system error ena */
+#define EHCI_INTR_FLRE 0x00000008 /* frame list rollover ena */
+#define EHCI_INTR_PCIE 0x00000004 /* port change ena */
+#define EHCI_INTR_UEIE 0x00000002 /* USB error intr ena */
+#define EHCI_INTR_UIE 0x00000001 /* USB intr ena */
+
+#define EHCI_FRINDEX 0x0c /* RW Frame Index register */
+
+#define EHCI_CTRLDSSEGMENT 0x10 /* RW Control Data Structure Segment */
+
+#define EHCI_PERIODICLISTBASE 0x14 /* RW Periodic List Base */
+#define EHCI_ASYNCLISTADDR 0x18 /* RW Async List Base */
+
+#define EHCI_CONFIGFLAG 0x40 /* RW Configure Flag register */
+#define EHCI_CONF_CF 0x00000001 /* RW configure flag */
+
+#define EHCI_PORTSC(n) (0x40+4*(n)) /* RO, RW, RWC Port Status reg */
+#define EHCI_PS_WKOC_E 0x00400000 /* RW wake on over current ena */
+#define EHCI_PS_WKDSCNNT_E 0x00200000 /* RW wake on disconnect ena */
+#define EHCI_PS_WKCNNT_E 0x00100000 /* RW wake on connect ena */
+#define EHCI_PS_PTC 0x000f0000 /* RW port test control */
+#define EHCI_PS_PIC 0x0000c000 /* RW port indicator control */
+#define EHCI_PS_PO 0x00002000 /* RW port owner */
+#define EHCI_PS_PP 0x00001000 /* RW,RO port power */
+#define EHCI_PS_LS 0x00000c00 /* RO line status */
+#define EHCI_PS_IS_LOWSPEED(x) (((x) & EHCI_PS_LS) == 0x00000400)
+#define EHCI_PS_PR 0x00000100 /* RW port reset */
+#define EHCI_PS_SUSP 0x00000080 /* RW suspend */
+#define EHCI_PS_FPR 0x00000040 /* RW force port resume */
+#define EHCI_PS_OCC 0x00000020 /* RWC over current change */
+#define EHCI_PS_OCA 0x00000010 /* RO over current active */
+#define EHCI_PS_PEC 0x00000008 /* RWC port enable change */
+#define EHCI_PS_PE 0x00000004 /* RW port enable */
+#define EHCI_PS_CSC 0x00000002 /* RWC connect status change */
+#define EHCI_PS_CS 0x00000001 /* RO connect status */
+#define EHCI_PS_CLEAR (EHCI_PS_OCC|EHCI_PS_PEC|EHCI_PS_CSC)
+
+#define EHCI_PORT_RESET_COMPLETE 2 /* ms */
+
+#define EHCI_FLALIGN_ALIGN 0x1000
+
+/* No data structure may cross a page boundary. */
+#define EHCI_PAGE_SIZE 0x1000
+#define EHCI_PAGE(x) ((x) &~ 0xfff)
+#define EHCI_PAGE_OFFSET(x) ((x) & 0xfff)
+
+typedef u_int32_t ehci_link_t;
+#define EHCI_LINK_TERMINATE 0x00000001
+#define EHCI_LINK_TYPE(x) ((x) & 0x00000006)
+#define EHCI_LINK_ITD 0x0
+#define EHCI_LINK_QH 0x2
+#define EHCI_LINK_SITD 0x4
+#define EHCI_LINK_FSTN 0x6
+#define EHCI_LINK_ADDR(x) ((x) &~ 0x1f)
+
+typedef u_int32_t ehci_physaddr_t;
+
+/* Isochronous Transfer Descriptor */
+typedef struct {
+ ehci_link_t itd_next;
+ /* XXX many more */
+} ehci_itd_t;
+#define EHCI_ITD_ALIGN 32
+
+/* Split Transaction Isochronous Transfer Descriptor */
+typedef struct {
+ ehci_link_t sitd_next;
+ /* XXX many more */
+} ehci_sitd_t;
+#define EHCI_SITD_ALIGN 32
+
+/* Queue Element Transfer Descriptor */
+#define EHCI_QTD_NBUFFERS 5
+typedef struct {
+ ehci_link_t qtd_next;
+ ehci_link_t qtd_altnext;
+ u_int32_t qtd_status;
+#define EHCI_QTD_GET_STATUS(x) (((x) >> 0) & 0xff)
+#define EHCI_QTD_ACTIVE 0x80
+#define EHCI_QTD_HALTED 0x40
+#define EHCI_QTD_BUFERR 0x20
+#define EHCI_QTD_BABBLE 0x10
+#define EHCI_QTD_XACTERR 0x08
+#define EHCI_QTD_MISSEDMICRO 0x04
+#define EHCI_QTD_SPLITXSTATE 0x02
+#define EHCI_QTD_PINGSTATE 0x01
+#define EHCI_QTD_STATERRS 0x7c
+#define EHCI_QTD_GET_PID(x) (((x) >> 8) & 0x3)
+#define EHCI_QTD_SET_PID(x) ((x) << 8)
+#define EHCI_QTD_PID_OUT 0x0
+#define EHCI_QTD_PID_IN 0x1
+#define EHCI_QTD_PID_SETUP 0x2
+#define EHCI_QTD_GET_CERR(x) (((x) >> 10) & 0x3)
+#define EHCI_QTD_SET_CERR(x) ((x) << 10)
+#define EHCI_QTD_GET_C_PAGE(x) (((x) >> 12) & 0x7)
+#define EHCI_QTD_SET_C_PAGE(x) ((x) << 12)
+#define EHCI_QTD_GET_IOC(x) (((x) >> 15) & 0x1)
+#define EHCI_QTD_IOC 0x00008000
+#define EHCI_QTD_GET_BYTES(x) (((x) >> 16) & 0x7fff)
+#define EHCI_QTD_SET_BYTES(x) ((x) << 16)
+#define EHCI_QTD_GET_TOGGLE(x) (((x) >> 31) & 0x1)
+#define EHCI_QTD_TOGGLE 0x80000000
+ ehci_physaddr_t qtd_buffer[EHCI_QTD_NBUFFERS];
+} ehci_qtd_t;
+#define EHCI_QTD_ALIGN 32
+
+/* Queue Head */
+typedef struct {
+ ehci_link_t qh_link;
+ u_int32_t qh_endp;
+#define EHCI_QH_GET_ADDR(x) (((x) >> 0) & 0x7f) /* endpoint addr */
+#define EHCI_QH_SET_ADDR(x) (x)
+#define EHCI_QH_ADDRMASK 0x0000007f
+#define EHCI_QH_GET_INACT(x) (((x) >> 7) & 0x01) /* inactivate on next */
+#define EHCI_QH_INACT 0x00000080
+#define EHCI_QH_GET_ENDPT(x) (((x) >> 8) & 0x0f) /* endpoint no */
+#define EHCI_QH_SET_ENDPT(x) ((x) << 8)
+#define EHCI_QH_GET_EPS(x) (((x) >> 12) & 0x03) /* endpoint speed */
+#define EHCI_QH_SET_EPS(x) ((x) << 12)
+#define EHCI_QH_SPEED_FULL 0x0
+#define EHCI_QH_SPEED_LOW 0x1
+#define EHCI_QH_SPEED_HIGH 0x2
+#define EHCI_QH_GET_DTC(x) (((x) >> 14) & 0x01) /* data toggle control */
+#define EHCI_QH_DTC 0x00004000
+#define EHCI_QH_GET_HRECL(x) (((x) >> 15) & 0x01) /* head of reclamation */
+#define EHCI_QH_HRECL 0x00008000
+#define EHCI_QH_GET_MPL(x) (((x) >> 16) & 0x7ff) /* max packet len */
+#define EHCI_QH_SET_MPL(x) ((x) << 16)
+#define EHCI_QG_MPLMASK 0x07ff0000
+#define EHCI_QH_GET_CTL(x) (((x) >> 26) & 0x01) /* control endpoint */
+#define EHCI_QH_CTL 0x08000000
+#define EHCI_QH_GET_NRL(x) (((x) >> 28) & 0x0f) /* NAK reload */
+#define EHCI_QH_SET_NRL(x) ((x) << 28)
+ u_int32_t qh_endphub;
+#define EHCI_QH_GET_SMASK(x) (((x) >> 0) & 0xff) /* intr sched mask */
+#define EHCI_QH_SET_SMASK(x) ((x) << 0)
+#define EHCI_QH_GET_CMASK(x) (((x) >> 8) & 0xff) /* split completion mask */
+#define EHCI_QH_SET_CMASK(x) ((x) << 8)
+#define EHCI_QH_GET_HUBA(x) (((x) >> 16) & 0x7f) /* hub address */
+#define EHCI_QH_SET_HUBA(x) ((x) << 16)
+#define EHCI_QH_GET_PORT(x) (((x) >> 23) & 0x7f) /* hub port */
+#define EHCI_QH_SET_PORT(x) ((x) << 23)
+#define EHCI_QH_GET_MULT(x) (((x) >> 30) & 0x03) /* pipe multiplier */
+#define EHCI_QH_SET_MULT(x) ((x) << 30)
+ ehci_link_t qh_curqtd;
+ ehci_qtd_t qh_qtd;
+} ehci_qh_t;
+#define EHCI_QH_ALIGN 32
+
+/* Periodic Frame Span Traversal Node */
+typedef struct {
+ ehci_link_t fstn_link;
+ ehci_link_t fstn_back;
+} ehci_fstn_t;
+#define EHCI_FSTN_ALIGN 32
+
+#endif /* _DEV_PCI_EHCIREG_H_ */
diff --git a/sys/dev/usb/ehcivar.h b/sys/dev/usb/ehcivar.h
new file mode 100644
index 00000000000..1aa7c866580
--- /dev/null
+++ b/sys/dev/usb/ehcivar.h
@@ -0,0 +1,138 @@
+/* $OpenBSD: ehcivar.h,v 1.1 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: ehcivar.h,v 1.12 2001/12/31 12:16:57 augustss Exp $ */
+
+/*
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (lennart@augustsson.net).
+ *
+ * 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.
+ */
+
+typedef struct ehci_soft_qtd {
+ ehci_qtd_t qtd;
+ struct ehci_soft_qtd *nextqtd; /* mirrors nextqtd in TD */
+ ehci_physaddr_t physaddr;
+ usbd_xfer_handle xfer;
+ LIST_ENTRY(ehci_soft_qtd) hnext;
+ u_int16_t len;
+} ehci_soft_qtd_t;
+#define EHCI_SQTD_SIZE ((sizeof (struct ehci_soft_qtd) + EHCI_QTD_ALIGN - 1) / EHCI_QTD_ALIGN * EHCI_QTD_ALIGN)
+#define EHCI_SQTD_CHUNK (EHCI_PAGE_SIZE / EHCI_SQTD_SIZE)
+
+typedef struct ehci_soft_qh {
+ ehci_qh_t qh;
+ struct ehci_soft_qh *next;
+ struct ehci_soft_qtd *sqtd;
+ ehci_physaddr_t physaddr;
+} ehci_soft_qh_t;
+#define EHCI_SQH_SIZE ((sizeof (struct ehci_soft_qh) + EHCI_QH_ALIGN - 1) / EHCI_QH_ALIGN * EHCI_QH_ALIGN)
+#define EHCI_SQH_CHUNK (EHCI_PAGE_SIZE / EHCI_SQH_SIZE)
+
+struct ehci_xfer {
+ struct usbd_xfer xfer;
+ struct usb_task abort_task;
+ LIST_ENTRY(ehci_xfer) inext; /* list of active xfers */
+ ehci_soft_qtd_t *sqtdstart;
+ ehci_soft_qtd_t *sqtdend;
+#ifdef DIAGNOSTIC
+ int isdone;
+#endif
+};
+#define EXFER(xfer) ((struct ehci_xfer *)(xfer))
+
+
+#define EHCI_HASH_SIZE 128
+#define EHCI_COMPANION_MAX 8
+
+typedef struct ehci_softc {
+ struct usbd_bus sc_bus; /* base device */
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ bus_size_t sc_size;
+ u_int sc_offs; /* offset to operational regs */
+
+ char sc_vendor[16]; /* vendor string for root hub */
+ int sc_id_vendor; /* vendor ID for root hub */
+
+ void *sc_powerhook; /* cookie from power hook */
+ void *sc_shutdownhook; /* cookie from shutdown hook */
+
+ u_int sc_ncomp;
+ u_int sc_npcomp;
+ struct usbd_bus *sc_comps[EHCI_COMPANION_MAX];
+
+ usb_dma_t sc_fldma;
+ u_int sc_flsize;
+
+ LIST_HEAD(, ehci_xfer) sc_intrhead;
+
+ ehci_soft_qh_t *sc_freeqhs;
+ ehci_soft_qtd_t *sc_freeqtds;
+
+ int sc_noport;
+ u_int8_t sc_addr; /* device address */
+ u_int8_t sc_conf; /* device configuration */
+ usbd_xfer_handle sc_intrxfer;
+ char sc_isreset;
+ char sc_softwake;
+
+ u_int32_t sc_eintrs;
+ ehci_soft_qh_t *sc_async_head;
+
+ SIMPLEQ_HEAD(, usbd_xfer) sc_free_xfers; /* free xfers */
+
+ struct lock sc_doorbell_lock;
+
+ usb_callout_t sc_tmo_pcd;
+
+ device_ptr_t sc_child; /* /dev/usb# device */
+
+ char sc_dying;
+} ehci_softc_t;
+
+#define EREAD1(sc, a) bus_space_read_1((sc)->iot, (sc)->ioh, (a))
+#define EREAD2(sc, a) bus_space_read_2((sc)->iot, (sc)->ioh, (a))
+#define EREAD4(sc, a) bus_space_read_4((sc)->iot, (sc)->ioh, (a))
+#define EWRITE1(sc, a, x) bus_space_write_1((sc)->iot, (sc)->ioh, (a), (x))
+#define EWRITE2(sc, a, x) bus_space_write_2((sc)->iot, (sc)->ioh, (a), (x))
+#define EWRITE4(sc, a, x) bus_space_write_4((sc)->iot, (sc)->ioh, (a), (x))
+#define EOREAD1(sc, a) bus_space_read_1((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a))
+#define EOREAD2(sc, a) bus_space_read_2((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a))
+#define EOREAD4(sc, a) bus_space_read_4((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a))
+#define EOWRITE1(sc, a, x) bus_space_write_1((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a), (x))
+#define EOWRITE2(sc, a, x) bus_space_write_2((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a), (x))
+#define EOWRITE4(sc, a, x) bus_space_write_4((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a), (x))
+
+usbd_status ehci_init(ehci_softc_t *);
+int ehci_intr(void *);
+int ehci_detach(ehci_softc_t *, int);
+int ehci_activate(device_ptr_t, enum devact);
diff --git a/sys/dev/usb/files.usb b/sys/dev/usb/files.usb
index c3132ad709b..77fa22bf4ab 100644
--- a/sys/dev/usb/files.usb
+++ b/sys/dev/usb/files.usb
@@ -1,5 +1,5 @@
-# $OpenBSD: files.usb,v 1.21 2001/10/02 01:37:36 millert Exp $
-# $NetBSD: files.usb,v 1.16 2000/02/14 20:29:54 augustss Exp $
+# $OpenBSD: files.usb,v 1.22 2002/05/07 18:08:04 nate Exp $
+# $NetBSD: files.usb,v 1.38 2002/01/02 03:21:36 augustss Exp $
#
# Config file and device description for machine-independent USB code.
# Included by ports that need it. Ports that use it must provide
@@ -7,8 +7,7 @@
device usb { }
attach usb at usbus
-file dev/usb/hid.c usb
-file dev/usb/usb.c usb needs-flag
+file dev/usb/usb.c usb needs-flag
file dev/usb/usbdi.c usb
file dev/usb/usbdi_util.c usb
file dev/usb/usb_mem.c usb
@@ -35,62 +34,91 @@ device uaudio: audio, auconv, mulaw
attach uaudio at uhub
file dev/usb/uaudio.c uaudio
+# MIDI devices
+device umidi: midibus
+attach umidi at uhub
+file dev/usb/umidi.c umidi
+file dev/usb/umidi_quirks.c umidi
+
# Modem and com serial port
device ucom
attach ucom at ucombus
-file dev/usb/ucom.c ucom | ucombus needs-flag
+file dev/usb/ucom.c ucom | ucombus needs-flag
+
# Generic devices
device ugen
attach ugen at uhub
-file dev/usb/ugen.c ugen needs-flag
+file dev/usb/ugen.c ugen needs-flag
+
+
+# HID
+# HID "bus"
+define uhidbus {[ reportid = -1 ]}
+
+# HID processing
+define hid
+file dev/usb/hid.c hid
+
+# HID root device for multiple report IDs
+device uhidev: hid, uhidbus
+attach uhidev at uhub
+file dev/usb/uhidev.c uhidev
# Generic HID devices
-device uhid
-attach uhid at uhub
-file dev/usb/uhid.c uhid needs-flag
+device uhid: hid
+attach uhid at uhidbus
+file dev/usb/uhid.c uhid needs-flag
# Keyboards
-device ukbd: wskbddev
-attach ukbd at uhub
-file dev/usb/ukbd.c ukbd needs-flag
-file dev/usb/ukbdmap.c ukbd
+device ukbd: hid, wskbddev
+attach ukbd at uhidbus
+file dev/usb/ukbd.c ukbd needs-flag
+file dev/usb/ukbdmap.c ukbd
+
+# Mice
+device ums: hid, wsmousedev
+attach ums at uhidbus
+file dev/usb/ums.c ums
+
# Printers
device ulpt
attach ulpt at uhub
-file dev/usb/ulpt.c ulpt needs-flag
+file dev/usb/ulpt.c ulpt needs-flag
+
# Mass storage
-device umass: scsi, atapi
+device umass: scsi, atapi, ata
attach umass at uhub
file dev/usb/umass.c umass
+#file dev/usb/umass_isdata.c umass & wd
+file dev/usb/umass_quirks.c umass
+file dev/usb/umass_scsi.c umass & (scsibus | atapiscsi)
-# Modems
-device umodem: ucombus
-attach umodem at uhub
-file dev/usb/umodem.c umodem
-
-# Mice
-device ums: wsmousedev
-attach ums at uhub
-file dev/usb/ums.c ums
+# Misc
# Diamond Multimedia Rio 500
device urio
attach urio at uhub
-file dev/usb/urio.c urio needs-flag
+file dev/usb/urio.c urio needs-flag
# Handspring Visor
device uvisor: ucombus
attach uvisor at uhub
file dev/usb/uvisor.c uvisor
-# YAP firmware loader
+# YAP phone firmware loader
device uyap: ezload
attach uyap at uhub
file dev/usb/uyap.c uyap
+# D-Link DSB-R100 FM radio
+device udsbr: radio
+attach udsbr at uhub
+file dev/usb/udsbr.c udsbr
+
+
# Ethernet adapters
# ADMtek AN986 Pegasus
device aue: ether, ifnet, mii, ifmedia
@@ -108,25 +136,48 @@ attach kue at uhub
file dev/usb/if_kue.c kue
# Prolific PL2302 host-host
-device upl: ifnet
+device upl: ether, ifnet, ifmedia
attach upl at uhub
file dev/usb/if_upl.c upl
+# Realtek RTL8150L(M)
+device url: ether, ifnet, mii
+attach url at uhub
+file dev/usb/if_url.c url
+
+
# Serial drivers
+# Modems
+device umodem: ucombus
+attach umodem at uhub
+file dev/usb/umodem.c umodem
+
# FTDI serial driver
device uftdi: ucombus
attach uftdi at uhub
file dev/usb/uftdi.c uftdi
# Prolific PL2303 serial driver
-device uplcom: ucombus
-attach uplcom at uhub
-file dev/usb/uplcom.c uplcom
+device uplcom: ucombus
+attach uplcom at uhub
+file dev/usb/uplcom.c uplcom
+
+# MCT USB-232 serial driver
+device umct: ucombus
+attach umct at uhub
+file dev/usb/umct.c umct
+
+# SUNTAC Slipper U VS-10U driver
+device uvscom: ucombus
+attach uvscom at uhub
+file dev/usb/uvscom.c uvscom
+
# Scanners
+# Generic scanner support
device uscanner
attach uscanner at uhub
-file dev/usb/uscanner.c uscanner needs-flag
+file dev/usb/uscanner.c uscanner needs-flag
# Avision SCSI over USB, HP5300
device usscanner: scsi
diff --git a/sys/dev/usb/hid.c b/sys/dev/usb/hid.c
index dcd656415cc..2a8a91a35cb 100644
--- a/sys/dev/usb/hid.c
+++ b/sys/dev/usb/hid.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: hid.c,v 1.9 2000/11/08 18:10:37 aaron Exp $ */
-/* $NetBSD: hid.c,v 1.16 2000/06/01 14:28:57 augustss Exp $ */
+/* $OpenBSD: hid.c,v 1.10 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: hid.c,v 1.22 2002/01/12 17:11:03 tsutsui Exp $ */
/* $FreeBSD: src/sys/dev/usb/hid.c,v 1.11 1999/11/17 22:33:39 n_hibma Exp $ */
/*
@@ -51,10 +51,10 @@
#include <dev/usb/hid.h>
-#ifdef UHID_DEBUG
-#define DPRINTF(x) if (usbdebug) logprintf x
-#define DPRINTFN(n,x) if (usbdebug>(n)) logprintf x
-extern int usbdebug;
+#ifdef UHIDEV_DEBUG
+#define DPRINTF(x) if (uhidevdebug) logprintf x
+#define DPRINTFN(n,x) if (uhidevdebug>(n)) logprintf x
+extern int uhidevdebug;
#else
#define DPRINTF(x)
#define DPRINTFN(n,x)
@@ -62,7 +62,7 @@ extern int usbdebug;
Static void hid_clear_local(struct hid_item *);
-#define MAXUSAGE 100
+#define MAXUSAGE 256
struct hid_data {
u_char *start;
u_char *end;
@@ -73,13 +73,14 @@ struct hid_data {
int minset;
int multi;
int multimax;
- int kindset;
+ enum hid_kind kind;
};
Static void
hid_clear_local(struct hid_item *c)
{
+ DPRINTFN(5,("hid_clear_local\n"));
c->usage = 0;
c->usage_minimum = 0;
c->usage_maximum = 0;
@@ -93,15 +94,18 @@ hid_clear_local(struct hid_item *c)
}
struct hid_data *
-hid_start_parse(void *d, int len, int kindset)
+hid_start_parse(void *d, int len, enum hid_kind kind)
{
struct hid_data *s;
s = malloc(sizeof *s, M_TEMP, M_WAITOK);
+ if (s == NULL)
+ panic("hid_start_parse");
memset(s, 0, sizeof *s);
+
s->start = s->p = d;
s->end = (char *)d + len;
- s->kindset = kindset;
+ s->kind = kind;
return (s);
}
@@ -128,15 +132,19 @@ hid_get_item(struct hid_data *s, struct hid_item *h)
u_char *p;
struct hid_item *hi;
int i;
+ enum hid_kind retkind;
top:
+ DPRINTFN(5,("hid_get_item: multi=%d multimax=%d\n",
+ s->multi, s->multimax));
if (s->multimax != 0) {
if (s->multi < s->multimax) {
c->usage = s->usages[min(s->multi, s->nu-1)];
s->multi++;
*h = *c;
c->loc.pos += c->loc.size;
- h->next = 0;
+ h->next = NULL;
+ DPRINTFN(5,("return multi\n"));
return (1);
} else {
c->loc.count = s->multimax;
@@ -174,12 +182,12 @@ hid_get_item(struct hid_data *s, struct hid_item *h)
dval = 0;
break;
case 1:
- dval = (int8_t)*data++;
+ dval = /*(int8_t)*/ *data++;
break;
case 2:
dval = *data++;
dval |= *data++ << 8;
- dval = (int16_t)dval;
+ dval = /*(int16_t)*/ dval;
break;
case 4:
dval = *data++;
@@ -192,15 +200,22 @@ hid_get_item(struct hid_data *s, struct hid_item *h)
continue;
}
+ DPRINTFN(5,("hid_get_item: bType=%d bTag=%d dval=%d\n",
+ bType, bTag, dval));
switch (bType) {
case 0: /* Main */
switch (bTag) {
case 8: /* Input */
- if (!(s->kindset & (1 << hid_input)))
+ retkind = hid_input;
+ ret:
+ if (s->kind != retkind) {
+ s->minset = 0;
+ s->nu = 0;
+ hid_clear_local(c);
continue;
- c->kind = hid_input;
+ }
+ c->kind = retkind;
c->flags = dval;
- ret:
if (c->flags & HIO_VARIABLE) {
s->multimax = c->loc.count;
s->multi = 0;
@@ -217,19 +232,18 @@ hid_get_item(struct hid_data *s, struct hid_item *h)
}
goto top;
} else {
+ c->usage = c->_usage_page; /* XXX */
*h = *c;
- h->next = 0;
+ h->next = NULL;
c->loc.pos +=
- c->loc.size * c->loc.count;
- hid_clear_local(c);
+ c->loc.size * c->loc.count;
s->minset = 0;
+ s->nu = 0;
+ hid_clear_local(c);
return (1);
}
case 9: /* Output */
- if (!(s->kindset & (1 << hid_output)))
- continue;
- c->kind = hid_output;
- c->flags = dval;
+ retkind = hid_output;
goto ret;
case 10: /* Collection */
c->kind = hid_collection;
@@ -240,16 +254,12 @@ hid_get_item(struct hid_data *s, struct hid_item *h)
s->nu = 0;
return (1);
case 11: /* Feature */
- if (!(s->kindset & (1 << hid_feature)))
- continue;
- c->kind = hid_feature;
- c->flags = dval;
+ retkind = hid_feature;
goto ret;
case 12: /* End collection */
c->kind = hid_endcollection;
c->collevel--;
*h = *c;
- hid_clear_local(c);
s->nu = 0;
return (1);
default:
@@ -285,6 +295,7 @@ hid_get_item(struct hid_data *s, struct hid_item *h)
break;
case 8:
c->report_ID = dval;
+ c->loc.pos = 0;
break;
case 9:
c->loc.count = dval;
@@ -367,35 +378,51 @@ 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 *idp)
+hid_report_size(void *buf, int len, enum hid_kind k, u_int8_t id)
{
struct hid_data *d;
struct hid_item h;
- int size, id;
+ int lo, hi;
- id = 0;
- for (d = hid_start_parse(buf, len, 1<<k); hid_get_item(d, &h); )
- if (h.report_ID != 0)
- id = h.report_ID;
+ h.report_ID = 0;
+ lo = hi = -1;
+ DPRINTFN(2,("hid_report_size: kind=%d id=%d\n", k, id));
+ for (d = hid_start_parse(buf, len, k); hid_get_item(d, &h); ) {
+ DPRINTFN(2,("hid_report_size: item kind=%d id=%d pos=%d "
+ "size=%d count=%d\n",
+ h.kind, h.report_ID, h.loc.pos, h.loc.size,
+ h.loc.count));
+ if (h.report_ID == id && h.kind == k) {
+ if (lo < 0) {
+ lo = h.loc.pos;
+#ifdef DIAGNOSTIC
+ if (lo != 0) {
+ printf("hid_report_size: lo != 0\n");
+ }
+#endif
+ }
+ hi = h.loc.pos + h.loc.size * h.loc.count;
+ DPRINTFN(2,("hid_report_size: lo=%d hi=%d\n", lo, hi));
+ }
+ }
hid_end_parse(d);
- size = h.loc.pos;
- if (id != 0) {
- size += 8;
- *idp = id; /* XXX wrong */
- } else
- *idp = 0;
- return ((size + 7) / 8);
+ return ((hi - lo + 7) / 8);
}
int
-hid_locate(void *desc, int size, u_int32_t u, enum hid_kind k,
+hid_locate(void *desc, int size, u_int32_t u, u_int8_t id, enum hid_kind k,
struct hid_location *loc, u_int32_t *flags)
{
struct hid_data *d;
struct hid_item h;
- for (d = hid_start_parse(desc, size, 1<<k); hid_get_item(d, &h); ) {
- if (h.kind == k && !(h.flags & HIO_CONST) && h.usage == u) {
+ h.report_ID = 0;
+ DPRINTFN(5,("hid_locate: enter usage=0x%x kind=%d id=%d\n", u, k, id));
+ for (d = hid_start_parse(desc, size, k); hid_get_item(d, &h); ) {
+ DPRINTFN(5,("hid_locate: usage=0x%x kind=%d id=%d flags=0x%x\n",
+ h.usage, h.kind, h.report_ID, h.flags));
+ if (h.kind == k && !(h.flags & HIO_CONST) &&
+ h.usage == u && h.report_ID == id) {
if (loc != NULL)
*loc = h.loc;
if (flags != NULL)
@@ -437,19 +464,33 @@ hid_get_data(u_char *buf, struct hid_location *loc)
}
int
-hid_is_collection(void *desc, int size, u_int32_t usage)
+hid_is_collection(void *desc, int size, u_int8_t id, u_int32_t usage)
{
struct hid_data *hd;
struct hid_item hi;
- int err;
+ u_int32_t coll_usage = ~0;
- hd = hid_start_parse(desc, size, hid_input);
+ hd = hid_start_parse(desc, size, hid_none);
if (hd == NULL)
return (0);
- err = hid_get_item(hd, &hi) &&
- hi.kind == hid_collection &&
- hi.usage == usage;
+ DPRINTFN(2,("hid_is_collection: id=%d usage=0x%x\n", id, usage));
+ while (hid_get_item(hd, &hi)) {
+ DPRINTFN(2,("hid_is_collection: kind=%d id=%d usage=0x%x"
+ "(0x%x)\n",
+ hi.kind, hi.report_ID, hi.usage, coll_usage));
+ if (hi.kind == hid_collection &&
+ hi.collection == HCOLL_APPLICATION)
+ coll_usage = hi.usage;
+ if (hi.kind == hid_endcollection &&
+ coll_usage == usage &&
+ hi.report_ID == id) {
+ DPRINTFN(2,("hid_is_collection: found\n"));
+ hid_end_parse(hd);
+ return (1);
+ }
+ }
+ DPRINTFN(2,("hid_is_collection: not found\n"));
hid_end_parse(hd);
- return (err);
+ return (0);
}
diff --git a/sys/dev/usb/hid.h b/sys/dev/usb/hid.h
index 73608bbbaff..928a86ce337 100644
--- a/sys/dev/usb/hid.h
+++ b/sys/dev/usb/hid.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: hid.h,v 1.4 2000/11/08 18:10:37 aaron Exp $ */
-/* $NetBSD: hid.h,v 1.6 2000/06/01 14:28:57 augustss Exp $ */
+/* $OpenBSD: hid.h,v 1.5 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: hid.h,v 1.7 2001/12/28 17:32:36 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/hid.h,v 1.7 1999/11/17 22:33:40 n_hibma Exp $ */
/*
@@ -40,7 +40,12 @@
*/
enum hid_kind {
- hid_input, hid_output, hid_feature, hid_collection, hid_endcollection
+ hid_input,
+ hid_output,
+ hid_feature,
+ hid_collection,
+ hid_endcollection,
+ hid_none
};
struct hid_location {
@@ -81,11 +86,11 @@ struct hid_item {
struct hid_item *next;
};
-struct hid_data *hid_start_parse(void *d, int len, int kindset);
+struct hid_data *hid_start_parse(void *d, int len, enum hid_kind kind);
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, u_int32_t *flags);
+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, u_int8_t id,
+ 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);
+int hid_is_collection(void *desc, int size, u_int8_t id, u_int32_t usage);
diff --git a/sys/dev/usb/if_upl.c b/sys/dev/usb/if_upl.c
index 2684f9efddf..49e29bdce8b 100644
--- a/sys/dev/usb/if_upl.c
+++ b/sys/dev/usb/if_upl.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: if_upl.c,v 1.5 2002/03/12 09:51:20 kjc Exp $ */
-/* $NetBSD: if_upl.c,v 1.15 2001/06/14 05:44:27 itojun Exp $ */
+/* $OpenBSD: if_upl.c,v 1.6 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: if_upl.c,v 1.17 2002/03/05 04:12:59 itojun Exp $ */
/*
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
@@ -78,27 +78,19 @@
#include <net/bpf.h>
#endif
-#if defined(__NetBSD__)
#ifdef INET
#include <netinet/in.h>
#include <netinet/in_var.h>
+#if defined(__NetBSD__)
#include <netinet/if_inarp.h>
-#else
-#error upl without INET?
-#endif
-#endif
-
-#if defined(__OpenBSD__)
-#ifdef INET
-#include <netinet/in.h>
+#elif defined(__OpenBSD__)
#include <netinet/in_systm.h>
-#include <netinet/in_var.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h>
+#endif
#else
#error upl without INET?
#endif
-#endif
#ifdef NS
#include <netns/ns.h>
@@ -333,20 +325,22 @@ USB_ATTACH(upl)
ifp->if_addrlen = 0;
ifp->if_hdrlen = 0;
ifp->if_output = upl_output;
+ ifp->if_baudrate = 12000000;
#if defined(__NetBSD__)
ifp->if_input = upl_input;
+ ifp->if_dlt = DLT_RAW;
#endif
- ifp->if_baudrate = 12000000;
IFQ_SET_READY(&ifp->if_snd);
/* Attach the interface. */
if_attach(ifp);
+#if defined(__NetBSD__)
+ if_alloc_sadl(ifp);
+#endif
-#if NBPFILTER > 0
-#if defined(__NetBSD__) || defined(__FreeBSD__)
+#if defined(__NetBSD__) && NBPFILTER > 0
bpfattach(ifp, DLT_RAW, 0);
#endif
-#endif
#if NRND > 0
rnd_attach_source(&sc->sc_rnd_source, USBDEVNAME(sc->sc_dev),
RND_TYPE_NET, 0);
diff --git a/sys/dev/usb/if_url.c b/sys/dev/usb/if_url.c
new file mode 100644
index 00000000000..d0d542a4171
--- /dev/null
+++ b/sys/dev/usb/if_url.c
@@ -0,0 +1,1609 @@
+/* $OpenBSD: if_url.c,v 1.1 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: if_url.c,v 1.2 2002/03/28 21:49:19 ichiro Exp $ */
+/*
+ * Copyright (c) 2001, 2002
+ * Shingo WATANABE <nabe@nabechan.org>. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Shingo WATANABE.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * The RTL8150L(Realtek USB to fast ethernet controller) spec can be found at
+ * ftp://ftp.realtek.com.tw/lancard/data_sheet/8150/8150v14.pdf
+ * ftp://152.104.125.40/lancard/data_sheet/8150/8150v14.pdf
+ */
+
+/*
+ * TODO:
+ * Interrupt Endpoint support
+ * External PHYs
+ * powerhook() support?
+ */
+
+#include "opt_inet.h"
+#include "opt_ns.h"
+#include "bpfilter.h"
+#include "rnd.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/lock.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+
+#include <sys/device.h>
+#if NRND > 0
+#include <sys/rnd.h>
+#endif
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+#define BPF_MTAP(ifp, m) bpf_mtap((ifp)->if_bpf, (m))
+
+#include <net/if_ether.h>
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_inarp.h>
+#endif
+#ifdef NS
+#include <netns/ns.h>
+#include <netns/ns_if.h>
+#endif
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include <dev/mii/urlphyreg.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+#include <dev/usb/usbdevs.h>
+
+#include <dev/usb/if_urlreg.h>
+
+
+/* Function declarations */
+USB_DECLARE_DRIVER(url);
+
+Static int url_openpipes(struct url_softc *);
+Static int url_rx_list_init(struct url_softc *);
+Static int url_tx_list_init(struct url_softc *);
+Static int url_newbuf(struct url_softc *, struct url_chain *, struct mbuf *);
+Static void url_start(struct ifnet *);
+Static int url_send(struct url_softc *, struct mbuf *, int);
+Static void url_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
+Static void url_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
+Static void url_tick(void *);
+Static void url_tick_task(void *);
+Static int url_ioctl(struct ifnet *, u_long, caddr_t);
+Static void url_stop_task(struct url_softc *);
+Static void url_stop(struct ifnet *, int);
+Static void url_watchdog(struct ifnet *);
+Static int url_ifmedia_change(struct ifnet *);
+Static void url_ifmedia_status(struct ifnet *, struct ifmediareq *);
+Static void url_lock_mii(struct url_softc *);
+Static void url_unlock_mii(struct url_softc *);
+Static int url_int_miibus_readreg(device_ptr_t, int, int);
+Static void url_int_miibus_writereg(device_ptr_t, int, int, int);
+Static void url_miibus_statchg(device_ptr_t);
+Static int url_init(struct ifnet *);
+Static void url_setmulti(struct url_softc *);
+Static void url_reset(struct url_softc *);
+
+Static int url_csr_read_1(struct url_softc *, int);
+Static int url_csr_read_2(struct url_softc *, int);
+Static int url_csr_write_1(struct url_softc *, int, int);
+Static int url_csr_write_2(struct url_softc *, int, int);
+Static int url_csr_write_4(struct url_softc *, int, int);
+Static int url_mem(struct url_softc *, int, int, void *, int);
+
+/* Macros */
+#ifdef URL_DEBUG
+#define DPRINTF(x) if (urldebug) logprintf x
+#define DPRINTFN(n,x) if (urldebug >= (n)) logprintf x
+int urldebug = 0;
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n,x)
+#endif
+
+#define URL_SETBIT(sc, reg, x) \
+ url_csr_write_1(sc, reg, url_csr_read_1(sc, reg) | (x))
+
+#define URL_SETBIT2(sc, reg, x) \
+ url_csr_write_2(sc, reg, url_csr_read_2(sc, reg) | (x))
+
+#define URL_CLRBIT(sc, reg, x) \
+ url_csr_write_1(sc, reg, url_csr_read_1(sc, reg) & ~(x))
+
+#define URL_CLRBIT2(sc, reg, x) \
+ url_csr_write_2(sc, reg, url_csr_read_2(sc, reg) & ~(x))
+
+static const struct url_type {
+ struct usb_devno url_dev;
+ u_int16_t url_flags;
+#define URL_EXT_PHY 0x0001
+} url_devs [] = {
+ /* MELCO LUA-KTX */
+ {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAKTX }, 0},
+ /* GREEN HOUSE USBKR100 */
+ {{ USB_VENDOR_GREENHOUSE2, USB_PRODUCT_GREENHOUSE2_USBKR100}, 0}
+};
+#define url_lookup(v, p) ((struct url_type *)usb_lookup(url_devs, v, p))
+
+
+/* Probe */
+USB_MATCH(url)
+{
+ USB_MATCH_START(url, uaa);
+
+ if (uaa->iface != NULL)
+ return (UMATCH_NONE);
+
+ return (url_lookup(uaa->vendor, uaa->product) != NULL ?
+ UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
+}
+/* Attach */
+USB_ATTACH(url)
+{
+ USB_ATTACH_START(url, sc, uaa);
+ usbd_device_handle dev = uaa->device;
+ usbd_interface_handle iface;
+ usbd_status err;
+ usb_interface_descriptor_t *id;
+ usb_endpoint_descriptor_t *ed;
+ char devinfo[1024];
+ char *devname = USBDEVNAME(sc->sc_dev);
+ struct ifnet *ifp;
+ struct mii_data *mii;
+ u_char eaddr[ETHER_ADDR_LEN];
+ int i, s;
+
+ usbd_devinfo(dev, 0, devinfo);
+ USB_ATTACH_SETUP;
+ printf("%s: %s\n", devname, devinfo);
+
+ /* Move the device into the configured state. */
+ err = usbd_set_config_no(dev, URL_CONFIG_NO, 1);
+ if (err) {
+ printf("%s: setting config no failed\n", devname);
+ goto bad;
+ }
+
+ usb_init_task(&sc->sc_tick_task, url_tick_task, sc);
+ lockinit(&sc->sc_mii_lock, PZERO, "urlmii", 0, 0);
+ usb_init_task(&sc->sc_stop_task, (void (*)(void *)) url_stop_task, sc);
+
+ /* get control interface */
+ err = usbd_device2interface_handle(dev, URL_IFACE_INDEX, &iface);
+ if (err) {
+ printf("%s: failed to get interface, err=%s\n", devname,
+ usbd_errstr(err));
+ goto bad;
+ }
+
+ sc->sc_udev = dev;
+ sc->sc_ctl_iface = iface;
+ sc->sc_flags = url_lookup(uaa->vendor, uaa->product)->url_flags;
+
+ /* get interface descriptor */
+ id = usbd_get_interface_descriptor(sc->sc_ctl_iface);
+
+ /* find endpoints */
+ sc->sc_bulkin_no = sc->sc_bulkout_no = sc->sc_intrin_no = -1;
+ for (i = 0; i < id->bNumEndpoints; i++) {
+ ed = usbd_interface2endpoint_descriptor(sc->sc_ctl_iface, i);
+ if (ed == NULL) {
+ printf("%s: couldn't get endpoint %d\n", devname, i);
+ goto bad;
+ }
+ if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK &&
+ UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN)
+ sc->sc_bulkin_no = ed->bEndpointAddress; /* RX */
+ else if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK &&
+ UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT)
+ sc->sc_bulkout_no = ed->bEndpointAddress; /* TX */
+ else if ((ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT &&
+ UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN)
+ sc->sc_intrin_no = ed->bEndpointAddress; /* Status */
+ }
+
+ if (sc->sc_bulkin_no == -1 || sc->sc_bulkout_no == -1 ||
+ sc->sc_intrin_no == -1) {
+ printf("%s: missing endpoint\n", devname);
+ goto bad;
+ }
+
+ s = splnet();
+
+ /* reset the adapter */
+ url_reset(sc);
+
+ /* Get Ethernet Address */
+ err = url_mem(sc, URL_CMD_READMEM, URL_IDR0, (void *)eaddr,
+ ETHER_ADDR_LEN);
+ if (err) {
+ printf("%s: read MAC address faild\n", devname);
+ splx(s);
+ goto bad;
+ }
+
+ /* Print Ethernet Address */
+ printf("%s: Ethernet address %s\n", devname, ether_sprintf(eaddr));
+
+ /* initialize interface infomation */
+ ifp = GET_IFP(sc);
+ ifp->if_softc = sc;
+ strncpy(ifp->if_xname, devname, IFNAMSIZ);
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_start = url_start;
+ ifp->if_ioctl = url_ioctl;
+ ifp->if_watchdog = url_watchdog;
+ ifp->if_init = url_init;
+ ifp->if_stop = url_stop;
+
+ IFQ_SET_READY(&ifp->if_snd);
+
+ /*
+ * Do ifmedia setup.
+ */
+ mii = &sc->sc_mii;
+ mii->mii_ifp = ifp;
+ mii->mii_readreg = url_int_miibus_readreg;
+ mii->mii_writereg = url_int_miibus_writereg;
+#if 0
+ if (sc->sc_flags & URL_EXT_PHY) {
+ mii->mii_readreg = url_ext_miibus_readreg;
+ mii->mii_writereg = url_ext_miibus_writereg;
+ }
+#endif
+ mii->mii_statchg = url_miibus_statchg;
+ mii->mii_flags = MIIF_AUTOTSLEEP;
+ ifmedia_init(&mii->mii_media, 0,
+ url_ifmedia_change, url_ifmedia_status);
+ mii_attach(self, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, 0);
+ if (LIST_FIRST(&mii->mii_phys) == NULL) {
+ ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 0, NULL);
+ ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_NONE);
+ } else
+ ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO);
+
+ /* attach the interface */
+ if_attach(ifp);
+ Ether_ifattach(ifp, eaddr);
+
+#if NRND > 0
+ rnd_attach_source(&sc->rnd_source, devname, RND_TYPE_NET, 0);
+#endif
+
+ usb_callout_init(sc->sc_stat_ch);
+ sc->sc_attached = 1;
+ splx(s);
+
+ usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, dev, USBDEV(sc->sc_dev));
+
+ USB_ATTACH_SUCCESS_RETURN;
+
+ bad:
+ sc->sc_dying = 1;
+ USB_ATTACH_ERROR_RETURN;
+}
+
+/* detach */
+USB_DETACH(url)
+{
+ USB_DETACH_START(url, sc);
+ struct ifnet *ifp = GET_IFP(sc);
+ int s;
+
+ DPRINTF(("%s: %s: enter\n", USBDEVNAME(sc->sc_dev), __FUNCTION__));
+
+ /* Detached before attached finished */
+ if (!sc->sc_attached)
+ return (0);
+
+ usb_uncallout(sc->sc_stat_ch, url_tick, sc);
+
+ /* Remove any pending tasks */
+ usb_rem_task(sc->sc_udev, &sc->sc_tick_task);
+ usb_rem_task(sc->sc_udev, &sc->sc_stop_task);
+
+ s = splusb();
+
+ if (--sc->sc_refcnt >= 0) {
+ /* Wait for processes to go away */
+ usb_detach_wait(USBDEV(sc->sc_dev));
+ }
+
+ if (ifp->if_flags & IFF_RUNNING)
+ url_stop(GET_IFP(sc), 1);
+
+#if NRND > 0
+ rnd_detach_source(&sc->rnd_source);
+#endif
+ mii_detach(&sc->sc_mii, MII_PHY_ANY, MII_OFFSET_ANY);
+ ifmedia_delete_instance(&sc->sc_mii.mii_media, IFM_INST_ANY);
+ ether_ifdetach(ifp);
+ if_detach(ifp);
+
+#ifdef DIAGNOSTIC
+ if (sc->sc_pipe_tx != NULL)
+ printf("%s: detach has active tx endpoint.\n",
+ USBDEVNAME(sc->sc_dev));
+ if (sc->sc_pipe_rx != NULL)
+ printf("%s: detach has active rx endpoint.\n",
+ USBDEVNAME(sc->sc_dev));
+ if (sc->sc_pipe_intr != NULL)
+ printf("%s: detach has active intr endpoint.\n",
+ USBDEVNAME(sc->sc_dev));
+#endif
+
+ sc->sc_attached = 0;
+
+ splx(s);
+
+ usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
+ USBDEV(sc->sc_dev));
+
+ return (0);
+}
+
+/* read/write memory */
+Static int
+url_mem(struct url_softc *sc, int cmd, int offset, void *buf, int len)
+{
+ usb_device_request_t req;
+ usbd_status err;
+
+ if (sc == NULL)
+ return (0);
+
+ DPRINTFN(0x200,
+ ("%s: %s: enter\n", USBDEVNAME(sc->sc_dev), __FUNCTION__));
+
+ if (sc->sc_dying)
+ return (0);
+
+ if (cmd == URL_CMD_READMEM)
+ req.bmRequestType = UT_READ_VENDOR_DEVICE;
+ else
+ req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req.bRequest = URL_REQ_MEM;
+ USETW(req.wValue, offset);
+ USETW(req.wIndex, 0x0000);
+ USETW(req.wLength, len);
+
+ sc->sc_refcnt++;
+ err = usbd_do_request(sc->sc_udev, &req, buf);
+ if (--sc->sc_refcnt < 0)
+ usb_detach_wakeup(USBDEV(sc->sc_dev));
+ if (err) {
+ DPRINTF(("%s: url_mem(): %s failed. off=%04x, err=%d\n",
+ USBDEVNAME(sc->sc_dev),
+ cmd == URL_CMD_READMEM ? "read" : "write",
+ offset, err));
+ }
+
+ return (err);
+}
+
+/* read 1byte from register */
+Static int
+url_csr_read_1(struct url_softc *sc, int reg)
+{
+ u_int8_t val = 0;
+
+ DPRINTFN(0x100,
+ ("%s: %s: enter\n", USBDEVNAME(sc->sc_dev), __FUNCTION__));
+
+ if (sc->sc_dying)
+ return (0);
+
+ return (url_mem(sc, URL_CMD_READMEM, reg, &val, 1) ? 0 : val);
+}
+
+/* read 2bytes from register */
+Static int
+url_csr_read_2(struct url_softc *sc, int reg)
+{
+ uWord val;
+
+ DPRINTFN(0x100,
+ ("%s: %s: enter\n", USBDEVNAME(sc->sc_dev), __FUNCTION__));
+
+ if (sc->sc_dying)
+ return (0);
+
+ USETW(val, 0);
+ return (url_mem(sc, URL_CMD_READMEM, reg, &val, 2) ? 0 : UGETW(val));
+}
+
+/* write 1byte to register */
+Static int
+url_csr_write_1(struct url_softc *sc, int reg, int aval)
+{
+ u_int8_t val = aval;
+
+ DPRINTFN(0x100,
+ ("%s: %s: enter\n", USBDEVNAME(sc->sc_dev), __FUNCTION__));
+
+ if (sc->sc_dying)
+ return (0);
+
+ return (url_mem(sc, URL_CMD_WRITEMEM, reg, &val, 1) ? -1 : 0);
+}
+
+/* write 2bytes to register */
+Static int
+url_csr_write_2(struct url_softc *sc, int reg, int aval)
+{
+ uWord val;
+
+ DPRINTFN(0x100,
+ ("%s: %s: enter\n", USBDEVNAME(sc->sc_dev), __FUNCTION__));
+
+ USETW(val, aval);
+
+ if (sc->sc_dying)
+ return (0);
+
+ return (url_mem(sc, URL_CMD_WRITEMEM, reg, &val, 2) ? -1 : 0);
+}
+
+/* write 4bytes to register */
+Static int
+url_csr_write_4(struct url_softc *sc, int reg, int aval)
+{
+ uDWord val;
+
+ DPRINTFN(0x100,
+ ("%s: %s: enter\n", USBDEVNAME(sc->sc_dev), __FUNCTION__));
+
+ USETDW(val, aval);
+
+ if (sc->sc_dying)
+ return (0);
+
+ return (url_mem(sc, URL_CMD_WRITEMEM, reg, &val, 4) ? -1 : 0);
+}
+
+Static int
+url_init(struct ifnet *ifp)
+{
+ struct url_softc *sc = ifp->if_softc;
+ struct mii_data *mii = GET_MII(sc);
+ u_char *eaddr;
+ int i, s;
+
+ DPRINTF(("%s: %s: enter\n", USBDEVNAME(sc->sc_dev), __FUNCTION__));
+
+ if (sc->sc_dying)
+ return (EIO);
+
+ s = splnet();
+
+ /* Cancel pending I/O and free all TX/RX buffers */
+ url_stop(ifp, 1);
+
+ eaddr = LLADDR(ifp->if_sadl);
+ for (i = 0; i < ETHER_ADDR_LEN; i++)
+ url_csr_write_1(sc, URL_IDR0 + i, eaddr[i]);
+
+ /* Init transmission control register */
+ URL_CLRBIT(sc, URL_TCR,
+ URL_TCR_TXRR1 | URL_TCR_TXRR0 |
+ URL_TCR_IFG1 | URL_TCR_IFG0 |
+ URL_TCR_NOCRC);
+
+ /* Init receive control register */
+ URL_SETBIT2(sc, URL_RCR, URL_RCR_TAIL | URL_RCR_AD);
+ if (ifp->if_flags & IFF_BROADCAST)
+ URL_SETBIT2(sc, URL_RCR, URL_RCR_AB);
+ else
+ URL_CLRBIT2(sc, URL_RCR, URL_RCR_AB);
+
+ /* If we want promiscuous mode, accept all physical frames. */
+ if (ifp->if_flags & IFF_PROMISC)
+ URL_SETBIT2(sc, URL_RCR, URL_RCR_AAM|URL_RCR_AAP);
+ else
+ URL_CLRBIT2(sc, URL_RCR, URL_RCR_AAM|URL_RCR_AAP);
+
+
+ /* Initialize transmit ring */
+ if (url_tx_list_init(sc) == ENOBUFS) {
+ printf("%s: tx list init failed\n", USBDEVNAME(sc->sc_dev));
+ splx(s);
+ return (EIO);
+ }
+
+ /* Initialize receive ring */
+ if (url_rx_list_init(sc) == ENOBUFS) {
+ printf("%s: rx list init failed\n", USBDEVNAME(sc->sc_dev));
+ splx(s);
+ return (EIO);
+ }
+
+ /* Load the multicast filter */
+ url_setmulti(sc);
+
+ /* Enable RX and TX */
+ URL_SETBIT(sc, URL_CR, URL_CR_TE | URL_CR_RE);
+
+ mii_mediachg(mii);
+
+ if (sc->sc_pipe_tx == NULL || sc->sc_pipe_rx == NULL) {
+ if (url_openpipes(sc)) {
+ splx(s);
+ return (EIO);
+ }
+ }
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ splx(s);
+
+ usb_callout(sc->sc_stat_ch, hz, url_tick, sc);
+
+ return (0);
+}
+
+Static void
+url_reset(struct url_softc *sc)
+{
+ int i;
+
+ DPRINTF(("%s: %s: enter\n", USBDEVNAME(sc->sc_dev), __FUNCTION__));
+
+ if (sc->sc_dying)
+ return;
+
+ URL_SETBIT(sc, URL_CR, URL_CR_SOFT_RST);
+
+ for (i = 0; i < URL_TX_TIMEOUT; i++) {
+ if (!(url_csr_read_1(sc, URL_CR) & URL_CR_SOFT_RST))
+ break;
+ delay(10); /* XXX */
+ }
+
+ delay(10000); /* XXX */
+}
+
+int
+url_activate(device_ptr_t self, enum devact act)
+{
+ struct url_softc *sc = (struct url_softc *)self;
+
+ DPRINTF(("%s: %s: enter, act=%d\n", USBDEVNAME(sc->sc_dev),
+ __FUNCTION__, act));
+
+ switch (act) {
+ case DVACT_ACTIVATE:
+ return (EOPNOTSUPP);
+ break;
+
+ case DVACT_DEACTIVATE:
+ if_deactivate(&sc->sc_ec.ec_if);
+ sc->sc_dying = 1;
+ break;
+ }
+
+ return (0);
+}
+
+#define url_calchash(addr) (ether_crc32_be((addr), ETHER_ADDR_LEN) >> 26)
+
+
+Static void
+url_setmulti(struct url_softc *sc)
+{
+ struct ifnet *ifp;
+ struct ether_multi *enm;
+ struct ether_multistep step;
+ u_int32_t hashes[2] = { 0, 0 };
+ int h = 0;
+ int mcnt = 0;
+
+ DPRINTF(("%s: %s: enter\n", USBDEVNAME(sc->sc_dev), __FUNCTION__));
+
+ if (sc->sc_dying)
+ return;
+
+ ifp = GET_IFP(sc);
+
+ if (ifp->if_flags & IFF_PROMISC) {
+ URL_SETBIT2(sc, URL_RCR, URL_RCR_AAM|URL_RCR_AAP);
+ return;
+ } else if (ifp->if_flags & IFF_ALLMULTI) {
+ allmulti:
+ ifp->if_flags |= IFF_ALLMULTI;
+ URL_SETBIT2(sc, URL_RCR, URL_RCR_AAM);
+ URL_CLRBIT2(sc, URL_RCR, URL_RCR_AAP);
+ return;
+ }
+
+ /* first, zot all the existing hash bits */
+ url_csr_write_4(sc, URL_MAR0, 0);
+ url_csr_write_4(sc, URL_MAR4, 0);
+
+ /* now program new ones */
+ ETHER_FIRST_MULTI(step, &sc->sc_ec, enm);
+ while (enm != NULL) {
+ if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
+ ETHER_ADDR_LEN) != 0)
+ goto allmulti;
+
+ h = url_calchash(enm->enm_addrlo);
+ if (h < 32)
+ hashes[0] |= (1 << h);
+ else
+ hashes[1] |= (1 << (h -32));
+ mcnt++;
+ ETHER_NEXT_MULTI(step, enm);
+ }
+
+ ifp->if_flags &= ~IFF_ALLMULTI;
+
+ URL_CLRBIT2(sc, URL_RCR, URL_RCR_AAM|URL_RCR_AAP);
+
+ if (mcnt){
+ URL_SETBIT2(sc, URL_RCR, URL_RCR_AM);
+ } else {
+ URL_CLRBIT2(sc, URL_RCR, URL_RCR_AM);
+ }
+ url_csr_write_4(sc, URL_MAR0, hashes[0]);
+ url_csr_write_4(sc, URL_MAR4, hashes[1]);
+}
+
+Static int
+url_openpipes(struct url_softc *sc)
+{
+ struct url_chain *c;
+ usbd_status err;
+ int i;
+ int error = 0;
+
+ if (sc->sc_dying)
+ return (EIO);
+
+ sc->sc_refcnt++;
+
+ /* Open RX pipe */
+ err = usbd_open_pipe(sc->sc_ctl_iface, sc->sc_bulkin_no,
+ USBD_EXCLUSIVE_USE, &sc->sc_pipe_rx);
+ if (err) {
+ printf("%s: open rx pipe failed: %s\n",
+ USBDEVNAME(sc->sc_dev), usbd_errstr(err));
+ error = EIO;
+ goto done;
+ }
+
+ /* Open TX pipe */
+ err = usbd_open_pipe(sc->sc_ctl_iface, sc->sc_bulkout_no,
+ USBD_EXCLUSIVE_USE, &sc->sc_pipe_tx);
+ if (err) {
+ printf("%s: open tx pipe failed: %s\n",
+ USBDEVNAME(sc->sc_dev), usbd_errstr(err));
+ error = EIO;
+ goto done;
+ }
+
+#if 0
+ /* XXX: interrupt endpoint is not yet supported */
+ /* Open Interrupt pipe */
+ err = usbd_open_pipe_intr(sc->sc_ctl_iface, sc->sc_intrin_no,
+ USBD_EXCLUSIVE_USE, &sc->sc_pipe_intr, sc,
+ &sc->sc_cdata.url_ibuf, URL_INTR_PKGLEN,
+ url_intr, URL_INTR_INTERVAL);
+ if (err) {
+ printf("%s: open intr pipe failed: %s\n",
+ USBDEVNAME(sc->sc_dev), usbd_errstr(err));
+ error = EIO;
+ goto done;
+ }
+#endif
+
+
+ /* Start up the receive pipe. */
+ for (i = 0; i < URL_RX_LIST_CNT; i++) {
+ c = &sc->sc_cdata.url_rx_chain[i];
+ usbd_setup_xfer(c->url_xfer, sc->sc_pipe_rx,
+ c, c->url_buf, URL_BUFSZ,
+ USBD_SHORT_XFER_OK | USBD_NO_COPY,
+ USBD_NO_TIMEOUT, url_rxeof);
+ (void)usbd_transfer(c->url_xfer);
+ DPRINTF(("%s: %s: start read\n", USBDEVNAME(sc->sc_dev),
+ __FUNCTION__));
+ }
+
+ done:
+ if (--sc->sc_refcnt < 0)
+ usb_detach_wakeup(USBDEV(sc->sc_dev));
+
+ return (error);
+}
+
+Static int
+url_newbuf(struct url_softc *sc, struct url_chain *c, struct mbuf *m)
+{
+ struct mbuf *m_new = NULL;
+
+ DPRINTF(("%s: %s: enter\n", USBDEVNAME(sc->sc_dev), __FUNCTION__));
+
+ if (m == NULL) {
+ MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+ if (m_new == NULL) {
+ printf("%s: no memory for rx list "
+ "-- packet dropped!\n", USBDEVNAME(sc->sc_dev));
+ return (ENOBUFS);
+ }
+ MCLGET(m_new, M_DONTWAIT);
+ if (!(m_new->m_flags & M_EXT)) {
+ printf("%s: no memory for rx list "
+ "-- packet dropped!\n", USBDEVNAME(sc->sc_dev));
+ m_freem(m_new);
+ return (ENOBUFS);
+ }
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+ } else {
+ m_new = m;
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+ m_new->m_data = m_new->m_ext.ext_buf;
+ }
+
+ m_adj(m_new, ETHER_ALIGN);
+ c->url_mbuf = m_new;
+
+ return (0);
+}
+
+
+Static int
+url_rx_list_init(struct url_softc *sc)
+{
+ struct url_cdata *cd;
+ struct url_chain *c;
+ int i;
+
+ DPRINTF(("%s: %s: enter\n", USBDEVNAME(sc->sc_dev), __FUNCTION__));
+
+ cd = &sc->sc_cdata;
+ for (i = 0; i < URL_RX_LIST_CNT; i++) {
+ c = &cd->url_rx_chain[i];
+ c->url_sc = sc;
+ c->url_idx = i;
+ if (url_newbuf(sc, c, NULL) == ENOBUFS)
+ return (ENOBUFS);
+ if (c->url_xfer == NULL) {
+ c->url_xfer = usbd_alloc_xfer(sc->sc_udev);
+ if (c->url_xfer == NULL)
+ return (ENOBUFS);
+ c->url_buf = usbd_alloc_buffer(c->url_xfer, URL_BUFSZ);
+ if (c->url_buf == NULL) {
+ usbd_free_xfer(c->url_xfer);
+ return (ENOBUFS);
+ }
+ }
+ }
+
+ return (0);
+}
+
+Static int
+url_tx_list_init(struct url_softc *sc)
+{
+ struct url_cdata *cd;
+ struct url_chain *c;
+ int i;
+
+ DPRINTF(("%s: %s: enter\n", USBDEVNAME(sc->sc_dev), __FUNCTION__));
+
+ cd = &sc->sc_cdata;
+ for (i = 0; i < URL_TX_LIST_CNT; i++) {
+ c = &cd->url_tx_chain[i];
+ c->url_sc = sc;
+ c->url_idx = i;
+ c->url_mbuf = NULL;
+ if (c->url_xfer == NULL) {
+ c->url_xfer = usbd_alloc_xfer(sc->sc_udev);
+ if (c->url_xfer == NULL)
+ return (ENOBUFS);
+ c->url_buf = usbd_alloc_buffer(c->url_xfer, URL_BUFSZ);
+ if (c->url_buf == NULL) {
+ usbd_free_xfer(c->url_xfer);
+ return (ENOBUFS);
+ }
+ }
+ }
+
+ return (0);
+}
+
+Static void
+url_start(struct ifnet *ifp)
+{
+ struct url_softc *sc = ifp->if_softc;
+ struct mbuf *m_head = NULL;
+
+ DPRINTF(("%s: %s: enter, link=%d\n", USBDEVNAME(sc->sc_dev),
+ __FUNCTION__, sc->sc_link));
+
+ if (sc->sc_dying)
+ return;
+
+ if (!sc->sc_link)
+ return;
+
+ if (ifp->if_flags & IFF_OACTIVE)
+ return;
+
+ IFQ_POLL(&ifp->if_snd, m_head);
+ if (m_head == NULL)
+ return;
+
+ if (url_send(sc, m_head, 0)) {
+ ifp->if_flags |= IFF_OACTIVE;
+ return;
+ }
+
+ IFQ_DEQUEUE(&ifp->if_snd, m_head);
+
+#if NBPFILTER > 0
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m_head);
+#endif
+
+ ifp->if_flags |= IFF_OACTIVE;
+
+ /* Set a timeout in case the chip goes out to lunch. */
+ ifp->if_timer = 5;
+}
+
+Static int
+url_send(struct url_softc *sc, struct mbuf *m, int idx)
+{
+ int total_len;
+ struct url_chain *c;
+ usbd_status err;
+
+ DPRINTF(("%s: %s: enter\n", USBDEVNAME(sc->sc_dev),__FUNCTION__));
+
+ c = &sc->sc_cdata.url_tx_chain[idx];
+
+ /* Copy the mbuf data into a contiguous buffer */
+ m_copydata(m, 0, m->m_pkthdr.len, c->url_buf);
+ c->url_mbuf = m;
+ total_len = m->m_pkthdr.len;
+
+ if (total_len < URL_MIN_FRAME_LEN)
+ total_len = URL_MIN_FRAME_LEN;
+ usbd_setup_xfer(c->url_xfer, sc->sc_pipe_tx, c, c->url_buf, total_len,
+ USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
+ URL_TX_TIMEOUT, url_txeof);
+
+ /* Transmit */
+ sc->sc_refcnt++;
+ err = usbd_transfer(c->url_xfer);
+ if (--sc->sc_refcnt < 0)
+ usb_detach_wakeup(USBDEV(sc->sc_dev));
+ if (err != USBD_IN_PROGRESS) {
+ printf("%s: url_send error=%s\n", USBDEVNAME(sc->sc_dev),
+ usbd_errstr(err));
+ /* Stop the interface */
+ usb_add_task(sc->sc_udev, &sc->sc_stop_task);
+ return (EIO);
+ }
+
+ DPRINTF(("%s: %s: send %d bytes\n", USBDEVNAME(sc->sc_dev),
+ __FUNCTION__, total_len));
+
+ sc->sc_cdata.url_tx_cnt++;
+
+ return (0);
+}
+
+Static void
+url_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
+{
+ struct url_chain *c = priv;
+ struct url_softc *sc = c->url_sc;
+ struct ifnet *ifp = GET_IFP(sc);
+ int s;
+
+ if (sc->sc_dying)
+ return;
+
+ s = splnet();
+
+ DPRINTF(("%s: %s: enter\n", USBDEVNAME(sc->sc_dev), __FUNCTION__));
+
+ ifp->if_timer = 0;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ if (status != USBD_NORMAL_COMPLETION) {
+ if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
+ splx(s);
+ return;
+ }
+ ifp->if_oerrors++;
+ printf("%s: usb error on tx: %s\n", USBDEVNAME(sc->sc_dev),
+ usbd_errstr(status));
+ if (status == USBD_STALLED) {
+ sc->sc_refcnt++;
+ usbd_clear_endpoint_stall(sc->sc_pipe_tx);
+ if (--sc->sc_refcnt < 0)
+ usb_detach_wakeup(USBDEV(sc->sc_dev));
+ }
+ splx(s);
+ return;
+ }
+
+ ifp->if_opackets++;
+
+ m_free(c->url_mbuf);
+ c->url_mbuf = NULL;
+
+ if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
+ url_start(ifp);
+
+ splx(s);
+}
+
+Static void
+url_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
+{
+ struct url_chain *c = priv;
+ struct url_softc *sc = c->url_sc;
+ struct ifnet *ifp = GET_IFP(sc);
+ struct mbuf *m;
+ u_int32_t total_len;
+ url_rxhdr_t rxhdr;
+ int s;
+
+ DPRINTF(("%s: %s: enter\n", USBDEVNAME(sc->sc_dev),__FUNCTION__));
+
+ if (sc->sc_dying)
+ return;
+
+ if (status != USBD_NORMAL_COMPLETION) {
+ if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
+ return;
+ sc->sc_rx_errs++;
+ if (usbd_ratecheck(&sc->sc_rx_notice)) {
+ printf("%s: %u usb errors on rx: %s\n",
+ USBDEVNAME(sc->sc_dev), sc->sc_rx_errs,
+ usbd_errstr(status));
+ sc->sc_rx_errs = 0;
+ }
+ if (status == USBD_STALLED) {
+ sc->sc_refcnt++;
+ usbd_clear_endpoint_stall(sc->sc_pipe_rx);
+ if (--sc->sc_refcnt < 0)
+ usb_detach_wakeup(USBDEV(sc->sc_dev));
+ }
+ goto done;
+ }
+
+ usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
+
+ memcpy(mtod(c->url_mbuf, char *), c->url_buf, total_len);
+
+ if (total_len <= ETHER_CRC_LEN) {
+ ifp->if_ierrors++;
+ goto done;
+ }
+
+ memcpy(&rxhdr, c->url_buf + total_len - ETHER_CRC_LEN, sizeof(rxhdr));
+
+ DPRINTF(("%s: RX Status: %dbytes%s%s%s%s packets\n",
+ USBDEVNAME(sc->sc_dev),
+ UGETW(rxhdr) & URL_RXHDR_BYTEC_MASK,
+ UGETW(rxhdr) & URL_RXHDR_VALID_MASK ? ", Valid" : "",
+ UGETW(rxhdr) & URL_RXHDR_RUNTPKT_MASK ? ", Runt" : "",
+ UGETW(rxhdr) & URL_RXHDR_PHYPKT_MASK ? ", Physical match" : "",
+ UGETW(rxhdr) & URL_RXHDR_MCASTPKT_MASK ? ", Multicast" : ""));
+
+ if ((UGETW(rxhdr) & URL_RXHDR_VALID_MASK) == 0) {
+ ifp->if_ierrors++;
+ goto done;
+ }
+
+ ifp->if_ipackets++;
+ total_len -= ETHER_CRC_LEN;
+
+ m = c->url_mbuf;
+ m->m_pkthdr.len = m->m_len = total_len;
+ m->m_pkthdr.rcvif = ifp;
+
+ s = splnet();
+
+ if (url_newbuf(sc, c, NULL) == ENOBUFS) {
+ ifp->if_ierrors++;
+ goto done1;
+ }
+
+#if NBPFILTER > 0
+ if (ifp->if_bpf)
+ BPF_MTAP(ifp, m);
+#endif
+
+ DPRINTF(("%s: %s: deliver %d\n", USBDEVNAME(sc->sc_dev),
+ __FUNCTION__, m->m_len));
+ IF_INPUT(ifp, m);
+
+ done1:
+ splx(s);
+
+ done:
+ /* Setup new transfer */
+ usbd_setup_xfer(xfer, sc->sc_pipe_rx, c, c->url_buf, URL_BUFSZ,
+ USBD_SHORT_XFER_OK | USBD_NO_COPY,
+ USBD_NO_TIMEOUT, url_rxeof);
+ sc->sc_refcnt++;
+ usbd_transfer(xfer);
+ if (--sc->sc_refcnt < 0)
+ usb_detach_wakeup(USBDEV(sc->sc_dev));
+
+ DPRINTF(("%s: %s: start rx\n", USBDEVNAME(sc->sc_dev), __FUNCTION__));
+}
+
+#if 0
+Static void url_intr()
+{
+}
+#endif
+
+Static int
+url_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+ struct url_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *)data;
+ struct mii_data *mii;
+ int s, error = 0;
+
+ DPRINTF(("%s: %s: enter\n", USBDEVNAME(sc->sc_dev), __FUNCTION__));
+
+ if (sc->sc_dying)
+ return (EIO);
+
+ s = splnet();
+
+ switch (cmd) {
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ mii = GET_MII(sc);
+ error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
+ break;
+
+ default:
+ error = ether_ioctl(ifp, cmd, data);
+ if (error == ENETRESET) {
+ url_setmulti(sc);
+ error = 0;
+ }
+ break;
+ }
+
+ splx(s);
+
+ return (error);
+}
+
+Static void
+url_watchdog(struct ifnet *ifp)
+{
+ struct url_softc *sc = ifp->if_softc;
+ struct url_chain *c;
+ usbd_status stat;
+ int s;
+
+ DPRINTF(("%s: %s: enter\n", USBDEVNAME(sc->sc_dev), __FUNCTION__));
+
+ ifp->if_oerrors++;
+ printf("%s: watchdog timeout\n", USBDEVNAME(sc->sc_dev));
+
+ s = splusb();
+ c = &sc->sc_cdata.url_tx_chain[0];
+ usbd_get_xfer_status(c->url_xfer, NULL, NULL, NULL, &stat);
+ url_txeof(c->url_xfer, c, stat);
+
+ if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
+ url_start(ifp);
+ splx(s);
+}
+
+Static void
+url_stop_task(struct url_softc *sc)
+{
+ url_stop(GET_IFP(sc), 1);
+}
+
+/* Stop the adapter and free any mbufs allocated to the RX and TX lists. */
+Static void
+url_stop(struct ifnet *ifp, int disable)
+{
+ struct url_softc *sc = ifp->if_softc;
+ usbd_status err;
+ int i;
+
+ DPRINTF(("%s: %s: enter\n", USBDEVNAME(sc->sc_dev), __FUNCTION__));
+
+ ifp->if_timer = 0;
+
+ url_reset(sc);
+
+ usb_uncallout(sc->sc_stat_ch, url_tick, sc);
+
+ /* Stop transfers */
+ /* RX endpoint */
+ if (sc->sc_pipe_rx != NULL) {
+ err = usbd_abort_pipe(sc->sc_pipe_rx);
+ if (err)
+ printf("%s: abort rx pipe failed: %s\n",
+ USBDEVNAME(sc->sc_dev), usbd_errstr(err));
+ err = usbd_close_pipe(sc->sc_pipe_rx);
+ if (err)
+ printf("%s: close rx pipe failed: %s\n",
+ USBDEVNAME(sc->sc_dev), usbd_errstr(err));
+ sc->sc_pipe_rx = NULL;
+ }
+
+ /* TX endpoint */
+ if (sc->sc_pipe_tx != NULL) {
+ err = usbd_abort_pipe(sc->sc_pipe_tx);
+ if (err)
+ printf("%s: abort tx pipe failed: %s\n",
+ USBDEVNAME(sc->sc_dev), usbd_errstr(err));
+ err = usbd_close_pipe(sc->sc_pipe_tx);
+ if (err)
+ printf("%s: close tx pipe failed: %s\n",
+ USBDEVNAME(sc->sc_dev), usbd_errstr(err));
+ sc->sc_pipe_tx = NULL;
+ }
+
+#if 0
+ /* XXX: Interrupt endpoint is not yet supported!! */
+ /* Interrupt endpoint */
+ if (sc->sc_pipe_intr != NULL) {
+ err = usbd_abort_pipe(sc->sc_pipe_intr);
+ if (err)
+ printf("%s: abort intr pipe failed: %s\n",
+ USBDEVNAME(sc->sc_dev), usbd_errstr(err));
+ err = usbd_close_pipe(sc->sc_pipe_intr);
+ if (err)
+ printf("%s: close intr pipe failed: %s\n",
+ USBDEVNAME(sc->sc_dev), usbd_errstr(err));
+ sc->sc_pipe_intr = NULL;
+ }
+#endif
+
+ /* Free RX resources. */
+ for (i = 0; i < URL_RX_LIST_CNT; i++) {
+ if (sc->sc_cdata.url_rx_chain[i].url_mbuf != NULL) {
+ m_freem(sc->sc_cdata.url_rx_chain[i].url_mbuf);
+ sc->sc_cdata.url_rx_chain[i].url_mbuf = NULL;
+ }
+ if (sc->sc_cdata.url_rx_chain[i].url_xfer != NULL) {
+ usbd_free_xfer(sc->sc_cdata.url_rx_chain[i].url_xfer);
+ sc->sc_cdata.url_rx_chain[i].url_xfer = NULL;
+ }
+ }
+
+ /* Free TX resources. */
+ for (i = 0; i < URL_TX_LIST_CNT; i++) {
+ if (sc->sc_cdata.url_tx_chain[i].url_mbuf != NULL) {
+ m_freem(sc->sc_cdata.url_tx_chain[i].url_mbuf);
+ sc->sc_cdata.url_tx_chain[i].url_mbuf = NULL;
+ }
+ if (sc->sc_cdata.url_tx_chain[i].url_xfer != NULL) {
+ usbd_free_xfer(sc->sc_cdata.url_tx_chain[i].url_xfer);
+ sc->sc_cdata.url_tx_chain[i].url_xfer = NULL;
+ }
+ }
+
+ sc->sc_link = 0;
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+}
+
+/* Set media options */
+Static int
+url_ifmedia_change(struct ifnet *ifp)
+{
+ struct url_softc *sc = ifp->if_softc;
+ struct mii_data *mii = GET_MII(sc);
+
+ DPRINTF(("%s: %s: enter\n", USBDEVNAME(sc->sc_dev), __FUNCTION__));
+
+ if (sc->sc_dying)
+ return (0);
+
+ sc->sc_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))
+ mii_phy_reset(miisc);
+ }
+
+ return (mii_mediachg(mii));
+}
+
+/* Report current media status. */
+Static void
+url_ifmedia_status(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+ struct url_softc *sc = ifp->if_softc;
+ struct mii_data *mii = GET_MII(sc);
+
+ DPRINTF(("%s: %s: enter\n", USBDEVNAME(sc->sc_dev), __FUNCTION__));
+
+ if (sc->sc_dying)
+ return;
+
+ if ((ifp->if_flags & IFF_RUNNING) == 0) {
+ ifmr->ifm_active = IFM_ETHER | IFM_NONE;
+ ifmr->ifm_status = 0;
+ return;
+ }
+
+ mii_pollstat(mii);
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+}
+
+Static void
+url_tick(void *xsc)
+{
+ struct url_softc *sc = xsc;
+
+ if (sc == NULL)
+ return;
+
+ DPRINTFN(0xff, ("%s: %s: enter\n", USBDEVNAME(sc->sc_dev),
+ __FUNCTION__));
+
+ if (sc->sc_dying)
+ return;
+
+ /* Perform periodic stuff in process context */
+ usb_add_task(sc->sc_udev, &sc->sc_tick_task);
+}
+
+Static void
+url_tick_task(void *xsc)
+{
+ struct url_softc *sc = xsc;
+ struct ifnet *ifp;
+ struct mii_data *mii;
+ int s;
+
+ if (sc == NULL)
+ return;
+
+ DPRINTFN(0xff, ("%s: %s: enter\n", USBDEVNAME(sc->sc_dev),
+ __FUNCTION__));
+
+ if (sc->sc_dying)
+ return;
+
+ ifp = GET_IFP(sc);
+ mii = GET_MII(sc);
+
+ if (mii == NULL)
+ return;
+
+ s = splnet();
+
+ mii_tick(mii);
+ if (!sc->sc_link) {
+ mii_pollstat(mii);
+ if (mii->mii_media_status & IFM_ACTIVE &&
+ IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
+ DPRINTF(("%s: %s: got link\n",
+ USBDEVNAME(sc->sc_dev), __FUNCTION__));
+ sc->sc_link++;
+ if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
+ url_start(ifp);
+ }
+ }
+
+ usb_callout(sc->sc_stat_ch, hz, url_tick, sc);
+
+ splx(s);
+}
+
+/* Get exclusive access to the MII registers */
+Static void
+url_lock_mii(struct url_softc *sc)
+{
+ DPRINTFN(0xff, ("%s: %s: enter\n", USBDEVNAME(sc->sc_dev),
+ __FUNCTION__));
+
+ sc->sc_refcnt++;
+ lockmgr(&sc->sc_mii_lock, LK_EXCLUSIVE, NULL);
+}
+
+Static void
+url_unlock_mii(struct url_softc *sc)
+{
+ DPRINTFN(0xff, ("%s: %s: enter\n", USBDEVNAME(sc->sc_dev),
+ __FUNCTION__));
+
+ lockmgr(&sc->sc_mii_lock, LK_RELEASE, NULL);
+ if (--sc->sc_refcnt < 0)
+ usb_detach_wakeup(USBDEV(sc->sc_dev));
+}
+
+Static int
+url_int_miibus_readreg(device_ptr_t dev, int phy, int reg)
+{
+ struct url_softc *sc;
+ u_int16_t val;
+
+ if (dev == NULL)
+ return (0);
+
+ sc = USBGETSOFTC(dev);
+
+ DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x\n",
+ USBDEVNAME(sc->sc_dev), __FUNCTION__, phy, reg));
+
+ if (sc->sc_dying) {
+#ifdef DIAGNOSTIC
+ printf("%s: %s: dying\n", USBDEVNAME(sc->sc_dev),
+ __FUNCTION__);
+#endif
+ return (0);
+ }
+
+ /* XXX: one PHY only for the RTL8150 internal PHY */
+ if (phy != 0) {
+ DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n",
+ USBDEVNAME(sc->sc_dev), __FUNCTION__, phy));
+ return (0);
+ }
+
+ url_lock_mii(sc);
+
+ switch (reg) {
+ case MII_BMCR: /* Control Register */
+ reg = URL_BMCR;
+ break;
+ case MII_BMSR: /* Status Register */
+ reg = URL_BMSR;
+ break;
+ case MII_PHYIDR1:
+ case MII_PHYIDR2:
+ val = 0;
+ goto R_DONE;
+ break;
+ case MII_ANAR: /* Autonegotiation advertisement */
+ reg = URL_ANAR;
+ break;
+ case MII_ANLPAR: /* Autonegotiation link partner abilities */
+ reg = URL_ANLP;
+ break;
+ case URLPHY_MSR: /* Media Status Register */
+ reg = URL_MSR;
+ break;
+ default:
+ printf("%s: %s: bad register %04x\n",
+ USBDEVNAME(sc->sc_dev), __FUNCTION__, reg);
+ val = 0;
+ goto R_DONE;
+ break;
+ }
+
+ if (reg == URL_MSR)
+ val = url_csr_read_1(sc, reg);
+ else
+ val = url_csr_read_2(sc, reg);
+
+ R_DONE:
+ DPRINTFN(0xff, ("%s: %s: phy=%d reg=0x%04x => 0x%04x\n",
+ USBDEVNAME(sc->sc_dev), __FUNCTION__, phy, reg, val));
+
+ url_unlock_mii(sc);
+ return (val);
+}
+
+Static void
+url_int_miibus_writereg(device_ptr_t dev, int phy, int reg, int data)
+{
+ struct url_softc *sc;
+
+ if (dev == NULL)
+ return;
+
+ sc = USBGETSOFTC(dev);
+
+ DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x data=0x%04x\n",
+ USBDEVNAME(sc->sc_dev), __FUNCTION__, phy, reg, data));
+
+ if (sc->sc_dying) {
+#ifdef DIAGNOSTIC
+ printf("%s: %s: dying\n", USBDEVNAME(sc->sc_dev),
+ __FUNCTION__);
+#endif
+ return;
+ }
+
+ /* XXX: one PHY only for the RTL8150 internal PHY */
+ if (phy != 0) {
+ DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n",
+ USBDEVNAME(sc->sc_dev), __FUNCTION__, phy));
+ return;
+ }
+
+ url_lock_mii(sc);
+
+ switch (reg) {
+ case MII_BMCR: /* Control Register */
+ reg = URL_BMCR;
+ break;
+ case MII_BMSR: /* Status Register */
+ reg = URL_BMSR;
+ break;
+ case MII_PHYIDR1:
+ case MII_PHYIDR2:
+ goto W_DONE;
+ break;
+ case MII_ANAR: /* Autonegotiation advertisement */
+ reg = URL_ANAR;
+ break;
+ case MII_ANLPAR: /* Autonegotiation link partner abilities */
+ reg = URL_ANLP;
+ break;
+ case URLPHY_MSR: /* Media Status Register */
+ reg = URL_MSR;
+ break;
+ default:
+ printf("%s: %s: bad register %04x\n",
+ USBDEVNAME(sc->sc_dev), __FUNCTION__, reg);
+ goto W_DONE;
+ break;
+ }
+
+ if (reg == URL_MSR)
+ url_csr_write_1(sc, reg, data);
+ else
+ url_csr_write_2(sc, reg, data);
+ W_DONE:
+
+ url_unlock_mii(sc);
+ return;
+}
+
+Static void
+url_miibus_statchg(device_ptr_t dev)
+{
+#ifdef URL_DEBUG
+ struct url_softc *sc;
+
+ if (dev == NULL)
+ return;
+
+ sc = USBGETSOFTC(dev);
+ DPRINTF(("%s: %s: enter\n", USBDEVNAME(sc->sc_dev), __FUNCTION__));
+#endif
+ /* Nothing to do */
+}
+
+#if 0
+/*
+ * external PHYs support, but not test.
+ */
+Static int
+url_ext_miibus_redreg(device_ptr_t dev, int phy, int reg)
+{
+ struct url_softc *sc = USBGETSOFTC(dev);
+ u_int16_t val;
+
+ DPRINTF(("%s: %s: enter, phy=%d reg=0x%04x\n",
+ USBDEVNAME(sc->sc_dev), __FUNCTION__, phy, reg));
+
+ if (sc->sc_dying) {
+#ifdef DIAGNOSTIC
+ printf("%s: %s: dying\n", USBDEVNAME(sc->sc_dev),
+ __FUNCTION__);
+#endif
+ return (0);
+ }
+
+ url_lock_mii(sc);
+
+ url_csr_write_1(sc, URL_PHYADD, phy & URL_PHYADD_MASK);
+ /*
+ * RTL8150L will initiate a MII management data transaction
+ * if PHYCNT_OWN bit is set 1 by software. After transaction,
+ * this bit is auto cleared by TRL8150L.
+ */
+ url_csr_write_1(sc, URL_PHYCNT,
+ (reg | URL_PHYCNT_PHYOWN) & ~URL_PHYCNT_RWCR);
+ for (i = 0; i < URL_TIMEOUT; i++) {
+ if ((url_csr_read_1(sc, URL_PHYCNT) & URL_PHYCNT_PHYOWN) == 0)
+ break;
+ }
+ if (i == URL_TIMEOUT) {
+ printf("%s: MII read timed out\n", USBDEVNAME(sc->sc_dev));
+ }
+
+ val = url_csr_read_2(sc, URL_PHYDAT);
+
+ DPRINTF(("%s: %s: phy=%d reg=0x%04x => 0x%04x\n",
+ USBDEVNAME(sc->sc_dev), __FUNCTION__, phy, reg, val));
+
+ url_unlock_mii(sc);
+ return (val);
+}
+
+Static void
+url_ext_miibus_writereg(device_ptr_t dev, int phy, int reg, int data)
+{
+ struct url_softc *sc = USBGETSOFTC(dev);
+
+ DPRINTF(("%s: %s: enter, phy=%d reg=0x%04x data=0x%04x\n",
+ USBDEVNAME(sc->sc_dev), __FUNCTION__, phy, reg, data));
+
+ if (sc->sc_dying) {
+#ifdef DIAGNOSTIC
+ printf("%s: %s: dying\n", USBDEVNAME(sc->sc_dev),
+ __FUNCTION__);
+#endif
+ return;
+ }
+
+ url_lock_mii(sc);
+
+ url_csr_write_2(sc, URL_PHYDAT, data);
+ url_csr_write_1(sc, URL_PHYADD, phy);
+ url_csr_write_1(sc, URL_PHYCNT, reg | URL_PHYCNT_RWCR); /* Write */
+
+ for (i=0; i < URL_TIMEOUT; i++) {
+ if (url_csr_read_1(sc, URL_PHYCNT) & URL_PHYCNT_PHYOWN)
+ break;
+ }
+
+ if (i == URL_TIMEOUT) {
+ printf("%s: MII write timed out\n",
+ USBDEVNAME(sc->sc_dev));
+ }
+
+ url_unlock_mii(sc);
+ return;
+}
+#endif
+
diff --git a/sys/dev/usb/if_urlreg.h b/sys/dev/usb/if_urlreg.h
new file mode 100644
index 00000000000..f76bb380f00
--- /dev/null
+++ b/sys/dev/usb/if_urlreg.h
@@ -0,0 +1,195 @@
+/* $OpenBSD: if_urlreg.h,v 1.1 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: if_urlreg.h,v 1.1 2002/03/28 21:09:11 ichiro Exp $ */
+/*
+ * Copyright (c) 2001, 2002
+ * Shingo WATANABE <nabe@nabechan.org>. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Shingo WATANABE.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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.
+ *
+ */
+
+#define URL_IFACE_INDEX 0
+#define URL_CONFIG_NO 1
+
+#define URL_TX_LIST_CNT 1
+#define URL_RX_LIST_CNT 1
+
+#define URL_TX_TIMEOUT 1000
+#define URL_TIMEOUT 10000
+
+#define ETHER_ALIGN 2
+
+
+/* Packet length */
+#define URL_MAX_MTU 1536
+#define URL_MIN_FRAME_LEN 60
+#define URL_BUFSZ URL_MAX_MTU
+
+/* Request */
+#define URL_REQ_MEM 0x05
+
+#define URL_CMD_READMEM 1
+#define URL_CMD_WRITEMEM 2
+
+/* Registers */
+#define URL_IDR0 0x0120 /* Ethernet Address, load from 93C46 */
+#define URL_IDR1 0x0121 /* Ethernet Address, load from 93C46 */
+#define URL_IDR2 0x0122 /* Ethernet Address, load from 93C46 */
+#define URL_IDR3 0x0123 /* Ethernet Address, load from 93C46 */
+#define URL_IDR4 0x0124 /* Ethernet Address, load from 93C46 */
+#define URL_IDR5 0x0125 /* Ethernet Address, load from 93C46 */
+
+#define URL_MAR0 0x0126 /* Multicast register */
+#define URL_MAR1 0x0127 /* Multicast register */
+#define URL_MAR2 0x0128 /* Multicast register */
+#define URL_MAR3 0x0129 /* Multicast register */
+#define URL_MAR4 0x012a /* Multicast register */
+#define URL_MAR5 0x012b /* Multicast register */
+#define URL_MAR6 0x012c /* Multicast register */
+#define URL_MAR7 0x012d /* Multicast register */
+#define URL_MAR URL_MAR0
+
+#define URL_CR 0x012e /* Command Register */
+#define URL_CR_WEPROM (1<<5) /* EEPROM Write Enable */
+#define URL_CR_SOFT_RST (1<<4) /* Software Reset */
+#define URL_CR_RE (1<<3) /* Ethernet Receive Enable */
+#define URL_CR_TE (1<<2) /* Ethernet Transmit Enable */
+#define URL_CR_EP3CLREN (1<<1) /* Enable clearing the performance counter */
+#define URL_CR_AUTOLOAD (1<<0) /* Auto-load the contents of 93C46 */
+
+#define URL_TCR 0x012f /* Transmit Control Register */
+#define URL_TCR_TXRR1 (1<<7) /* TX Retry Count */
+#define URL_TCR_TXRR0 (1<<6) /* TX Retry Count */
+#define URL_TCR_IFG1 (1<<4) /* Interframe Gap Time */
+#define URL_TCR_IFG0 (1<<4) /* Interframe Gap Time */
+#define URL_TCR_NOCRC (1<<0) /* no CRC Append */
+
+#define URL_RCR 0x0130 /* Receive Configuration Register */
+#define URL_RCR_TAIL (1<<7)
+#define URL_RCR_AER (1<<6)
+#define URL_RCR_AR (1<<5)
+#define URL_RCR_AM (1<<4)
+#define URL_RCR_AB (1<<3)
+#define URL_RCR_AD (1<<2)
+#define URL_RCR_AAM (1<<1)
+#define URL_RCR_AAP (1<<0)
+
+#define URL_MSR 0x137 /* Media Status Register */
+#define URL_MSR_TXFCE (1<<7)
+#define URL_MSR_RXFCE (1<<6)
+#define URL_MSR_DUPLEX (1<<4)
+#define URL_MSR_SPEED_100 (1<<3)
+#define URL_MSR_LINK (1<<2)
+#define URL_MSR_TXPF (1<<1)
+#define URL_MSR_RXPF (1<<0)
+
+#define URL_PHYADD 0x138 /* MII PHY Address select */
+#define URL_PHYADD_MASK 0x1f /* MII PHY Address select */
+
+#define URL_PHYDAT 0x139 /* MII PHY data */
+
+#define URL_PHYCNT 0x13b /* MII PHY control */
+#define URL_PHYCNT_PHYOWN (1<<6) /* Own bit */
+#define URL_PHYCNT_RWCR (1<<5) /* MII management data R/W control */
+#define URL_PHY_PHYOFF_MASK 0x1f /* PHY register offset */
+
+#define URL_BMCR 0x140 /* Basic mode control register */
+#define URL_BMSR 0x142 /* Basic mode status register */
+#define URL_ANAR 0x144 /* Auto-negotiation advertisement register */
+#define URL_ANLP 0x146 /* Auto-negotiation link partner ability register */
+
+
+typedef uWord url_rxhdr_t; /* Recive Header */
+#define URL_RXHDR_BYTEC_MASK (0x0fff) /* RX bytes count */
+#define URL_RXHDR_VALID_MASK (0x1000) /* Valid packet */
+#define URL_RXHDR_RUNTPKT_MASK (0x2000) /* Runt packet */
+#define URL_RXHDR_PHYPKT_MASK (0x4000) /* Physical match packet */
+#define URL_RXHDR_MCASTPKT_MASK (0x8000) /* Multicast packet */
+
+#define GET_IFP(sc) (&(sc)->sc_ec.ec_if)
+#define GET_MII(sc) (&(sc)->sc_mii)
+
+struct url_chain {
+ struct url_softc *url_sc;
+ usbd_xfer_handle url_xfer;
+ char *url_buf;
+ struct mbuf *url_mbuf;
+ int url_idx;
+};
+
+struct url_cdata {
+ struct url_chain url_tx_chain[URL_TX_LIST_CNT];
+ struct url_chain url_rx_chain[URL_TX_LIST_CNT];
+#if 0
+ /* XXX: Intrrupt Endpoint is not yet supported! */
+ struct url_intrpkg url_ibuf;
+#endif
+ int url_tx_prod;
+ int url_tx_cons;
+ int url_tx_cnt;
+ int url_rx_prod;
+};
+
+struct url_softc {
+ USBBASEDEVICE sc_dev; /* base device */
+ usbd_device_handle sc_udev;
+
+ /* USB */
+ usbd_interface_handle sc_ctl_iface;
+ /* int sc_ctl_iface_no; */
+ int sc_bulkin_no; /* bulk in endpoint */
+ int sc_bulkout_no; /* bulk out endpoint */
+ int sc_intrin_no; /* intr in endpoint */
+ usbd_pipe_handle sc_pipe_rx;
+ usbd_pipe_handle sc_pipe_tx;
+ usbd_pipe_handle sc_pipe_intr;
+ usb_callout_t sc_stat_ch;
+ u_int sc_rx_errs;
+ /* u_int sc_intr_errs; */
+ struct timeval sc_rx_notice;
+
+ /* Ethernet */
+ struct ethercom sc_ec; /* ethernet common */
+ struct mii_data sc_mii;
+ struct lock sc_mii_lock;
+ int sc_link;
+#define sc_media url_mii.mii_media
+#if NRND > 0
+ rndsource_element_t rnd_source;
+#endif
+ struct url_cdata sc_cdata;
+
+ int sc_attached;
+ int sc_dying;
+ int sc_refcnt;
+
+ struct usb_task sc_tick_task;
+ struct usb_task sc_stop_task;
+
+ u_int16_t sc_flags;
+};
diff --git a/sys/dev/usb/ohci.c b/sys/dev/usb/ohci.c
index c1e83997e64..4e1107f020f 100644
--- a/sys/dev/usb/ohci.c
+++ b/sys/dev/usb/ohci.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: ohci.c,v 1.26 2002/05/02 20:08:04 nate Exp $ */
-/* $NetBSD: ohci.c,v 1.104 2001/09/28 23:57:21 augustss Exp $ */
+/* $OpenBSD: ohci.c,v 1.27 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: ohci.c,v 1.122 2002/03/17 18:02:52 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/ohci.c,v 1.22 1999/11/17 22:33:40 n_hibma Exp $ */
/*
@@ -198,18 +198,18 @@ 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 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 *sc);
+Static void ohci_rhsc_enable(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_abort_xfer_end(void *);
Static void ohci_device_clear_toggle(usbd_pipe_handle pipe);
Static void ohci_noop(usbd_pipe_handle pipe);
@@ -236,7 +236,7 @@ Static void ohci_dump_itds(ohci_soft_itd_t *);
#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,
@@ -286,7 +286,7 @@ Static struct usbd_bus_methods ohci_bus_methods = {
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,
@@ -295,7 +295,7 @@ Static struct usbd_pipe_methods ohci_root_ctrl_methods = {
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,
@@ -304,7 +304,7 @@ Static struct usbd_pipe_methods ohci_root_intr_methods = {
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,
@@ -313,7 +313,7 @@ Static struct usbd_pipe_methods ohci_device_ctrl_methods = {
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,
@@ -322,7 +322,7 @@ Static struct usbd_pipe_methods ohci_device_intr_methods = {
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,
@@ -368,15 +368,19 @@ ohci_detach(struct ohci_softc *sc, int flags)
if (sc->sc_child != NULL)
rv = config_detach(sc->sc_child, flags);
-
+
if (rv != 0)
return (rv);
+ 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);
@@ -488,7 +492,7 @@ ohci_alloc_std_chain(struct ohci_pipe *opipe, ohci_softc_t *sc,
dataphys = DMAADDR(dma);
dataphysend = OHCI_PAGE(dataphys + len - 1);
tdflags = htole32(
- (rd ? OHCI_TD_IN : OHCI_TD_OUT) |
+ (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);
@@ -504,7 +508,7 @@ ohci_alloc_std_chain(struct ohci_pipe *opipe, ohci_softc_t *sc,
curlen = len;
} else {
/* must use multiple TDs, fill as much as possible. */
- curlen = 2 * OHCI_PAGE_SIZE -
+ curlen = 2 * OHCI_PAGE_SIZE -
(dataphys & (OHCI_PAGE_SIZE-1));
/* the length must be a multiple of the max size */
curlen -= curlen % UGETW(opipe->pipe.endpoint->edesc->wMaxPacketSize);
@@ -565,7 +569,7 @@ ohci_alloc_std_chain(struct ohci_pipe *opipe, ohci_softc_t *sc,
#if 0
Static void
-ohci_free_std_chain(ohci_softc_t *sc, ohci_soft_td_t *std,
+ohci_free_std_chain(ohci_softc_t *sc, ohci_soft_td_t *std,
ohci_soft_td_t *stdend)
{
ohci_soft_td_t *p;
@@ -637,15 +641,6 @@ ohci_free_sitd(ohci_softc_t *sc, ohci_soft_itd_t *sitd)
splx(s);
}
-void
-ohci_reset(ohci_softc_t *sc)
-{
- ohci_shutdown(sc);
- /* disable all interrupts and then switch on all desired
- interrupts */
- OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS);
-}
-
usbd_status
ohci_init(ohci_softc_t *sc)
{
@@ -665,7 +660,7 @@ ohci_init(ohci_softc_t *sc)
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);
@@ -681,7 +676,7 @@ ohci_init(ohci_softc_t *sc)
/* 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);
@@ -733,12 +728,12 @@ ohci_init(ohci_softc_t *sc)
sed->next = psed;
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]] =
+ sc->sc_hcca->hcca_interrupt_table[revbits[i]] =
htole32(sc->sc_eds[OHCI_NO_EDS-OHCI_NO_INTRS+i]->physaddr);
#ifdef OHCI_DEBUG
@@ -861,7 +856,7 @@ ohci_init(ohci_softc_t *sc)
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);
@@ -875,6 +870,8 @@ ohci_init(ohci_softc_t *sc)
timeout_set(&sc->sc_tmo_rhsc, ohci_rhsc_enable, sc);
#endif
+ usb_callout_init(sc->sc_tmo_rhsc);
+
return (USBD_NORMAL_COMPLETION);
bad5:
@@ -918,12 +915,23 @@ ohci_allocx(struct usbd_bus *bus)
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);
}
@@ -932,6 +940,14 @@ ohci_freex(struct usbd_bus *bus, usbd_xfer_handle xfer)
{
struct ohci_softc *sc = (struct ohci_softc *)bus;
+#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);
}
@@ -1065,15 +1081,22 @@ ohci_intr(void *p)
{
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
- printf("ohci_intr: ignored interrupt while polling\n");
+ static int repeat = 0;
+ if (repeat < 10) {
+ printf("ohci_intr: ignored interrupt while polling\n");
+ ++repeat;
+ }
#endif
return (0);
}
- return (ohci_intr1(sc));
+ return (ohci_intr1(sc));
}
Static int
@@ -1082,6 +1105,8 @@ ohci_intr1(ohci_softc_t *sc)
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
@@ -1111,7 +1136,7 @@ ohci_intr1(ohci_softc_t *sc)
sc->sc_bus.intr_context++;
sc->sc_bus.no_intrs++;
- DPRINTFN(7, ("ohci_intr: sc=%p intrs=0x%x(0x%x) eintrs=0x%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));
@@ -1123,13 +1148,13 @@ ohci_intr1(ohci_softc_t *sc)
sc->sc_overrun_cnt = 0;
}
/* XXX do what */
- intrs &= ~OHCI_SO;
+ eintrs &= ~OHCI_SO;
}
if (eintrs & OHCI_WDH) {
ohci_add_done(sc, done &~ OHCI_DONE_INTRS);
sc->sc_hcca->hcca_done_head = 0;
usb_schedsoftintr(&sc->sc_bus);
- intrs &= ~OHCI_WDH;
+ eintrs &= ~OHCI_WDH;
}
if (eintrs & OHCI_RD) {
printf("%s: resume detect\n", USBDEVNAME(sc->sc_bus.bdev));
@@ -1143,24 +1168,28 @@ ohci_intr1(ohci_softc_t *sc)
}
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);
-#if defined (__OpenBSD__)
+ DPRINTFN(2, ("%s: rhsc interrupt disabled\n",
+ USBDEVNAME(sc->sc_bus.bdev)));
+
/* Do not allow RHSC interrupts > 1 per second */
- timeout_add(&sc->sc_tmo_rhsc, hz);
-#endif
+ 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);
}
@@ -1183,6 +1212,10 @@ ohci_rhsc_enable(void *v_sc)
{
ohci_softc_t *sc = v_sc;
+ ohci_rhsc(sc, sc->sc_intrxfer);
+ DPRINTFN(2, ("%s: rhsc interrupt enabled\n",
+ USBDEVNAME(sc->sc_bus.bdev)));
+
ohci_rhsc_able(sc, 1);
}
@@ -1253,6 +1286,8 @@ ohci_softintr(void *v)
usbd_xfer_handle xfer;
int len, cc, s;
+ DPRINTFN(10,("ohci_softintr: enter\n:"));
+
sc->sc_bus.intr_context++;
s = splhardusb();
@@ -1262,7 +1297,7 @@ ohci_softintr(void *v)
sc->sc_sidone = NULL;
splx(s);
- DPRINTFN(10,("ohci_process_done: sdone=%p sidone=%p\n", sdone, sidone));
+ DPRINTFN(10,("ohci_softintr: sdone=%p sidone=%p\n", sdone, sidone));
#ifdef OHCI_DEBUG
if (ohcidebug > 10) {
@@ -1277,9 +1312,11 @@ ohci_softintr(void *v)
DPRINTFN(10, ("ohci_process_done: std=%p xfer=%p hcpriv=%p\n",
std, xfer, xfer ? xfer->hcpriv : 0));
if (xfer == NULL) {
- /* 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.
+ * Shouldn't happen, but some chips are broken(?).
*/
continue;
}
@@ -1313,7 +1350,7 @@ ohci_softintr(void *v)
* the endpoint.
*/
ohci_soft_td_t *p, *n;
- struct ohci_pipe *opipe =
+ struct ohci_pipe *opipe =
(struct ohci_pipe *)xfer->pipe;
DPRINTFN(15,("ohci_process_done: error cc=%d (%s)\n",
@@ -1340,7 +1377,7 @@ ohci_softintr(void *v)
#ifdef OHCI_DEBUG
if (ohcidebug > 10) {
- DPRINTF(("ohci_process_done: ITD done:\n"));
+ DPRINTF(("ohci_softintr: ITD done:\n"));
ohci_dump_itds(sidone);
}
#endif
@@ -1367,7 +1404,7 @@ ohci_softintr(void *v)
cc = OHCI_ITD_GET_CC(le32toh(sitd->itd.itd_flags));
if (cc == OHCI_CC_NO_ERROR) {
/* XXX compute length for input */
- struct ohci_pipe *opipe =
+ struct ohci_pipe *opipe =
(struct ohci_pipe *)xfer->pipe;
if (sitd->flags & OHCI_CALL_DONE) {
opipe->u.iso.inuse -= xfer->nframes;
@@ -1383,7 +1420,13 @@ ohci_softintr(void *v)
}
}
+ if (sc->sc_softwake) {
+ sc->sc_softwake = 0;
+ wakeup(&sc->sc_softwake);
+ }
+
sc->sc_bus.intr_context--;
+ DPRINTFN(10,("ohci_softintr: done:\n"));
}
void
@@ -1408,7 +1451,7 @@ ohci_device_intr_done(usbd_xfer_handle xfer)
ohci_soft_td_t *data, *tail;
- DPRINTFN(10,("ohci_intr_done: xfer=%p, actlen=%d\n",
+ DPRINTFN(10,("ohci_intr_done: xfer=%p, actlen=%d\n",
xfer, xfer->actlen));
xfer->hcpriv = NULL;
@@ -1421,9 +1464,9 @@ ohci_device_intr_done(usbd_xfer_handle xfer)
return;
}
tail->xfer = NULL;
-
+
data->td.td_flags = htole32(
- OHCI_TD_IN | OHCI_TD_NOCC |
+ 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 |= htole32(OHCI_TD_R);
@@ -1446,7 +1489,7 @@ ohci_device_intr_done(usbd_xfer_handle xfer)
void
ohci_device_bulk_done(usbd_xfer_handle xfer)
{
- DPRINTFN(10,("ohci_bulk_done: xfer=%p, actlen=%d\n",
+ DPRINTFN(10,("ohci_bulk_done: xfer=%p, actlen=%d\n",
xfer, xfer->actlen));
xfer->hcpriv = NULL;
@@ -1462,7 +1505,7 @@ ohci_rhsc(ohci_softc_t *sc, usbd_xfer_handle xfer)
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) {
@@ -1515,6 +1558,8 @@ ohci_waitintr(ohci_softc_t *sc, usbd_xfer_handle xfer)
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 OHCI_DEBUG
@@ -1539,6 +1584,15 @@ void
ohci_poll(struct usbd_bus *bus)
{
ohci_softc_t *sc = (ohci_softc_t *)bus;
+#ifdef OHCI_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);
@@ -1565,7 +1619,7 @@ ohci_device_request(usbd_xfer_handle xfer)
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;
@@ -1651,11 +1705,15 @@ ohci_device_request(usbd_xfer_handle xfer)
}
splx(s);
-#if 0
- if (ohcidebug > 10) {
+#ifdef OHCI_DEBUG
+ 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);
}
@@ -1677,6 +1735,8 @@ ohci_device_request(usbd_xfer_handle xfer)
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;
@@ -1690,7 +1750,7 @@ ohci_add_ed(ohci_soft_ed_t *sed, ohci_soft_ed_t *head)
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;
@@ -1740,7 +1800,7 @@ ohci_hash_find_td(ohci_softc_t *sc, ohci_physaddr_t a)
int h = HASH(a);
ohci_soft_td_t *std;
- 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)
@@ -1756,7 +1816,7 @@ ohci_hash_add_itd(ohci_softc_t *sc, ohci_soft_itd_t *sitd)
SPLUSBCHECK;
- DPRINTFN(10,("ohci_hash_add_itd: sitd=%p physaddr=0x%08lx\n",
+ 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);
@@ -1768,7 +1828,7 @@ 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",
+ DPRINTFN(10,("ohci_hash_rem_itd: sitd=%p physaddr=0x%08lx\n",
sitd, (u_long)sitd->physaddr));
LIST_REMOVE(sitd, hnext);
@@ -1780,7 +1840,7 @@ 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]);
+ for (sitd = LIST_FIRST(&sc->sc_hash_itds[h]);
sitd != NULL;
sitd = LIST_NEXT(sitd, hnext))
if (sitd->physaddr == a)
@@ -1791,15 +1851,32 @@ ohci_hash_find_itd(ohci_softc_t *sc, ohci_physaddr_t a)
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);
}
@@ -1816,19 +1893,19 @@ ohci_dump_td(ohci_soft_td_t *std)
{
char sbuf[128];
- bitmask_snprintf((int)le32toh(std->td.td_flags),
+ bitmask_snprintf((u_int32_t)le32toh(std->td.td_flags),
"\20\23R\24OUT\25IN\31TOG1\32SETTOGGLE",
sbuf, sizeof(sbuf));
- DPRINTF(("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)));
+ 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
@@ -1836,20 +1913,20 @@ ohci_dump_itd(ohci_soft_itd_t *sitd)
{
int i;
- DPRINTF(("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)));
+ 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++)
- DPRINTF(("offs[%d]=0x%04x ", i,
- (u_int)le16toh(sitd->itd.itd_offset[i])));
- DPRINTF(("\n"));
+ printf("offs[%d]=0x%04x ", i,
+ (u_int)le16toh(sitd->itd.itd_offset[i]));
+ printf("\n");
}
void
@@ -1864,21 +1941,21 @@ ohci_dump_ed(ohci_soft_ed_t *sed)
{
char sbuf[128], sbuf2[128];
- bitmask_snprintf((int)le32toh(sed->ed.ed_flags),
+ bitmask_snprintf((u_int32_t)le32toh(sed->ed.ed_flags),
"\20\14OUT\15IN\16LOWSPEED\17SKIP\20ISO",
sbuf, sizeof(sbuf));
- bitmask_snprintf((u_long)le32toh(sed->ed.ed_headp),
+ bitmask_snprintf((u_int32_t)le32toh(sed->ed.ed_headp),
"\20\1HALT\2CARRY", sbuf2, sizeof(sbuf2));
- DPRINTF(("ED(%p) at 0x%08lx: addr=%d endpt=%d maxp=%d %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)));
+ printf("ED(%p) at 0x%08lx: addr=%d endpt=%d maxp=%d flags=%s\n"
+ "tailp=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
@@ -1903,6 +1980,9 @@ ohci_open(usbd_pipe_handle pipe)
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;
@@ -1946,17 +2026,17 @@ ohci_open(usbd_pipe_handle pipe)
fmt = OHCI_ED_FORMAT_GEN | OHCI_ED_DIR_TD;
}
sed->ed.ed_flags = htole32(
- OHCI_ED_SET_FA(addr) |
+ OHCI_ED_SET_FA(addr) |
OHCI_ED_SET_EN(ed->bEndpointAddress) |
- (dev->lowspeed ? OHCI_ED_SPEED : 0) | fmt |
- OHCI_ED_SET_MAXP(UGETW(ed->wMaxPacketSize)));
+ (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 = 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;
@@ -1991,7 +2071,7 @@ ohci_open(usbd_pipe_handle pipe)
ohci_free_sed(sc, sed);
bad0:
return (USBD_NOMEM);
-
+
}
/*
@@ -2009,22 +2089,25 @@ ohci_close_pipe(usbd_pipe_handle pipe, ohci_soft_ed_t *head)
s = splusb();
#ifdef DIAGNOSTIC
sed->ed.ed_flags |= htole32(OHCI_ED_SKIP);
- if ((le32toh(sed->ed.ed_tailp) & OHCI_HEADMASK) !=
+ if ((le32toh(sed->ed.ed_tailp) & OHCI_HEADMASK) !=
(le32toh(sed->ed.ed_headp) & OHCI_HEADMASK)) {
- ohci_physaddr_t td = le32toh(sed->ed.ed_headp);
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)le32toh(sed->ed.ed_headp),
(int)le32toh(sed->ed.ed_tailp),
pipe, std);
+#ifdef USB_DEBUG
+ usbd_dump_pipe(&opipe->pipe);
+#endif
+#ifdef OHCI_DEBUG
+ ohci_dump_ed(sed);
+ if (std)
+ ohci_dump_td(std);
+#endif
usb_delay_ms(&sc->sc_bus, 2);
- if ((le32toh(sed->ed.ed_tailp) & 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");
}
@@ -2034,7 +2117,7 @@ ohci_close_pipe(usbd_pipe_handle pipe, ohci_soft_ed_t *head)
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
@@ -2048,68 +2131,96 @@ void
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_uncallout(xfer->timeout_handle, ohci_timeout, xfer);
+ if (xfer->device->bus->intr_context || !curproc)
+ panic("ohci_abort_xfer: not in process context\n");
- sed = opipe->sed;
+ /*
+ * 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));
sed->ed.ed_flags |= htole32(OHCI_ED_SKIP); /* force hardware skip */
-#if 1
- if (xfer->device->bus->intr_context) {
- /* We have no process context, so we can't use tsleep(). */
- usb_callout(xfer->pipe->abort_handle,
- hz / USB_FRAMES_PER_SECOND, ohci_abort_xfer_end, xfer);
- } 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;
-
+ /*
+ * 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();
+ sc->sc_softwake = 1;
+ usb_schedsoftintr(&sc->sc_bus);
+ tsleep(&sc->sc_softwake, PZERO, "ohciab", 0);
+ 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) {
splx(s);
- printf("ohci_abort_xfer: hcpriv==0\n");
+ printf("ohci_abort_xfer: hcpriv is NULL\n");
return;
}
#endif
+#ifdef OHCI_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)p->physaddr, (int)le32toh(sed->ed.ed_tailp)));
- sed->ed.ed_headp = htole32(p->physaddr); /* unlink TDs */
+ /*
+ * 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);
@@ -2124,7 +2235,7 @@ Static usb_device_descriptor_t ohci_devd = {
{0x00, 0x01}, /* USB version */
UDCLASS_HUB, /* class */
UDSUBCLASS_HUB, /* subclass */
- 0, /* protocol */
+ UDPROTO_FSHUB,
64, /* max packet */
{0},{0},{0x00,0x01}, /* device id */
1,2,0, /* string indicies */
@@ -2152,7 +2263,7 @@ Static usb_interface_descriptor_t ohci_ifcd = {
1,
UICLASS_HUB,
UISUBCLASS_HUB,
- 0,
+ UIPROTO_FSHUB,
0
};
@@ -2176,10 +2287,7 @@ Static usb_hub_descriptor_t ohci_hubd = {
};
Static int
-ohci_str(p, l, s)
- usb_string_descriptor_t *p;
- int l;
- char *s;
+ohci_str(usb_string_descriptor_t *p, int l, const char *s)
{
int i;
@@ -2235,7 +2343,7 @@ ohci_root_ctrl_start(usbd_xfer_handle xfer)
#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);
@@ -2250,7 +2358,7 @@ ohci_root_ctrl_start(usbd_xfer_handle xfer)
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.
*/
@@ -2419,13 +2527,13 @@ ohci_root_ctrl_start(usbd_xfer_handle xfer)
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);
@@ -2482,8 +2590,13 @@ ohci_root_ctrl_start(usbd_xfer_handle xfer)
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); /* XXX */
+ 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;
}
@@ -2578,7 +2691,7 @@ Static void
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;
@@ -2781,7 +2894,7 @@ ohci_device_bulk_abort(usbd_xfer_handle xfer)
ohci_abort_xfer(xfer, USBD_CANCELLED);
}
-/*
+/*
* Close a device bulk pipe.
*/
Static void
@@ -2843,7 +2956,7 @@ ohci_device_intr_start(usbd_xfer_handle xfer)
tail->xfer = NULL;
data->td.td_flags = htole32(
- OHCI_TD_IN | OHCI_TD_NOCC |
+ 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 |= htole32(OHCI_TD_R);
@@ -2916,7 +3029,7 @@ ohci_device_intr_close(usbd_pipe_handle pipe)
pipe, nslots, pos));
s = splusb();
sed->ed.ed_flags |= htole32(OHCI_ED_SKIP);
- if ((le32toh(sed->ed.ed_tailp) & OHCI_HEADMASK) !=
+ if ((le32toh(sed->ed.ed_tailp) & OHCI_HEADMASK) !=
(le32toh(sed->ed.ed_headp) & OHCI_HEADMASK))
usb_delay_ms(&sc->sc_bus, 2);
@@ -2979,7 +3092,7 @@ ohci_device_setintr(ohci_softc_t *sc, struct ohci_pipe *opipe, int ival)
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();
@@ -3035,7 +3148,7 @@ ohci_device_isoc_enter(usbd_xfer_handle xfer)
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_soft_itd_t *sitd, *nsitd;
ohci_physaddr_t buf, offs, noffs, bp0;
int i, ncur, nframes;
int s;
@@ -3050,7 +3163,7 @@ ohci_device_isoc_enter(usbd_xfer_handle xfer)
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",
+ DPRINTFN(2,("ohci_device_isoc_enter: start next=%d\n",
iso->next));
}
@@ -3064,7 +3177,7 @@ ohci_device_isoc_enter(usbd_xfer_handle xfer)
noffs = offs + xfer->frlengths[i];
if (ncur == OHCI_ITD_NOFFSET || /* all offsets used */
OHCI_PAGE(buf + noffs) > bp0 + OHCI_PAGE_SIZE) { /* too many page crossings */
-
+
/* Allocate next ITD */
nsitd = ohci_alloc_sitd(sc);
if (nsitd == NULL) {
@@ -3076,7 +3189,7 @@ ohci_device_isoc_enter(usbd_xfer_handle xfer)
/* Fill current ITD */
sitd->itd.itd_flags = htole32(
- OHCI_ITD_NOCC |
+ OHCI_ITD_NOCC |
OHCI_ITD_SET_SF(iso->next) |
OHCI_ITD_SET_DI(6) | /* delay intr a little */
OHCI_ITD_SET_FC(ncur));
@@ -3088,7 +3201,7 @@ ohci_device_isoc_enter(usbd_xfer_handle xfer)
sitd->flags = 0;
sitd = nsitd;
- iso->next = iso->next + ncur;
+ iso->next = iso->next + ncur;
bp0 = OHCI_PAGE(buf + offs);
ncur = 0;
}
@@ -3098,13 +3211,13 @@ ohci_device_isoc_enter(usbd_xfer_handle xfer)
nsitd = ohci_alloc_sitd(sc);
if (nsitd == NULL) {
/* XXX what now? */
- printf("%s: isoc TD alloc failed\n",
+ printf("%s: isoc TD alloc failed\n",
USBDEVNAME(sc->sc_bus.bdev));
return;
}
/* Fixup last used ITD */
sitd->itd.itd_flags = htole32(
- OHCI_ITD_NOCC |
+ OHCI_ITD_NOCC |
OHCI_ITD_SET_SF(iso->next) |
OHCI_ITD_SET_DI(0) |
OHCI_ITD_SET_FC(ncur));
@@ -3160,7 +3273,7 @@ ohci_device_isoc_start(usbd_xfer_handle xfer)
#ifdef DIAGNOSTIC
if (xfer->status != USBD_IN_PROGRESS)
- printf("uhci_device_isoc_start: not in progress %p\n", xfer);
+ printf("ohci_device_isoc_start: not in progress %p\n", xfer);
#endif
/* XXX anything to do? */
@@ -3182,7 +3295,7 @@ ohci_device_isoc_abort(usbd_xfer_handle xfer)
DPRINTFN(1,("ohci_device_isoc_abort: xfer=%p\n", xfer));
/* Transfer is already done. */
- if (xfer->status != USBD_NOT_STARTED &&
+ if (xfer->status != USBD_NOT_STARTED &&
xfer->status != USBD_IN_PROGRESS) {
splx(s);
printf("ohci_device_isoc_abort: early return\n");
@@ -3230,7 +3343,7 @@ ohci_device_isoc_done(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_itd_t *sitd, *nsitd;
+ ohci_soft_itd_t *sitd, *nsitd;
DPRINTFN(1,("ohci_device_isoc_done: xfer=%p\n", xfer));
diff --git a/sys/dev/usb/ohcivar.h b/sys/dev/usb/ohcivar.h
index 79b11e59168..19f4d228691 100644
--- a/sys/dev/usb/ohcivar.h
+++ b/sys/dev/usb/ohcivar.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: ohcivar.h,v 1.15 2002/05/02 20:08:04 nate Exp $ */
-/* $NetBSD: ohcivar.h,v 1.28 2001/09/28 23:57:21 augustss Exp $ */
+/* $OpenBSD: ohcivar.h,v 1.16 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: ohcivar.h,v 1.30 2001/12/31 12:20:35 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/ohcivar.h,v 1.13 1999/11/17 22:33:41 n_hibma Exp $ */
/*
@@ -106,6 +106,7 @@ typedef struct ohci_softc {
int sc_noport;
u_int8_t sc_addr; /* device address */
u_int8_t sc_conf; /* device configuration */
+ char sc_softwake;
ohci_soft_ed_t *sc_freeeds;
ohci_soft_td_t *sc_freetds;
@@ -138,13 +139,18 @@ typedef struct ohci_softc {
char sc_dying;
} ohci_softc_t;
-void ohci_reset(ohci_softc_t *);
+struct ohci_xfer {
+ struct usbd_xfer xfer;
+ struct usb_task abort_task;
+};
+
+#define OXFER(xfer) ((struct ehci_xfer *)(xfer))
+
usbd_status ohci_init(ohci_softc_t *);
int ohci_intr(void *);
#if defined(__NetBSD__) || defined(__OpenBSD__)
int ohci_detach(ohci_softc_t *, int);
int ohci_activate(device_ptr_t, enum devact);
#endif
-Static void ohci_rhsc_enable(void *sc);
#define MS_TO_TICKS(ms) ((ms) * hz / 1000)
diff --git a/sys/dev/usb/ucom.c b/sys/dev/usb/ucom.c
index 4145bc2242e..eb32bd3ad49 100644
--- a/sys/dev/usb/ucom.c
+++ b/sys/dev/usb/ucom.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: ucom.c,v 1.9 2001/10/31 04:24:44 nate Exp $ */
-/* $NetBSD: ucom.c,v 1.39 2001/08/16 22:31:24 augustss Exp $ */
+/* $OpenBSD: ucom.c,v 1.10 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: ucom.c,v 1.40 2001/11/13 06:24:54 lukem Exp $ */
/*
* Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@@ -85,12 +85,16 @@ int ucomdebug = 0;
#define UCOMUNIT_MASK 0x3ffff
#define UCOMDIALOUT_MASK 0x80000
#define UCOMCALLUNIT_MASK 0x40000
+
+#define LINESW(tp, func) ((tp)->t_linesw->func)
#endif
#if defined(__OpenBSD__)
#define UCOMUNIT_MASK 0x3f
#define UCOMDIALOUT_MASK 0x80
#define UCOMCALLUNIT_MASK 0x40
+
+#define LINESW(tp, func) (linesw[(tp)->t_line].func)
#endif
#define UCOMUNIT(x) (minor(x) & UCOMUNIT_MASK)
@@ -147,7 +151,7 @@ Static int ucomparam(struct tty *, struct termios *);
Static void ucomstart(struct tty *);
Static void ucom_shutdown(struct ucom_softc *);
Static int ucom_do_ioctl(struct ucom_softc *, u_long, caddr_t,
- int, struct proc *);
+ int, usb_proc_ptr);
Static void ucom_dtr(struct ucom_softc *, int);
Static void ucom_rts(struct ucom_softc *, int);
Static void ucom_break(struct ucom_softc *, int);
@@ -297,7 +301,7 @@ ucom_shutdown(struct ucom_softc *sc)
}
int
-ucomopen(dev_t dev, int flag, int mode, struct proc *p)
+ucomopen(dev_t dev, int flag, int mode, usb_proc_ptr p)
{
int unit = UCOMUNIT(dev);
usbd_status err;
@@ -463,7 +467,7 @@ ucomopen(dev_t dev, int flag, int mode, struct proc *p)
if (error)
goto bad;
- error = (*linesw[tp->t_line].l_open)(dev, tp);
+ error = (*LINESW(tp, l_open))(dev, tp);
if (error)
goto bad;
@@ -504,7 +508,7 @@ bad:
}
int
-ucomclose(dev_t dev, int flag, int mode, struct proc *p)
+ucomclose(dev_t dev, int flag, int mode, usb_proc_ptr p)
{
struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
struct tty *tp = sc->sc_tty;
@@ -515,7 +519,7 @@ ucomclose(dev_t dev, int flag, int mode, struct proc *p)
sc->sc_refcnt++;
- (*linesw[tp->t_line].l_close)(tp, flag);
+ (*LINESW(tp, l_close))(tp, flag);
ttyclose(tp);
#if defined(__NetBSD__)
@@ -551,7 +555,7 @@ ucomread(dev_t dev, struct uio *uio, int flag)
return (EIO);
sc->sc_refcnt++;
- error = ((*linesw[tp->t_line].l_read)(tp, uio, flag));
+ error = (*LINESW(tp, l_read))(tp, uio, flag);
if (--sc->sc_refcnt < 0)
usb_detach_wakeup(USBDEV(sc->sc_dev));
return (error);
@@ -568,18 +572,15 @@ ucomwrite(dev_t dev, struct uio *uio, int flag)
return (EIO);
sc->sc_refcnt++;
- error = ((*linesw[tp->t_line].l_write)(tp, uio, flag));
+ error = (*LINESW(tp, l_write))(tp, uio, flag);
if (--sc->sc_refcnt < 0)
usb_detach_wakeup(USBDEV(sc->sc_dev));
return (error);
}
-#if 0
+#if defined(__NetBSD__)
int
-ucompoll(dev, events, p)
- dev_t dev;
- int events;
- struct proc *p;
+ucompoll(dev_t dev, int events, usb_proc_ptr p)
{
struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
struct tty *tp = sc->sc_tty;
@@ -589,7 +590,7 @@ ucompoll(dev, events, p)
return (EIO);
sc->sc_refcnt++;
- error = ((*linesw[tp->t_line].l_poll)(tp, events, p));
+ error = (*LINESW(tp, l_poll))(tp, events, p);
if (--sc->sc_refcnt < 0)
usb_detach_wakeup(USBDEV(sc->sc_dev));
return (error);
@@ -606,7 +607,7 @@ ucomtty(dev_t dev)
}
int
-ucomioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
+ucomioctl(dev_t dev, u_long cmd, caddr_t data, int flag, usb_proc_ptr p)
{
struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
int error;
@@ -620,7 +621,7 @@ ucomioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
Static int
ucom_do_ioctl(struct ucom_softc *sc, u_long cmd, caddr_t data,
- int flag, struct proc *p)
+ int flag, usb_proc_ptr p)
{
struct tty *tp = sc->sc_tty;
int error;
@@ -631,7 +632,7 @@ ucom_do_ioctl(struct ucom_softc *sc, u_long cmd, caddr_t data,
DPRINTF(("ucomioctl: cmd=0x%08lx\n", cmd));
- error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
+ error = (*LINESW(tp, l_ioctl))(tp, cmd, data, flag, p);
if (error >= 0)
return (error);
@@ -805,7 +806,7 @@ ucom_status_change(struct ucom_softc *sc)
sc->sc_methods->ucom_get_status(sc->sc_parent, sc->sc_portno,
&sc->sc_lsr, &sc->sc_msr);
if (ISSET((sc->sc_msr ^ old_msr), UMSR_DCD))
- (*linesw[tp->t_line].l_modem)(tp,
+ (*LINESW(tp, l_modem))(tp,
ISSET(sc->sc_msr, UMSR_DCD));
} else {
sc->sc_lsr = 0;
@@ -866,7 +867,7 @@ ucomparam(struct tty *tp, struct termios *t)
* explicit request.
*/
DPRINTF(("ucomparam: l_modem\n"));
- (void) (*linesw[tp->t_line].l_modem)(tp, 1 /* XXX carrier */ );
+ (void) (*LINESW(tp, l_modem))(tp, 1 /* XXX carrier */ );
#if 0
XXX what if the hardware is not open
@@ -1033,7 +1034,7 @@ ucomwritecb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
CLR(tp->t_state, TS_FLUSH);
else
ndflush(&tp->t_outq, cc);
- (*linesw[tp->t_line].l_start)(tp);
+ (*LINESW(tp, l_start))(tp);
splx(s);
return;
@@ -1067,7 +1068,7 @@ ucomreadcb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
{
struct ucom_softc *sc = (struct ucom_softc *)p;
struct tty *tp = sc->sc_tty;
- int (*rint)(int c, struct tty *tp) = linesw[tp->t_line].l_rint;
+ int (*rint)(int c, struct tty *tp) = LINESW(tp, l_rint);
usbd_status err;
u_int32_t cc;
u_char *cp;
@@ -1168,9 +1169,9 @@ ucomsubmatch(struct device *parent, void *match, void *aux)
ucomsubmatch(struct device *parent, struct cfdata *cf, void *aux)
#endif
{
- struct ucom_attach_args *uca = aux;
+ struct ucom_attach_args *uca = aux;
#if defined(__OpenBSD__)
- struct cfdata *cf = match;
+ struct cfdata *cf = match;
#endif
if (uca->portno != UCOM_UNK_PORTNO &&
diff --git a/sys/dev/usb/ucomvar.h b/sys/dev/usb/ucomvar.h
index d3619824464..0e4e9b40a7a 100644
--- a/sys/dev/usb/ucomvar.h
+++ b/sys/dev/usb/ucomvar.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: ucomvar.h,v 1.8 2002/01/30 20:45:34 nordin Exp $ */
-/* $NetBSD: ucomvar.h,v 1.9 2001/01/23 21:56:17 augustss Exp $ */
+/* $OpenBSD: ucomvar.h,v 1.9 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: ucomvar.h,v 1.10 2001/12/31 12:15:21 augustss Exp $ */
/*
* Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -56,7 +56,7 @@ struct ucom_methods {
#define UCOM_SET_BREAK 3
int (*ucom_param)(void *sc, int portno, struct termios *);
int (*ucom_ioctl)(void *sc, int portno, u_long cmd,
- caddr_t data, int flag, struct proc *p);
+ caddr_t data, int flag, usb_proc_ptr p);
int (*ucom_open)(void *sc, int portno);
void (*ucom_close)(void *sc, int portno);
void (*ucom_read)(void *sc, int portno, u_char **ptr, u_int32_t *count);
@@ -105,10 +105,11 @@ struct ucom_attach_args {
void *arg;
};
-int ucomprint(void *aux, const char *pnp);
-#if defined(__OpenBSD__)
-int ucomsubmatch(struct device *parent, void *cf, void *aux);
+#if defined(__NetBSD__)
+int ucomsubmatch(struct device *, struct cfdata *, void *);
#else
-int ucomsubmatch(struct device *parent, struct cfdata *cf, void *aux);
+int ucomsubmatch(struct device *, void *, void *);
#endif
+
+int ucomprint(void *aux, const char *pnp);
void ucom_status_change(struct ucom_softc *);
diff --git a/sys/dev/usb/udsbr.c b/sys/dev/usb/udsbr.c
new file mode 100644
index 00000000000..dc7a35abb09
--- /dev/null
+++ b/sys/dev/usb/udsbr.c
@@ -0,0 +1,279 @@
+/* $OpenBSD: udsbr.c,v 1.1 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: udsbr.c,v 1.6 2002/02/12 10:51:49 tron Exp $ */
+
+/*
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (lennart@augustsson.net).
+ *
+ * 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.
+ */
+
+/*
+ * Driver for the D-Link DSB-R100 FM radio.
+ * I apologize for the magic hex constants, but this is what happens
+ * when you have to reverse engineer the driver.
+ * Parts of the code borrowed from Linux and parts from Warner Losh's
+ * FreeBSD driver.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+
+#include <sys/radioio.h>
+#include <dev/radio_if.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+
+#include <dev/usb/usbdevs.h>
+
+#ifdef UDSBR_DEBUG
+#define DPRINTF(x) if (udsbrdebug) logprintf x
+#define DPRINTFN(n,x) if (udsbrdebug>(n)) logprintf x
+int udsbrdebug = 0;
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n,x)
+#endif
+
+#define UDSBR_CONFIG_NO 1
+
+Static int udsbr_get_info(void *, struct radio_info *);
+Static int udsbr_set_info(void *, struct radio_info *);
+
+struct radio_hw_if udsbr_hw_if = {
+ NULL, /* open */
+ NULL, /* close */
+ udsbr_get_info,
+ udsbr_set_info,
+ NULL
+};
+
+struct udsbr_softc {
+ USBBASEDEVICE sc_dev;
+ usbd_device_handle sc_udev;
+
+ char sc_mute;
+ char sc_vol;
+ u_int32_t sc_freq;
+
+ struct device *sc_child;
+
+ char sc_dying;
+};
+
+Static int udsbr_req(struct udsbr_softc *sc, int ureq, int value,
+ int index);
+Static void udsbr_start(struct udsbr_softc *sc);
+Static void udsbr_stop(struct udsbr_softc *sc);
+Static void udsbr_setfreq(struct udsbr_softc *sc, int freq);
+Static int udsbr_status(struct udsbr_softc *sc);
+
+USB_DECLARE_DRIVER(udsbr);
+
+USB_MATCH(udsbr)
+{
+ USB_MATCH_START(udsbr, uaa);
+
+ DPRINTFN(50,("udsbr_match\n"));
+
+ if (uaa->iface != NULL)
+ return (UMATCH_NONE);
+
+ if (uaa->vendor != USB_VENDOR_CYPRESS ||
+ uaa->product != USB_PRODUCT_CYPRESS_FMRADIO)
+ return (UMATCH_NONE);
+ return (UMATCH_VENDOR_PRODUCT);
+}
+
+USB_ATTACH(udsbr)
+{
+ USB_ATTACH_START(udsbr, sc, uaa);
+ usbd_device_handle dev = uaa->device;
+ char devinfo[1024];
+ usbd_status err;
+
+ DPRINTFN(10,("udsbr_attach: sc=%p\n", sc));
+
+ usbd_devinfo(dev, 0, devinfo);
+ USB_ATTACH_SETUP;
+ printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo);
+
+ err = usbd_set_config_no(dev, UDSBR_CONFIG_NO, 1);
+ if (err) {
+ printf("%s: setting config no failed\n",
+ USBDEVNAME(sc->sc_dev));
+ USB_ATTACH_ERROR_RETURN;
+ }
+
+ sc->sc_udev = dev;
+
+ DPRINTFN(10, ("udsbr_attach: %p\n", sc->sc_udev));
+
+ usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
+ USBDEV(sc->sc_dev));
+
+ sc->sc_child = radio_attach_mi(&udsbr_hw_if, sc, USBDEV(sc->sc_dev));
+
+ USB_ATTACH_SUCCESS_RETURN;
+}
+
+USB_DETACH(udsbr)
+{
+ USB_DETACH_START(udsbr, sc);
+ int rv = 0;
+
+ if (sc->sc_child != NULL)
+ rv = config_detach(sc->sc_child, flags);
+
+ usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
+ USBDEV(sc->sc_dev));
+
+ return (rv);
+}
+
+int
+udsbr_activate(device_ptr_t self, enum devact act)
+{
+ struct udsbr_softc *sc = (struct udsbr_softc *)self;
+ int rv = 0;
+
+ switch (act) {
+ case DVACT_ACTIVATE:
+ return (EOPNOTSUPP);
+ break;
+
+ case DVACT_DEACTIVATE:
+ sc->sc_dying = 1;
+ if (sc->sc_child != NULL)
+ rv = config_deactivate(sc->sc_child);
+ break;
+ }
+ return (rv);
+}
+
+int
+udsbr_req(struct udsbr_softc *sc, int ureq, int value, int index)
+{
+ usb_device_request_t req;
+ usbd_status err;
+ u_char data;
+
+ DPRINTFN(1,("udsbr_req: ureq=0x%02x value=0x%04x index=0x%04x\n",
+ ureq, value, index));
+ req.bmRequestType = UT_READ_VENDOR_DEVICE;
+ req.bRequest = ureq;
+ USETW(req.wValue, value);
+ USETW(req.wIndex, index);
+ USETW(req.wLength, 1);
+ err = usbd_do_request(sc->sc_udev, &req, &data);
+ if (err) {
+ printf("%s: request failed err=%d\n", USBDEVNAME(sc->sc_dev),
+ err);
+ }
+ return !(data & 1);
+}
+
+void
+udsbr_start(struct udsbr_softc *sc)
+{
+ (void)udsbr_req(sc, 0x00, 0x0000, 0x00c7);
+ (void)udsbr_req(sc, 0x02, 0x0001, 0x0000);
+}
+
+void
+udsbr_stop(struct udsbr_softc *sc)
+{
+ (void)udsbr_req(sc, 0x00, 0x0016, 0x001c);
+ (void)udsbr_req(sc, 0x02, 0x0000, 0x0000);
+}
+
+void
+udsbr_setfreq(struct udsbr_softc *sc, int freq)
+{
+ DPRINTF(("udsbr_setfreq: setfreq=%d\n", freq));
+ /*
+ * Freq now is in Hz. We need to convert it to the frequency
+ * 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.
+ */
+ freq = (freq * 1000 + 10700001) / 12500;
+ (void)udsbr_req(sc, 0x01, (freq >> 8) & 0xff, freq & 0xff);
+ (void)udsbr_req(sc, 0x00, 0x0096, 0x00b7);
+ usbd_delay_ms(sc->sc_udev, 240); /* wait for signal to settle */
+}
+
+int
+udsbr_status(struct udsbr_softc *sc)
+{
+ return (udsbr_req(sc, 0x00, 0x0000, 0x0024));
+}
+
+
+int
+udsbr_get_info(void *v, struct radio_info *ri)
+{
+ struct udsbr_softc *sc = v;
+
+ ri->mute = sc->sc_mute;
+ ri->volume = sc->sc_vol ? 255 : 0;
+ ri->caps = RADIO_CAPS_DETECT_STEREO;
+ ri->rfreq = 0;
+ ri->lock = 0;
+ ri->freq = sc->sc_freq;
+ ri->info = udsbr_status(sc) ? RADIO_INFO_STEREO : 0;
+
+ return (0);
+}
+
+int
+udsbr_set_info(void *v, struct radio_info *ri)
+{
+ struct udsbr_softc *sc = v;
+
+ sc->sc_mute = ri->mute != 0;
+ sc->sc_vol = ri->volume != 0;
+ sc->sc_freq = ri->freq;
+ udsbr_setfreq(sc, sc->sc_freq);
+
+ if (sc->sc_mute || sc->sc_vol == 0)
+ udsbr_stop(sc);
+ else
+ udsbr_start(sc);
+
+ return (0);
+}
diff --git a/sys/dev/usb/uftdi.c b/sys/dev/usb/uftdi.c
index 9a9b94784e7..a86b3785fc4 100644
--- a/sys/dev/usb/uftdi.c
+++ b/sys/dev/usb/uftdi.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: uftdi.c,v 1.3 2001/05/03 02:20:33 aaron Exp $ */
-/* $NetBSD: uftdi.c,v 1.6 2001/01/23 21:56:17 augustss Exp $ */
+/* $OpenBSD: uftdi.c,v 1.4 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: uftdi.c,v 1.9 2001/12/17 14:34:37 ichiro Exp $ */
/*
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@@ -95,15 +95,19 @@ struct uftdi_softc {
device_ptr_t sc_subdev;
u_char sc_dying;
+
+ u_int last_lcr;
};
Static void uftdi_get_status(void *, int portno, u_char *lsr, u_char *msr);
Static void uftdi_set(void *, int, int, int);
Static int uftdi_param(void *, int, struct termios *);
Static int uftdi_open(void *sc, int portno);
-Static void uftdi_read(void *sc, int portno, u_char **ptr,u_int32_t *count);
+Static void uftdi_read(void *sc, int portno, u_char **ptr,
+ u_int32_t *count);
Static void uftdi_write(void *sc, int portno, u_char *to, u_char *from,
u_int32_t *count);
+Static void uftdi_break(void *sc, int portno, int onoff);
struct ucom_methods uftdi_methods = {
uftdi_get_status,
@@ -376,7 +380,7 @@ uftdi_set(void *vsc, int portno, int reg, int onoff)
ctl = onoff ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW;
break;
case UCOM_SET_BREAK:
- /* XXX how do we set break? */
+ uftdi_break(sc, portno, onoff);
return;
default:
return;
@@ -456,6 +460,8 @@ uftdi_param(void *vsc, int portno, struct termios *t)
data |= FTDI_SIO_SET_DATA_BITS(8);
break;
}
+ sc->last_lcr = data;
+
req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
req.bRequest = FTDI_SIO_SET_DATA;
USETW(req.wValue, data);
@@ -484,3 +490,27 @@ uftdi_get_status(void *vsc, int portno, u_char *lsr, u_char *msr)
if (lsr != NULL)
*lsr = sc->sc_lsr;
}
+
+void
+uftdi_break(void *vsc, int portno, int onoff)
+{
+ struct uftdi_softc *sc = vsc;
+ usb_device_request_t req;
+ int data;
+
+ DPRINTF(("uftdi_break: sc=%p, port=%d onoff=%d\n", vsc, portno,
+ onoff));
+
+ if (onoff) {
+ data = sc->last_lcr | FTDI_SIO_SET_BREAK;
+ } else {
+ data = sc->last_lcr;
+ }
+
+ req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req.bRequest = FTDI_SIO_SET_DATA;
+ USETW(req.wValue, data);
+ USETW(req.wIndex, portno);
+ USETW(req.wLength, 0);
+ (void)usbd_do_request(sc->sc_udev, &req, NULL);
+}
diff --git a/sys/dev/usb/uftdireg.h b/sys/dev/usb/uftdireg.h
index 08019addafb..ce2dfb2ea78 100644
--- a/sys/dev/usb/uftdireg.h
+++ b/sys/dev/usb/uftdireg.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: uftdireg.h,v 1.3 2001/10/31 04:24:44 nate Exp $ */
-/* $NetBSD: uftdireg.h,v 1.3 2001/06/12 14:59:28 wiz Exp $ */
+/* $OpenBSD: uftdireg.h,v 1.4 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: uftdireg.h,v 1.4 2001/12/17 14:31:02 ichiro Exp $ */
/*
* Definitions for the FTDI USB Single Port Serial Converter -
@@ -121,6 +121,7 @@ enum {
#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11)
#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11)
#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11)
+#define FTDI_SIO_SET_BREAK (0x1 << 14)
/*
diff --git a/sys/dev/usb/ugen.c b/sys/dev/usb/ugen.c
index 8052edd6834..6ba08f1ab6e 100644
--- a/sys/dev/usb/ugen.c
+++ b/sys/dev/usb/ugen.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: ugen.c,v 1.18 2002/05/02 20:08:04 nate Exp $ */
-/* $NetBSD: ugen.c,v 1.49 2001/10/24 22:31:04 augustss Exp $ */
+/* $OpenBSD: ugen.c,v 1.19 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: ugen.c,v 1.58 2002/02/20 20:30:12 christos Exp $ */
/* $FreeBSD: src/sys/dev/usb/ugen.c,v 1.26 1999/11/17 22:33:41 n_hibma Exp $ */
/*
@@ -20,8 +20,8 @@
* 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.
+ * 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.
@@ -150,16 +150,16 @@ Static struct cdevsw ugen_cdevsw = {
};
#endif
-Static void ugenintr(usbd_xfer_handle xfer, usbd_private_handle addr,
+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, struct proc *);
+Static int ugen_do_ioctl(struct ugen_softc *, int, u_long,
+ caddr_t, int, usb_proc_ptr);
Static int ugen_set_config(struct ugen_softc *sc, int configno);
-Static usb_config_descriptor_t *ugen_get_cdesc(struct ugen_softc *sc,
+Static usb_config_descriptor_t *ugen_get_cdesc(struct ugen_softc *sc,
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);
@@ -201,7 +201,7 @@ USB_ATTACH(ugen)
/* 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,7 +211,7 @@ USB_ATTACH(ugen)
/* 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;
@@ -247,6 +247,19 @@ ugen_set_config(struct ugen_softc *sc, int configno)
DPRINTFN(1,("ugen_set_config: %s to configno %d, sc=%p\n",
USBDEVNAME(sc->sc_dev), configno, sc));
+
+ /*
+ * We start at 1, not 0, because we don't care whether the
+ * control endpoint is open or not. It is always present.
+ */
+ for (endptno = 1; endptno < USB_MAX_ENDPOINTS; endptno++)
+ if (sc->sc_is_open[endptno]) {
+ DPRINTFN(1,
+ ("ugen_set_config: %s - endpoint %d is open\n",
+ USBDEVNAME(sc->sc_dev), endptno));
+ return (USBD_IN_USE);
+ }
+
/* Avoid setting the current value. */
if (usbd_get_config_descriptor(dev)->bConfigurationValue != configno) {
err = usbd_set_config_no(dev, configno, 1);
@@ -272,7 +285,7 @@ ugen_set_config(struct ugen_softc *sc, int configno)
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",
+ "(%d,%d), sce=%p\n",
endptno, endpt, UE_GET_ADDR(endpt),
UE_GET_DIR(endpt), sce));
sce->sc = sc;
@@ -284,7 +297,7 @@ ugen_set_config(struct ugen_softc *sc, int configno)
}
int
-ugenopen(dev_t dev, int flag, int mode, struct proc *p)
+ugenopen(dev_t dev, int flag, int mode, usb_proc_ptr p)
{
struct ugen_softc *sc;
int unit = UGENUNIT(dev);
@@ -299,7 +312,7 @@ ugenopen(dev_t dev, int flag, int mode, struct proc *p)
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)
@@ -330,7 +343,7 @@ ugenopen(dev_t dev, int flag, int mode, struct proc *p)
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) {
@@ -339,14 +352,14 @@ ugenopen(dev_t dev, int flag, int mode, struct proc *p)
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,
- sce->ibuf, isize, ugenintr,
+ 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,
+ sce->ibuf, isize, ugenintr,
USBD_DEFAULT_INTERVAL);
if (err) {
free(sce->ibuf, M_USBDEV);
@@ -356,7 +369,7 @@ ugenopen(dev_t dev, int flag, int mode, struct proc *p)
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);
@@ -371,7 +384,7 @@ ugenopen(dev_t dev, int flag, int mode, struct proc *p)
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);
@@ -408,6 +421,7 @@ ugenopen(dev_t dev, int flag, int mode, struct proc *p)
usbd_free_xfer(sce->isoreqs[i].xfer);
return (ENOMEM);
case UE_CONTROL:
+ sce->timeout = USBD_DEFAULT_TIMEOUT;
return (EINVAL);
}
}
@@ -416,7 +430,7 @@ ugenopen(dev_t dev, int flag, int mode, struct proc *p)
}
int
-ugenclose(dev_t dev, int flag, int mode, struct proc *p)
+ugenclose(dev_t dev, int flag, int mode, usb_proc_ptr p)
{
int endpt = UGENENDPOINT(dev);
struct ugen_softc *sc;
@@ -448,31 +462,30 @@ ugenclose(dev_t dev, int flag, int mode, struct proc *p)
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);
usbd_close_pipe(sce->pipeh);
sce->pipeh = NULL;
- switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
- case UE_INTERRUPT:
- ndflush(&sce->q, sce->q.c_cc);
- clfree(&sce->q);
- break;
- case UE_ISOCHRONOUS:
- for (i = 0; i < UGEN_NISOREQS; ++i)
- usbd_free_xfer(sce->isoreqs[i].xfer);
-
- default:
- break;
+ switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
+ case UE_INTERRUPT:
+ ndflush(&sce->q, sce->q.c_cc);
+ clfree(&sce->q);
+ break;
+ case UE_ISOCHRONOUS:
+ for (i = 0; i < UGEN_NISOREQS; ++i)
+ usbd_free_xfer(sce->isoreqs[i].xfer);
+
+ default:
+ break;
}
if (sce->ibuf != NULL) {
free(sce->ibuf, M_USBDEV);
sce->ibuf = NULL;
clfree(&sce->q);
-
}
}
sc->sc_is_open[endpt] = 0;
@@ -558,8 +571,8 @@ ugen_do_read(struct ugen_softc *sc, int endpt, struct uio *uio, int flag)
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)
@@ -677,7 +690,7 @@ ugen_do_write(struct ugen_softc *sc, int endpt, struct uio *uio, int flag)
if (error)
break;
DPRINTFN(1, ("ugenwrite: transfer %d bytes\n", n));
- err = usbd_bulk_transfer(xfer, sce->pipeh, 0,
+ err = usbd_bulk_transfer(xfer, sce->pipeh, 0,
sce->timeout, buf, &n,"ugenwb");
if (err) {
if (err == USBD_INTERRUPTED)
@@ -798,14 +811,15 @@ ugenintr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status)
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]));
@@ -821,7 +835,7 @@ 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,
+ugen_isoc_rintr(usbd_xfer_handle xfer, usbd_private_handle addr,
usbd_status status)
{
struct isoreq *req = addr;
@@ -959,7 +973,8 @@ ugen_get_cdesc(struct ugen_softc *sc, int index, int *lenp)
if (lenp)
*lenp = len;
cdesc = malloc(len, M_TEMP, M_WAITOK);
- err = usbd_get_config_desc_full(sc->sc_udev, index, cdesc,len);
+ err = usbd_get_config_desc_full(sc->sc_udev, index, cdesc,
+ len);
if (err) {
free(cdesc, M_TEMP);
return (0);
@@ -982,7 +997,7 @@ ugen_get_alt_index(struct ugen_softc *sc, int ifaceidx)
Static int
ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd,
- caddr_t addr, int flag, struct proc *p)
+ caddr_t addr, int flag, usb_proc_ptr p)
{
struct ugen_endpoint *sce;
usbd_status err;
@@ -1006,18 +1021,12 @@ ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd,
/* All handled in the upper FS layer. */
return (0);
case USB_SET_SHORT_XFER:
- /* This flag only affects read */
if (endpt == USB_CONTROL_ENDPOINT)
return (EINVAL);
+ /* This flag only affects read */
sce = &sc->sc_endpoints[endpt][IN];
- if (sce == NULL)
+ if (sce == NULL || sce->pipeh == 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
@@ -1025,14 +1034,12 @@ ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd,
return (0);
case USB_SET_TIMEOUT:
sce = &sc->sc_endpoints[endpt][IN];
- if (sce == NULL)
+ if (sce == NULL
+ /* XXX this shouldn't happen, but the distinction between
+ input and output pipes isn't clear enough.
+ || sce->pipeh == 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:
@@ -1058,13 +1065,19 @@ ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd,
if (!(flag & FWRITE))
return (EPERM);
err = ugen_set_config(sc, *(int *)addr);
- if (err)
+ switch (err) {
+ case USBD_NORMAL_COMPLETION:
+ break;
+ case USBD_IN_USE:
+ return (EBUSY);
+ default:
return (EIO);
+ }
break;
case USB_GET_ALTINTERFACE:
ai = (struct usb_alt_interface *)addr;
- err = usbd_device2interface_handle(sc->sc_udev,
- ai->uai_interface_index, &iface);
+ err = usbd_device2interface_handle(sc->sc_udev,
+ ai->uai_interface_index, &iface);
if (err)
return (EINVAL);
idesc = usbd_get_interface_descriptor(iface);
@@ -1076,11 +1089,12 @@ ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd,
if (!(flag & FWRITE))
return (EPERM);
ai = (struct usb_alt_interface *)addr;
- err = usbd_device2interface_handle(sc->sc_udev,
- ai->uai_interface_index, &iface);
+ err = usbd_device2interface_handle(sc->sc_udev,
+ ai->uai_interface_index, &iface);
if (err)
return (EINVAL);
- err = ugen_set_interface(sc, ai->uai_interface_index, ai->uai_alt_no);
+ err = ugen_set_interface(sc, ai->uai_interface_index,
+ ai->uai_alt_no);
if (err)
return (EINVAL);
break;
@@ -1094,7 +1108,8 @@ ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd,
free(cdesc, M_TEMP);
return (EINVAL);
}
- ai->uai_alt_no = usbd_get_no_alts(cdesc, idesc->bInterfaceNumber);
+ ai->uai_alt_no = usbd_get_no_alts(cdesc,
+ idesc->bInterfaceNumber);
free(cdesc, M_TEMP);
break;
case USB_GET_DEVICE_DESC:
@@ -1137,7 +1152,7 @@ ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd,
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);
@@ -1172,7 +1187,7 @@ ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd,
}
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);
@@ -1209,7 +1224,7 @@ ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd,
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);
@@ -1219,8 +1234,9 @@ ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd,
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;
@@ -1248,7 +1264,7 @@ ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd,
}
int
-ugenioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
+ugenioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, usb_proc_ptr p)
{
int endpt = UGENENDPOINT(dev);
struct ugen_softc *sc;
@@ -1264,7 +1280,7 @@ ugenioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
}
int
-ugenpoll(dev_t dev, int events, struct proc *p)
+ugenpoll(dev_t dev, int events, usb_proc_ptr p)
{
struct ugen_softc *sc;
struct ugen_endpoint *sce;
@@ -1309,12 +1325,12 @@ ugenpoll(dev_t dev, int events, struct proc *p)
}
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:
diff --git a/sys/dev/usb/uhci.c b/sys/dev/usb/uhci.c
index d6c71087c94..090f26f99f8 100644
--- a/sys/dev/usb/uhci.c
+++ b/sys/dev/usb/uhci.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: uhci.c,v 1.23 2002/01/10 00:46:36 nordin Exp $ */
-/* $NetBSD: uhci.c,v 1.142 2001/10/25 02:08:13 augustss Exp $ */
+/* $OpenBSD: uhci.c,v 1.24 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: uhci.c,v 1.158 2002/03/17 18:02:53 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/uhci.c,v 1.33 1999/11/17 22:33:41 n_hibma Exp $ */
/*
@@ -174,10 +174,10 @@ Static void uhci_enter_ctl_q(uhci_softc_t *, uhci_soft_qh_t *,
Static void uhci_exit_ctl_q(uhci_softc_t *, uhci_soft_qh_t *);
#endif
-Static void uhci_free_std_chain(uhci_softc_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_poll_hub(void *);
Static void uhci_waitintr(uhci_softc_t *, usbd_xfer_handle);
@@ -187,6 +187,7 @@ Static void uhci_idone(uhci_intr_info_t *);
Static void uhci_abort_xfer(usbd_xfer_handle, usbd_status status);
Static void uhci_timeout(void *);
+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 *);
@@ -249,8 +250,8 @@ Static void uhci_softintr(void *);
Static usbd_status uhci_device_request(usbd_xfer_handle xfer);
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,
+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);
@@ -301,7 +302,7 @@ struct usbd_bus_methods uhci_bus_methods = {
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,
@@ -310,7 +311,7 @@ struct usbd_pipe_methods uhci_root_ctrl_methods = {
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,
@@ -366,7 +367,7 @@ 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(UHCI_DEBUG)
+#if defined(DIAGNOSTIC) || defined(UHCI_DEBUG)
if (le32toh(pqh->qh.qh_hlink) & UHCI_PTR_T) {
printf("uhci_find_prev_qh: QH not found\n");
return (NULL);
@@ -401,13 +402,12 @@ uhci_init(uhci_softc_t *sc)
uhci_dumpregs(sc);
#endif
- uhci_run(sc, 0); /* stop the controller */
UWRITE2(sc, UHCI_INTR, 0); /* disable interrupts */
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)
@@ -416,7 +416,7 @@ uhci_init(uhci_softc_t *sc)
UWRITE2(sc, UHCI_FRNUM, 0); /* set frame number to 0 */
UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma)); /* 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.
@@ -470,7 +470,7 @@ uhci_init(uhci_softc_t *sc)
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.
@@ -493,8 +493,8 @@ uhci_init(uhci_softc_t *sc)
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] = htole32(std->physaddr);
}
@@ -516,7 +516,7 @@ uhci_init(uhci_softc_t *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 */
@@ -552,7 +552,7 @@ uhci_detach(struct uhci_softc *sc, int flags)
if (sc->sc_child != NULL)
rv = config_detach(sc->sc_child, flags);
-
+
if (rv != 0)
return (rv);
@@ -568,7 +568,7 @@ uhci_detach(struct uhci_softc *sc, int flags)
break;
SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, xfer, next);
free(xfer, M_USB);
- }
+ }
/* XXX free other data structures XXX */
@@ -582,10 +582,10 @@ uhci_allocm(struct usbd_bus *bus, usb_dma_t *dma, u_int32_t size)
struct uhci_softc *sc = (struct uhci_softc *)bus;
u_int32_t n;
- /*
+ /*
* XXX
* Since we are allocating a buffer we can assume that we will
- * need TDs for it. Since we don't want to alolocate those from
+ * need TDs for it. Since we don't want to allocate those from
* an interrupt context, we allocate them here and free them again.
* This is no guarantee that we'll get the TDs next time...
*/
@@ -594,7 +594,8 @@ uhci_allocm(struct usbd_bus *bus, usb_dma_t *dma, u_int32_t size)
u_int32_t i;
uhci_soft_td_t **stds;
DPRINTF(("uhci_allocm: get %d TDs\n", n));
- stds = malloc(sizeof(uhci_soft_td_t *) * n, M_TEMP, M_NOWAIT);
+ stds = malloc(sizeof(uhci_soft_td_t *) * n, M_TEMP,
+ M_NOWAIT);
if (stds == NULL)
panic("uhci_allocm");
memset(stds, 0, sizeof(uhci_soft_td_t *) * n);
@@ -693,7 +694,7 @@ uhci_power(int why, void *v)
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));
switch (why) {
@@ -739,7 +740,7 @@ uhci_power(int why, void *v)
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 */
uhci_run(sc, 1); /* and start traffic again */
usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY);
@@ -792,9 +793,9 @@ uhci_dump_td(uhci_soft_td_t *p)
(long)le32toh(p->td.td_token),
(long)le32toh(p->td.td_buffer)));
- bitmask_snprintf((int)le32toh(p->td.td_link), "\20\1T\2Q\3VF",
+ bitmask_snprintf((u_int32_t)le32toh(p->td.td_link), "\20\1T\2Q\3VF",
sbuf, sizeof(sbuf));
- bitmask_snprintf((int)le32toh(p->td.td_status),
+ 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));
@@ -891,7 +892,7 @@ 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
@@ -924,8 +925,8 @@ uhci_dump_ii(uhci_intr_info_t *ii)
}
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,
+ 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,
@@ -1010,7 +1011,7 @@ uhci_add_loop(uhci_softc_t *sc) {
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 =
+ sc->sc_last_qh->qh.qh_hlink =
htole32(sc->sc_hctl_start->physaddr | UHCI_PTR_QH);
}
}
@@ -1073,7 +1074,7 @@ uhci_remove_hs_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
}
pqh = uhci_find_prev_qh(sc->sc_hctl_start, sqh);
- pqh->hlink = sqh->hlink;
+ pqh->hlink = sqh->hlink;
pqh->qh.qh_hlink = sqh->qh.qh_hlink;
delay(UHCI_QH_REMOVE_DELAY);
if (sc->sc_hctl_end == sqh)
@@ -1090,9 +1091,9 @@ uhci_add_ls_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
DPRINTFN(10, ("uhci_add_ls_ctrl: sqh=%p\n", sqh));
eqh = sc->sc_lctl_end;
- sqh->hlink = eqh->hlink;
+ sqh->hlink = eqh->hlink;
sqh->qh.qh_hlink = eqh->qh.qh_hlink;
- eqh->hlink = sqh;
+ eqh->hlink = sqh;
eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH);
sc->sc_lctl_end = sqh;
}
@@ -1112,7 +1113,7 @@ uhci_remove_ls_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
delay(UHCI_QH_REMOVE_DELAY);
}
pqh = uhci_find_prev_qh(sc->sc_lctl_start, sqh);
- pqh->hlink = sqh->hlink;
+ pqh->hlink = sqh->hlink;
pqh->qh.qh_hlink = sqh->qh.qh_hlink;
delay(UHCI_QH_REMOVE_DELAY);
if (sc->sc_lctl_end == sqh)
@@ -1129,9 +1130,9 @@ uhci_add_bulk(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
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->hlink = sqh;
eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH);
sc->sc_bulk_end = sqh;
uhci_add_loop(sc);
@@ -1167,6 +1168,9 @@ 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
@@ -1190,15 +1194,10 @@ uhci_intr1(uhci_softc_t *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);
-#if defined(DIAGNOSTIC) && defined(__NetBSD__)
- if (sc->sc_suspend != PWR_RESUME)
- 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));
@@ -1223,13 +1222,13 @@ uhci_intr1(uhci_softc_t *sc)
}
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 */
if (!sc->sc_dying) {
- printf("%s: host controller halted\n",
+ printf("%s: host controller halted\n",
USBDEVNAME(sc->sc_bus.bdev));
#ifdef UHCI_DEBUG
uhci_dump_all(sc);
@@ -1275,6 +1274,11 @@ uhci_softintr(void *v)
for (ii = LIST_FIRST(&sc->sc_intrhead); ii; ii = LIST_NEXT(ii, list))
uhci_check_intr(sc, ii);
+ if (sc->sc_softwake) {
+ sc->sc_softwake = 0;
+ wakeup(&sc->sc_softwake);
+ }
+
sc->sc_bus.intr_context--;
}
@@ -1292,6 +1296,12 @@ uhci_check_intr(uhci_softc_t *sc, uhci_intr_info_t *ii)
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;
@@ -1301,7 +1311,7 @@ uhci_check_intr(uhci_softc_t *sc, uhci_intr_info_t *ii)
return;
}
#endif
- /*
+ /*
* If the last TD is still active we need to check whether there
* is a an error somewhere in the middle, or whether there was a
* short packet (SPD and not ACTIVE).
@@ -1318,7 +1328,7 @@ uhci_check_intr(uhci_softc_t *sc, uhci_intr_info_t *ii)
goto 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_ACTLEN(status) <
UHCI_TD_GET_MAXLEN(le32toh(std->td.td_token)))
goto done;
}
@@ -1361,12 +1371,6 @@ uhci_idone(uhci_intr_info_t *ii)
}
#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;
@@ -1422,14 +1426,15 @@ uhci_idone(uhci_intr_info_t *ii)
upipe->nexttoggle = UHCI_TD_GET_DT(le32toh(std->td.td_token));
status &= UHCI_TD_ERROR;
- DPRINTFN(10, ("uhci_idone: 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 UHCI_DEBUG
char sbuf[128];
- bitmask_snprintf((int)status, "\20\22BITSTUFF\23CRCTO\24NAK\25"
+ bitmask_snprintf((u_int32_t)status,
+ "\20\22BITSTUFF\23CRCTO\24NAK\25"
"BABBLE\26DBUFFER\27STALLED\30ACTIVE",
sbuf, sizeof(sbuf));
@@ -1461,17 +1466,33 @@ void
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 UHCI_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);
}
/*
@@ -1502,7 +1523,7 @@ uhci_waitintr(uhci_softc_t *sc, usbd_xfer_handle xfer)
/* 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
@@ -1528,11 +1549,11 @@ uhci_reset(uhci_softc_t *sc)
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++)
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));
}
@@ -1680,9 +1701,9 @@ uhci_alloc_std_chain(struct uhci_pipe *upipe, uhci_softc_t *sc, int len,
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");
@@ -1705,14 +1726,14 @@ uhci_alloc_std_chain(struct uhci_pipe *upipe, uhci_softc_t *sc, int len,
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;
@@ -1728,14 +1749,14 @@ uhci_alloc_std_chain(struct uhci_pipe *upipe, uhci_softc_t *sc, int len,
*ep = p;
} else
l = maxp;
- p->td.td_token =
+ 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);
}
@@ -1762,7 +1783,7 @@ uhci_device_bulk_transfer(usbd_xfer_handle xfer)
if (err)
return (err);
- /*
+ /*
* Pipe isn't running (otherwise err would be USBD_INPROG),
* so start it first.
*/
@@ -1861,44 +1882,68 @@ uhci_device_bulk_abort(usbd_xfer_handle xfer)
}
/*
- * XXX This way of aborting is neither safe, nor good.
- * But it will have to do until I figure out what to do.
- * I apologize for the delay().
+ * 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_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));
- s = splusb();
-
- /* Transfer is already done. */
- if (xfer->status != USBD_NOT_STARTED &&
- xfer->status != USBD_IN_PROGRESS) {
+ 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 interrupt routine ignore it, */
- xfer->status = status;
+ if (xfer->device->bus->intr_context || !curproc)
+ panic("uhci_abort_xfer: not in process context\n");
- /* don't timeout, */
+ /*
+ * 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);
-
- /* make hardware ignore it, */
+ 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));
-
- xfer->hcpriv = ii;
-
splx(s);
- delay(1000);
+ /*
+ * 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();
+ sc->sc_softwake = 1;
+ usb_schedsoftintr(&sc->sc_bus);
+ DPRINTFN(1,("uhci_abort_xfer: tsleep\n"));
+ tsleep(&sc->sc_softwake, PZERO, "uhciab", 0);
+ splx(s);
+
+ /*
+ * Step 3: Execute callback.
+ */
+ xfer->hcpriv = ii;
+ DPRINTFN(1,("uhci_abort_xfer: callback\n"));
s = splusb();
#ifdef DIAGNOSTIC
ii->isdone = 1;
@@ -1928,7 +1973,7 @@ uhci_device_ctrl_transfer(usbd_xfer_handle xfer)
if (err)
return (err);
- /*
+ /*
* Pipe isn't running (otherwise err would be USBD_INPROG),
* so start it first.
*/
@@ -1968,7 +2013,7 @@ uhci_device_intr_transfer(usbd_xfer_handle xfer)
if (err)
return (err);
- /*
+ /*
* Pipe isn't running (otherwise err would be USBD_INPROG),
* so start it first.
*/
@@ -2024,7 +2069,7 @@ uhci_device_intr_start(usbd_xfer_handle xfer)
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];
@@ -2067,7 +2112,7 @@ uhci_device_intr_abort(usbd_xfer_handle xfer)
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);
}
@@ -2088,7 +2133,7 @@ uhci_device_intr_close(usbd_pipe_handle pipe)
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.
*/
@@ -2125,7 +2170,7 @@ uhci_device_request(usbd_xfer_handle xfer)
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);
@@ -2159,9 +2204,9 @@ uhci_device_request(usbd_xfer_handle xfer)
stat->link.std = NULL;
stat->td.td_link = htole32(UHCI_PTR_T);
- stat->td.td_status = htole32(UHCI_TD_SET_ERRCNT(3) | ls |
+ stat->td.td_status = htole32(UHCI_TD_SET_ERRCNT(3) | ls |
UHCI_TD_ACTIVE | UHCI_TD_IOC);
- stat->td.td_token =
+ 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);
@@ -2188,7 +2233,7 @@ uhci_device_request(usbd_xfer_handle xfer)
sqh->qh.qh_elink = htole32(setup->physaddr | UHCI_PTR_TD);
s = splusb();
- if (dev->lowspeed)
+ if (dev->speed == USB_SPEED_LOW)
uhci_add_ls_ctrl(sc, sqh);
else
uhci_add_hs_ctrl(sc, sqh);
@@ -2211,7 +2256,7 @@ uhci_device_request(usbd_xfer_handle xfer)
uhci_dump_qh(sxqh);
for (xqh = sxqh;
xqh != NULL;
- xqh = (maxqh++ == 5 || xqh->hlink == sxqh ||
+ xqh = (maxqh++ == 5 || xqh->hlink == sxqh ||
xqh->hlink == xqh ? NULL : xqh->hlink)) {
uhci_dump_qh(xqh);
}
@@ -2263,7 +2308,7 @@ uhci_device_isoc_enter(usbd_xfer_handle xfer)
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;
@@ -2359,7 +2404,7 @@ uhci_device_isoc_start(usbd_xfer_handle xfer)
#endif
s = splusb();
-
+
/* Set up interrupt info. */
ii->xfer = xfer;
ii->stdstart = end;
@@ -2370,7 +2415,7 @@ uhci_device_isoc_start(usbd_xfer_handle xfer)
ii->isdone = 0;
#endif
uhci_add_intr_info(sc, ii);
-
+
splx(s);
return (USBD_IN_PROGRESS);
@@ -2387,7 +2432,7 @@ uhci_device_isoc_abort(usbd_xfer_handle xfer)
s = splusb();
/* Transfer is already done. */
- if (xfer->status != USBD_NOT_STARTED &&
+ if (xfer->status != USBD_NOT_STARTED &&
xfer->status != USBD_IN_PROGRESS) {
splx(s);
return;
@@ -2571,7 +2616,7 @@ uhci_device_intr_done(usbd_xfer_handle xfer)
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) {
@@ -2628,7 +2673,7 @@ uhci_device_ctrl_done(usbd_xfer_handle xfer)
uhci_del_intr_info(ii); /* remove from active list */
- if (upipe->pipe.device->lowspeed)
+ 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);
@@ -2651,7 +2696,7 @@ uhci_device_bulk_done(usbd_xfer_handle xfer)
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));
}
@@ -2717,10 +2762,10 @@ uhci_device_setintr(uhci_softc_t *sc, struct uhci_pipe *upipe, int ival)
DPRINTFN(2, ("uhci_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.
*/
@@ -2764,7 +2809,7 @@ uhci_open(usbd_pipe_handle pipe)
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;
@@ -2799,8 +2844,8 @@ uhci_open(usbd_pipe_handle pipe)
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);
@@ -2841,7 +2886,7 @@ usb_device_descriptor_t uhci_devd = {
{0x00, 0x01}, /* USB version */
UDCLASS_HUB, /* class */
UDSUBCLASS_HUB, /* subclass */
- 0, /* protocol */
+ UDPROTO_FSHUB, /* protocol */
64, /* max packet */
{0},{0},{0x00,0x01}, /* device id */
1,2,0, /* string indicies */
@@ -2869,7 +2914,7 @@ usb_interface_descriptor_t uhci_ifcd = {
1,
UICLASS_HUB,
UISUBCLASS_HUB,
- 0,
+ UIPROTO_FSHUB,
0
};
@@ -2922,7 +2967,7 @@ uhci_root_ctrl_transfer(usbd_xfer_handle xfer)
if (err)
return (err);
- /*
+ /*
* Pipe isn't running (otherwise err would be USBD_INPROG),
* so start it first.
*/
@@ -2949,7 +2994,7 @@ uhci_root_ctrl_start(usbd_xfer_handle xfer)
#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);
@@ -2964,7 +3009,7 @@ uhci_root_ctrl_start(usbd_xfer_handle xfer)
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.
*/
@@ -3132,7 +3177,7 @@ uhci_root_ctrl_start(usbd_xfer_handle xfer)
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;
@@ -3172,19 +3217,19 @@ uhci_root_ctrl_start(usbd_xfer_handle xfer)
status = change = 0;
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)
@@ -3221,7 +3266,7 @@ uhci_root_ctrl_start(usbd_xfer_handle xfer)
case UHF_PORT_RESET:
x = URWMASK(UREAD2(sc, port));
UWRITE2(sc, port, x | UHCI_PORTSC_PR);
- usb_delay_ms(&sc->sc_bus, 50); /*XXX USB v1.1 7.1.7.3 */
+ usb_delay_ms(&sc->sc_bus, USB_PORT_ROOT_RESET_DELAY);
UWRITE2(sc, port, x & ~UHCI_PORTSC_PR);
delay(100);
x = UREAD2(sc, port);
diff --git a/sys/dev/usb/uhcireg.h b/sys/dev/usb/uhcireg.h
index 4f71a231ba7..c0d73cedc4c 100644
--- a/sys/dev/usb/uhcireg.h
+++ b/sys/dev/usb/uhcireg.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: uhcireg.h,v 1.9 2001/10/31 04:24:44 nate Exp $ */
-/* $NetBSD: uhcireg.h,v 1.14 2001/08/06 15:15:08 augustss Exp $ */
+/* $OpenBSD: uhcireg.h,v 1.10 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: uhcireg.h,v 1.15 2002/02/11 11:41:30 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/uhcireg.h,v 1.12 1999/11/17 22:33:42 n_hibma Exp $ */
/*
@@ -76,6 +76,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
diff --git a/sys/dev/usb/uhcivar.h b/sys/dev/usb/uhcivar.h
index ef076c26dba..b8fdfeea482 100644
--- a/sys/dev/usb/uhcivar.h
+++ b/sys/dev/usb/uhcivar.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: uhcivar.h,v 1.11 2001/06/12 19:11:59 mickey Exp $ */
-/* $NetBSD: uhcivar.h,v 1.32 2000/08/13 16:18:09 augustss Exp $ */
+/* $OpenBSD: uhcivar.h,v 1.12 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: uhcivar.h,v 1.33 2002/02/11 11:41:30 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/uhcivar.h,v 1.14 1999/11/17 22:33:42 n_hibma Exp $ */
/*
@@ -84,6 +84,7 @@ typedef struct uhci_intr_info {
struct uhci_xfer {
struct usbd_xfer xfer;
uhci_intr_info_t iinfo;
+ struct usb_task abort_task;
int curframe;
};
@@ -161,6 +162,7 @@ typedef struct uhci_softc {
u_int8_t sc_saved_sof;
u_int16_t sc_saved_frnum;
+ char sc_softwake;
char sc_isreset;
char sc_suspend;
char sc_dying;
diff --git a/sys/dev/usb/uhid.c b/sys/dev/usb/uhid.c
index fca9cd5d787..48fb9f7d21d 100644
--- a/sys/dev/usb/uhid.c
+++ b/sys/dev/usb/uhid.c
@@ -1,6 +1,5 @@
-/* $OpenBSD: uhid.c,v 1.16 2002/05/02 20:08:04 nate Exp $ */
-/* $NetBSD: uhid.c,v 1.45 2001/10/26 17:58:21 augustss Exp $ */
-/* $FreeBSD: src/sys/dev/usb/uhid.c,v 1.22 1999/11/17 22:33:43 n_hibma Exp $ */
+/* $OpenBSD: uhid.c,v 1.17 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: uhid.c,v 1.51 2002/03/17 18:02:53 augustss Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -48,16 +47,8 @@
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/signalvar.h>
-#if defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/device.h>
#include <sys/ioctl.h>
-#elif defined(__FreeBSD__)
-#include <sys/ioccom.h>
-#include <sys/filio.h>
-#include <sys/module.h>
-#include <sys/bus.h>
-#include <sys/ioccom.h>
-#endif
#include <sys/conf.h>
#include <sys/tty.h>
#include <sys/file.h>
@@ -75,8 +66,7 @@
#include <dev/usb/hid.h>
#include <dev/usb/usb_quirks.h>
-/* Report descriptor for broken Wacom Graphire */
-#include <dev/usb/ugraphire_rdesc.h>
+#include <dev/usb/uhidev.h>
#ifdef UHID_DEBUG
#define DPRINTF(x) if (uhiddebug) logprintf x
@@ -88,33 +78,20 @@ int uhiddebug = 0;
#endif
struct uhid_softc {
- USBBASEDEVICE sc_dev; /* base device */
- usbd_device_handle sc_udev;
- usbd_interface_handle sc_iface; /* interface */
- usbd_pipe_handle sc_intrpipe; /* interrupt pipe */
- int sc_ep_addr;
+ struct uhidev sc_hdev;
int sc_isize;
int sc_osize;
int sc_fsize;
- u_int8_t sc_iid;
- u_int8_t sc_oid;
- u_int8_t sc_fid;
- u_char *sc_ibuf;
u_char *sc_obuf;
- void *sc_repdesc;
- int sc_repdesc_size;
-
struct clist sc_q;
struct selinfo sc_rsel;
- struct proc *sc_async; /* process that wants SIGIO */
+ usb_proc_ptr sc_async; /* process that wants SIGIO */
u_char sc_state; /* driver state */
-#define UHID_OPEN 0x01 /* device is open */
-#define UHID_ASLP 0x02 /* waiting for device data */
-#define UHID_NEEDCLEAR 0x04 /* needs clearing endpoint stall */
-#define UHID_IMMED 0x08 /* return read data immediately */
+#define UHID_ASLP 0x01 /* waiting for device data */
+#define UHID_IMMED 0x02 /* return read data immediately */
int sc_refcnt;
u_char sc_dying;
@@ -124,153 +101,52 @@ struct uhid_softc {
#define UHID_CHUNK 128 /* chunk size for read */
#define UHID_BSIZE 1020 /* buffer size */
-#if defined(__NetBSD__) || defined(__OpenBSD__)
cdev_decl(uhid);
-#elif defined(__FreeBSD__)
-d_open_t uhidopen;
-d_close_t uhidclose;
-d_read_t uhidread;
-d_write_t uhidwrite;
-d_ioctl_t uhidioctl;
-d_poll_t uhidpoll;
-
-#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
-};
-#endif
-Static void uhid_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
+Static void uhid_intr(struct uhidev *, void *, u_int len);
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,struct proc*);
+Static int uhid_do_ioctl(struct uhid_softc*, u_long, caddr_t, int,
+ usb_proc_ptr);
USB_DECLARE_DRIVER(uhid);
USB_MATCH(uhid)
{
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);
+ struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa;
+
+ DPRINTF(("uhid_match: report=%d\n", uha->reportid));
+
+ if (uha->matchlvl)
+ return (uha->matchlvl);
return (UMATCH_IFACECLASS_GENERIC);
}
USB_ATTACH(uhid)
{
USB_ATTACH_START(uhid, sc, uaa);
- usbd_interface_handle iface = uaa->iface;
- usb_interface_descriptor_t *id;
- usb_endpoint_descriptor_t *ed;
- int size;
+ struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa;
+ int size, repid;
void *desc;
- usbd_status err;
- char devinfo[1024];
-
- sc->sc_udev = uaa->device;
- sc->sc_iface = iface;
- id = usbd_get_interface_descriptor(iface);
- usbd_devinfo(uaa->device, 0, devinfo);
- USB_ATTACH_SETUP;
- printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev),
- devinfo, id->bInterfaceClass, id->bInterfaceSubClass);
-
- ed = usbd_interface2endpoint_descriptor(iface, 0);
- if (ed == NULL) {
- printf("%s: could not read endpoint descriptor\n",
- USBDEVNAME(sc->sc_dev));
- sc->sc_dying = 1;
- USB_ATTACH_ERROR_RETURN;
- }
-
- DPRINTFN(10,("uhid_attach: bLength=%d bDescriptorType=%d "
- "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d"
- " bInterval=%d\n",
- ed->bLength, ed->bDescriptorType,
- ed->bEndpointAddress & UE_ADDR,
- UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out",
- ed->bmAttributes & UE_XFERTYPE,
- UGETW(ed->wMaxPacketSize), ed->bInterval));
-
- if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN ||
- (ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) {
- printf("%s: unexpected endpoint\n", USBDEVNAME(sc->sc_dev));
- sc->sc_dying = 1;
- USB_ATTACH_ERROR_RETURN;
- }
-
- sc->sc_ep_addr = ed->bEndpointAddress;
-
- 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);
- sc->sc_osize = hid_report_size(desc, size, hid_output, &sc->sc_oid);
- sc->sc_fsize = hid_report_size(desc, size, hid_feature, &sc->sc_fid);
+ sc->sc_hdev.sc_intr = uhid_intr;
+ sc->sc_hdev.sc_parent = uha->parent;
+ sc->sc_hdev.sc_report_id = uha->reportid;
- sc->sc_repdesc = desc;
- sc->sc_repdesc_size = size;
+ uhidev_get_report_desc(uha->parent, &desc, &size);
+ repid = uha->reportid;
+ sc->sc_isize = hid_report_size(desc, size, hid_input, repid);
+ sc->sc_osize = hid_report_size(desc, size, hid_output, repid);
+ sc->sc_fsize = hid_report_size(desc, size, hid_feature, repid);
-#ifdef __FreeBSD__
- {
- static int global_init_done = 0;
-
- if (!global_init_done) {
- cdevsw_add(&uhid_cdevsw);
- global_init_done = 1;
- }
- }
-#endif
-
- usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
- USBDEV(sc->sc_dev));
+ printf(": input=%d, output=%d, feature=%d\n",
+ sc->sc_isize, sc->sc_osize, sc->sc_fsize);
USB_ATTACH_SUCCESS_RETURN;
}
-#if defined(__NetBSD__) || defined(__OpenBSD__)
int
uhid_activate(device_ptr_t self, enum devact act)
{
@@ -287,36 +163,28 @@ uhid_activate(device_ptr_t self, enum devact act)
}
return (0);
}
-#endif
USB_DETACH(uhid)
{
USB_DETACH_START(uhid, sc);
int s;
-#if defined(__NetBSD__) || defined(__OpenBSD__)
int maj, mn;
DPRINTF(("uhid_detach: sc=%p flags=%d\n", sc, flags));
-#else
- DPRINTF(("uhid_detach: sc=%p\n", sc));
-#endif
sc->sc_dying = 1;
- if (sc->sc_intrpipe != NULL)
- usbd_abort_pipe(sc->sc_intrpipe);
- if (sc->sc_state & UHID_OPEN) {
+ if (sc->sc_hdev.sc_state & UHIDEV_OPEN) {
s = splusb();
if (--sc->sc_refcnt >= 0) {
/* Wake everyone */
wakeup(&sc->sc_q);
/* Wait for processes to go away. */
- usb_detach_wait(USBDEV(sc->sc_dev));
+ usb_detach_wait(USBDEV(sc->sc_hdev.sc_dev));
}
splx(s);
}
-#if defined(__NetBSD__) || defined(__OpenBSD__)
/* locate the major number */
for (maj = 0; maj < nchrdev; maj++)
if (cdevsw[maj].d_open == uhidopen)
@@ -325,47 +193,33 @@ USB_DETACH(uhid)
/* Nuke the vnodes for any open instances (calls close). */
mn = self->dv_unit;
vdevgone(maj, mn, mn, VCHR);
-#elif defined(__FreeBSD__)
- /* XXX not implemented yet */
-#endif
- if (sc->sc_repdesc)
- free(sc->sc_repdesc, M_USBDEV);
-
- usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
- USBDEV(sc->sc_dev));
+#if 0
+ usbd_add_drv_event(USB_EVENT_DRIVER_DETACH,
+ sc->sc_hdev.sc_parent->sc_udev,
+ USBDEV(sc->sc_hdev.sc_dev));
+#endif
return (0);
}
void
-uhid_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status)
+uhid_intr(struct uhidev *addr, void *data, u_int len)
{
- struct uhid_softc *sc = addr;
+ struct uhid_softc *sc = (struct uhid_softc *)addr;
#ifdef UHID_DEBUG
if (uhiddebug > 5) {
- u_int32_t cc, i;
+ u_int32_t i;
- usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL);
- DPRINTF(("uhid_intr: status=%d cc=%d\n", status, cc));
DPRINTF(("uhid_intr: data ="));
- for (i = 0; i < cc; i++)
- DPRINTF((" %02x", sc->sc_ibuf[i]));
+ for (i = 0; i < len; i++)
+ DPRINTF((" %02x", ((u_char *)data)[i]));
DPRINTF(("\n"));
}
#endif
- if (status == USBD_CANCELLED)
- return;
-
- if (status != USBD_NORMAL_COMPLETION) {
- DPRINTF(("uhid_intr: status=%d\n", status));
- sc->sc_state |= UHID_NEEDCLEAR;
- return;
- }
-
- (void) b_to_q(sc->sc_ibuf, sc->sc_isize, &sc->sc_q);
+ (void)b_to_q(data, len, &sc->sc_q);
if (sc->sc_state & UHID_ASLP) {
sc->sc_state &= ~UHID_ASLP;
@@ -380,10 +234,10 @@ uhid_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status)
}
int
-uhidopen(dev_t dev, int flag, int mode, struct proc *p)
+uhidopen(dev_t dev, int flag, int mode, usb_proc_ptr p)
{
struct uhid_softc *sc;
- usbd_status err;
+ int error;
USB_GET_SC_OPEN(uhid, UHIDUNIT(dev), sc);
@@ -392,40 +246,23 @@ uhidopen(dev_t dev, int flag, int mode, struct proc *p)
if (sc->sc_dying)
return (ENXIO);
- if (sc->sc_state & UHID_OPEN)
- return (EBUSY);
- sc->sc_state |= UHID_OPEN;
+ error = uhidev_open(&sc->sc_hdev);
+ if (error)
+ return (error);
if (clalloc(&sc->sc_q, UHID_BSIZE, 0) == -1) {
- sc->sc_state &= ~UHID_OPEN;
+ uhidev_close(&sc->sc_hdev);
return (ENOMEM);
}
-
- sc->sc_ibuf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
sc->sc_obuf = malloc(sc->sc_osize, M_USBDEV, M_WAITOK);
-
- /* Set up interrupt pipe. */
- 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_state &= ~UHID_OPEN;
- return (EIO);
- }
-
sc->sc_state &= ~UHID_IMMED;
-
- sc->sc_async = 0;
+ sc->sc_async = NULL;
return (0);
}
int
-uhidclose(dev_t dev, int flag, int mode, struct proc *p)
+uhidclose(dev_t dev, int flag, int mode, usb_proc_ptr p)
{
struct uhid_softc *sc;
@@ -433,19 +270,10 @@ uhidclose(dev_t dev, int flag, int mode, struct proc *p)
DPRINTF(("uhidclose: sc=%p\n", sc));
- /* Disable interrupts. */
- usbd_abort_pipe(sc->sc_intrpipe);
- usbd_close_pipe(sc->sc_intrpipe);
- sc->sc_intrpipe = 0;
-
clfree(&sc->sc_q);
-
- free(sc->sc_ibuf, M_USBDEV);
free(sc->sc_obuf, M_USBDEV);
-
- sc->sc_state &= ~UHID_OPEN;
-
- sc->sc_async = 0;
+ sc->sc_async = NULL;
+ uhidev_close(&sc->sc_hdev);
return (0);
}
@@ -455,6 +283,7 @@ uhid_do_read(struct uhid_softc *sc, struct uio *uio, int flag)
{
int s;
int error = 0;
+ int extra;
size_t length;
u_char buffer[UHID_CHUNK];
usbd_status err;
@@ -462,12 +291,12 @@ uhid_do_read(struct uhid_softc *sc, struct uio *uio, int flag)
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);
+ extra = sc->sc_hdev.sc_report_id != 0;
+ err = uhidev_get_report(&sc->sc_hdev, UHID_INPUT_REPORT,
+ buffer, sc->sc_isize + extra);
if (err)
return (EIO);
- return (uiomove(buffer, sc->sc_isize, uio));
+ return (uiomove(buffer+extra, sc->sc_isize, uio));
}
s = splusb();
@@ -486,11 +315,6 @@ uhid_do_read(struct uhid_softc *sc, struct uio *uio, int flag)
sc->sc_state &= ~UHID_ASLP;
break;
}
- if (sc->sc_state & UHID_NEEDCLEAR) {
- DPRINTFN(-1,("uhidread: clearing stall\n"));
- sc->sc_state &= ~UHID_NEEDCLEAR;
- usbd_clear_endpoint_stall(sc->sc_intrpipe);
- }
}
splx(s);
@@ -523,7 +347,7 @@ uhidread(dev_t dev, struct uio *uio, int flag)
sc->sc_refcnt++;
error = uhid_do_read(sc, uio, flag);
if (--sc->sc_refcnt < 0)
- usb_detach_wakeup(USBDEV(sc->sc_dev));
+ usb_detach_wakeup(USBDEV(sc->sc_hdev.sc_dev));
return (error);
}
@@ -545,12 +369,8 @@ uhid_do_write(struct uhid_softc *sc, struct uio *uio, int flag)
return (EINVAL);
error = uiomove(sc->sc_obuf, size, uio);
if (!error) {
- if (sc->sc_oid)
- err = usbd_set_report(sc->sc_iface, UHID_OUTPUT_REPORT,
- sc->sc_obuf[0], sc->sc_obuf+1, size-1);
- else
- err = usbd_set_report(sc->sc_iface, UHID_OUTPUT_REPORT,
- 0, sc->sc_obuf, size);
+ err = uhidev_set_report(&sc->sc_hdev, UHID_OUTPUT_REPORT,
+ sc->sc_obuf, size);
if (err)
error = EIO;
}
@@ -569,18 +389,20 @@ uhidwrite(dev_t dev, struct uio *uio, int flag)
sc->sc_refcnt++;
error = uhid_do_write(sc, uio, flag);
if (--sc->sc_refcnt < 0)
- usb_detach_wakeup(USBDEV(sc->sc_dev));
+ usb_detach_wakeup(USBDEV(sc->sc_hdev.sc_dev));
return (error);
}
int
uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, caddr_t addr,
- int flag, struct proc *p)
+ int flag, usb_proc_ptr p)
{
struct usb_ctl_report_desc *rd;
struct usb_ctl_report *re;
- int size, id;
+ u_char buffer[UHID_CHUNK];
+ int size, extra;
usbd_status err;
+ void *desc;
DPRINTFN(2, ("uhidioctl: cmd=%lx\n", cmd));
@@ -611,17 +433,18 @@ uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, caddr_t addr,
break;
case USB_GET_REPORT_DESC:
+ uhidev_get_report_desc(sc->sc_hdev.sc_parent, &desc, &size);
rd = (struct usb_ctl_report_desc *)addr;
- size = min(sc->sc_repdesc_size, sizeof rd->ucrd_data);
+ size = min(size, sizeof rd->ucrd_data);
rd->ucrd_size = size;
- memcpy(rd->ucrd_data, sc->sc_repdesc, size);
+ memcpy(rd->ucrd_data, desc, size);
break;
case USB_SET_IMMED:
if (*(int *)addr) {
- /* XXX should read into ibuf, but does it matter? */
- err = usbd_get_report(sc->sc_iface, UHID_INPUT_REPORT,
- sc->sc_iid, sc->sc_ibuf, sc->sc_isize);
+ extra = sc->sc_hdev.sc_report_id != 0;
+ err = uhidev_get_report(&sc->sc_hdev, UHID_INPUT_REPORT,
+ buffer, sc->sc_isize + extra);
if (err)
return (EOPNOTSUPP);
@@ -635,21 +458,21 @@ uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, caddr_t addr,
switch (re->ucr_report) {
case UHID_INPUT_REPORT:
size = sc->sc_isize;
- id = sc->sc_iid;
break;
case UHID_OUTPUT_REPORT:
size = sc->sc_osize;
- id = sc->sc_oid;
break;
case UHID_FEATURE_REPORT:
size = sc->sc_fsize;
- id = sc->sc_fid;
break;
default:
return (EINVAL);
}
- err = usbd_get_report(sc->sc_iface, re->ucr_report, id,
- re->ucr_data, size);
+ extra = sc->sc_hdev.sc_report_id != 0;
+ err = uhidev_get_report(&sc->sc_hdev, re->ucr_report,
+ re->ucr_data, size + extra);
+ if (extra)
+ memcpy(re->ucr_data, re->ucr_data+1, size);
if (err)
return (EIO);
break;
@@ -659,26 +482,26 @@ uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, caddr_t addr,
switch (re->ucr_report) {
case UHID_INPUT_REPORT:
size = sc->sc_isize;
- id = sc->sc_iid;
break;
case UHID_OUTPUT_REPORT:
size = sc->sc_osize;
- id = sc->sc_oid;
break;
case UHID_FEATURE_REPORT:
size = sc->sc_fsize;
- id = sc->sc_fid;
break;
default:
return (EINVAL);
}
- err = usbd_set_report(sc->sc_iface, re->ucr_report, id,
- re->ucr_data,
- size);
+ err = uhidev_set_report(&sc->sc_hdev, re->ucr_report,
+ re->ucr_data, size);
if (err)
return (EIO);
break;
+ case USB_GET_REPORT_ID:
+ *(int *)addr = sc->sc_hdev.sc_report_id;
+ break;
+
default:
return (EINVAL);
}
@@ -686,7 +509,7 @@ uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, caddr_t addr,
}
int
-uhidioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
+uhidioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, usb_proc_ptr p)
{
struct uhid_softc *sc;
int error;
@@ -696,12 +519,12 @@ uhidioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
sc->sc_refcnt++;
error = uhid_do_ioctl(sc, cmd, addr, flag, p);
if (--sc->sc_refcnt < 0)
- usb_detach_wakeup(USBDEV(sc->sc_dev));
+ usb_detach_wakeup(USBDEV(sc->sc_hdev.sc_dev));
return (error);
}
int
-uhidpoll(dev_t dev, int events, struct proc *p)
+uhidpoll(dev_t dev, int events, usb_proc_ptr p)
{
struct uhid_softc *sc;
int revents = 0;
@@ -725,7 +548,3 @@ uhidpoll(dev_t dev, int events, struct proc *p)
splx(s);
return (revents);
}
-
-#if defined(__FreeBSD__)
-DRIVER_MODULE(uhid, uhub, uhid_driver, uhid_devclass, usbd_driver_load, 0);
-#endif
diff --git a/sys/dev/usb/uhidev.c b/sys/dev/usb/uhidev.c
new file mode 100644
index 00000000000..263ab111bf1
--- /dev/null
+++ b/sys/dev/usb/uhidev.c
@@ -0,0 +1,513 @@
+/* $OpenBSD: uhidev.c,v 1.1 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: uhidev.c,v 1.5 2002/02/27 01:30:50 augustss Exp $ */
+
+/*
+ * Copyright (c) 2001 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.
+ */
+
+/*
+ * HID spec: http://www.usb.org/developers/data/devclass/hid1_1.pdf
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/signalvar.h>
+#include <sys/device.h>
+#include <sys/ioctl.h>
+#include <sys/conf.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbhid.h>
+
+#include <dev/usb/usbdevs.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+#include <dev/usb/hid.h>
+#include <dev/usb/usb_quirks.h>
+
+#include <dev/usb/uhidev.h>
+
+/* Report descriptor for broken Wacom Graphire */
+#include <dev/usb/ugraphire_rdesc.h>
+
+#ifdef UHIDEV_DEBUG
+#define DPRINTF(x) if (uhidevdebug) logprintf x
+#define DPRINTFN(n,x) if (uhidevdebug>(n)) logprintf x
+int uhidevdebug = 0;
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n,x)
+#endif
+
+Static void uhidev_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
+
+Static int uhidev_maxrepid(void *buf, int len);
+Static int uhidevprint(void *aux, const char *pnp);
+#if defined(__NetBSD__)
+Static int uhidevsubmatch(struct device *parent, struct cfdata *cf, void *aux);
+#else
+Static int uhidevsubmatch(struct device *parent, void *cf, void *aux);
+#endif
+
+USB_DECLARE_DRIVER(uhidev);
+
+USB_MATCH(uhidev)
+{
+ USB_MATCH_START(uhidev, 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);
+}
+
+int repproto = 1;
+
+USB_ATTACH(uhidev)
+{
+ USB_ATTACH_START(uhidev, sc, uaa);
+ usbd_interface_handle iface = uaa->iface;
+ usb_interface_descriptor_t *id;
+ usb_endpoint_descriptor_t *ed;
+ struct uhidev_attach_arg uha;
+ struct uhidev *dev;
+ int size, nrepid, repid, repsz;
+ int repsizes[256];
+ void *desc;
+ usbd_status err;
+ char devinfo[1024];
+
+ sc->sc_udev = uaa->device;
+ sc->sc_iface = iface;
+ id = usbd_get_interface_descriptor(iface);
+ usbd_devinfo(uaa->device, 0, devinfo);
+ USB_ATTACH_SETUP;
+ printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev),
+ devinfo, id->bInterfaceClass, id->bInterfaceSubClass);
+
+ (void)usbd_set_idle(iface, 0, 0);
+#if 0
+
+ qflags = usbd_get_quirks(sc->sc_udev)->uq_flags;
+ if ((qflags & UQ_NO_SET_PROTO) == 0 &&
+ id->bInterfaceSubClass != UISUBCLASS_BOOT)
+ (void)usbd_set_protocol(iface, 1);
+#endif
+
+ ed = usbd_interface2endpoint_descriptor(iface, 0);
+ if (ed == NULL) {
+ printf("%s: could not read endpoint descriptor\n",
+ USBDEVNAME(sc->sc_dev));
+ sc->sc_dying = 1;
+ USB_ATTACH_ERROR_RETURN;
+ }
+
+ DPRINTFN(10,("uhidev_attach: bLength=%d bDescriptorType=%d "
+ "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d"
+ " bInterval=%d\n",
+ ed->bLength, ed->bDescriptorType,
+ ed->bEndpointAddress & UE_ADDR,
+ UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out",
+ ed->bmAttributes & UE_XFERTYPE,
+ UGETW(ed->wMaxPacketSize), ed->bInterval));
+
+ if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN ||
+ (ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) {
+ printf("%s: unexpected endpoint\n", USBDEVNAME(sc->sc_dev));
+ sc->sc_dying = 1;
+ USB_ATTACH_ERROR_RETURN;
+ }
+
+ sc->sc_ep_addr = ed->bEndpointAddress;
+
+ /* XXX need to extend this */
+ 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;
+ }
+
+ sc->sc_repdesc = desc;
+ sc->sc_repdesc_size = size;
+
+ uha.uaa = uaa;
+ nrepid = uhidev_maxrepid(desc, size);
+ if (nrepid < 0)
+ USB_ATTACH_SUCCESS_RETURN;
+ if (nrepid > 0)
+ printf("%s: %d report ids\n", USBDEVNAME(sc->sc_dev), nrepid);
+ nrepid++;
+ sc->sc_subdevs = malloc(nrepid * sizeof(device_ptr_t),
+ M_USBDEV, M_NOWAIT);
+ bzero(sc->sc_subdevs, nrepid * sizeof(device_ptr_t));
+ if (sc->sc_subdevs == NULL) {
+ printf("%s: no memory\n", USBDEVNAME(sc->sc_dev));
+ USB_ATTACH_ERROR_RETURN;
+ }
+ sc->sc_nrepid = nrepid;
+ sc->sc_isize = 0;
+
+ usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
+ USBDEV(sc->sc_dev));
+
+ for (repid = 0; repid < nrepid; repid++) {
+ repsz = hid_report_size(desc, size, hid_input, repid);
+ DPRINTF(("uhidev_match: repid=%d, repsz=%d\n", repid, repsz));
+ repsizes[repid] = repsz;
+ if (repsz > 0) {
+ if (repsz > sc->sc_isize)
+ sc->sc_isize = repsz;
+ }
+ }
+ sc->sc_isize += nrepid != 1; /* space for report ID */
+ DPRINTF(("uhidev_attach: isize=%d\n", sc->sc_isize));
+
+ uha.parent = sc;
+ for (repid = 0; repid < nrepid; repid++) {
+ DPRINTF(("uhidev_match: try repid=%d\n", repid));
+ if (hid_report_size(desc, size, hid_input, repid) == 0 &&
+ hid_report_size(desc, size, hid_output, repid) == 0 &&
+ hid_report_size(desc, size, hid_feature, repid) == 0) {
+ ; /* already NULL in sc->sc_subdevs[repid] */
+ } else {
+ uha.reportid = repid;
+ dev = (struct uhidev *)config_found_sm(self, &uha,
+ uhidevprint, uhidevsubmatch);
+ sc->sc_subdevs[repid] = dev;
+ if (dev != NULL) {
+ dev->sc_in_rep_size = repsizes[repid];
+#ifdef DIAGNOSTIC
+ DPRINTF(("uhidev_match: repid=%d dev=%p\n",
+ repid, dev));
+ if (dev->sc_intr == NULL) {
+ printf("%s: sc_intr == NULL\n",
+ USBDEVNAME(sc->sc_dev));
+ USB_ATTACH_ERROR_RETURN;
+ }
+#endif
+ }
+ }
+ }
+
+ USB_ATTACH_SUCCESS_RETURN;
+}
+
+int
+uhidev_maxrepid(void *buf, int len)
+{
+ struct hid_data *d;
+ struct hid_item h;
+ int maxid;
+
+ maxid = -1;
+ h.report_ID = 0;
+ for (d = hid_start_parse(buf, len, hid_none); hid_get_item(d, &h); )
+ if (h.report_ID > maxid)
+ maxid = h.report_ID;
+ hid_end_parse(d);
+ return (maxid);
+}
+
+int
+uhidevprint(void *aux, const char *pnp)
+{
+ struct uhidev_attach_arg *uha = aux;
+
+ if (pnp)
+ printf("uhid at %s", pnp);
+ if (uha->reportid != 0)
+ printf(" reportid %d", uha->reportid);
+ return (UNCONF);
+}
+
+#if defined(__NetBSD__)
+Static int uhidevsubmatch(struct device *parent, struct cfdata *cf, void *aux)
+#else
+Static int uhidevsubmatch(struct device *parent, void *match, void *aux)
+#endif
+{
+ struct uhidev_attach_arg *uha = aux;
+#if defined(__OpenBSD__)
+ struct cfdata *cf = match;
+#endif
+
+ if (cf->uhidevcf_reportid != UHIDEV_UNK_REPORTID &&
+ cf->uhidevcf_reportid != uha->reportid)
+ return (0);
+ if (cf->uhidevcf_reportid == uha->reportid)
+ uha->matchlvl = UMATCH_VENDOR_PRODUCT;
+ else
+ uha->matchlvl = 0;
+ return ((*cf->cf_attach->ca_match)(parent, cf, aux));
+}
+
+int
+uhidev_activate(device_ptr_t self, enum devact act)
+{
+ struct uhidev_softc *sc = (struct uhidev_softc *)self;
+ int i, rv;
+
+ switch (act) {
+ case DVACT_ACTIVATE:
+ return (EOPNOTSUPP);
+ break;
+
+ case DVACT_DEACTIVATE:
+ rv = 0;
+ for (i = 0; i < sc->sc_nrepid; i++)
+ if (sc->sc_subdevs[i] != NULL)
+ rv |= config_deactivate(
+ &sc->sc_subdevs[i]->sc_dev);
+ sc->sc_dying = 1;
+ break;
+ }
+ return (rv);
+}
+
+USB_DETACH(uhidev)
+{
+ USB_DETACH_START(uhidev, sc);
+ int i, rv;
+
+ DPRINTF(("uhidev_detach: sc=%p flags=%d\n", sc, flags));
+
+ sc->sc_dying = 1;
+ if (sc->sc_intrpipe != NULL)
+ usbd_abort_pipe(sc->sc_intrpipe);
+
+ if (sc->sc_repdesc != NULL)
+ free(sc->sc_repdesc, M_USBDEV);
+
+ rv = 0;
+ for (i = 0; i < sc->sc_nrepid; i++) {
+ if (sc->sc_subdevs[i] != NULL) {
+ rv |= config_detach(&sc->sc_subdevs[i]->sc_dev, flags);
+ sc->sc_subdevs[i] = NULL;
+ }
+ }
+
+ usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
+ USBDEV(sc->sc_dev));
+
+ return (rv);
+}
+
+void
+uhidev_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status)
+{
+ struct uhidev_softc *sc = addr;
+ struct uhidev *scd;
+ u_char *p;
+ u_int rep;
+ u_int32_t cc;
+
+ usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL);
+
+#ifdef UHIDEV_DEBUG
+ if (uhidevdebug > 5) {
+ u_int32_t i;
+
+ DPRINTF(("uhidev_intr: status=%d cc=%d\n", status, cc));
+ DPRINTF(("uhidev_intr: data ="));
+ for (i = 0; i < cc; i++)
+ DPRINTF((" %02x", sc->sc_ibuf[i]));
+ DPRINTF(("\n"));
+ }
+#endif
+
+ if (status == USBD_CANCELLED)
+ return;
+
+ if (status != USBD_NORMAL_COMPLETION) {
+ DPRINTF(("%s: interrupt status=%d\n", USBDEVNAME(sc->sc_dev),
+ status));
+ usbd_clear_endpoint_stall_async(sc->sc_intrpipe);
+ return;
+ }
+
+ p = sc->sc_ibuf;
+ if (sc->sc_nrepid != 1)
+ rep = *p++, cc--;
+ else
+ rep = 0;
+ if (rep >= sc->sc_nrepid) {
+ printf("uhidev_intr: bad repid %d\n", rep);
+ return;
+ }
+ scd = sc->sc_subdevs[rep];
+ DPRINTFN(5,("uhidev_intr: rep=%d, scd=%p state=0x%x\n",
+ rep, scd, scd ? scd->sc_state : 0));
+ if (scd == NULL || !(scd->sc_state & UHIDEV_OPEN))
+ return;
+#ifdef DIAGNOSTIC
+ if (scd->sc_in_rep_size != cc)
+ printf("%s: bad input length %d != %d\n",USBDEVNAME(sc->sc_dev),
+ scd->sc_in_rep_size, cc);
+#endif
+ scd->sc_intr(scd, p, cc);
+}
+
+void
+uhidev_get_report_desc(struct uhidev_softc *sc, void **desc, int *size)
+{
+ *desc = sc->sc_repdesc;
+ *size = sc->sc_repdesc_size;
+}
+
+int
+uhidev_open(struct uhidev *scd)
+{
+ struct uhidev_softc *sc = scd->sc_parent;
+ usbd_status err;
+
+ DPRINTF(("uhidev_open: open pipe, state=%d refcnt=%d\n",
+ scd->sc_state, sc->sc_refcnt));
+
+ if (scd->sc_state & UHIDEV_OPEN)
+ return (EBUSY);
+ scd->sc_state |= UHIDEV_OPEN;
+ if (sc->sc_refcnt++)
+ return (0);
+
+ if (sc->sc_isize == 0)
+ return (0);
+
+ sc->sc_ibuf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
+
+ /* Set up interrupt pipe. */
+ DPRINTF(("uhidev_open: isize=%d, ep=0x%02x\n", sc->sc_isize,
+ sc->sc_ep_addr));
+ 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, uhidev_intr, USBD_DEFAULT_INTERVAL);
+ if (err) {
+ DPRINTF(("uhidopen: usbd_open_pipe_intr failed, "
+ "error=%d\n",err));
+ free(sc->sc_ibuf, M_USBDEV);
+ scd->sc_state &= ~UHIDEV_OPEN;
+ sc->sc_refcnt = 0;
+ sc->sc_intrpipe = NULL;
+ return (EIO);
+ }
+ return (0);
+}
+
+void
+uhidev_close(struct uhidev *scd)
+{
+ struct uhidev_softc *sc = scd->sc_parent;
+
+ if (!(scd->sc_state & UHIDEV_OPEN))
+ return;
+ scd->sc_state &= ~UHIDEV_OPEN;
+ if (--sc->sc_refcnt)
+ return;
+ DPRINTF(("uhidev_close: close pipe\n"));
+
+ /* Disable interrupts. */
+ if (sc->sc_intrpipe != NULL) {
+ usbd_abort_pipe(sc->sc_intrpipe);
+ usbd_close_pipe(sc->sc_intrpipe);
+ sc->sc_intrpipe = NULL;
+ }
+
+ if (sc->sc_ibuf != NULL) {
+ free(sc->sc_ibuf, M_USBDEV);
+ sc->sc_ibuf = NULL;
+ }
+}
+
+usbd_status
+uhidev_set_report(struct uhidev *scd, int type, void *data, int len)
+{
+ /* XXX */
+ char buf[100];
+ if (scd->sc_report_id) {
+ buf[0] = scd->sc_report_id;
+ memcpy(buf+1, data, len);
+ len++;
+ data = buf;
+ }
+
+ return usbd_set_report(scd->sc_parent->sc_iface, type,
+ scd->sc_report_id, data, len);
+}
+
+void
+uhidev_set_report_async(struct uhidev *scd, int type, void *data, int len)
+{
+ /* XXX */
+ char buf[100];
+ if (scd->sc_report_id) {
+ buf[0] = scd->sc_report_id;
+ memcpy(buf+1, data, len);
+ len++;
+ data = buf;
+ }
+
+ usbd_set_report_async(scd->sc_parent->sc_iface, type,
+ scd->sc_report_id, data, len);
+}
+
+usbd_status
+uhidev_get_report(struct uhidev *scd, int type, void *data, int len)
+{
+ return usbd_get_report(scd->sc_parent->sc_iface, type,
+ scd->sc_report_id, data, len);
+}
diff --git a/sys/dev/usb/uhidev.h b/sys/dev/usb/uhidev.h
new file mode 100644
index 00000000000..8d2700132cb
--- /dev/null
+++ b/sys/dev/usb/uhidev.h
@@ -0,0 +1,91 @@
+/* $OpenBSD: uhidev.h,v 1.1 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: uhidev.h,v 1.2 2001/12/29 18:56:52 augustss Exp $ */
+
+/*
+ * Copyright (c) 2001 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.
+ */
+
+#if defined(__NetBSD__)
+#include "locators.h"
+#endif
+
+#define uhidevcf_reportid cf_loc[UHIDBUSCF_REPORTID]
+#define UHIDEV_UNK_REPORTID UHIDBUSCF_REPORTID_DEFAULT
+
+struct uhidev_softc {
+ USBBASEDEVICE sc_dev; /* base device */
+ usbd_device_handle sc_udev;
+ usbd_interface_handle sc_iface; /* interface */
+ usbd_pipe_handle sc_intrpipe; /* interrupt pipe */
+ int sc_ep_addr;
+
+ u_char *sc_ibuf;
+ u_int sc_isize;
+
+ void *sc_repdesc;
+ int sc_repdesc_size;
+
+ u_int sc_nrepid;
+ struct uhidev **sc_subdevs;
+
+ int sc_refcnt;
+ u_char sc_dying;
+};
+
+struct uhidev {
+ USBBASEDEVICE sc_dev; /* base device */
+ struct uhidev_softc *sc_parent;
+ uByte sc_report_id;
+ u_int8_t sc_state;
+ int sc_in_rep_size;
+#define UHIDEV_OPEN 0x01 /* device is open */
+ void (*sc_intr)(struct uhidev *, void *, u_int);
+};
+
+struct uhidev_attach_arg {
+ struct usb_attach_arg *uaa;
+ struct uhidev_softc *parent;
+ int reportid;
+ int reportsize;
+ int matchlvl;
+};
+
+void uhidev_get_report_desc(struct uhidev_softc *, void **, int *);
+int uhidev_open(struct uhidev *);
+void uhidev_close(struct uhidev *);
+usbd_status uhidev_set_report(struct uhidev *scd, int type, void *data,int len);
+void uhidev_set_report_async(struct uhidev *scd, int type, void *data, int len);
+usbd_status uhidev_get_report(struct uhidev *scd, int type, void *data,int len);
diff --git a/sys/dev/usb/uhub.c b/sys/dev/usb/uhub.c
index a28b3886d1d..364de76d3f4 100644
--- a/sys/dev/usb/uhub.c
+++ b/sys/dev/usb/uhub.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: uhub.c,v 1.14 2001/10/31 04:24:44 nate Exp $ */
-/* $NetBSD: uhub.c,v 1.52 2001/10/26 17:53:59 augustss Exp $ */
+/* $OpenBSD: uhub.c,v 1.15 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: uhub.c,v 1.57 2001/11/20 16:08:37 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/uhub.c,v 1.18 1999/11/17 22:33:43 n_hibma Exp $ */
/*
@@ -268,6 +268,7 @@ USB_ATTACH(uhub)
* For all ports
* get port status
* if device connected
+ * wait 100 ms
* turn on reset
* wait
* clear C_PORT_RESET
@@ -323,6 +324,7 @@ uhub_explore(usbd_device_handle dev)
struct uhub_softc *sc = dev->hub->hubsoftc;
struct usbd_port *up;
usbd_status err;
+ int speed;
int port;
int change, status;
@@ -423,15 +425,38 @@ uhub_explore(usbd_device_handle dev)
/* 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);
+ dev->depth + 1, speed, port, up);
/* XXX retry a few times? */
if (err) {
DPRINTFN(-1,("uhub_explore: usb_new_device failed, "
diff --git a/sys/dev/usb/ukbd.c b/sys/dev/usb/ukbd.c
index 52a208b9c84..b57d0f4e37b 100644
--- a/sys/dev/usb/ukbd.c
+++ b/sys/dev/usb/ukbd.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: ukbd.c,v 1.11 2002/04/03 17:27:58 jason Exp $ */
-/* $NetBSD: ukbd.c,v 1.69 2001/10/24 21:02:18 augustss Exp $ */
+/* $OpenBSD: ukbd.c,v 1.12 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: ukbd.c,v 1.79 2001/12/30 19:37:43 augustss Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -66,6 +66,7 @@
#include <dev/usb/usbdi_util.h>
#include <dev/usb/usbdevs.h>
#include <dev/usb/usb_quirks.h>
+#include <dev/usb/uhidev.h>
#include <dev/usb/hid.h>
#include <dev/usb/ukbdvar.h>
@@ -88,119 +89,96 @@ int ukbddebug = 0;
#define DPRINTFN(n,x)
#endif
-#define NKEYCODE 6
-
-#define NUM_LOCK 0x01
-#define CAPS_LOCK 0x02
-#define SCROLL_LOCK 0x04
+#define MAXKEYCODE 6
+#define MAXMOD 8 /* max 32 */
struct ukbd_data {
- u_int8_t modifiers;
-#define MOD_CONTROL_L 0x01
-#define MOD_CONTROL_R 0x10
-#define MOD_SHIFT_L 0x02
-#define MOD_SHIFT_R 0x20
-#define MOD_ALT_L 0x04
-#define MOD_ALT_R 0x40
-#define MOD_WIN_L 0x08
-#define MOD_WIN_R 0x80
- u_int8_t reserved;
- u_int8_t keycode[NKEYCODE];
+ u_int32_t modifiers;
+ u_int8_t keycode[MAXKEYCODE];
};
#define PRESS 0x000
#define RELEASE 0x100
#define CODEMASK 0x0ff
-/* Translate USB bitmap to USB keycode. */
-#define NMOD 8
-Static const struct {
- int mask, key;
-} ukbd_mods[NMOD] = {
- { MOD_CONTROL_L, 224 },
- { MOD_CONTROL_R, 228 },
- { MOD_SHIFT_L, 225 },
- { MOD_SHIFT_R, 229 },
- { MOD_ALT_L, 226 },
- { MOD_ALT_R, 230 },
- { MOD_WIN_L, 227 },
- { MOD_WIN_R, 231 },
-};
-
#if defined(WSDISPLAY_COMPAT_RAWKBD)
#define NN 0 /* no translation */
/*
* Translate USB keycodes to US keyboard XT scancodes.
- * Scancodes >= 128 represent EXTENDED keycodes.
+ * Scancodes >= 0x80 represent EXTENDED keycodes.
+ *
+ * See http://www.microsoft.com/HWDEV/TECH/input/Scancode.asp
*/
Static const u_int8_t ukbd_trtab[256] = {
- NN, NN, NN, NN, 30, 48, 46, 32, /* 00 - 07 */
- 18, 33, 34, 35, 23, 36, 37, 38, /* 08 - 0F */
- 50, 49, 24, 25, 16, 19, 31, 20, /* 10 - 17 */
- 22, 47, 17, 45, 21, 44, 2, 3, /* 18 - 1F */
- 4, 5, 6, 7, 8, 9, 10, 11, /* 20 - 27 */
- 28, 1, 14, 15, 57, 12, 13, 26, /* 28 - 2F */
- 27, 43, 43, 39, 40, 41, 51, 52, /* 30 - 37 */
- 53, 58, 59, 60, 61, 62, 63, 64, /* 38 - 3F */
- 65, 66, 67, 68, 87, 88, 170, 70, /* 40 - 47 */
- 127, 210, 199, 201, 211, 207, 209, 205, /* 48 - 4F */
- 203, 208, 200, 69, 181, 55, 74, 78, /* 50 - 57 */
- 156, 79, 80, 81, 75, 76, 77, 71, /* 58 - 5F */
- 72, 73, 82, 83, 86, 221, NN, NN, /* 60 - 67 */
- NN, NN, NN, NN, NN, NN, NN, NN, /* 68 - 6F */
- NN, NN, NN, NN, NN, NN, NN, NN, /* 70 - 77 */
- NN, NN, NN, NN, NN, NN, NN, NN, /* 78 - 7F */
- NN, NN, NN, NN, NN, NN, NN, NN, /* 80 - 87 */
- NN, NN, NN, NN, NN, NN, NN, NN, /* 88 - 8F */
- NN, NN, NN, NN, NN, NN, NN, NN, /* 90 - 97 */
- NN, NN, NN, NN, NN, NN, NN, NN, /* 98 - 9F */
- NN, NN, NN, NN, NN, NN, NN, NN, /* A0 - A7 */
- NN, NN, NN, NN, NN, NN, NN, NN, /* A8 - AF */
- NN, NN, NN, NN, NN, NN, NN, NN, /* B0 - B7 */
- NN, NN, NN, NN, NN, NN, NN, NN, /* B8 - BF */
- NN, NN, NN, NN, NN, NN, NN, NN, /* C0 - C7 */
- NN, NN, NN, NN, NN, NN, NN, NN, /* C8 - CF */
- NN, NN, NN, NN, NN, NN, NN, NN, /* D0 - D7 */
- NN, NN, NN, NN, NN, NN, NN, NN, /* D8 - DF */
- 29, 42, 56, 219, 157, 54, 184,220, /* E0 - E7 */
- NN, NN, NN, NN, NN, NN, NN, NN, /* E8 - EF */
- NN, NN, NN, NN, NN, NN, NN, NN, /* F0 - F7 */
- NN, NN, NN, NN, NN, NN, NN, NN, /* F8 - FF */
+ NN, NN, NN, NN, 0x1e, 0x30, 0x2e, 0x20, /* 00 - 07 */
+ 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, /* 08 - 0f */
+ 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, /* 10 - 17 */
+ 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, 0x02, 0x03, /* 18 - 1f */
+ 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, /* 20 - 27 */
+ 0x1c, 0x01, 0x0e, 0x0f, 0x39, 0x0c, 0x0d, 0x1a, /* 28 - 2f */
+ 0x1b, 0x2b, 0x2b, 0x27, 0x28, 0x29, 0x33, 0x34, /* 30 - 37 */
+ 0x35, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, /* 38 - 3f */
+ 0x41, 0x42, 0x43, 0x44, 0x57, 0x58, 0xaa, 0x46, /* 40 - 47 */
+ 0x7f, 0xd2, 0xc7, 0xc9, 0xd3, 0xcf, 0xd1, 0xcd, /* 48 - 4f */
+ 0xcb, 0xd0, 0xc8, 0x45, 0xb5, 0x37, 0x4a, 0x4e, /* 50 - 57 */
+ 0x9c, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47, /* 58 - 5f */
+ 0x48, 0x49, 0x52, 0x53, 0x56, 0xdd, NN, 0x59, /* 60 - 67 */
+ 0x5d, 0x5e, 0x5f, NN, NN, NN, NN, NN, /* 68 - 6f */
+ NN, NN, NN, NN, NN, NN, NN, NN, /* 70 - 77 */
+ NN, NN, NN, NN, NN, NN, NN, NN, /* 78 - 7f */
+ NN, NN, NN, NN, NN, 0x7e, NN, 0x73, /* 80 - 87 */
+ 0x70, 0x7d, 0x79, 0x7b, 0x5c, NN, NN, NN, /* 88 - 8f */
+ NN, NN, 0x78, 0x77, 0x76, NN, NN, NN, /* 90 - 97 */
+ NN, NN, NN, NN, NN, NN, NN, NN, /* 98 - 9f */
+ NN, NN, NN, NN, NN, NN, NN, NN, /* a0 - a7 */
+ NN, NN, NN, NN, NN, NN, NN, NN, /* a8 - af */
+ NN, NN, NN, NN, NN, NN, NN, NN, /* b0 - b7 */
+ NN, NN, NN, NN, NN, NN, NN, NN, /* b8 - bf */
+ NN, NN, NN, NN, NN, NN, NN, NN, /* c0 - c7 */
+ NN, NN, NN, NN, NN, NN, NN, NN, /* c8 - cf */
+ NN, NN, NN, NN, NN, NN, NN, NN, /* d0 - d7 */
+ NN, NN, NN, NN, NN, NN, NN, NN, /* d8 - df */
+ 0x1d, 0x2a, 0x38, 0xdb, 0x9d, 0x36, 0xb8, 0xdc, /* e0 - e7 */
+ NN, NN, NN, NN, NN, NN, NN, NN, /* e8 - ef */
+ NN, NN, NN, NN, NN, NN, NN, NN, /* f0 - f7 */
+ NN, NN, NN, NN, NN, NN, NN, NN, /* f8 - ff */
};
#endif /* defined(WSDISPLAY_COMPAT_RAWKBD) */
#define KEY_ERROR 0x01
-#define MAXKEYS (NMOD+2*NKEYCODE)
+#define MAXKEYS (MAXMOD+2*MAXKEYCODE)
struct ukbd_softc {
- USBBASEDEVICE sc_dev; /* base device */
- usbd_device_handle sc_udev;
- usbd_interface_handle sc_iface; /* interface */
- usbd_pipe_handle sc_intrpipe; /* interrupt pipe */
- int sc_ep_addr;
+ struct uhidev sc_hdev;
struct ukbd_data sc_ndata;
struct ukbd_data sc_odata;
+ struct hid_location sc_modloc[MAXMOD];
+ u_int sc_nmod;
+ struct {
+ u_int32_t mask;
+ u_int8_t key;
+ } sc_mods[MAXMOD];
+
+ struct hid_location sc_keycodeloc;
+ u_int sc_nkeycode;
char sc_enabled;
int sc_console_keyboard; /* we are the console keyboard */
char sc_debounce; /* for quirk handling */
+ usb_callout_t sc_delay; /* for quirk handling */
struct ukbd_data sc_data; /* for quirk handling */
+ struct hid_location sc_numloc;
+ struct hid_location sc_capsloc;
+ struct hid_location sc_scroloc;
int sc_leds;
-#if defined(__OpenBSD__)
- struct timeout sc_delay; /* for quirk handling */
- struct timeout sc_rawrepeat_ch;
-#else
- struct callout sc_delay; /* for quirk handling */
- struct callout sc_rawrepeat_ch;
-#endif
+ usb_callout_t sc_rawrepeat_ch;
-#if defined(__NetBSD__) || defined(__OpenBSD__)
struct device *sc_wskbddev;
#if defined(WSDISPLAY_COMPAT_RAWKBD)
#define REP_DELAY1 400
@@ -213,7 +191,6 @@ struct ukbd_softc {
int sc_polling;
int sc_npollchar;
u_int16_t sc_pollchars[MAXKEYS];
-#endif
u_char sc_dying;
};
@@ -254,22 +231,21 @@ Static int ukbd_is_console;
Static void ukbd_cngetc(void *, u_int *, int *);
Static void ukbd_cnpollc(void *, int);
-#if defined(__NetBSD__) || defined(__OpenBSD__)
const struct wskbd_consops ukbd_consops = {
ukbd_cngetc,
ukbd_cnpollc,
};
-#endif
-Static void ukbd_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
+Static const char *ukbd_parse_desc(struct ukbd_softc *sc);
+
+Static void ukbd_intr(struct uhidev *addr, void *ibuf, u_int len);
Static void ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud);
Static void ukbd_delayed_decode(void *addr);
Static int ukbd_enable(void *, int);
Static void ukbd_set_leds(void *, int);
-#if defined(__NetBSD__) || defined(__OpenBSD__)
-Static int ukbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
+Static int ukbd_ioctl(void *, u_long, caddr_t, int, usb_proc_ptr );
#ifdef WSDISPLAY_COMPAT_RAWKBD
Static void ukbd_rawrepeat(void *v);
#endif
@@ -290,90 +266,53 @@ const struct wskbd_mapdata ukbd_keymapdata = {
KB_US,
#endif
};
-#endif
USB_DECLARE_DRIVER(ukbd);
USB_MATCH(ukbd)
{
USB_MATCH_START(ukbd, uaa);
- usb_interface_descriptor_t *id;
+ struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa;
+ int size;
+ void *desc;
- /* Check that this is a keyboard that speaks the boot protocol. */
- if (uaa->iface == NULL)
- return (UMATCH_NONE);
- id = usbd_get_interface_descriptor(uaa->iface);
- if (id == NULL ||
- id->bInterfaceClass != UICLASS_HID ||
- id->bInterfaceSubClass != UISUBCLASS_BOOT ||
- id->bInterfaceProtocol != UIPROTO_BOOT_KEYBOARD)
+ uhidev_get_report_desc(uha->parent, &desc, &size);
+ if (!hid_is_collection(desc, size, uha->reportid,
+ HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD)))
return (UMATCH_NONE);
- return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO);
+
+ return (UMATCH_IFACECLASS);
}
USB_ATTACH(ukbd)
{
USB_ATTACH_START(ukbd, sc, uaa);
- usbd_interface_handle iface = uaa->iface;
- usb_interface_descriptor_t *id;
- usb_endpoint_descriptor_t *ed;
- usbd_status err;
+ struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa;
u_int32_t qflags;
- char devinfo[1024];
-#if defined(__NetBSD__) || defined(__OpenBSD__)
+ const char *parseerr;
struct wskbddev_attach_args a;
-#else
- int i;
-#endif
- sc->sc_udev = uaa->device;
- sc->sc_iface = iface;
- id = usbd_get_interface_descriptor(iface);
- usbd_devinfo(uaa->device, 0, devinfo);
- USB_ATTACH_SETUP;
- printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev),
- devinfo, id->bInterfaceClass, id->bInterfaceSubClass);
-
- ed = usbd_interface2endpoint_descriptor(iface, 0);
- if (ed == NULL) {
- printf("%s: could not read endpoint descriptor\n",
- USBDEVNAME(sc->sc_dev));
+ sc->sc_hdev.sc_intr = ukbd_intr;
+ sc->sc_hdev.sc_parent = uha->parent;
+ sc->sc_hdev.sc_report_id = uha->reportid;
+
+ parseerr = ukbd_parse_desc(sc);
+ if (parseerr != NULL) {
+ printf("\n%s: attach failed, %s\n",
+ sc->sc_hdev.sc_dev.dv_xname, parseerr);
USB_ATTACH_ERROR_RETURN;
}
+
+#ifdef DIAGNOSTIC
+ printf(": %d modifier keys, %d key codes", sc->sc_nmod,
+ sc->sc_nkeycode);
+#endif
+ printf("\n");
- DPRINTFN(10,("ukbd_attach: bLength=%d bDescriptorType=%d "
- "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d"
- " bInterval=%d\n",
- ed->bLength, ed->bDescriptorType,
- ed->bEndpointAddress & UE_ADDR,
- UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out",
- ed->bmAttributes & UE_XFERTYPE,
- UGETW(ed->wMaxPacketSize), ed->bInterval));
-
- if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN ||
- (ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) {
- printf("%s: unexpected endpoint\n",
- USBDEVNAME(sc->sc_dev));
- USB_ATTACH_ERROR_RETURN;
- }
- qflags = usbd_get_quirks(uaa->device)->uq_flags;
- if ((qflags & UQ_NO_SET_PROTO) == 0) {
- err = usbd_set_protocol(iface, 0);
- DPRINTFN(5, ("ukbd_attach: protocol set\n"));
- if (err) {
- printf("%s: set protocol failed\n",
- USBDEVNAME(sc->sc_dev));
- USB_ATTACH_ERROR_RETURN;
- }
- }
+ qflags = usbd_get_quirks(uha->parent->sc_udev)->uq_flags;
sc->sc_debounce = (qflags & UQ_SPUR_BUT_UP) != 0;
- /* Ignore if SETIDLE fails since it is not crucial. */
- (void)usbd_set_idle(iface, 0, 0);
-
- sc->sc_ep_addr = ed->bEndpointAddress;
-
/*
* Remember if we're the console keyboard.
*
@@ -398,26 +337,14 @@ USB_ATTACH(ukbd)
a.accessops = &ukbd_accessops;
a.accesscookie = sc;
-#if defined(__OpenBSD__)
-#ifdef WSDISPLAY_COMPAT_RAWKBD
- timeout_set(&sc->sc_rawrepeat_ch, ukbd_rawrepeat, sc);
-#endif
- timeout_set(&sc->sc_delay, ukbd_delayed_decode, sc);
-#endif
-
-#if defined(__NetBSD__)
- callout_init(&sc->sc_rawrepeat_ch);
- callout_init(&sc->sc_delay);
-#endif
+ usb_callout_init(sc->sc_rawrepeat_ch);
+ usb_callout_init(sc->sc_delay);
/* Flash the leds; no real purpose, just shows we're alive. */
ukbd_set_leds(sc, WSKBD_LED_SCROLL | WSKBD_LED_NUM | WSKBD_LED_CAPS);
- usbd_delay_ms(uaa->device, 400);
+ usbd_delay_ms(uha->parent->sc_udev, 400);
ukbd_set_leds(sc, 0);
- usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
- USBDEV(sc->sc_dev));
-
sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
USB_ATTACH_SUCCESS_RETURN;
@@ -427,38 +354,27 @@ int
ukbd_enable(void *v, int on)
{
struct ukbd_softc *sc = v;
- usbd_status err;
if (on && sc->sc_dying)
return (EIO);
/* Should only be called to change state */
if (sc->sc_enabled == on) {
-#ifdef UKBD_DEBUG
+#ifdef DIAGNOSTIC
printf("ukbd_enable: %s: bad call on=%d\n",
- USBDEVNAME(sc->sc_dev), on);
+ USBDEVNAME(sc->sc_hdev.sc_dev), on);
#endif
return (EBUSY);
}
DPRINTF(("ukbd_enable: sc=%p on=%d\n", sc, on));
+ sc->sc_enabled = on;
if (on) {
- /* 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_ndata, sizeof(sc->sc_ndata), ukbd_intr,
- USBD_DEFAULT_INTERVAL);
- if (err)
- return (EIO);
+ return (uhidev_open(&sc->sc_hdev));
} else {
- /* Disable interrupts. */
- usbd_abort_pipe(sc->sc_intrpipe);
- usbd_close_pipe(sc->sc_intrpipe);
- sc->sc_intrpipe = NULL;
+ uhidev_close(&sc->sc_hdev);
+ return (0);
}
- sc->sc_enabled = on;
-
- return (0);
}
int
@@ -507,7 +423,8 @@ USB_DETACH(ukbd)
* XXX Should notify some other keyboard that it can be
* XXX console, if there are any other keyboards.
*/
- printf("%s: was console keyboard\n", USBDEVNAME(sc->sc_dev));
+ printf("%s: was console keyboard\n",
+ USBDEVNAME(sc->sc_hdev.sc_dev));
wskbd_cndetach();
ukbd_is_console = 1;
#endif
@@ -517,37 +434,34 @@ USB_DETACH(ukbd)
rv = config_detach(sc->sc_wskbddev, flags);
/* The console keyboard does not get a disable call, so check pipe. */
- if (sc->sc_intrpipe != NULL) {
- usbd_abort_pipe(sc->sc_intrpipe);
- usbd_close_pipe(sc->sc_intrpipe);
- sc->sc_intrpipe = NULL;
- }
-
- usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
- USBDEV(sc->sc_dev));
+ if (sc->sc_hdev.sc_state & UHIDEV_OPEN)
+ uhidev_close(&sc->sc_hdev);
return (rv);
}
void
-ukbd_intr(xfer, addr, status)
- usbd_xfer_handle xfer;
- usbd_private_handle addr;
- usbd_status status;
+ukbd_intr(struct uhidev *addr, void *ibuf, u_int len)
{
- struct ukbd_softc *sc = addr;
+ struct ukbd_softc *sc = (struct ukbd_softc *)addr;
struct ukbd_data *ud = &sc->sc_ndata;
+ int i;
- DPRINTFN(5, ("ukbd_intr: status=%d\n", status));
- if (status == USBD_CANCELLED)
- return;
-
- if (status) {
- DPRINTF(("ukbd_intr: status=%d\n", status));
- if (status == USBD_STALLED)
- usbd_clear_endpoint_stall_async(sc->sc_intrpipe);
- return;
+#ifdef UKBD_DEBUG
+ if (ukbddebug > 5) {
+ printf("ukbd_intr: data");
+ for (i = 0; i < len; i++)
+ printf(" 0x%02x", ((u_char *)ibuf)[i]);
+ printf("\n");
}
+#endif
+
+ ud->modifiers = 0;
+ for (i = 0; i < sc->sc_nmod; i++)
+ if (hid_get_data(ibuf, &sc->sc_modloc[i]))
+ ud->modifiers |= sc->sc_mods[i].mask;
+ memcpy(ud->keycode, (char *)ibuf + sc->sc_keycodeloc.pos / 8,
+ sc->sc_nkeycode);
if (sc->sc_debounce && !sc->sc_polling) {
/*
@@ -557,12 +471,8 @@ ukbd_intr(xfer, addr, status)
* We avoid this bug by holding off decoding for 20 ms.
*/
sc->sc_data = *ud;
-#if defined(__OpenBSD__)
- timeout_add(&sc->sc_delay, hz / 50);
-#else
- callout_reset(&sc->sc_delay, hz / 50, ukbd_delayed_decode, sc);
-#endif
-#if DDB
+ usb_callout(sc->sc_delay, hz / 50, ukbd_delayed_decode, sc);
+#ifdef DDB
} else if (sc->sc_console_keyboard && !sc->sc_polling) {
/*
* For the console keyboard we can't deliver CTL-ALT-ESC
@@ -571,11 +481,7 @@ ukbd_intr(xfer, addr, status)
* loses bigtime.
*/
sc->sc_data = *ud;
-#if defined(__OpenBSD__)
- timeout_add(&sc->sc_delay, 1); /* NOT an immediate timeout */
-#else
- callout_reset(&sc->sc_delay, 0, ukbd_delayed_decode, sc);
-#endif
+ usb_callout(sc->sc_delay, 1, ukbd_delayed_decode, sc);
#endif
} else {
ukbd_decode(sc, ud);
@@ -607,7 +513,7 @@ ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud)
*/
if (ukbdtrace) {
struct ukbdtraceinfo *p = &ukbdtracedata[ukbdtraceindex];
- p->unit = sc->sc_dev.dv_unit;
+ p->unit = sc->sc_hdev.sc_dev.dv_unit;
microtime(&p->tv);
p->ud = *ud;
if (++ukbdtraceindex >= UKBDTRACESIZE)
@@ -632,19 +538,19 @@ ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud)
mod = ud->modifiers;
omod = sc->sc_odata.modifiers;
if (mod != omod)
- for (i = 0; i < NMOD; i++)
- if (( mod & ukbd_mods[i].mask) !=
- (omod & ukbd_mods[i].mask))
- ADDKEY(ukbd_mods[i].key |
- (mod & ukbd_mods[i].mask
+ for (i = 0; i < sc->sc_nmod; i++)
+ if (( mod & sc->sc_mods[i].mask) !=
+ (omod & sc->sc_mods[i].mask))
+ ADDKEY(sc->sc_mods[i].key |
+ (mod & sc->sc_mods[i].mask
? PRESS : RELEASE));
- if (memcmp(ud->keycode, sc->sc_odata.keycode, NKEYCODE) != 0) {
+ if (memcmp(ud->keycode, sc->sc_odata.keycode, sc->sc_nkeycode) != 0) {
/* Check for released keys. */
- for (i = 0; i < NKEYCODE; i++) {
+ for (i = 0; i < sc->sc_nkeycode; i++) {
key = sc->sc_odata.keycode[i];
if (key == 0)
continue;
- for (j = 0; j < NKEYCODE; j++)
+ for (j = 0; j < sc->sc_nkeycode; j++)
if (key == ud->keycode[j])
goto rfound;
DPRINTFN(3,("ukbd_intr: relse key=0x%02x\n", key));
@@ -654,11 +560,11 @@ ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud)
}
/* Check for pressed keys. */
- for (i = 0; i < NKEYCODE; i++) {
+ for (i = 0; i < sc->sc_nkeycode; i++) {
key = ud->keycode[i];
if (key == 0)
continue;
- for (j = 0; j < NKEYCODE; j++)
+ for (j = 0; j < sc->sc_nkeycode; j++)
if (key == sc->sc_odata.keycode[j])
goto pfound;
DPRINTFN(2,("ukbd_intr: press key=0x%02x\n", key));
@@ -680,7 +586,7 @@ ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud)
}
#ifdef WSDISPLAY_COMPAT_RAWKBD
if (sc->sc_rawkbd) {
- char cbuf[MAXKEYS * 2];
+ u_char cbuf[MAXKEYS * 2];
int c;
int npress;
@@ -708,19 +614,11 @@ ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud)
s = spltty();
wskbd_rawinput(sc->sc_wskbddev, cbuf, j);
splx(s);
-#if defined(__OpenBSD__)
- timeout_del(&sc->sc_rawrepeat_ch);
-#else
- callout_stop(&sc->sc_rawrepeat_ch);
-#endif
+ usb_uncallout(sc->sc_rawrepeat_ch, ukbd_rawrepeat, sc);
if (npress != 0) {
sc->sc_nrep = npress;
-#if defined(__OpenBSD__)
- timeout_add(&sc->sc_rawrepeat_ch, hz * REP_DELAY1/1000);
-#else
- callout_reset(&sc->sc_rawrepeat_ch,
+ usb_callout(sc->sc_rawrepeat_ch,
hz * REP_DELAY1 / 1000, ukbd_rawrepeat, sc);
-#endif
}
return;
}
@@ -742,21 +640,24 @@ ukbd_set_leds(void *v, int leds)
struct ukbd_softc *sc = v;
u_int8_t res;
- DPRINTF(("ukbd_set_leds: sc=%p leds=%d\n", sc, leds));
+ DPRINTF(("ukbd_set_leds: sc=%p leds=%d, sc_leds=%d\n",
+ sc, leds, sc->sc_leds));
if (sc->sc_dying)
return;
+ if (sc->sc_leds == leds)
+ return;
sc->sc_leds = leds;
res = 0;
- if (leds & WSKBD_LED_SCROLL)
- res |= SCROLL_LOCK;
- if (leds & WSKBD_LED_NUM)
- res |= NUM_LOCK;
- if (leds & WSKBD_LED_CAPS)
- res |= CAPS_LOCK;
- res |= leds & 0xf8;
- usbd_set_report_async(sc->sc_iface, UHID_OUTPUT_REPORT, 0, &res, 1);
+ /* XXX not really right */
+ if ((leds & WSKBD_LED_SCROLL) && sc->sc_scroloc.size == 1)
+ res |= 1 << sc->sc_scroloc.pos;
+ if ((leds & WSKBD_LED_NUM) && sc->sc_numloc.size == 1)
+ res |= 1 << sc->sc_numloc.pos;
+ if ((leds & WSKBD_LED_CAPS) && sc->sc_capsloc.size == 1)
+ res |= 1 << sc->sc_capsloc.pos;
+ uhidev_set_report_async(&sc->sc_hdev, UHID_OUTPUT_REPORT, &res, 1);
}
#ifdef WSDISPLAY_COMPAT_RAWKBD
@@ -769,17 +670,13 @@ ukbd_rawrepeat(void *v)
s = spltty();
wskbd_rawinput(sc->sc_wskbddev, sc->sc_rep, sc->sc_nrep);
splx(s);
-#if defined(__OpenBSD__)
- timeout_add(&sc->sc_rawrepeat_ch, hz * REP_DELAYN / 1000);
-#else
- callout_reset(&sc->sc_rawrepeat_ch, hz * REP_DELAYN / 1000,
+ usb_callout(sc->sc_rawrepeat_ch, hz * REP_DELAYN / 1000,
ukbd_rawrepeat, sc);
-#endif
}
#endif
int
-ukbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
+ukbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, usb_proc_ptr p)
{
struct ukbd_softc *sc = v;
@@ -797,17 +694,19 @@ ukbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
case WSKBDIO_SETMODE:
DPRINTF(("ukbd_ioctl: set raw = %d\n", *(int *)data));
sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
-#if defined(__OpenBSD__)
- timeout_del(&sc->sc_rawrepeat_ch);
-#else
- callout_stop(&sc->sc_rawrepeat_ch);
-#endif
+ usb_uncallout(sc->sc_rawrepeat_ch, ukbd_rawrepeat, sc);
return (0);
#endif
}
return (-1);
}
+/*
+ * This is a hack to work around some broken ports that don't call
+ * cnpollc() before cngetc().
+ */
+static int pollenter, warned;
+
/* Console interface. */
void
ukbd_cngetc(void *v, u_int *type, int *data)
@@ -815,12 +714,25 @@ ukbd_cngetc(void *v, u_int *type, int *data)
struct ukbd_softc *sc = v;
int s;
int c;
+ int broken;
+
+ if (pollenter == 0) {
+ if (!warned) {
+ printf("\n"
+"This port is broken, it does not call cnpollc() before calling cngetc().\n"
+"This should be fixed, but it will work anyway (for now).\n");
+ warned = 1;
+ }
+ broken = 1;
+ ukbd_cnpollc(v, 1);
+ } else
+ broken = 0;
DPRINTFN(0,("ukbd_cngetc: enter\n"));
s = splusb();
sc->sc_polling = 1;
while(sc->sc_npollchar <= 0)
- usbd_dopoll(sc->sc_iface);
+ usbd_dopoll(sc->sc_hdev.sc_parent->sc_iface);
sc->sc_polling = 0;
c = sc->sc_pollchars[0];
sc->sc_npollchar--;
@@ -830,6 +742,8 @@ ukbd_cngetc(void *v, u_int *type, int *data)
*data = c & CODEMASK;
splx(s);
DPRINTFN(0,("ukbd_cngetc: return 0x%02x\n", c));
+ if (broken)
+ ukbd_cnpollc(v, 0);
}
void
@@ -840,7 +754,8 @@ ukbd_cnpollc(void *v, int on)
DPRINTFN(2,("ukbd_cnpollc: sc=%p on=%d\n", v, on));
- (void)usbd_interface2device_handle(sc->sc_iface,&dev);
+ usbd_interface2device_handle(sc->sc_hdev.sc_parent->sc_iface, &dev);
+ if (on) pollenter++; else pollenter--;
usbd_set_polling(dev, on);
}
@@ -856,3 +771,64 @@ ukbd_cnattach(void)
ukbd_is_console = 1;
return (0);
}
+
+const char *
+ukbd_parse_desc(struct ukbd_softc *sc)
+{
+ struct hid_data *d;
+ struct hid_item h;
+ int size;
+ void *desc;
+ int imod;
+
+ uhidev_get_report_desc(sc->sc_hdev.sc_parent, &desc, &size);
+ imod = 0;
+ sc->sc_nkeycode = 0;
+ d = hid_start_parse(desc, size, hid_input);
+ while (hid_get_item(d, &h)) {
+ /*printf("ukbd: id=%d kind=%d usage=0x%x flags=0x%x pos=%d size=%d cnt=%d\n",
+ h.report_ID, h.kind, h.usage, h.flags, h.loc.pos, h.loc.size, h.loc.count);*/
+ if (h.kind != hid_input || (h.flags & HIO_CONST) ||
+ HID_GET_USAGE_PAGE(h.usage) != HUP_KEYBOARD ||
+ h.report_ID != sc->sc_hdev.sc_report_id)
+ continue;
+ DPRINTF(("ukbd: imod=%d usage=0x%x flags=0x%x pos=%d size=%d "
+ "cnt=%d\n", imod,
+ h.usage, h.flags, h.loc.pos, h.loc.size, h.loc.count));
+ if (h.flags & HIO_VARIABLE) {
+ if (h.loc.size != 1)
+ return ("bad modifier size");
+ /* Single item */
+ if (imod < MAXMOD) {
+ sc->sc_modloc[imod] = h.loc;
+ sc->sc_mods[imod].mask = 1 << imod;
+ sc->sc_mods[imod].key = HID_GET_USAGE(h.usage);
+ imod++;
+ } else
+ return ("too many modifier keys");
+ } else {
+ /* Array */
+ if (h.loc.size != 8)
+ return ("key code size != 8");
+ if (h.loc.count > MAXKEYCODE)
+ return ("too many key codes");
+ if (h.loc.pos % 8 != 0)
+ return ("key codes not on byte boundary");
+ if (sc->sc_nkeycode != 0)
+ return ("multiple key code arrays\n");
+ sc->sc_keycodeloc = h.loc;
+ sc->sc_nkeycode = h.loc.count;
+ }
+ }
+ sc->sc_nmod = imod;
+ hid_end_parse(d);
+
+ hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_NUM_LOCK),
+ sc->sc_hdev.sc_report_id, hid_output, &sc->sc_numloc, NULL);
+ hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_CAPS_LOCK),
+ sc->sc_hdev.sc_report_id, hid_output, &sc->sc_capsloc, NULL);
+ hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_SCROLL_LOCK),
+ sc->sc_hdev.sc_report_id, hid_output, &sc->sc_scroloc, NULL);
+
+ return (NULL);
+}
diff --git a/sys/dev/usb/ukbdmap.c b/sys/dev/usb/ukbdmap.c
index 3c39bdc63b2..9d0ad9f25d8 100644
--- a/sys/dev/usb/ukbdmap.c
+++ b/sys/dev/usb/ukbdmap.c
@@ -1,8 +1,8 @@
-/* $OpenBSD: ukbdmap.c,v 1.9 2002/05/05 21:52:16 nate Exp $ */
-/* $NetBSD: ukbdmap.c,v 1.6 2001/04/04 05:31:57 toshii Exp $ */
+/* $OpenBSD: ukbdmap.c,v 1.10 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: ukbdmap.c,v 1.10 2002/03/17 18:01:07 augustss Exp $ */
/*
- * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * Copyright (c) 1999,2001 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -94,7 +94,7 @@ Static const keysym_t ukbd_keydesc_us[] = {
KC(47), KS_bracketleft, KS_braceleft,
KC(48), KS_bracketright,KS_braceright,
KC(49), KS_backslash, KS_bar,
- KC(50), KS_numbersign, KS_asciitilde,
+ KC(50), KS_backslash, KS_bar,
KC(51), KS_semicolon, KS_colon,
KC(52), KS_apostrophe, KS_quotedbl,
KC(53), KS_grave, KS_asciitilde,
@@ -256,6 +256,7 @@ Static const keysym_t ukbd_keydesc_sv[] = {
/* pos normal shifted altgr shift-altgr */
KC(45), KS_plus, KS_question, KS_backslash,
KC(48), KS_dead_diaeresis, KS_dead_circumflex, KS_dead_tilde,
+ KC(50), KS_comma, KS_asterisk,
KC(51), KS_odiaeresis,
KC(52), KS_adiaeresis,
KC(53), KS_paragraph, KS_onehalf,
@@ -273,6 +274,7 @@ Static const keysym_t ukbd_keydesc_no[] = {
/* pos normal shifted altgr shift-altgr */
KC(46), KS_backslash, KS_dead_grave, KS_dead_acute,
KC(48), KS_dead_diaeresis, KS_dead_circumflex, KS_dead_tilde,
+ KC(50), KS_comma, KS_asterisk,
KC(51), KS_oslash,
KC(52), KS_ae,
KC(53), KS_bar, KS_paragraph,
@@ -358,6 +360,7 @@ Static const keysym_t ukbd_keydesc_uk[] = {
KC(45), KS_minus, KS_underscore, KS_hyphen, KS_ssharp,
KC(46), KS_equal, KS_plus, KS_onehalf, KS_guillemotleft,
KC(49), KS_numbersign, KS_asciitilde, KS_sterling, KS_thorn,
+ KC(50), KS_numbersign, KS_asciitilde,
KC(52), KS_apostrophe, KS_at, KS_section, KS_Agrave,
KC(53), KS_grave, KS_grave, KS_agrave, KS_agrave,
KC(100), KS_backslash, KS_bar, KS_Udiaeresis,
diff --git a/sys/dev/usb/ulpt.c b/sys/dev/usb/ulpt.c
index cde41db63f3..b10baefbd4c 100644
--- a/sys/dev/usb/ulpt.c
+++ b/sys/dev/usb/ulpt.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: ulpt.c,v 1.9 2001/10/31 04:24:44 nate Exp $ */
-/* $NetBSD: ulpt.c,v 1.43 2001/10/19 15:30:25 nathanw Exp $ */
+/* $OpenBSD: ulpt.c,v 1.10 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: ulpt.c,v 1.49 2002/02/25 22:39:01 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/ulpt.c,v 1.24 1999/11/17 22:33:44 n_hibma Exp $ */
/*
@@ -40,7 +40,8 @@
*/
/*
- * Printer Class spec: http://www.usb.org/developers/data/devclass/usbprint11.pdf
+ * Printer Class spec:
+ * http://www.usb.org/developers/data/devclass/usbprint11.pdf
*/
#include <sys/param.h>
@@ -147,7 +148,9 @@ Static struct cdevsw ulpt_cdevsw = {
/* dump */ nodump,
/* psize */ nopsize,
/* flags */ 0,
+#if !defined(__FreeBSD__) || (__FreeBSD__ < 5)
/* bmaj */ -1
+#endif
};
#endif
@@ -307,8 +310,8 @@ USB_ATTACH(ulpt)
USETW(req.wValue, cd->bConfigurationValue);
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);
+ err = usbd_do_request_flags(dev, &req, devinfo, USBD_SHORT_XFER_OK,
+ &alen, USBD_DEFAULT_TIMEOUT);
if (err) {
printf("%s: cannot get device id\n", USBDEVNAME(sc->sc_dev));
} else if (alen <= 2) {
@@ -366,12 +369,12 @@ USB_DETACH(ulpt)
int s;
#if defined(__NetBSD__) || defined(__OpenBSD__)
int maj, mn;
-
- DPRINTF(("ulpt_detach: sc=%p flags=%d\n", sc, flags));
#elif defined(__FreeBSD__)
- DPRINTF(("ulpt_detach: sc=%p\n", sc));
+ struct vnode *vp;
#endif
+ DPRINTF(("ulpt_detach: sc=%p\n", sc));
+
sc->sc_dying = 1;
if (sc->sc_out_pipe != NULL)
usbd_abort_pipe(sc->sc_out_pipe);
@@ -396,7 +399,12 @@ USB_DETACH(ulpt)
mn = self->dv_unit;
vdevgone(maj, mn, mn, VCHR);
#elif defined(__FreeBSD__)
- /* XXX not implemented yet */
+ vp = SLIST_FIRST(&sc->dev->si_hlist);
+ if (vp)
+ VOP_REVOKE(vp, REVOKEALL);
+ vp = SLIST_FIRST(&sc->dev_noprime->si_hlist);
+ if (vp)
+ VOP_REVOKE(vp, REVOKEALL);
destroy_dev(sc->dev);
destroy_dev(sc->dev_noprime);
@@ -434,7 +442,6 @@ ulpt_reset(struct ulpt_softc *sc)
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);
@@ -446,6 +453,7 @@ ulpt_reset(struct ulpt_softc *sc)
* 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 */
@@ -471,7 +479,7 @@ int ulptusein = 1;
* Reset the printer, then wait until it's selected and not busy.
*/
int
-ulptopen(dev_t dev, int flag, int mode, struct proc *p)
+ulptopen(dev_t dev, int flag, int mode, usb_proc_ptr p)
{
u_char flags = ULPTFLAGS(dev);
struct ulpt_softc *sc;
@@ -546,8 +554,18 @@ ulptopen(dev_t dev, int flag, int mode, struct proc *p)
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;
}
@@ -590,7 +608,7 @@ ulpt_statusmsg(u_char status, struct ulpt_softc *sc)
}
int
-ulptclose(dev_t dev, int flag, int mode, struct proc *p)
+ulptclose(dev_t dev, int flag, int mode, usb_proc_ptr p)
{
struct ulpt_softc *sc;
@@ -680,7 +698,7 @@ ulptwrite(dev_t dev, struct uio *uio, int flags)
}
int
-ulptioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
+ulptioctl(dev_t dev, u_long cmd, caddr_t data, int flag, usb_proc_ptr p)
{
int error = 0;
diff --git a/sys/dev/usb/umass.c b/sys/dev/usb/umass.c
index 17e1d1bf45f..a47e31a0d27 100644
--- a/sys/dev/usb/umass.c
+++ b/sys/dev/usb/umass.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: umass.c,v 1.14 2002/03/14 03:16:08 millert Exp $ */
-/* $NetBSD: umass.c,v 1.49 2001/01/21 18:56:38 augustss Exp $ */
+/* $OpenBSD: umass.c,v 1.15 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: umass.c,v 1.87 2002/03/17 18:02:53 augustss Exp $ */
/*-
* Copyright (c) 1999 MAEKAWA Masahide <bishop@rr.iij4u.or.jp>,
* Nick Hibma <n_hibma@freebsd.org>
@@ -30,7 +30,7 @@
*/
/*
- * Universal Serial Bus Mass Storage Class Bulk-Only Transport
+ * Universal Serial Bus Mass Storage Class specs:
* http://www.usb.org/developers/data/devclass/usbmassover_11.pdf
* http://www.usb.org/developers/data/devclass/usbmassbulk_10.pdf
* http://www.usb.org/developers/data/devclass/usbmass-cbi10.pdf
@@ -51,13 +51,14 @@
*
* Over these wire protocols it handles the following command protocols
* - SCSI
- * - UFI (floppy command set)
- * - 8070 (ATA/ATAPI)
+ * - 8070 (ATA/ATAPI for rewritable removable media)
+ * - UFI (USB Floppy Interface)
*
- * UFI and 8070i are transformed versions of the SCSI command set. The
- * sc->transform method is used to convert the commands into the appropriate
- * format (if at all necessary). For example, UFI requires all commands to be
- * 12 bytes in length amongst other things.
+ * 8070i is a transformed version of the SCSI command set. UFI is a transformed
+ * version of the 8070i command set. The sc->transform method is used to
+ * convert the commands into the appropriate format (if at all necessary).
+ * For example, ATAPI requires all commands to be 12 bytes in length amongst
+ * other things.
*
* The source code below is marked and can be split into a number of pieces
* (in this order):
@@ -93,15 +94,15 @@
* umass_cam_cb again to complete the CAM command.
*/
-/* XXX Should we split the driver into a number of files? umass.c,
- * umass_scsi.c, umass_8070.c, umass_ufi.c, umass_bbb.c, umass_cbi.c or
- * something similar?
- */
-
-#if !defined(__OpenBSD__)
+#if defined(__NetBSD__)
#include "atapibus.h"
+#include "scsibus.h"
+#elif defined(__OpenBSD__)
+#include "atapiscsi.h"
#endif
+#include "wd.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
@@ -124,396 +125,15 @@
#include <dev/usb/usbdi_util.h>
#include <dev/usb/usbdevs.h>
-#if defined(__FreeBSD__)
-#include <cam/cam.h>
-#include <cam/cam_ccb.h>
-#include <cam/cam_sim.h>
-#include <cam/cam_xpt_sim.h>
-#include <cam/scsi/scsi_all.h>
-#include <cam/scsi/scsi_da.h>
-
-#ifdef UMASS_DO_CAM_RESCAN
-#include <sys/devicestat.h>
-#include <cam/cam_periph.h>
-#endif
+#include <dev/usb/umassvar.h>
+#include <dev/usb/umass_quirks.h>
+#include <dev/usb/umass_scsipi.h>
+#include <dev/usb/umass_isdata.h>
-#elif defined(__NetBSD__)
-#include <sys/scsiio.h>
-#include <dev/scsipi/scsi_all.h>
-#include <dev/scsipi/scsipi_all.h>
-#include <dev/scsipi/scsiconf.h>
-
-#include <dev/scsipi/atapiconf.h>
-
-#include <dev/scsipi/scsipi_disk.h>
-#include <dev/scsipi/scsi_disk.h>
-#include <dev/scsipi/scsi_changer.h>
-
-#include <dev/ata/atavar.h> /* XXX */
-
-#define SCSI_LINK_TARGET(sc) ((sc)->scsipi_scsi.target)
-#define SCSI_LINK_LUN(sc) ((sc)->scsipi_scsi.lun)
-#elif defined(__OpenBSD__)
-#include <scsi/scsi_all.h>
-#include <scsi/scsiconf.h>
-#include <scsi/scsi_disk.h>
-#include <machine/bus.h>
-
-#define SCSI_LINK_TARGET(sc) ((sc)->target)
-#define SCSI_LINK_LUN(sc) ((sc)->lun)
-#define scsipi_generic scsi_generic
-
-#endif
-
-#define SHORT_INQUIRY_LENGTH 36 /* XXX */
#ifdef UMASS_DEBUG
-#define DIF(m, x) if (umassdebug & (m)) do { x ; } while (0)
-#define DPRINTF(m, x) if (umassdebug & (m)) logprintf x
-#define UDMASS_UPPER 0x00008000 /* upper layer */
-#define UDMASS_GEN 0x00010000 /* general */
-#define UDMASS_SCSI 0x00020000 /* scsi */
-#define UDMASS_UFI 0x00040000 /* ufi command set */
-#define UDMASS_8070 0x00080000 /* 8070i command set */
-#define UDMASS_USB 0x00100000 /* USB general */
-#define UDMASS_BBB 0x00200000 /* Bulk-Only transfers */
-#define UDMASS_CBI 0x00400000 /* CBI transfers */
-#define UDMASS_ALL 0xffff0000 /* all of the above */
-
-#define UDMASS_XFER 0x40000000 /* all transfers */
-#define UDMASS_CMD 0x80000000
-
int umassdebug = 0;
-#else
-#define DIF(m, x) /* nop */
-#define DPRINTF(m, x) /* nop */
-#endif
-
-
-/* Generic definitions */
-
-#define UFI_COMMAND_LENGTH 12
-#define ATAPI_COMMAND_LENGTH 12
-/* Direction for umass_*_transfer */
-#define DIR_NONE 0
-#define DIR_IN 1
-#define DIR_OUT 2
-
-/* The transfer speed determines the timeout value */
-#define UMASS_DEFAULT_TRANSFER_SPEED 150 /* in kb/s, conservative est. */
-#define UMASS_FLOPPY_TRANSFER_SPEED 20
-#define UMASS_ZIP100_TRANSFER_SPEED 650
-
-#define UMASS_SPINUP_TIME 10000 /* ms */
-
-#ifdef __FreeBSD__
-/* device name */
-#define DEVNAME "umass"
-#define DEVNAME_SIM "umass-"
-
-#define UMASS_MAX_TRANSFER_SIZE 65536
-
-/* CAM specific definitions */
-
-/* The bus id, whatever that is */
-#define UMASS_SCSI_BUS 0
-
-/* All USB drives are 'connected' to one SIM (SCSI controller). umass3
- * ends up being target 3 on that SIM. When a request for target 3
- * comes in we fetch the softc with devclass_get_softc(target_id).
- *
- * The SIM is the highest target number. This makes sure that umass0 corresponds
- * to target 0 on the USB SCSI bus.
- */
-#ifndef UMASS_DEBUG
-#define UMASS_SCSIID_MAX 32 /* maximum number of drives expected */
-#else
-/* while debugging avoid unnecessary clutter in the output at umass_cam_rescan
- * (XPT_PATH_INQ)
- */
-#define UMASS_SCSIID_MAX 3 /* maximum number of drives expected */
-#endif
-#define UMASS_SCSIID_HOST UMASS_SCSIID_MAX
-#endif
-
-#define MS_TO_TICKS(ms) ((ms) * hz / 1000)
-
-
-/* Bulk-Only features */
-
-#define UR_BBB_RESET 0xff /* Bulk-Only reset */
-#define UR_BBB_GET_MAX_LUN 0xfe
-
-/* Command Block Wrapper */
-typedef struct {
- uDWord dCBWSignature;
-# define CBWSIGNATURE 0x43425355
- uDWord dCBWTag;
- uDWord dCBWDataTransferLength;
- uByte bCBWFlags;
-# define CBWFLAGS_OUT 0x00
-# define CBWFLAGS_IN 0x80
- uByte bCBWLUN;
- uByte bCDBLength;
-# define CBWCDBLENGTH 16
- uByte CBWCDB[CBWCDBLENGTH];
-} umass_bbb_cbw_t;
-#define UMASS_BBB_CBW_SIZE 31
-
-/* Command Status Wrapper */
-typedef struct {
- uDWord dCSWSignature;
-# define CSWSIGNATURE 0x53425355
- uDWord dCSWTag;
- uDWord dCSWDataResidue;
- uByte bCSWStatus;
-# define CSWSTATUS_GOOD 0x0
-# define CSWSTATUS_FAILED 0x1
-# define CSWSTATUS_PHASE 0x2
-} umass_bbb_csw_t;
-#define UMASS_BBB_CSW_SIZE 13
-
-/* CBI features */
-
-#define UR_CBI_ADSC 0x00
-
-typedef unsigned char umass_cbi_cbl_t[16]; /* Command block */
-
-typedef union {
- struct {
- unsigned char type;
- #define IDB_TYPE_CCI 0x00
- unsigned char value;
- #define IDB_VALUE_PASS 0x00
- #define IDB_VALUE_FAIL 0x01
- #define IDB_VALUE_PHASE 0x02
- #define IDB_VALUE_PERSISTENT 0x03
- #define IDB_VALUE_STATUS_MASK 0x03
- } common;
-
- struct {
- unsigned char asc;
- unsigned char ascq;
- } ufi;
-} umass_cbi_sbl_t;
-
-
-
-struct umass_softc; /* see below */
-
-typedef void (*transfer_cb_f)(struct umass_softc *sc, void *priv,
- int residue, int status);
-#define STATUS_CMD_OK 0 /* everything ok */
-#define STATUS_CMD_UNKNOWN 1 /* will have to fetch sense */
-#define STATUS_CMD_FAILED 2 /* transfer was ok, command failed */
-#define STATUS_WIRE_FAILED 3 /* couldn't even get command across */
-
-typedef void (*wire_reset_f)(struct umass_softc *sc, int status);
-typedef void (*wire_transfer_f)(struct umass_softc *sc, int lun,
- void *cmd, int cmdlen, void *data, int datalen,
- int dir, transfer_cb_f cb, void *priv);
-typedef void (*wire_state_f)(usbd_xfer_handle xfer,
- usbd_private_handle priv, usbd_status err);
-
-#if defined(__FreeBSD__)
-typedef int (*command_transform_f)(struct umass_softc *sc,
- unsigned char *cmd, int cmdlen,
- unsigned char **rcmd, int *rcmdlen);
-#endif
-
-
-/* the per device structure */
-struct umass_softc {
- USBBASEDEVICE sc_dev; /* base device */
- usbd_device_handle sc_udev; /* device */
-
- unsigned char drive;
-# define DRIVE_GENERIC 0 /* use defaults for this one */
-# define ZIP_100 1 /* to be used for quirks */
-# define ZIP_250 2
-# define SHUTTLE_EUSB 3
-# define INSYSTEM_USBCABLE 4
- unsigned char quirks;
- /* The drive does not support Test Unit Ready. Convert to
- * Start Unit.
- * Y-E Data
- * ZIP 100
- */
-# define NO_TEST_UNIT_READY 0x01
- /* The drive does not reset the Unit Attention state after
- * REQUEST SENSE has been sent. The INQUIRY command does not reset
- * the UA either, and so CAM runs in circles trying to retrieve the
- * initial INQUIRY data.
- * Y-E Data
- */
-# define RS_NO_CLEAR_UA 0x02 /* no REQUEST SENSE on INQUIRY*/
- /* The drive does not support START_STOP.
- * Shuttle E-USB
- */
-# define NO_START_STOP 0x04
- /* Don't ask for full inquiry data (255 bytes).
- * Yano ATAPI-USB
- */
-# define FORCE_SHORT_INQUIRY 0x08
-
- unsigned int proto;
-# define PROTO_UNKNOWN 0x0000 /* unknown protocol */
-# define PROTO_BBB 0x0001 /* USB wire protocol */
-# define PROTO_CBI 0x0002
-# define PROTO_CBI_I 0x0004
-# define PROTO_WIRE 0x00ff /* USB wire protocol mask */
-# define PROTO_SCSI 0x0100 /* command protocol */
-# define PROTO_ATAPI 0x0200
-# define PROTO_UFI 0x0400
-# define PROTO_RBC 0x0800
-# define PROTO_COMMAND 0xff00 /* command protocol mask */
-
- u_char subclass; /* interface subclass */
- u_char protocol; /* interface protocol */
-
- usbd_interface_handle iface; /* Mass Storage interface */
- int ifaceno; /* MS iface number */
-
- u_int8_t bulkin; /* bulk-in Endpoint Address */
- u_int8_t bulkout; /* bulk-out Endpoint Address */
- u_int8_t intrin; /* intr-in Endp. (CBI) */
- usbd_pipe_handle bulkin_pipe;
- usbd_pipe_handle bulkout_pipe;
- usbd_pipe_handle intrin_pipe;
-
- /* Reset the device in a wire protocol specific way */
- wire_reset_f reset;
-
- /* The start of a wire transfer. It prepares the whole transfer (cmd,
- * data, and status stage) and initiates it. It is up to the state
- * machine (below) to handle the various stages and errors in these
- */
- wire_transfer_f transfer;
-
- /* The state machine, handling the various states during a transfer */
- wire_state_f state;
-
-#if defined(__FreeBSD__)
- /* The command transform function is used to conver the SCSI commands
- * into their derivatives, like UFI, ATAPI, and friends.
- */
- command_transform_f transform; /* command transform */
-#endif
-
- /* Bulk specific variables for transfers in progress */
- umass_bbb_cbw_t cbw; /* command block wrapper */
- umass_bbb_csw_t csw; /* command status wrapper*/
- /* CBI specific variables for transfers in progress */
- umass_cbi_cbl_t cbl; /* command block */
- umass_cbi_sbl_t sbl; /* status block */
-
- /* generic variables for transfers in progress */
- /* ctrl transfer requests */
- usb_device_request_t request;
-
- /* xfer handles
- * Most of our operations are initiated from interrupt context, so
- * we need to avoid using the one that is in use. We want to avoid
- * allocating them in the interrupt context as well.
- */
- /* indices into array below */
-# define XFER_BBB_CBW 0 /* Bulk-Only */
-# define XFER_BBB_DATA 1
-# define XFER_BBB_DCLEAR 2
-# define XFER_BBB_CSW1 3
-# define XFER_BBB_CSW2 4
-# define XFER_BBB_SCLEAR 5
-# define XFER_BBB_RESET1 6
-# define XFER_BBB_RESET2 7
-# define XFER_BBB_RESET3 8
-
-# define XFER_CBI_CB 0 /* CBI */
-# define XFER_CBI_DATA 1
-# define XFER_CBI_STATUS 2
-# define XFER_CBI_DCLEAR 3
-# define XFER_CBI_SCLEAR 4
-# define XFER_CBI_RESET1 5
-# define XFER_CBI_RESET2 6
-# define XFER_CBI_RESET3 7
-
-# define XFER_NR 9 /* maximum number */
-
- usbd_xfer_handle transfer_xfer[XFER_NR]; /* for ctrl xfers */
-
- void *data_buffer;
-
- int transfer_dir; /* data direction */
- void *transfer_data; /* data buffer */
- int transfer_datalen; /* (maximum) length */
- int transfer_actlen; /* actual length */
- transfer_cb_f transfer_cb; /* callback */
- void *transfer_priv; /* for callback */
- int transfer_status;
-
- int transfer_state;
-# define TSTATE_IDLE 0
-# define TSTATE_BBB_COMMAND 1 /* CBW transfer */
-# define TSTATE_BBB_DATA 2 /* Data transfer */
-# define TSTATE_BBB_DCLEAR 3 /* clear endpt stall */
-# define TSTATE_BBB_STATUS1 4 /* clear endpt stall */
-# define TSTATE_BBB_SCLEAR 5 /* clear endpt stall */
-# define TSTATE_BBB_STATUS2 6 /* CSW transfer */
-# define TSTATE_BBB_RESET1 7 /* reset command */
-# define TSTATE_BBB_RESET2 8 /* in clear stall */
-# define TSTATE_BBB_RESET3 9 /* out clear stall */
-# define TSTATE_CBI_COMMAND 10 /* command transfer */
-# define TSTATE_CBI_DATA 11 /* data transfer */
-# define TSTATE_CBI_STATUS 12 /* status transfer */
-# define TSTATE_CBI_DCLEAR 13 /* clear ep stall */
-# define TSTATE_CBI_SCLEAR 14 /* clear ep stall */
-# define TSTATE_CBI_RESET1 15 /* reset command */
-# define TSTATE_CBI_RESET2 16 /* in clear stall */
-# define TSTATE_CBI_RESET3 17 /* out clear stall */
-# define TSTATE_STATES 18 /* # of states above */
-
-
- int transfer_speed; /* in kb/s */
- int timeout; /* in msecs */
-
- u_int8_t maxlun; /* max lun supported */
-
-#ifdef UMASS_DEBUG
- struct timeval tv;
-#endif
-
-#if defined(__FreeBSD__)
- /* SCSI/CAM specific variables */
- struct scsi_sense cam_scsi_sense;
-
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
- union {
- struct scsipi_link sc_link;
-#if defined(__NetBSD__)
- struct {
- struct ata_atapi_attach sc_aa;
- struct ata_drive_datas sc_aa_drive;
- } aa;
-#endif
- } u;
-#if defined(__NetBSD__)
- struct atapi_adapter sc_atapi_adapter;
-#define sc_adapter sc_atapi_adapter._generic
-#else
- struct scsi_adapter sc_atapi_adapter;
-#define sc_adapter sc_atapi_adapter
-#endif
- int sc_xfer_flags;
- usbd_status sc_sync_status;
- struct scsipi_sense sc_sense_cmd;
-
- device_ptr_t sc_child; /* child device, for detach */
- char sc_dying;
-
-#endif
-};
-
-#ifdef UMASS_DEBUG
char *states[TSTATE_STATES+1] = {
/* should be kept in sync with the list at transfer_state */
"Idle",
@@ -538,17 +158,9 @@ char *states[TSTATE_STATES+1] = {
};
#endif
-struct cam_sim *umass_sim; /* SCSI Interface Module */
-struct cam_path *umass_path; /* and its path */
-
-
/* USB device probe/attach/detach functions */
USB_DECLARE_DRIVER(umass);
Static void umass_disco(struct umass_softc *sc);
-Static int umass_match_proto(struct umass_softc *sc,
- usbd_interface_handle iface,
- usbd_device_handle dev);
-Static void umass_init_shuttle(struct umass_softc *sc);
/* generic transfer functions */
Static usbd_status umass_setup_transfer(struct umass_softc *sc,
@@ -556,113 +168,42 @@ Static usbd_status umass_setup_transfer(struct umass_softc *sc,
void *buffer, int buflen, int flags,
usbd_xfer_handle xfer);
Static usbd_status umass_setup_ctrl_transfer(struct umass_softc *sc,
- usbd_device_handle dev,
usb_device_request_t *req,
void *buffer, int buflen, int flags,
usbd_xfer_handle xfer);
-Static void umass_clear_endpoint_stall(struct umass_softc *sc,
- u_int8_t endpt, usbd_pipe_handle pipe,
- int state, usbd_xfer_handle xfer);
+Static void umass_clear_endpoint_stall(struct umass_softc *sc, int endpt,
+ usbd_xfer_handle xfer);
#if 0
-Static void umass_reset(struct umass_softc *sc,
- transfer_cb_f cb, void *priv);
+Static void umass_reset(struct umass_softc *sc, transfer_cb_f cb, void *priv);
#endif
/* Bulk-Only related functions */
-Static void umass_bbb_reset(struct umass_softc *sc, int status);
-Static void umass_bbb_transfer(struct umass_softc *sc, int lun,
- void *cmd, int cmdlen,
- void *data, int datalen, int dir,
- transfer_cb_f cb, void *priv);
-Static void umass_bbb_state(usbd_xfer_handle xfer,
- usbd_private_handle priv,
- usbd_status err);
-usbd_status umass_bbb_get_max_lun(struct umass_softc *sc,
- u_int8_t *maxlun);
+Static void umass_bbb_transfer(struct umass_softc *, int, void *, int, void *,
+ int, int, u_int, umass_callback, void *);
+Static void umass_bbb_reset(struct umass_softc *, int);
+Static void umass_bbb_state(usbd_xfer_handle, usbd_private_handle, usbd_status);
+usbd_status umass_bbb_get_max_lun(struct umass_softc *, u_int8_t *);
/* CBI related functions */
-Static int umass_cbi_adsc(struct umass_softc *sc, char *buffer,int buflen,
- usbd_xfer_handle xfer);
-Static void umass_cbi_reset(struct umass_softc *sc, int status);
-Static void umass_cbi_transfer(struct umass_softc *sc, int lun,
- void *cmd, int cmdlen,
- void *data, int datalen, int dir,
- transfer_cb_f cb, void *priv);
-Static void umass_cbi_state(usbd_xfer_handle xfer,
- usbd_private_handle priv, usbd_status err);
-
-#if defined(__FreeBSD__)
-/* CAM related functions */
-Static void umass_cam_action(struct cam_sim *sim, union ccb *ccb);
-Static void umass_cam_poll(struct cam_sim *sim);
-
-Static void umass_cam_cb(struct umass_softc *sc, void *priv,
- int residue, int status);
-Static void umass_cam_sense_cb(struct umass_softc *sc, void *priv,
- int residue, int status);
-
-#ifdef UMASS_DO_CAM_RESCAN
-Static void umass_cam_rescan(struct umass_softc *sc);
-#endif
-
-Static int umass_cam_attach_sim(void);
-Static int umass_cam_attach(struct umass_softc *sc);
-Static int umass_cam_detach_sim(void);
-Static int umass_cam_detach(struct umass_softc *sc);
-
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
+Static void umass_cbi_transfer(struct umass_softc *, int, void *, int, void *,
+ int, int, u_int, umass_callback, void *);
+Static void umass_cbi_reset(struct umass_softc *, int);
+Static void umass_cbi_state(usbd_xfer_handle, usbd_private_handle, usbd_status);
-#define UMASS_SCSIID_HOST 0x00
-#define UMASS_SCSIID_DEVICE 0x01
+Static int umass_cbi_adsc(struct umass_softc *, char *, int, usbd_xfer_handle);
-#define UMASS_ATAPI_DRIVE 0
-
-#define UMASS_MAX_TRANSFER_SIZE MAXBSIZE
-
-struct scsipi_device umass_dev =
-{
- NULL, /* Use default error handler */
- NULL, /* have a queue, served by this */
- NULL, /* have no async handler */
- NULL, /* Use default 'done' routine */
+const struct umass_wire_methods umass_bbb_methods = {
+ umass_bbb_transfer,
+ umass_bbb_reset,
+ umass_bbb_state
};
-Static int umass_scsipi_cmd(struct scsipi_xfer *xs);
-Static void umass_scsipi_minphys(struct buf *bp);
-Static int umass_scsipi_ioctl(struct scsipi_link *, u_long,
- caddr_t, int, struct proc *);
-Static void umass_scsipi_cb(struct umass_softc *sc, void *priv,
- int residue, int status);
-Static void umass_scsipi_sense_cb(struct umass_softc *sc, void *priv,
- int residue, int status);
-
-Static int scsipiprint(void *aux, const char *pnp);
-Static int umass_ufi_transform(struct umass_softc *sc,
- struct scsipi_generic *cmd, int cmdlen,
- struct scsipi_generic *rcmd, int *rcmdlen);
-
-#if NATAPIBUS > 0
-Static void umass_atapi_probedev(struct atapibus_softc *, int);
-#endif
-#endif
-
-#if defined(__FreeBSD__)
-/* SCSI specific functions */
-Static int umass_scsi_transform(struct umass_softc *sc,
- unsigned char *cmd, int cmdlen,
- unsigned char **rcmd, int *rcmdlen);
-
-/* UFI specific functions */
-Static int umass_ufi_transform(struct umass_softc *sc,
- unsigned char *cmd, int cmdlen,
- unsigned char **rcmd, int *rcmdlen);
-
-/* 8070 specific functions */
-Static int umass_8070_transform(struct umass_softc *sc,
- unsigned char *cmd, int cmdlen,
- unsigned char **rcmd, int *rcmdlen);
-#endif
+const struct umass_wire_methods umass_cbi_methods = {
+ umass_cbi_transfer,
+ umass_cbi_reset,
+ umass_cbi_state
+};
#ifdef UMASS_DEBUG
/* General debugging functions */
@@ -675,292 +216,180 @@ Static void umass_dump_buffer(struct umass_softc *sc, u_int8_t *buffer,
#endif
-void usbd_clear_endpoint_toggle(usbd_pipe_handle pipe); /* XXXXX */
-
/*
* USB device probe/attach/detach
*/
-/*
- * Match the device we are seeing with the devices supported. Fill in the
- * proto and drive fields in the softc accordingly.
- * This function is called from both probe and attach.
- */
-
-Static int
-umass_match_proto(sc, iface, dev)
- struct umass_softc *sc;
- usbd_interface_handle iface;
- usbd_device_handle dev;
+USB_MATCH(umass)
{
- usb_device_descriptor_t *dd;
+ USB_MATCH_START(umass, uaa);
+ const struct umass_quirk *quirk;
usb_interface_descriptor_t *id;
- u_int vendor, product;
- /*
- * Fill in sc->drive and sc->proto and return a match
- * value if both are determined and 0 otherwise.
- */
-
- sc->drive = DRIVE_GENERIC;
- sc->proto = PROTO_UNKNOWN;
- sc->transfer_speed = UMASS_DEFAULT_TRANSFER_SPEED;
-
- sc->sc_udev = dev;
- dd = usbd_get_device_descriptor(dev);
- vendor = UGETW(dd->idVendor);
- product = UGETW(dd->idProduct);
-
- if (vendor == USB_VENDOR_SHUTTLE &&
- product == USB_PRODUCT_SHUTTLE_EUSB) {
- sc->drive = SHUTTLE_EUSB;
-#if CBI_I
- sc->proto = PROTO_ATAPI | PROTO_CBI_I;
-#else
- sc->proto = PROTO_ATAPI | PROTO_CBI;
-#endif
- sc->subclass = UISUBCLASS_SFF8020I;
- sc->protocol = UIPROTO_MASS_CBI;
- sc->quirks |= NO_TEST_UNIT_READY | NO_START_STOP;
- return (UMATCH_VENDOR_PRODUCT);
- }
-
- if (vendor == USB_VENDOR_YANO &&
- product == USB_PRODUCT_YANO_U640MO) {
- sc->proto = PROTO_ATAPI | PROTO_CBI_I;
- sc->quirks |= FORCE_SHORT_INQUIRY;
- return (UMATCH_VENDOR_PRODUCT);
- }
-
- if (vendor == USB_VENDOR_SONY &&
- product == USB_PRODUCT_SONY_MSC) {
- printf ("XXX Sony MSC\n");
- sc->quirks |= FORCE_SHORT_INQUIRY;
- }
-
- if (vendor == USB_VENDOR_YEDATA &&
- product == USB_PRODUCT_YEDATA_FLASHBUSTERU) {
-
- /* Revisions < 1.28 do not handle the interrupt endpoint
- * very well.
- */
- if (UGETW(dd->bcdDevice) < 0x128)
- sc->proto = PROTO_UFI | PROTO_CBI;
- else
-#if CBI_I
- sc->proto = PROTO_UFI | PROTO_CBI_I;
-#else
- sc->proto = PROTO_UFI | PROTO_CBI;
-#endif
- /*
- * Revisions < 1.28 do not have the TEST UNIT READY command
- * Revisions == 1.28 have a broken TEST UNIT READY
- */
- if (UGETW(dd->bcdDevice) <= 0x128)
- sc->quirks |= NO_TEST_UNIT_READY;
-
- sc->subclass = UISUBCLASS_UFI;
- sc->protocol = UIPROTO_MASS_CBI;
-
- sc->quirks |= RS_NO_CLEAR_UA;
- sc->transfer_speed = UMASS_FLOPPY_TRANSFER_SPEED;
- return (UMATCH_VENDOR_PRODUCT_REV);
- }
+ if (uaa->iface == NULL)
+ return (UMATCH_NONE);
- if (vendor == USB_VENDOR_INSYSTEM &&
- product == USB_PRODUCT_INSYSTEM_USBCABLE) {
- sc->drive = INSYSTEM_USBCABLE;
- sc->proto = PROTO_ATAPI | PROTO_CBI;
- sc->quirks |= NO_TEST_UNIT_READY | NO_START_STOP;
- return (UMATCH_VENDOR_PRODUCT);
- }
+ quirk = umass_lookup(uaa->vendor, uaa->product);
+ if (quirk != NULL)
+ return (quirk->uq_match);
- id = usbd_get_interface_descriptor(iface);
+ id = usbd_get_interface_descriptor(uaa->iface);
if (id == NULL || id->bInterfaceClass != UICLASS_MASS)
return (UMATCH_NONE);
- if (vendor == USB_VENDOR_SONY && id->bInterfaceSubClass == 0xff) {
- /*
- * Sony DSC devices set the sub class to 0xff
- * instead of 1 (RBC). Fix that here.
- */
- id->bInterfaceSubClass = UISUBCLASS_RBC;
- /* They also should be able to do higher speed. */
- sc->transfer_speed = 500;
- }
-
- if (vendor == USB_VENDOR_FUJIPHOTO &&
- product == USB_PRODUCT_FUJIPHOTO_MASS0100)
- sc->quirks |= NO_TEST_UNIT_READY | NO_START_STOP;
-
- sc->subclass = id->bInterfaceSubClass;
- sc->protocol = id->bInterfaceProtocol;
-
- switch (sc->subclass) {
- case UISUBCLASS_SCSI:
- sc->proto |= PROTO_SCSI;
- break;
- case UISUBCLASS_UFI:
- sc->transfer_speed = UMASS_FLOPPY_TRANSFER_SPEED;
- sc->proto |= PROTO_UFI;
- break;
+ switch (id->bInterfaceSubClass) {
+ case UISUBCLASS_RBC:
case UISUBCLASS_SFF8020I:
- case UISUBCLASS_SFF8070I:
case UISUBCLASS_QIC157:
- sc->proto |= PROTO_ATAPI;
- break;
- case UISUBCLASS_RBC:
- sc->proto |= PROTO_RBC;
+ case UISUBCLASS_UFI:
+ case UISUBCLASS_SFF8070I:
+ case UISUBCLASS_SCSI:
break;
default:
- /* Assume that unsupported devices are ATAPI */
- DPRINTF(UDMASS_GEN, ("%s: Unsupported command protocol %d\n",
- USBDEVNAME(sc->sc_dev), id->bInterfaceSubClass));
-
- sc->proto |= PROTO_ATAPI;
- break;
+ return (UMATCH_IFACECLASS);
}
- switch (sc->protocol) {
- case UIPROTO_MASS_CBI:
- sc->proto |= PROTO_CBI;
- break;
+ switch (id->bInterfaceProtocol) {
case UIPROTO_MASS_CBI_I:
-#if CBI_I
- sc->proto |= PROTO_CBI_I;
-#else
- sc->proto |= PROTO_CBI;
-#endif
- break;
+ case UIPROTO_MASS_CBI:
+ case UIPROTO_MASS_BBB_OLD:
case UIPROTO_MASS_BBB:
- sc->proto |= PROTO_BBB;
- break;
- case UIPROTO_MASS_BBB_P:
- sc->drive = ZIP_100;
- sc->proto |= PROTO_BBB;
- sc->transfer_speed = UMASS_ZIP100_TRANSFER_SPEED;
- sc->quirks |= NO_TEST_UNIT_READY;
break;
default:
- DPRINTF(UDMASS_GEN, ("%s: Unsupported wire protocol %d\n",
- USBDEVNAME(sc->sc_dev), id->bInterfaceProtocol));
- return (UMATCH_NONE);
+ return (UMATCH_IFACECLASS_IFACESUBCLASS);
}
- return (UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO);
+ return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO);
}
-USB_MATCH(umass)
-{
- USB_MATCH_START(umass, uaa);
-#if defined(__FreeBSD__)
- struct umass_softc *sc = device_get_softc(self);
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
- struct umass_softc scs, *sc = &scs;
- memset(sc, 0, sizeof *sc);
- strcpy(sc->sc_dev.dv_xname, "umass");
-#endif
-
- if (uaa->iface == NULL)
- return(UMATCH_NONE);
-
- return (umass_match_proto(sc, uaa->iface, uaa->device));
-}
-
-void umass_delayed_attach(struct umass_softc *sc);
-
USB_ATTACH(umass)
{
USB_ATTACH_START(umass, sc, uaa);
+ const struct umass_quirk *quirk;
usb_interface_descriptor_t *id;
usb_endpoint_descriptor_t *ed;
- const char *sSubclass, *sProto;
+ const char *sWire, *sCommand;
char devinfo[1024];
- int i, bno;
- int err;
-
- /*
- * the softc struct is bzero-ed in device_set_driver. We can safely
- * call umass_detach without specifically initialising the struct.
- */
+ usbd_status err;
+ int i, bno, error;
usbd_devinfo(uaa->device, 0, devinfo);
USB_ATTACH_SETUP;
- sc->iface = uaa->iface;
- sc->ifaceno = uaa->ifaceno;
+ sc->sc_udev = uaa->device;
+ sc->sc_iface = uaa->iface;
+ sc->sc_ifaceno = uaa->ifaceno;
+
+ quirk = umass_lookup(uaa->vendor, uaa->product);
+ if (quirk != NULL) {
+ sc->sc_wire = quirk->uq_wire;
+ sc->sc_cmd = quirk->uq_cmd;
+ sc->sc_quirks = quirk->uq_flags;
+ sc->sc_busquirks = quirk->uq_busquirks;
+
+ if (quirk->uq_fixup != NULL)
+ (*quirk->uq_fixup)(sc);
+ } else {
+ sc->sc_wire = UMASS_WPROTO_UNSPEC;
+ sc->sc_cmd = UMASS_CPROTO_UNSPEC;
+ sc->sc_quirks = 0;
+ sc->sc_busquirks = 0;
+ }
- /* initialise the proto and drive values in the umass_softc (again) */
- if (umass_match_proto(sc, sc->iface, uaa->device) == 0) {
- printf("%s: match failed\n", USBDEVNAME(sc->sc_dev));
+ id = usbd_get_interface_descriptor(sc->sc_iface);
+ if (id == NULL)
USB_ATTACH_ERROR_RETURN;
+
+ if (sc->sc_wire == UMASS_WPROTO_UNSPEC) {
+ switch (id->bInterfaceProtocol) {
+ case UIPROTO_MASS_CBI:
+ sc->sc_wire = UMASS_WPROTO_CBI;
+ break;
+ case UIPROTO_MASS_CBI_I:
+ sc->sc_wire = UMASS_WPROTO_CBI_I;
+ break;
+ case UIPROTO_MASS_BBB:
+ case UIPROTO_MASS_BBB_OLD:
+ sc->sc_wire = UMASS_WPROTO_BBB;
+ break;
+ default:
+ DPRINTF(UDMASS_GEN,
+ ("%s: Unsupported wire protocol %u\n",
+ USBDEVNAME(sc->sc_dev),
+ id->bInterfaceProtocol));
+ USB_ATTACH_ERROR_RETURN;
+ }
}
- /*
- * The timeout is based on the maximum expected transfer size
- * divided by the expected transfer speed.
- * We multiply by 4 to make sure a busy system doesn't make things
- * fail.
- */
- sc->timeout = 4 * UMASS_MAX_TRANSFER_SIZE / sc->transfer_speed;
- sc->timeout += UMASS_SPINUP_TIME; /* allow for spinning up */
+ /* XXX - Now unsupported CBI with CCI */
+ if (sc->sc_wire == UMASS_WPROTO_CBI_I)
+ sc->sc_wire = UMASS_WPROTO_CBI;
+
+ if (sc->sc_cmd == UMASS_CPROTO_UNSPEC) {
+ switch (id->bInterfaceSubClass) {
+ case UISUBCLASS_SCSI:
+ sc->sc_cmd = UMASS_CPROTO_SCSI;
+ break;
+ case UISUBCLASS_UFI:
+ sc->sc_cmd = UMASS_CPROTO_UFI;
+ break;
+ case UISUBCLASS_SFF8020I:
+ case UISUBCLASS_SFF8070I:
+ case UISUBCLASS_QIC157:
+ sc->sc_cmd = UMASS_CPROTO_ATAPI;
+ break;
+ case UISUBCLASS_RBC:
+ sc->sc_cmd = UMASS_CPROTO_RBC;
+ break;
+ default:
+ DPRINTF(UDMASS_GEN,
+ ("%s: Unsupported command protocol %u\n",
+ USBDEVNAME(sc->sc_dev),
+ id->bInterfaceSubClass));
+ USB_ATTACH_ERROR_RETURN;
+ }
+ }
- id = usbd_get_interface_descriptor(sc->iface);
printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo);
- switch (sc->subclass) {
- case UISUBCLASS_RBC:
- sSubclass = "RBC";
- break;
- case UISUBCLASS_SCSI:
- sSubclass = "SCSI";
- break;
- case UISUBCLASS_UFI:
- sSubclass = "UFI";
+ switch (sc->sc_wire) {
+ case UMASS_WPROTO_CBI:
+ sWire = "CBI";
break;
- case UISUBCLASS_SFF8020I:
- sSubclass = "SFF8020i";
+ case UMASS_WPROTO_CBI_I:
+ sWire = "CBI with CCI";
break;
- case UISUBCLASS_SFF8070I:
- sSubclass = "SFF8070i";
- break;
- case UISUBCLASS_QIC157:
- sSubclass = "QIC157";
+ case UMASS_WPROTO_BBB:
+ sWire = "Bulk-Only";
break;
default:
- sSubclass = "unknown";
+ sWire = "unknown";
break;
}
- switch (sc->protocol) {
- case UIPROTO_MASS_CBI:
- sProto = "CBI";
+
+ switch (sc->sc_cmd) {
+ case UMASS_CPROTO_RBC:
+ sCommand = "RBC";
break;
- case UIPROTO_MASS_CBI_I:
- sProto = "CBI-I";
+ case UMASS_CPROTO_SCSI:
+ sCommand = "SCSI";
break;
- case UIPROTO_MASS_BBB:
- sProto = "BBB";
+ case UMASS_CPROTO_UFI:
+ sCommand = "UFI";
+ break;
+ case UMASS_CPROTO_ATAPI:
+ sCommand = "ATAPI";
break;
- case UIPROTO_MASS_BBB_P:
- sProto = "BBB-P";
+ case UMASS_CPROTO_ISD_ATA:
+ sCommand = "ISD-ATA";
break;
default:
- sProto = "unknown";
+ sCommand = "unknown";
break;
}
- printf("%s: using %s over %s\n", USBDEVNAME(sc->sc_dev), sSubclass,
- sProto);
- if (sc->drive == INSYSTEM_USBCABLE) {
- err = usbd_set_interface(0, 1);
- if (err) {
- DPRINTF(UDMASS_USB, ("%s: could not switch to "
- "Alt Interface %d\n",
- USBDEVNAME(sc->sc_dev), 1));
- umass_disco(sc);
- USB_ATTACH_ERROR_RETURN;
- }
- }
+ printf("%s: using %s over %s\n", USBDEVNAME(sc->sc_dev), sCommand,
+ sWire);
/*
* In addition to the Control endpoint the following endpoints
@@ -974,22 +403,22 @@ USB_ATTACH(umass)
* from the device descriptors of the current interface.
*/
for (i = 0 ; i < id->bNumEndpoints ; i++) {
- ed = usbd_interface2endpoint_descriptor(sc->iface, i);
- if (!ed) {
+ ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
+ if (ed == NULL) {
printf("%s: could not read endpoint descriptor\n",
USBDEVNAME(sc->sc_dev));
USB_ATTACH_ERROR_RETURN;
}
if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN
&& (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) {
- sc->bulkin = ed->bEndpointAddress;
+ sc->sc_epaddr[UMASS_BULKIN] = ed->bEndpointAddress;
} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT
&& (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) {
- sc->bulkout = ed->bEndpointAddress;
- } else if (sc->proto & PROTO_CBI_I
+ sc->sc_epaddr[UMASS_BULKOUT] = ed->bEndpointAddress;
+ } else if (sc->sc_wire == UMASS_WPROTO_CBI_I
&& UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN
&& (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) {
- sc->intrin = ed->bEndpointAddress;
+ sc->sc_epaddr[UMASS_INTRIN] = ed->bEndpointAddress;
#ifdef UMASS_DEBUG
if (UGETW(ed->wMaxPacketSize) > 2) {
DPRINTF(UDMASS_CBI, ("%s: intr size is %d\n",
@@ -1001,19 +430,21 @@ USB_ATTACH(umass)
}
/* check whether we found all the endpoints we need */
- if (!sc->bulkin || !sc->bulkout
- || (sc->proto & PROTO_CBI_I && !sc->intrin) ) {
- DPRINTF(UDMASS_USB, ("%s: endpoint not found %d/%d/%d\n",
- USBDEVNAME(sc->sc_dev),
- sc->bulkin, sc->bulkout, sc->intrin));
- umass_disco(sc);
+ if (!sc->sc_epaddr[UMASS_BULKIN] || !sc->sc_epaddr[UMASS_BULKOUT] ||
+ (sc->sc_wire == UMASS_WPROTO_CBI_I &&
+ !sc->sc_epaddr[UMASS_INTRIN])) {
+ DPRINTF(UDMASS_USB, ("%s: endpoint not found %u/%u/%u\n",
+ USBDEVNAME(sc->sc_dev), sc->sc_epaddr[UMASS_BULKIN],
+ sc->sc_epaddr[UMASS_BULKOUT],
+ sc->sc_epaddr[UMASS_INTRIN]));
USB_ATTACH_ERROR_RETURN;
}
/*
* Get the maximum LUN supported by the device.
*/
- if ((sc->proto & PROTO_WIRE) == PROTO_BBB) {
+ if (sc->sc_wire == UMASS_WPROTO_BBB &&
+ !(sc->sc_quirks & UMASS_QUIRK_NO_MAX_LUN)) {
err = umass_bbb_get_max_lun(sc, &sc->maxlun);
if (err) {
printf("%s: unable to get Max Lun: %s\n",
@@ -1025,19 +456,20 @@ USB_ATTACH(umass)
}
/* Open the bulk-in and -out pipe */
- err = usbd_open_pipe(sc->iface, sc->bulkout,
- USBD_EXCLUSIVE_USE, &sc->bulkout_pipe);
+ err = usbd_open_pipe(sc->sc_iface, sc->sc_epaddr[UMASS_BULKOUT],
+ USBD_EXCLUSIVE_USE,
+ &sc->sc_pipe[UMASS_BULKOUT]);
if (err) {
- DPRINTF(UDMASS_USB, ("%s: cannot open %d-out pipe (bulk)\n",
- USBDEVNAME(sc->sc_dev), sc->bulkout));
+ DPRINTF(UDMASS_USB, ("%s: cannot open %u-out pipe (bulk)\n",
+ USBDEVNAME(sc->sc_dev), sc->sc_epaddr[UMASS_BULKOUT]));
umass_disco(sc);
USB_ATTACH_ERROR_RETURN;
}
- err = usbd_open_pipe(sc->iface, sc->bulkin,
- USBD_EXCLUSIVE_USE, &sc->bulkin_pipe);
+ err = usbd_open_pipe(sc->sc_iface, sc->sc_epaddr[UMASS_BULKIN],
+ USBD_EXCLUSIVE_USE, &sc->sc_pipe[UMASS_BULKIN]);
if (err) {
- DPRINTF(UDMASS_USB, ("%s: could not open %d-in pipe (bulk)\n",
- USBDEVNAME(sc->sc_dev), sc->bulkin));
+ DPRINTF(UDMASS_USB, ("%s: could not open %u-in pipe (bulk)\n",
+ USBDEVNAME(sc->sc_dev), sc->sc_epaddr[UMASS_BULKIN]));
umass_disco(sc);
USB_ATTACH_ERROR_RETURN;
}
@@ -1053,12 +485,13 @@ USB_ATTACH(umass)
* code for handling the data on that endpoint simpler. No data
* arriving concurrently.
*/
- if (sc->proto & PROTO_CBI_I) {
- err = usbd_open_pipe(sc->iface, sc->intrin,
- USBD_EXCLUSIVE_USE, &sc->intrin_pipe);
+ if (sc->sc_wire == UMASS_WPROTO_CBI_I) {
+ err = usbd_open_pipe(sc->sc_iface, sc->sc_epaddr[UMASS_INTRIN],
+ USBD_EXCLUSIVE_USE, &sc->sc_pipe[UMASS_INTRIN]);
if (err) {
- DPRINTF(UDMASS_USB, ("%s: couldn't open %d-in (intr)\n",
- USBDEVNAME(sc->sc_dev), sc->intrin));
+ DPRINTF(UDMASS_USB, ("%s: couldn't open %u-in (intr)\n",
+ USBDEVNAME(sc->sc_dev),
+ sc->sc_epaddr[UMASS_INTRIN]));
umass_disco(sc);
USB_ATTACH_ERROR_RETURN;
}
@@ -1078,14 +511,14 @@ USB_ATTACH(umass)
}
}
/* Allocate buffer for data transfer (it's huge). */
- switch (sc->proto & PROTO_WIRE) {
- case PROTO_BBB:
+ switch (sc->sc_wire) {
+ case UMASS_WPROTO_BBB:
bno = XFER_BBB_DATA;
goto dalloc;
- case PROTO_CBI:
+ case UMASS_WPROTO_CBI:
bno = XFER_CBI_DATA;
goto dalloc;
- case PROTO_CBI_I:
+ case UMASS_WPROTO_CBI_I:
bno = XFER_CBI_DATA;
dalloc:
sc->data_buffer = usbd_alloc_buffer(sc->transfer_xfer[bno],
@@ -1100,123 +533,89 @@ USB_ATTACH(umass)
}
/* Initialise the wire protocol specific methods */
- if (sc->proto & PROTO_BBB) {
- sc->reset = umass_bbb_reset;
- sc->transfer = umass_bbb_transfer;
- sc->state = umass_bbb_state;
- } else if ((sc->proto & PROTO_CBI) || (sc->proto & PROTO_CBI_I)) {
- sc->reset = umass_cbi_reset;
- sc->transfer = umass_cbi_transfer;
- sc->state = umass_cbi_state;
-#ifdef UMASS_DEBUG
- } else {
- panic("%s:%d: Unknown proto 0x%02x\n",
- __FILE__, __LINE__, sc->proto);
-#endif
- }
-
- if (sc->drive == SHUTTLE_EUSB)
- umass_init_shuttle(sc);
-
- /*
- * Fill in the adapter.
- */
- sc->sc_adapter.scsipi_cmd = umass_scsipi_cmd;
- sc->sc_adapter.scsipi_minphys = umass_scsipi_minphys;
-
- /*
- * fill in the prototype scsipi_link.
- */
- switch (sc->proto & PROTO_COMMAND) {
- case PROTO_SCSI:
- case PROTO_UFI:
- case PROTO_ATAPI:
- case PROTO_RBC:
- if ((sc->proto & PROTO_COMMAND) != PROTO_SCSI)
- sc->u.sc_link.flags |= SDEV_ATAPI;
- else
- sc->u.sc_link.flags &= ~SDEV_ATAPI;
-
- sc->u.sc_link.adapter_buswidth = 2;
- sc->u.sc_link.adapter_target = UMASS_SCSIID_HOST;
- sc->u.sc_link.luns = sc->maxlun + 1;
-
- sc->u.sc_link.adapter_softc = sc;
- sc->u.sc_link.adapter = &sc->sc_adapter;
- sc->u.sc_link.device = &umass_dev;
- sc->u.sc_link.openings = 1;
-
- if(sc->quirks & NO_TEST_UNIT_READY)
- sc->u.sc_link.quirks |= ADEV_NOTUR;
+ switch (sc->sc_wire) {
+ case UMASS_WPROTO_BBB:
+ sc->sc_methods = &umass_bbb_methods;
+ break;
+ case UMASS_WPROTO_CBI:
+ case UMASS_WPROTO_CBI_I:
+ sc->sc_methods = &umass_cbi_methods;
break;
-
-
default:
- printf("%s: proto=0x%x not supported yet\n",
- USBDEVNAME(sc->sc_dev), sc->proto);
umass_disco(sc);
USB_ATTACH_ERROR_RETURN;
}
- if (cold) {
- startuphook_establish((void (*)(void *))umass_delayed_attach,
- sc);
- } else {
- /* hot plug, do it now */
- umass_delayed_attach(sc);
+ if (quirk != NULL && quirk->uq_init != NULL) {
+ err = (*quirk->uq_init)(sc);
+ if (err) {
+ umass_disco(sc);
+ USB_ATTACH_ERROR_RETURN;
+ }
}
- DPRINTF(UDMASS_GEN, ("%s: Attach finished\n", USBDEVNAME(sc->sc_dev)));
+ error = 0;
+ switch (sc->sc_cmd) {
+ case UMASS_CPROTO_RBC:
+ case UMASS_CPROTO_SCSI:
+#if defined(__OpenBSD__) || NSCSIBUS > 0
+ error = umass_scsi_attach(sc);
+#else
+ printf("%s: scsibus not configured\n", USBDEVNAME(sc->sc_dev));
+#endif
+ break;
- USB_ATTACH_SUCCESS_RETURN;
-}
+ case UMASS_CPROTO_UFI:
+ case UMASS_CPROTO_ATAPI:
+#if (NATAPIBUS > 0) || (NATAPISCSI > 0)
+ error = umass_atapi_attach(sc);
+#else
+ printf("%s: "UMASS_ATAPISTR" not configured\n",
+ USBDEVNAME(sc->sc_dev));
+#endif
+ break;
-void
-umass_delayed_attach(struct umass_softc *sc)
-{
- sc->sc_child = config_found(&sc->sc_dev, &sc->u, scsipiprint);
- if (sc->sc_child == NULL) {
+ case UMASS_CPROTO_ISD_ATA:
+#if defined (__NetBSD__) && NWD > 0
+ error = umass_isdata_attach(sc);
+#else
+ printf("%s: isdata not configured\n", USBDEVNAME(sc->sc_dev));
+#endif
+ break;
+
+ default:
+ printf("%s: command protocol=0x%x not supported\n",
+ USBDEVNAME(sc->sc_dev), sc->sc_cmd);
+ umass_disco(sc);
+ USB_ATTACH_ERROR_RETURN;
+ }
+ if (error) {
+ printf("%s: bus attach failed\n", USBDEVNAME(sc->sc_dev));
umass_disco(sc);
- /* Not an error, just not a complete success. */
- USB_ATTACH_SUCCESS_RETURN;
+ USB_ATTACH_ERROR_RETURN;
}
usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
USBDEV(sc->sc_dev));
-}
-Static int
-scsipiprint(aux, pnp)
- void *aux;
- const char *pnp;
-{
-#if !defined(__OpenBSD__)
- extern int atapi_print(void *aux, const char *pnp);
- struct scsipi_link *l = aux;
-
- if (l->type == BUS_SCSI)
- return (scsiprint(aux, pnp));
- else
- return (atapi_print(aux, pnp));
-#else
- return (scsiprint(aux, pnp));
-#endif
+ DPRINTF(UDMASS_GEN, ("%s: Attach finished\n", USBDEVNAME(sc->sc_dev)));
+
+ USB_ATTACH_SUCCESS_RETURN;
}
USB_DETACH(umass)
{
USB_DETACH_START(umass, sc);
- int rv = 0;
+ struct umassbus_softc *scbus = sc->bus;
+ int rv = 0, i;
DPRINTF(UDMASS_USB, ("%s: detached\n", USBDEVNAME(sc->sc_dev)));
/* Abort the pipes to wake up any waiting processes. */
- if (sc->bulkout_pipe != NULL)
- usbd_abort_pipe(sc->bulkout_pipe);
- if (sc->bulkin_pipe != NULL)
- usbd_abort_pipe(sc->bulkin_pipe);
- if (sc->intrin_pipe != NULL)
- usbd_abort_pipe(sc->intrin_pipe);
+ for (i = 0 ; i < UMASS_NEP ; i++) {
+ if (sc->sc_pipe[i] != NULL)
+ usbd_abort_pipe(sc->sc_pipe[i]);
+ }
#if 0
/* Do we really need reference counting? Perhaps in ioctl() */
@@ -1228,16 +627,13 @@ USB_DETACH(umass)
splx(s);
#endif
-#if defined(__FreeBSD__)
- if ((sc->proto & PROTO_SCSI) ||
- (sc->proto & PROTO_ATAPI) ||
- (sc->proto & PROTO_UFI))
- /* detach the device from the SCSI host controller (SIM) */
- rv = umass_cam_detach(sc);
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
- if (sc->sc_child != NULL)
- rv = config_detach(sc->sc_child, flags);
-#endif
+ if (scbus != NULL) {
+ if (scbus->sc_child != NULL)
+ rv = config_detach(scbus->sc_child, flags);
+ free(scbus, M_DEVBUF);
+ sc->bus = NULL;
+ }
+
if (rv != 0)
return (rv);
@@ -1246,16 +642,14 @@ USB_DETACH(umass)
usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
USBDEV(sc->sc_dev));
- return (0);
+ return (rv);
}
-#if defined(__NetBSD__) || defined(__OpenBSD__)
int
-umass_activate(self, act)
- struct device *self;
- enum devact act;
+umass_activate(struct device *dev, enum devact act)
{
- struct umass_softc *sc = (struct umass_softc *) self;
+ struct umass_softc *sc = (struct umass_softc *)dev;
+ struct umassbus_softc *scbus = sc->bus;
int rv = 0;
DPRINTF(UDMASS_USB, ("%s: umass_activate: %d\n",
@@ -1267,22 +661,19 @@ umass_activate(self, act)
break;
case DVACT_DEACTIVATE:
- if (sc->sc_child == NULL)
+ sc->sc_dying = 1;
+ if (scbus == NULL || scbus->sc_child == NULL)
break;
- rv = config_deactivate(sc->sc_child);
+ rv = config_deactivate(scbus->sc_child);
DPRINTF(UDMASS_USB, ("%s: umass_activate: child "
"returned %d\n", USBDEVNAME(sc->sc_dev), rv));
- if (rv == 0)
- sc->sc_dying = 1;
break;
}
return (rv);
}
-#endif
Static void
-umass_disco(sc)
- struct umass_softc *sc;
+umass_disco(struct umass_softc *sc)
{
int i;
@@ -1296,27 +687,10 @@ umass_disco(sc)
}
/* Remove all the pipes. */
- if (sc->bulkout_pipe != NULL)
- usbd_close_pipe(sc->bulkout_pipe);
- if (sc->bulkin_pipe != NULL)
- usbd_close_pipe(sc->bulkin_pipe);
- if (sc->intrin_pipe != NULL)
- usbd_close_pipe(sc->intrin_pipe);
-}
-
-Static void
-umass_init_shuttle(struct umass_softc *sc)
-{
- usb_device_request_t req;
- u_char status[2];
-
- /* The Linux driver does this */
- req.bmRequestType = UT_READ_VENDOR_DEVICE;
- req.bRequest = 1;
- USETW(req.wValue, 0);
- USETW(req.wIndex, sc->ifaceno);
- USETW(req.wLength, sizeof status);
- (void)usbd_do_request(sc->sc_udev, &req, &status);
+ for (i = 0 ; i < UMASS_NEP ; i++) {
+ if (sc->sc_pipe[i] != NULL)
+ usbd_close_pipe(sc->sc_pipe[i]);
+ }
}
/*
@@ -1336,7 +710,7 @@ umass_setup_transfer(struct umass_softc *sc, usbd_pipe_handle pipe,
/* Initialiase a USB transfer and then schedule it */
usbd_setup_xfer(xfer, pipe, (void *)sc, buffer, buflen,
- flags | sc->sc_xfer_flags, sc->timeout, sc->state);
+ flags | sc->sc_xfer_flags, sc->timeout, sc->sc_methods->wire_state);
err = usbd_transfer(xfer);
DPRINTF(UDMASS_XFER,("%s: start xfer buffer=%p buflen=%d flags=0x%x "
@@ -1353,10 +727,8 @@ umass_setup_transfer(struct umass_softc *sc, usbd_pipe_handle pipe,
Static usbd_status
-umass_setup_ctrl_transfer(struct umass_softc *sc, usbd_device_handle dev,
- usb_device_request_t *req,
- void *buffer, int buflen, int flags,
- usbd_xfer_handle xfer)
+umass_setup_ctrl_transfer(struct umass_softc *sc, usb_device_request_t *req,
+ void *buffer, int buflen, int flags, usbd_xfer_handle xfer)
{
usbd_status err;
@@ -1365,8 +737,8 @@ umass_setup_ctrl_transfer(struct umass_softc *sc, usbd_device_handle dev,
/* Initialiase a USB control transfer and then schedule it */
- usbd_setup_default_xfer(xfer, dev, (void *) sc,
- sc->timeout, req, buffer, buflen, flags, sc->state);
+ usbd_setup_default_xfer(xfer, sc->sc_udev, (void *) sc, sc->timeout,
+ req, buffer, buflen, flags, sc->sc_methods->wire_state);
err = usbd_transfer(xfer);
if (err && err != USBD_IN_PROGRESS) {
@@ -1381,30 +753,23 @@ umass_setup_ctrl_transfer(struct umass_softc *sc, usbd_device_handle dev,
}
Static void
-umass_clear_endpoint_stall(struct umass_softc *sc,
- u_int8_t endpt, usbd_pipe_handle pipe,
- int state, usbd_xfer_handle xfer)
+umass_clear_endpoint_stall(struct umass_softc *sc, int endpt,
+ usbd_xfer_handle xfer)
{
- usbd_device_handle dev;
-
if (sc->sc_dying)
return;
DPRINTF(UDMASS_BBB, ("%s: Clear endpoint 0x%02x stall\n",
- USBDEVNAME(sc->sc_dev), endpt));
-
- usbd_interface2device_handle(sc->iface, &dev);
+ USBDEVNAME(sc->sc_dev), sc->sc_epaddr[endpt]));
- sc->transfer_state = state;
+ usbd_clear_endpoint_toggle(sc->sc_pipe[endpt]);
- usbd_clear_endpoint_toggle(pipe);
-
- sc->request.bmRequestType = UT_WRITE_ENDPOINT;
- sc->request.bRequest = UR_CLEAR_FEATURE;
- USETW(sc->request.wValue, UF_ENDPOINT_HALT);
- USETW(sc->request.wIndex, endpt);
- USETW(sc->request.wLength, 0);
- umass_setup_ctrl_transfer(sc, dev, &sc->request, NULL, 0, 0, xfer);
+ sc->sc_req.bmRequestType = UT_WRITE_ENDPOINT;
+ sc->sc_req.bRequest = UR_CLEAR_FEATURE;
+ USETW(sc->sc_req.wValue, UF_ENDPOINT_HALT);
+ USETW(sc->sc_req.wIndex, sc->sc_epaddr[endpt]);
+ USETW(sc->sc_req.wLength, 0);
+ umass_setup_ctrl_transfer(sc, &sc->sc_req, NULL, 0, 0, xfer);
}
#if 0
@@ -1426,10 +791,9 @@ umass_reset(struct umass_softc *sc, transfer_cb_f cb, void *priv)
Static void
umass_bbb_reset(struct umass_softc *sc, int status)
{
- usbd_device_handle dev;
-
- KASSERT(sc->proto & PROTO_BBB,
- ("sc->proto == 0x%02x wrong for umass_bbb_reset\n", sc->proto));
+ KASSERT(sc->sc_wire & UMASS_WPROTO_BBB,
+ ("sc->sc_wire == 0x%02x wrong for umass_bbb_reset\n",
+ sc->sc_wire));
if (sc->sc_dying)
return;
@@ -1456,31 +820,32 @@ umass_bbb_reset(struct umass_softc *sc, int status)
sc->transfer_state = TSTATE_BBB_RESET1;
sc->transfer_status = status;
- usbd_interface2device_handle(sc->iface, &dev);
-
/* reset is a class specific interface write */
- sc->request.bmRequestType = UT_WRITE_CLASS_INTERFACE;
- sc->request.bRequest = UR_BBB_RESET;
- USETW(sc->request.wValue, 0);
- USETW(sc->request.wIndex, sc->ifaceno);
- USETW(sc->request.wLength, 0);
- umass_setup_ctrl_transfer(sc, dev, &sc->request, NULL, 0, 0,
+ sc->sc_req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
+ sc->sc_req.bRequest = UR_BBB_RESET;
+ USETW(sc->sc_req.wValue, 0);
+ USETW(sc->sc_req.wIndex, sc->sc_ifaceno);
+ USETW(sc->sc_req.wLength, 0);
+ umass_setup_ctrl_transfer(sc, &sc->sc_req, NULL, 0, 0,
sc->transfer_xfer[XFER_BBB_RESET1]);
}
Static void
umass_bbb_transfer(struct umass_softc *sc, int lun, void *cmd, int cmdlen,
- void *data, int datalen, int dir,
- transfer_cb_f cb, void *priv)
+ void *data, int datalen, int dir, u_int timeout,
+ umass_callback cb, void *priv)
{
static int dCBWtag = 42; /* unique for CBW of transfer */
DPRINTF(UDMASS_BBB,("%s: umass_bbb_transfer cmd=0x%02x\n",
USBDEVNAME(sc->sc_dev), *(u_char *)cmd));
- KASSERT(sc->proto & PROTO_BBB,
- ("sc->proto == 0x%02x wrong for umass_bbb_transfer\n",
- sc->proto));
+ KASSERT(sc->sc_wire & UMASS_WPROTO_BBB,
+ ("sc->sc_wire == 0x%02x wrong for umass_bbb_transfer\n",
+ sc->sc_wire));
+
+ /* Be a little generous. */
+ sc->timeout = timeout + USBD_DEFAULT_TIMEOUT;
/*
* Do a Bulk-Only transfer with cmdlen bytes from cmd, possibly
@@ -1552,7 +917,7 @@ umass_bbb_transfer(struct umass_softc *sc, int lun, void *cmd, int cmdlen,
sc->cbw.bCBWFlags = (dir == DIR_IN? CBWFLAGS_IN:CBWFLAGS_OUT);
sc->cbw.bCBWLUN = lun;
sc->cbw.bCDBLength = cmdlen;
- bcopy(cmd, sc->cbw.CBWCDB, cmdlen);
+ memcpy(sc->cbw.CBWCDB, cmd, cmdlen);
DIF(UDMASS_BBB, umass_bbb_dump_cbw(sc, &sc->cbw));
@@ -1569,7 +934,7 @@ umass_bbb_transfer(struct umass_softc *sc, int lun, void *cmd, int cmdlen,
sc->transfer_state = TSTATE_BBB_COMMAND;
/* Send the CBW from host to device via bulk-out endpoint. */
- if (umass_setup_transfer(sc, sc->bulkout_pipe,
+ if (umass_setup_transfer(sc, sc->sc_pipe[UMASS_BULKOUT],
&sc->cbw, UMASS_BBB_CBW_SIZE, 0,
sc->transfer_xfer[XFER_BBB_CBW])) {
umass_bbb_reset(sc, STATUS_WIRE_FAILED);
@@ -1584,8 +949,9 @@ umass_bbb_state(usbd_xfer_handle xfer, usbd_private_handle priv,
struct umass_softc *sc = (struct umass_softc *) priv;
usbd_xfer_handle next_xfer;
- KASSERT(sc->proto & PROTO_BBB,
- ("sc->proto == 0x%02x wrong for umass_bbb_state\n",sc->proto));
+ KASSERT(sc->sc_wire & UMASS_WPROTO_BBB,
+ ("sc->sc_wire == 0x%02x wrong for umass_bbb_state\n",
+ sc->sc_wire));
if (sc->sc_dying)
return;
@@ -1624,7 +990,7 @@ umass_bbb_state(usbd_xfer_handle xfer, usbd_private_handle priv,
/* Data transport phase, setup transfer */
sc->transfer_state = TSTATE_BBB_DATA;
if (sc->transfer_dir == DIR_IN) {
- if (umass_setup_transfer(sc, sc->bulkin_pipe,
+ if (umass_setup_transfer(sc, sc->sc_pipe[UMASS_BULKIN],
sc->data_buffer, sc->transfer_datalen,
USBD_SHORT_XFER_OK | USBD_NO_COPY,
sc->transfer_xfer[XFER_BBB_DATA]))
@@ -1634,7 +1000,7 @@ umass_bbb_state(usbd_xfer_handle xfer, usbd_private_handle priv,
} else if (sc->transfer_dir == DIR_OUT) {
memcpy(sc->data_buffer, sc->transfer_data,
sc->transfer_datalen);
- if (umass_setup_transfer(sc, sc->bulkout_pipe,
+ if (umass_setup_transfer(sc, sc->sc_pipe[UMASS_BULKOUT],
sc->data_buffer, sc->transfer_datalen,
USBD_NO_COPY,/* fixed length transfer */
sc->transfer_xfer[XFER_BBB_DATA]))
@@ -1656,18 +1022,16 @@ umass_bbb_state(usbd_xfer_handle xfer, usbd_private_handle priv,
&sc->transfer_actlen, NULL);
if (err) {
- DPRINTF(UDMASS_BBB, ("%s: Data-%s %db failed, "
+ DPRINTF(UDMASS_BBB, ("%s: Data-%s %d failed, "
"%s\n", USBDEVNAME(sc->sc_dev),
(sc->transfer_dir == DIR_IN?"in":"out"),
sc->transfer_datalen,usbd_errstr(err)));
if (err == USBD_STALLED) {
+ sc->transfer_state = TSTATE_BBB_DCLEAR;
umass_clear_endpoint_stall(sc,
(sc->transfer_dir == DIR_IN?
- sc->bulkin:sc->bulkout),
- (sc->transfer_dir == DIR_IN?
- sc->bulkin_pipe:sc->bulkout_pipe),
- TSTATE_BBB_DCLEAR,
+ UMASS_BULKIN:UMASS_BULKOUT),
sc->transfer_xfer[XFER_BBB_DCLEAR]);
return;
} else {
@@ -1723,9 +1087,8 @@ umass_bbb_state(usbd_xfer_handle xfer, usbd_private_handle priv,
}
/* Read the Command Status Wrapper via bulk-in endpoint. */
- if (umass_setup_transfer(sc, sc->bulkin_pipe,
- &sc->csw, UMASS_BBB_CSW_SIZE, 0,
- next_xfer)) {
+ if (umass_setup_transfer(sc, sc->sc_pipe[UMASS_BULKIN],
+ &sc->csw, UMASS_BBB_CSW_SIZE, 0, next_xfer)) {
umass_bbb_reset(sc, STATUS_WIRE_FAILED);
return;
}
@@ -1744,10 +1107,9 @@ umass_bbb_state(usbd_xfer_handle xfer, usbd_private_handle priv,
* retry it, otherwise fail.
*/
if (sc->transfer_state == TSTATE_BBB_STATUS1) {
- umass_clear_endpoint_stall(sc,
- sc->bulkin, sc->bulkin_pipe,
- TSTATE_BBB_SCLEAR,
- sc->transfer_xfer[XFER_BBB_SCLEAR]);
+ sc->transfer_state = TSTATE_BBB_SCLEAR;
+ umass_clear_endpoint_stall(sc, UMASS_BULKIN,
+ sc->transfer_xfer[XFER_BBB_SCLEAR]);
return;
} else {
umass_bbb_reset(sc, STATUS_WIRE_FAILED);
@@ -1757,6 +1119,11 @@ umass_bbb_state(usbd_xfer_handle xfer, usbd_private_handle priv,
DIF(UDMASS_BBB, umass_bbb_dump_csw(sc, &sc->csw));
+ /* Translate weird command-status signatures. */
+ if ((sc->sc_quirks & UMASS_QUIRK_WRONG_CSWSIG) &&
+ UGETDW(sc->csw.dCSWSignature) == CSWSIGNATURE_OLYMPUS_C1)
+ USETDW(sc->csw.dCSWSignature, CSWSIGNATURE);
+
/* Check CSW and handle any error */
if (UGETDW(sc->csw.dCSWSignature) != CSWSIGNATURE) {
/* Invalid CSW: Wrong signature or wrong tag might
@@ -1801,9 +1168,8 @@ umass_bbb_state(usbd_xfer_handle xfer, usbd_private_handle priv,
panic("%s: transferred %d bytes instead of %d bytes\n",
USBDEVNAME(sc->sc_dev),
sc->transfer_actlen, sc->transfer_datalen);
- }
#if 0
- else if (sc->transfer_datalen - sc->transfer_actlen
+ } else if (sc->transfer_datalen - sc->transfer_actlen
!= UGETDW(sc->csw.dCSWDataResidue)) {
DPRINTF(UDMASS_BBB, ("%s: actlen=%d != residue=%d\n",
USBDEVNAME(sc->sc_dev),
@@ -1812,10 +1178,8 @@ umass_bbb_state(usbd_xfer_handle xfer, usbd_private_handle priv,
umass_bbb_reset(sc, STATUS_WIRE_FAILED);
return;
-
- }
#endif
- else if (sc->csw.bCSWStatus == CSWSTATUS_FAILED) {
+ } else if (sc->csw.bCSWStatus == CSWSTATUS_FAILED) {
DPRINTF(UDMASS_BBB, ("%s: Command Failed, res = %d\n",
USBDEVNAME(sc->sc_dev),
UGETDW(sc->csw.dCSWDataResidue)));
@@ -1843,8 +1207,8 @@ umass_bbb_state(usbd_xfer_handle xfer, usbd_private_handle priv,
printf("%s: BBB reset failed, %s\n",
USBDEVNAME(sc->sc_dev), usbd_errstr(err));
- umass_clear_endpoint_stall(sc,
- sc->bulkin, sc->bulkin_pipe, TSTATE_BBB_RESET2,
+ sc->transfer_state = TSTATE_BBB_RESET2;
+ umass_clear_endpoint_stall(sc, UMASS_BULKIN,
sc->transfer_xfer[XFER_BBB_RESET2]);
return;
@@ -1854,8 +1218,8 @@ umass_bbb_state(usbd_xfer_handle xfer, usbd_private_handle priv,
USBDEVNAME(sc->sc_dev), usbd_errstr(err));
/* no error recovery, otherwise we end up in a loop */
- umass_clear_endpoint_stall(sc,
- sc->bulkout, sc->bulkout_pipe, TSTATE_BBB_RESET3,
+ sc->transfer_state = TSTATE_BBB_RESET3;
+ umass_clear_endpoint_stall(sc, UMASS_BULKOUT,
sc->transfer_xfer[XFER_BBB_RESET3]);
return;
@@ -1889,19 +1253,16 @@ Static int
umass_cbi_adsc(struct umass_softc *sc, char *buffer, int buflen,
usbd_xfer_handle xfer)
{
- usbd_device_handle dev;
-
- KASSERT(sc->proto & (PROTO_CBI|PROTO_CBI_I),
- ("sc->proto == 0x%02x wrong for umass_cbi_adsc\n",sc->proto));
-
- usbd_interface2device_handle(sc->iface, &dev);
-
- sc->request.bmRequestType = UT_WRITE_CLASS_INTERFACE;
- sc->request.bRequest = UR_CBI_ADSC;
- USETW(sc->request.wValue, 0);
- USETW(sc->request.wIndex, sc->ifaceno);
- USETW(sc->request.wLength, buflen);
- return umass_setup_ctrl_transfer(sc, dev, &sc->request, buffer,
+ KASSERT(sc->sc_wire & (UMASS_WPROTO_CBI|UMASS_WPROTO_CBI_I),
+ ("sc->sc_wire == 0x%02x wrong for umass_cbi_adsc\n",
+ sc->sc_wire));
+
+ sc->sc_req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
+ sc->sc_req.bRequest = UR_CBI_ADSC;
+ USETW(sc->sc_req.wValue, 0);
+ USETW(sc->sc_req.wIndex, sc->sc_ifaceno);
+ USETW(sc->sc_req.wLength, buflen);
+ return umass_setup_ctrl_transfer(sc, &sc->sc_req, buffer,
buflen, 0, xfer);
}
@@ -1912,8 +1273,9 @@ umass_cbi_reset(struct umass_softc *sc, int status)
int i;
# define SEND_DIAGNOSTIC_CMDLEN 12
- KASSERT(sc->proto & (PROTO_CBI|PROTO_CBI_I),
- ("sc->proto == 0x%02x wrong for umass_cbi_reset\n",sc->proto));
+ KASSERT(sc->sc_wire & (UMASS_WPROTO_CBI|UMASS_WPROTO_CBI_I),
+ ("sc->sc_wire == 0x%02x wrong for umass_cbi_reset\n",
+ sc->sc_wire));
if (sc->sc_dying)
return;
@@ -1959,19 +1321,22 @@ umass_cbi_reset(struct umass_softc *sc, int status)
Static void
umass_cbi_transfer(struct umass_softc *sc, int lun,
- void *cmd, int cmdlen, void *data, int datalen, int dir,
- transfer_cb_f cb, void *priv)
+ void *cmd, int cmdlen, void *data, int datalen, int dir,
+ u_int timeout, umass_callback cb, void *priv)
{
DPRINTF(UDMASS_CBI,("%s: umass_cbi_transfer cmd=0x%02x, len=%d\n",
USBDEVNAME(sc->sc_dev), *(u_char *)cmd, datalen));
- KASSERT(sc->proto & (PROTO_CBI|PROTO_CBI_I),
- ("sc->proto == 0x%02x wrong for umass_cbi_transfer\n",
- sc->proto));
+ KASSERT(sc->sc_wire & (UMASS_WPROTO_CBI|UMASS_WPROTO_CBI_I),
+ ("sc->sc_wire == 0x%02x wrong for umass_cbi_transfer\n",
+ sc->sc_wire));
if (sc->sc_dying)
return;
+ /* Be a little generous. */
+ sc->timeout = timeout + USBD_DEFAULT_TIMEOUT;
+
/*
* Do a CBI transfer with cmdlen bytes from cmd, possibly
* a data phase of datalen bytes from/to the device and finally a
@@ -2019,8 +1384,9 @@ umass_cbi_state(usbd_xfer_handle xfer, usbd_private_handle priv,
{
struct umass_softc *sc = (struct umass_softc *) priv;
- KASSERT(sc->proto & (PROTO_CBI|PROTO_CBI_I),
- ("sc->proto == 0x%02x wrong for umass_cbi_state\n", sc->proto));
+ KASSERT(sc->sc_wire & (UMASS_WPROTO_CBI|UMASS_WPROTO_CBI_I),
+ ("sc->sc_wire == 0x%02x wrong for umass_cbi_state\n",
+ sc->sc_wire));
if (sc->sc_dying)
return;
@@ -2043,10 +1409,10 @@ umass_cbi_state(usbd_xfer_handle xfer, usbd_private_handle priv,
/* Status transport by control pipe (section 2.3.2.1).
* The command contained in the command block failed.
*
- * The control pipe has already been unstalled by the
- * USB stack.
- * Section 2.4.3.1.1 states that the bulk in endpoints
- * should not stalled at this point.
+ * The control pipe has already been unstalled by the
+ * USB stack.
+ * Section 2.4.3.1.1 states that the bulk in endpoints
+ * should not stalled at this point.
*/
sc->transfer_state = TSTATE_IDLE;
@@ -2065,7 +1431,7 @@ umass_cbi_state(usbd_xfer_handle xfer, usbd_private_handle priv,
sc->transfer_state = TSTATE_CBI_DATA;
if (sc->transfer_dir == DIR_IN) {
- if (umass_setup_transfer(sc, sc->bulkin_pipe,
+ if (umass_setup_transfer(sc, sc->sc_pipe[UMASS_BULKIN],
sc->transfer_data, sc->transfer_datalen,
USBD_SHORT_XFER_OK | USBD_NO_COPY,
sc->transfer_xfer[XFER_CBI_DATA]))
@@ -2074,17 +1440,17 @@ umass_cbi_state(usbd_xfer_handle xfer, usbd_private_handle priv,
} else if (sc->transfer_dir == DIR_OUT) {
memcpy(sc->data_buffer, sc->transfer_data,
sc->transfer_datalen);
- if (umass_setup_transfer(sc, sc->bulkout_pipe,
+ if (umass_setup_transfer(sc, sc->sc_pipe[UMASS_BULKOUT],
sc->transfer_data, sc->transfer_datalen,
USBD_NO_COPY,/* fixed length transfer */
sc->transfer_xfer[XFER_CBI_DATA]))
umass_cbi_reset(sc, STATUS_WIRE_FAILED);
- } else if (sc->proto & PROTO_CBI_I) {
+ } else if (sc->sc_wire == UMASS_WPROTO_CBI_I) {
DPRINTF(UDMASS_CBI, ("%s: no data phase\n",
USBDEVNAME(sc->sc_dev)));
sc->transfer_state = TSTATE_CBI_STATUS;
- if (umass_setup_transfer(sc, sc->intrin_pipe,
+ if (umass_setup_transfer(sc, sc->sc_pipe[UMASS_INTRIN],
&sc->sbl, sizeof(sc->sbl),
0, /* fixed length transfer */
sc->transfer_xfer[XFER_CBI_STATUS])){
@@ -2110,15 +1476,14 @@ umass_cbi_state(usbd_xfer_handle xfer, usbd_private_handle priv,
USBDEVNAME(sc->sc_dev), sc->transfer_actlen));
if (err) {
- DPRINTF(UDMASS_CBI, ("%s: Data-%s %db failed, "
+ DPRINTF(UDMASS_CBI, ("%s: Data-%s %d failed, "
"%s\n", USBDEVNAME(sc->sc_dev),
(sc->transfer_dir == DIR_IN?"in":"out"),
sc->transfer_datalen,usbd_errstr(err)));
if (err == USBD_STALLED) {
- umass_clear_endpoint_stall(sc,
- sc->bulkin, sc->bulkin_pipe,
- TSTATE_CBI_DCLEAR,
+ sc->transfer_state = TSTATE_CBI_DCLEAR;
+ umass_clear_endpoint_stall(sc, UMASS_BULKIN,
sc->transfer_xfer[XFER_CBI_DCLEAR]);
} else {
umass_cbi_reset(sc, STATUS_WIRE_FAILED);
@@ -2134,10 +1499,10 @@ umass_cbi_state(usbd_xfer_handle xfer, usbd_private_handle priv,
umass_dump_buffer(sc, sc->transfer_data,
sc->transfer_actlen, 48));
- if (sc->proto & PROTO_CBI_I) {
+ if (sc->sc_wire == UMASS_WPROTO_CBI_I) {
sc->transfer_state = TSTATE_CBI_STATUS;
memset(&sc->sbl, 0, sizeof(sc->sbl));
- if (umass_setup_transfer(sc, sc->intrin_pipe,
+ if (umass_setup_transfer(sc, sc->sc_pipe[UMASS_INTRIN],
&sc->sbl, sizeof(sc->sbl),
0, /* fixed length transfer */
sc->transfer_xfer[XFER_CBI_STATUS])){
@@ -2162,9 +1527,8 @@ umass_cbi_state(usbd_xfer_handle xfer, usbd_private_handle priv,
*/
if (err == USBD_STALLED) {
- umass_clear_endpoint_stall(sc,
- sc->intrin, sc->intrin_pipe,
- TSTATE_CBI_SCLEAR,
+ sc->transfer_state = TSTATE_CBI_SCLEAR;
+ umass_clear_endpoint_stall(sc, UMASS_INTRIN,
sc->transfer_xfer[XFER_CBI_SCLEAR]);
} else {
umass_cbi_reset(sc, STATUS_WIRE_FAILED);
@@ -2174,7 +1538,7 @@ umass_cbi_state(usbd_xfer_handle xfer, usbd_private_handle priv,
/* Dissect the information in the buffer */
- if (sc->proto & PROTO_UFI) {
+ if (sc->sc_cmd == UMASS_CPROTO_UFI) {
int status;
/* Section 3.4.3.1.3 specifies that the UFI command
@@ -2250,8 +1614,8 @@ umass_cbi_state(usbd_xfer_handle xfer, usbd_private_handle priv,
printf("%s: CBI reset failed, %s\n",
USBDEVNAME(sc->sc_dev), usbd_errstr(err));
- umass_clear_endpoint_stall(sc,
- sc->bulkin, sc->bulkin_pipe, TSTATE_CBI_RESET2,
+ sc->transfer_state = TSTATE_CBI_RESET2;
+ umass_clear_endpoint_stall(sc, UMASS_BULKIN,
sc->transfer_xfer[XFER_CBI_RESET2]);
return;
@@ -2261,8 +1625,8 @@ umass_cbi_state(usbd_xfer_handle xfer, usbd_private_handle priv,
USBDEVNAME(sc->sc_dev), usbd_errstr(err));
/* no error recovery, otherwise we end up in a loop */
- umass_clear_endpoint_stall(sc,
- sc->bulkout, sc->bulkout_pipe, TSTATE_CBI_RESET3,
+ sc->transfer_state = TSTATE_CBI_RESET3;
+ umass_clear_endpoint_stall(sc, UMASS_BULKOUT,
sc->transfer_xfer[XFER_CBI_RESET3]);
return;
@@ -2292,26 +1656,21 @@ umass_cbi_state(usbd_xfer_handle xfer, usbd_private_handle priv,
usbd_status
umass_bbb_get_max_lun(struct umass_softc *sc, u_int8_t *maxlun)
{
- usbd_device_handle dev;
usb_device_request_t req;
usbd_status err;
- usb_interface_descriptor_t *id;
*maxlun = 0; /* Default to 0. */
DPRINTF(UDMASS_BBB, ("%s: Get Max Lun\n", USBDEVNAME(sc->sc_dev)));
- usbd_interface2device_handle(sc->iface, &dev);
- id = usbd_get_interface_descriptor(sc->iface);
-
/* The Get Max Lun command is a class-specific request. */
req.bmRequestType = UT_READ_CLASS_INTERFACE;
req.bRequest = UR_BBB_GET_MAX_LUN;
USETW(req.wValue, 0);
- USETW(req.wIndex, id->bInterfaceNumber);
+ USETW(req.wIndex, sc->sc_ifaceno);
USETW(req.wLength, 1);
- err = usbd_do_request(dev, &req, maxlun);
+ err = usbd_do_request(sc->sc_udev, &req, maxlun);
switch (err) {
case USBD_NORMAL_COMPLETION:
DPRINTF(UDMASS_BBB, ("%s: Max Lun %d\n",
@@ -2348,706 +1707,6 @@ umass_bbb_get_max_lun(struct umass_softc *sc, u_int8_t *maxlun)
-#if defined(__FreeBSD__)
-/*
- * CAM specific functions (used by SCSI, UFI, 8070)
- */
-
-Static int
-umass_cam_attach_sim()
-{
- struct cam_devq *devq; /* Per device Queue */
-
- /* A HBA is attached to the CAM layer.
- *
- * The CAM layer will then after a while start probing for
- * devices on the bus. The number of devices is limitted to one.
- */
-
- /* SCSI transparent command set */
-
- devq = cam_simq_alloc(1 /*maximum openings*/);
- if (devq == NULL)
- return(ENOMEM);
-
- umass_sim = cam_sim_alloc(umass_cam_action, umass_cam_poll, DEVNAME,
- NULL /*priv*/, 0 /*unit number*/,
- 1 /*maximum device openings*/,
- 0 /*maximum tagged device openings*/,
- devq);
- if (umass_sim == NULL) {
- cam_simq_free(devq);
- return(ENOMEM);
- }
-
- if(xpt_bus_register(umass_sim, 0) != CAM_SUCCESS)
- return(ENOMEM);
-
- if (xpt_create_path(&umass_path, NULL, cam_sim_path(umass_sim),
- UMASS_SCSIID_HOST, 0)
- != CAM_REQ_CMP)
- return(ENOMEM);
-
- return(0);
-}
-
-#ifdef UMASS_DO_CAM_RESCAN
-/* this function is only used from umass_cam_rescan, so mention
- * prototype down here.
- */
-Static void umass_cam_rescan_callback(struct cam_periph *periph,union ccb *ccb);
-
-Static void
-umass_cam_rescan_callback(struct cam_periph *periph, union ccb *ccb)
-{
-#ifdef UMASS_DEBUG
- struct umass_softc *sc = devclass_get_softc(umass_devclass,
- ccb->ccb_h.target_id);
-
- if (ccb->ccb_h.status != CAM_REQ_CMP) {
- DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d: Rescan failed, 0x%04x\n",
- USBDEVNAME(sc->sc_dev), UMASS_SCSI_BUS,
- ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
- ccb->ccb_h.status));
- } else {
- DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d: Rescan succeeded, freeing resources.\n",
- USBDEVNAME(sc->sc_dev), UMASS_SCSI_BUS,
- ccb->ccb_h.target_id, ccb->ccb_h.target_lun));
- }
-#endif
-
- xpt_free_path(ccb->ccb_h.path);
- free(ccb, M_USBDEV);
-}
-
-Static void
-umass_cam_rescan(struct umass_softc *sc)
-{
- struct cam_path *path;
- union ccb *ccb = malloc(sizeof(union ccb), M_USBDEV, M_WAITOK);
-
- memset(ccb, 0, sizeof(union ccb));
-
- DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d: scanning bus for new device %d\n",
- USBDEVNAME(sc->sc_dev), cam_sim_path(umass_sim),
- device_get_unit(sc->sc_dev), 0,
- device_get_unit(sc->sc_dev)));
-
- if (xpt_create_path(&path, xpt_periph, cam_sim_path(umass_sim),
- device_get_unit(sc->sc_dev), 0)
- != CAM_REQ_CMP)
- return;
-
- xpt_setup_ccb(&ccb->ccb_h, path, 5/*priority (low)*/);
- ccb->ccb_h.func_code = XPT_SCAN_BUS;
- ccb->ccb_h.cbfcnp = umass_cam_rescan_callback;
- ccb->crcn.flags = CAM_FLAG_NONE;
- xpt_action(ccb);
-
- /* The scan is in progress now. */
-}
-#endif
-
-Static int
-umass_cam_attach(struct umass_softc *sc)
-{
- /* SIM already attached at module load. The device is a target on the
- * one SIM we registered: target device_get_unit(self).
- */
-
- /* The artificial limit UMASS_SCSIID_MAX is there because CAM expects
- * a limit to the number of targets that are present on a SIM.
- */
- if (device_get_unit(sc->sc_dev) > UMASS_SCSIID_MAX) {
- printf("%s: Increase UMASS_SCSIID_MAX (currently %d) in %s "
- "and try again.\n", USBDEVNAME(sc->sc_dev),
- UMASS_SCSIID_MAX, __FILE__);
- return(1);
- }
-
-#ifdef UMASS_DO_CAM_RESCAN
- if (!cold) {
- /* Notify CAM of the new device. Any failure is benign, as the
- * user can still do it by hand (camcontrol rescan <busno>).
- * Only do this if we are not booting, because CAM does a scan
- * after booting has completed, when interrupts have been
- * enabled.
- */
- umass_cam_rescan(sc);
- }
-#endif
-
- return(0); /* always succesful */
-}
-
-/* umass_cam_detach
- * detach from the CAM layer
- */
-
-Static int
-umass_cam_detach_sim()
-{
- if (umass_sim)
- return(EBUSY); /* XXX CAM can't handle disappearing SIMs yet */
-
- if (umass_path) {
- /* XXX do we need to send an asynchroneous event for the SIM?
- xpt_async(AC_LOST_DEVICE, umass_path, NULL);
- */
- xpt_free_path(umass_path);
- umass_path = NULL;
- }
-
- if (umass_sim) {
- if (xpt_bus_deregister(cam_sim_path(umass_sim)))
- cam_sim_free(umass_sim, /*free_devq*/TRUE);
- else
- return(EBUSY);
-
- umass_sim = NULL;
- }
-
- return(0);
-}
-
-Static int
-umass_cam_detach(struct umass_softc *sc)
-{
- struct cam_path *path;
-
- /* detach of sim not done until module unload */
- DPRINTF(UDMASS_SCSI, ("%s: losing CAM device entry\n",
- USBDEVNAME(sc->sc_dev)));
-
- if (xpt_create_path(&path, NULL, cam_sim_path(umass_sim),
- device_get_unit(sc->sc_dev), CAM_LUN_WILDCARD)
- != CAM_REQ_CMP)
- return(ENOMEM);
- xpt_async(AC_LOST_DEVICE, path, NULL);
- xpt_free_path(path);
-
- return(0);
-}
-
-
-
-/* umass_cam_action
- * CAM requests for action come through here
- */
-
-Static void
-umass_cam_action(struct cam_sim *sim, union ccb *ccb)
-{
- struct umass_softc *sc = devclass_get_softc(umass_devclass,
- ccb->ccb_h.target_id);
-
- /* The softc is still there, but marked as going away. umass_cam_detach
- * has not yet notified CAM of the lost device however.
- */
- if (sc && sc->sc_dying) {
- DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:func_code 0x%04x: "
- "Invalid target (gone)\n",
- USBDEVNAME(sc->sc_dev), UMASS_SCSI_BUS,
- ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
- ccb->ccb_h.func_code));
- ccb->ccb_h.status = CAM_TID_INVALID;
- xpt_done(ccb);
- return;
- }
-
- /* Verify, depending on the operation to perform, that we either got a
- * valid sc, because an existing target was referenced, or otherwise
- * the SIM is addressed.
- *
- * This avoids bombing out at a printf and does give the CAM layer some
- * sensible feedback on errors.
- */
- switch (ccb->ccb_h.func_code) {
- case XPT_SCSI_IO:
- case XPT_RESET_DEV:
- case XPT_GET_TRAN_SETTINGS:
- case XPT_SET_TRAN_SETTINGS:
- case XPT_CALC_GEOMETRY:
- /* the opcodes requiring a target. These should never occur. */
- if (sc == NULL) {
- printf("%s:%d:%d:%d:func_code 0x%04x: "
- "Invalid target\n",
- DEVNAME_SIM, UMASS_SCSI_BUS,
- ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
- ccb->ccb_h.func_code);
-
- ccb->ccb_h.status = CAM_TID_INVALID;
- xpt_done(ccb);
- return;
- }
- break;
- case XPT_PATH_INQ:
- case XPT_NOOP:
- /* The opcodes sometimes aimed at a target (sc is valid),
- * sometimes aimed at the SIM (sc is invalid and target is
- * CAM_TARGET_WILDCARD)
- */
- if (sc == NULL && ccb->ccb_h.target_id != CAM_TARGET_WILDCARD) {
- DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:func_code 0x%04x: "
- "Invalid target\n",
- DEVNAME_SIM, UMASS_SCSI_BUS,
- ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
- ccb->ccb_h.func_code));
-
- ccb->ccb_h.status = CAM_TID_INVALID;
- xpt_done(ccb);
- return;
- }
- break;
- default:
- /* XXX Hm, we should check the input parameters */
- }
-
- /* Perform the requested action */
- switch (ccb->ccb_h.func_code) {
- case XPT_SCSI_IO:
- {
- struct ccb_scsiio *csio = &ccb->csio; /* deref union */
- int dir;
- unsigned char *cmd;
- int cmdlen;
-
- DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_SCSI_IO: "
- "cmd: 0x%02x, flags: 0x%02x, "
- "%db cmd/%db data/%db sense\n",
- USBDEVNAME(sc->sc_dev), UMASS_SCSI_BUS,
- ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
- csio->cdb_io.cdb_bytes[0],
- ccb->ccb_h.flags & CAM_DIR_MASK,
- csio->cdb_len, csio->dxfer_len,
- csio->sense_len));
-
- /* clear the end of the buffer to make sure we don't send out
- * garbage.
- */
- DIF(UDMASS_SCSI, if ((ccb->ccb_h.flags & CAM_DIR_MASK)
- == CAM_DIR_OUT)
- umass_dump_buffer(sc, csio->data_ptr,
- csio->dxfer_len, 48));
-
- if (sc->transfer_state != TSTATE_IDLE) {
- DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_SCSI_IO: "
- "I/O requested while busy (state %d, %s)\n",
- USBDEVNAME(sc->sc_dev), UMASS_SCSI_BUS,
- ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
- sc->transfer_state,states[sc->transfer_state]));
- ccb->ccb_h.status = CAM_SCSI_BUSY;
- xpt_done(ccb);
- return;
- }
-
- switch(ccb->ccb_h.flags&CAM_DIR_MASK) {
- case CAM_DIR_IN:
- dir = DIR_IN;
- break;
- case CAM_DIR_OUT:
- dir = DIR_OUT;
- break;
- default:
- dir = DIR_NONE;
- }
-
- ccb->ccb_h.status = CAM_REQ_INPROG | CAM_SIM_QUEUED;
- if (sc->transform(sc, csio->cdb_io.cdb_bytes, csio->cdb_len,
- &cmd, &cmdlen)) {
- sc->transfer(sc, ccb->ccb_h.target_lun, cmd, cmdlen,
- csio->data_ptr,
- csio->dxfer_len, dir,
- umass_cam_cb, (void *) ccb);
- } else {
- ccb->ccb_h.status = CAM_REQ_INVALID;
- xpt_done(ccb);
- }
-
- break;
- }
- case XPT_PATH_INQ:
- {
- struct ccb_pathinq *cpi = &ccb->cpi;
-
- DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_PATH_INQ:.\n",
- (sc == NULL? DEVNAME_SIM:USBDEVNAME(sc->sc_dev)),
- UMASS_SCSI_BUS,
- ccb->ccb_h.target_id, ccb->ccb_h.target_lun));
-
- /* host specific information */
- cpi->version_num = 1;
- cpi->hba_inquiry = 0;
- cpi->target_sprt = 0;
- cpi->hba_misc = 0;
- cpi->hba_eng_cnt = 0;
- cpi->max_target = UMASS_SCSIID_MAX; /* one target */
- cpi->max_lun = 0; /* no LUN's supported */
- cpi->initiator_id = UMASS_SCSIID_HOST;
- strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
- strncpy(cpi->hba_vid, "USB SCSI", HBA_IDLEN);
- strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
- cpi->unit_number = cam_sim_unit(sim);
- cpi->bus_id = UMASS_SCSI_BUS;
- if (sc) {
- cpi->base_transfer_speed = sc->transfer_speed;
- cpi->max_lun = sc->maxlun;
- }
-
- cpi->ccb_h.status = CAM_REQ_CMP;
- xpt_done(ccb);
- break;
- }
- case XPT_RESET_DEV:
- {
- DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_RESET_DEV:.\n",
- USBDEVNAME(sc->sc_dev), UMASS_SCSI_BUS,
- ccb->ccb_h.target_id, ccb->ccb_h.target_lun));
-
- ccb->ccb_h.status = CAM_REQ_INPROG;
- umass_reset(sc, umass_cam_cb, (void *) ccb);
- break;
- }
- case XPT_GET_TRAN_SETTINGS:
- {
- struct ccb_trans_settings *cts = &ccb->cts;
-
- DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_GET_TRAN_SETTINGS:.\n",
- USBDEVNAME(sc->sc_dev), UMASS_SCSI_BUS,
- ccb->ccb_h.target_id, ccb->ccb_h.target_lun));
-
- cts->valid = 0;
- cts->flags = 0; /* no disconnection, tagging */
-
- ccb->ccb_h.status = CAM_REQ_CMP;
- xpt_done(ccb);
- break;
- }
- case XPT_SET_TRAN_SETTINGS:
- {
- DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_SET_TRAN_SETTINGS:.\n",
- USBDEVNAME(sc->sc_dev), UMASS_SCSI_BUS,
- ccb->ccb_h.target_id, ccb->ccb_h.target_lun));
-
- ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
- xpt_done(ccb);
- break;
- }
- case XPT_CALC_GEOMETRY:
- {
- struct ccb_calc_geometry *ccg = &ccb->ccg;
-
- DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_CALC_GEOMETRY: "
- "Volume size = %d\n",
- USBDEVNAME(sc->sc_dev), UMASS_SCSI_BUS,
- ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
- ccg->volume_size));
-
- /* XXX We should probably ask the drive for the details
- * instead of cluching them up ourselves
- */
- if (sc->drive == ZIP_100) {
- ccg->heads = 64;
- ccg->secs_per_track = 32;
- ccg->cylinders = ccg->volume_size / ccg->heads
- / ccg->secs_per_track;
- ccb->ccb_h.status = CAM_REQ_CMP;
- break;
- } else if (sc->proto & PROTO_UFI) {
- ccg->heads = 2;
- if (ccg->volume_size == 2880)
- ccg->secs_per_track = 18;
- else
- ccg->secs_per_track = 9;
- ccg->cylinders = 80;
- break;
- } else {
- ccb->ccb_h.status = CAM_REQ_CMP_ERR;
- }
-
- xpt_done(ccb);
- break;
- }
- case XPT_NOOP:
- {
- DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_NOOP:.\n",
- (sc == NULL? DEVNAME_SIM:USBDEVNAME(sc->sc_dev)),
- UMASS_SCSI_BUS,
- ccb->ccb_h.target_id, ccb->ccb_h.target_lun));
-
- ccb->ccb_h.status = CAM_REQ_CMP;
- xpt_done(ccb);
- break;
- }
- default:
- DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:func_code 0x%04x: "
- "Not implemented\n",
- (sc == NULL? DEVNAME_SIM:USBDEVNAME(sc->sc_dev)),
- UMASS_SCSI_BUS,
- ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
- ccb->ccb_h.func_code));
-
- ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
- xpt_done(ccb);
- break;
- }
-}
-
-/* umass_cam_poll
- * all requests are handled through umass_cam_action, requests
- * are never pending. So, nothing to do here.
- */
-Static void
-umass_cam_poll(struct cam_sim *sim)
-{
-#ifdef UMASS_DEBUG
- struct umass_softc *sc = (struct umass_softc *) sim->softc;
-
- DPRINTF(UDMASS_SCSI, ("%s: CAM poll\n",
- USBDEVNAME(sc->sc_dev)));
-#endif
-
- /* nop */
-}
-
-
-/* umass_cam_cb
- * finalise a completed CAM command
- */
-
-Static void
-umass_cam_cb(struct umass_softc *sc, void *priv, int residue, int status)
-{
- union ccb *ccb = (union ccb *) priv;
- struct ccb_scsiio *csio = &ccb->csio; /* deref union */
-
- csio->resid = residue;
-
- switch (status) {
- case STATUS_CMD_OK:
- ccb->ccb_h.status = CAM_REQ_CMP;
- xpt_done(ccb);
- break;
-
- case STATUS_CMD_UNKNOWN:
- case STATUS_CMD_FAILED:
- switch (ccb->ccb_h.func_code) {
- case XPT_SCSI_IO:
- {
- unsigned char *cmd;
- int cmdlen;
-
- /* fetch sense data */
- DPRINTF(UDMASS_SCSI,("%s: Fetching %db sense data\n",
- USBDEVNAME(sc->sc_dev),
- sc->cam_scsi_sense.length));
-
- sc->cam_scsi_sense.length = csio->sense_len;
-
- if (sc->transform(sc, (char *) &sc->cam_scsi_sense,
- sizeof(sc->cam_scsi_sense),
- &cmd, &cmdlen)) {
- sc->transfer(sc, ccb->ccb_h.target_lun,
- cmd, cmdlen,
- &csio->sense_data,
- csio->sense_len, DIR_IN,
- umass_cam_sense_cb, (void *) ccb);
- } else {
-#ifdef UMASS_DEBUG
- panic("transform(REQUEST_SENSE) failed\n");
-#else
- csio->resid = sc->transfer_datalen;
- ccb->ccb_h.status = CAM_REQ_CMP_ERR;
- xpt_done(ccb);
-#endif
- }
- break;
- }
- case XPT_RESET_DEV: /* Reset failed */
- ccb->ccb_h.status = CAM_REQ_CMP_ERR;
- xpt_done(ccb);
- break;
- default:
- panic("umass_cam_cb called for func_code %d\n",
- ccb->ccb_h.func_code);
- }
- break;
-
- case STATUS_WIRE_FAILED:
- /* the wire protocol failed and will have recovered
- * (hopefully). We return an error to CAM and let CAM retry
- * the command if necessary.
- */
- ccb->ccb_h.status = CAM_REQ_CMP_ERR;
- xpt_done(ccb);
- break;
-
- default:
- panic("%s: Unknown status %d in umass_cam_cb\n",
- USBDEVNAME(sc->sc_dev), status);
- }
-}
-
-/* Finalise a completed autosense operation
- */
-Static void
-umass_cam_sense_cb(struct umass_softc *sc, void *priv, int residue, int status)
-{
- union ccb *ccb = (union ccb *) priv;
- struct ccb_scsiio *csio = &ccb->csio; /* deref union */
-
- switch (status) {
- case STATUS_CMD_OK:
- case STATUS_CMD_UNKNOWN:
- /* Getting sense data succeeded. The length of the sense data
- * is not returned in any way. The sense data itself contains
- * the length of the sense data that is valid.
- */
- if (sc->quirks & RS_NO_CLEAR_UA
- && csio->cdb_io.cdb_bytes[0] == INQUIRY
- && (csio->sense_data.flags & SSD_KEY)
- == SSD_KEY_UNIT_ATTENTION) {
- /* Ignore unit attention errors in the case where
- * the Unit Attention state is not cleared on
- * REQUEST SENSE. They will appear again at the next
- * command.
- */
- ccb->ccb_h.status = CAM_REQ_CMP;
- } else if ((csio->sense_data.flags & SSD_KEY)
- == SSD_KEY_NO_SENSE) {
- /* No problem after all (in the case of CBI without
- * CCI)
- */
- ccb->ccb_h.status = CAM_REQ_CMP;
- } else {
- ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR
- | CAM_AUTOSNS_VALID;
- csio->scsi_status = SCSI_STATUS_CHECK_COND;
- }
- xpt_done(ccb);
- break;
-
- default:
- DPRINTF(UDMASS_SCSI, ("%s: Autosense failed, status %d\n",
- USBDEVNAME(sc->sc_dev), status));
- ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
- xpt_done(ccb);
- }
-}
-
-
-Static int
-umass_driver_load(module_t mod, int what, void *arg)
-{
- int err;
-
- switch (what) {
- case MOD_UNLOAD:
- err = umass_cam_detach_sim();
- if (err)
- return(err);
- return(usbd_driver_load(mod, what, arg));
- case MOD_LOAD:
- /* We don't attach to CAM at this point, because it will try
- * and malloc memory for it. This is not possible when the
- * boot loader loads umass as a module before the kernel
- * has been bootstrapped.
- */
- default:
- return(usbd_driver_load(mod, what, arg));
- }
-}
-
-
-
-/* (even the comment is missing) */
-
-DRIVER_MODULE(umass, uhub, umass_driver, umass_devclass, umass_driver_load, 0);
-
-
-/*
- * SCSI specific functions
- */
-
-Static int
-umass_scsi_transform(struct umass_softc *sc, unsigned char *cmd, int cmdlen,
- unsigned char **rcmd, int *rcmdlen)
-{
- *rcmd = cmd; /* trivial copy */
- *rcmdlen = cmdlen;
-
- switch (cmd[0]) {
- case TEST_UNIT_READY:
- if (sc->quirks & NO_TEST_UNIT_READY) {
- DPRINTF(UDMASS_SCSI, ("%s: Converted TEST_UNIT_READY "
- "to START_UNIT\n", USBDEVNAME(sc->sc_dev)));
- cmd[0] = START_STOP_UNIT;
- cmd[4] = SSS_START;
- }
- break;
- }
-
- return 1; /* success */
-}
-
-/*
- * UFI specific functions
- */
-
-Static int
-umass_ufi_transform(struct umass_softc *sc, unsigned char *cmd, int cmdlen,
- unsigned char **rcmd, int *rcmdlen)
-{
- *rcmd = cmd;
- /* A UFI command is always 12 bytes in length */
- /* XXX cmd[(cmdlen+1)..12] contains garbage */
- *rcmdlen = 12;
-
- switch (cmd[0]) {
- case TEST_UNIT_READY:
- if (sc->quirks & NO_TEST_UNIT_READY) {
- DPRINTF(UDMASS_UFI, ("%s: Converted TEST_UNIT_READY "
- "to START_UNIT\n", USBDEVNAME(sc->sc_dev)));
- cmd[0] = START_STOP_UNIT;
- cmd[4] = SSS_START;
- }
- return 1;
- case INQUIRY:
- case START_STOP_UNIT:
- case MODE_SENSE:
- case PREVENT_ALLOW:
- case READ_10:
- case READ_12:
- case READ_CAPACITY:
- case REQUEST_SENSE:
- case REZERO_UNIT:
- case POSITION_TO_ELEMENT: /* SEEK_10 */
- case SEND_DIAGNOSTIC:
- case WRITE_10:
- case WRITE_12:
- /* FORMAT_UNIT */
- /* MODE_SELECT */
- /* READ_FORMAT_CAPACITY */
- /* VERIFY */
- /* WRITE_AND_VERIFY */
- return 1; /* success */
- default:
- return 0; /* success */
- }
-}
-
-/*
- * 8070 specific functions
- */
-Static int
-umass_8070_transform(struct umass_softc *sc, unsigned char *cmd, int cmdlen,
- unsigned char **rcmd, int *rcmdlen)
-{
- return 0; /* failure */
-}
-
-#endif /* __FreeBSD__ */
-
#ifdef UMASS_DEBUG
Static void
@@ -3059,11 +1718,13 @@ umass_bbb_dump_cbw(struct umass_softc *sc, umass_bbb_cbw_t *cbw)
int tag = UGETDW(cbw->dCBWTag);
int flags = cbw->bCBWFlags;
- DPRINTF(UDMASS_BBB, ("%s: CBW %d: cmd = %db "
- "(0x%02x%02x%02x%02x%02x%02x%s), "
+ DPRINTF(UDMASS_BBB, ("%s: CBW %d: cmdlen=%d "
+ "(0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%s), "
"data = %d bytes, dir = %s\n",
USBDEVNAME(sc->sc_dev), tag, clen,
- c[0], c[1], c[2], c[3], c[4], c[5], (clen > 6? "...":""),
+ c[0], c[1], c[2], c[3], c[4], c[5],
+ c[6], c[7], c[8], c[9],
+ (clen > 10? "...":""),
dlen, (flags == CBWFLAGS_IN? "in":
(flags == CBWFLAGS_OUT? "out":"<invalid>"))));
}
@@ -3113,482 +1774,3 @@ umass_dump_buffer(struct umass_softc *sc, u_int8_t *buffer, int buflen,
USBDEVNAME(sc->sc_dev), s1, s2, s3));
}
#endif
-
-
-
-
-
-
-
-
-#if defined(__NetBSD__) || defined(__OpenBSD__)
-Static int
-umass_scsipi_cmd(xs)
- struct scsipi_xfer *xs;
-{
- struct scsipi_link *sc_link = xs->sc_link;
- struct umass_softc *sc = sc_link->adapter_softc;
- struct scsipi_generic *cmd, trcmd;
- int cmdlen;
- int dir;
-#ifdef UMASS_DEBUG
- microtime(&sc->tv);
-#endif
-
- memset(&trcmd, 0, sizeof(trcmd));
-
-#if defined(__NetBSD__)
- DIF(UDMASS_UPPER, sc_link->flags |= DEBUGLEVEL);
-#endif
-#if defined(__OpenBSD__)
- DIF(UDMASS_UPPER, sc_link->flags |= SCSIDEBUG_LEVEL);
-#endif
-
-#if defined(__NetBSD__) || defined(__OpenBSD__)
- DPRINTF(UDMASS_CMD, ("%s: umass_scsi_cmd: %d:%d xs=%p cmd=0x%02x "
- "(quirks=0x%x, poll=%d)\n", USBDEVNAME(sc->sc_dev),
- SCSI_LINK_TARGET(sc_link), SCSI_LINK_LUN(sc_link),
- xs, xs->cmd->opcode, sc_link->quirks,
- xs->xs_control & XS_CTL_POLL));
-#endif
-
-#if defined(USB_DEBUG) && defined(SCSIDEBUG)
- if (umassdebug & UDMASS_SCSI)
- show_scsipi_xs(xs);
- else if (umassdebug & ~UDMASS_CMD)
- show_scsipi_cmd(xs);
-#endif
-
- if (sc->sc_dying) {
- xs->error = XS_DRIVER_STUFFUP;
- goto done;
- }
-
-#ifdef UMASS_DEBUG
-#if defined(__NetBSD__)
- if ((sc_link->type == BUS_ATAPI ?
- sc_link->scsipi_atapi.drive : SCSI_LINK_TARGET(sc_link))
- != UMASS_SCSIID_DEVICE) {
- DPRINTF(UDMASS_SCSI, ("%s: wrong SCSI ID %d\n",
- USBDEVNAME(sc->sc_dev),
- SCSI_LINK_TARGET(sc_link)));
- xs->error = XS_DRIVER_STUFFUP;
- goto done;
- }
-#endif
-#if defined(__OpenBSD__)
- if (sc_link->target != UMASS_SCSIID_DEVICE) {
- DPRINTF(UDMASS_SCSI, ("%s: wrong SCSI ID %d\n",
- USBDEVNAME(sc->sc_dev),
- sc_link->target));
- xs->error = XS_DRIVER_STUFFUP;
- goto done;
- }
-#endif
-#endif
-
- cmd = xs->cmd;
-
- if (xs->cmd->opcode == SCSI_MODE_SENSE &&
- (sc_link->quirks & SDEV_NOMODESENSE)) {
- /*printf("%s: SCSI_MODE_SENSE\n", USBDEVNAME(sc->sc_dev));*/
- xs->error = XS_TIMEOUT;
- goto done;
- }
-
- if (xs->cmd->opcode == START_STOP &&
- (sc->quirks & NO_START_STOP)) {
- /*printf("%s: START_STOP\n", USBDEVNAME(sc->sc_dev));*/
- xs->error = XS_NOERROR;
- goto done;
- }
-
- if (xs->cmd->opcode == INQUIRY &&
- (sc->quirks & FORCE_SHORT_INQUIRY)) {
- memcpy(&trcmd, cmd, sizeof trcmd);
- trcmd.bytes[4] = SHORT_INQUIRY_LENGTH;
- cmd = &trcmd;
- }
-
- dir = DIR_NONE;
- if (xs->datalen) {
- switch (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
- case XS_CTL_DATA_IN:
- dir = DIR_IN;
- break;
- case XS_CTL_DATA_OUT:
- dir = DIR_OUT;
- break;
- }
- }
-
- if (xs->datalen > UMASS_MAX_TRANSFER_SIZE) {
- printf("umass_cmd: large datalen, %d\n", xs->datalen);
- xs->error = XS_DRIVER_STUFFUP;
- goto done;
- }
-
- cmdlen = xs->cmdlen;
- if (sc->proto & PROTO_UFI) {
- if (!umass_ufi_transform(sc, cmd, cmdlen, &trcmd, &cmdlen)) {
- xs->error = XS_DRIVER_STUFFUP;
- goto done;
- }
- cmd= &trcmd;
- }
-
- if (sc->proto & PROTO_ATAPI) {
- bcopy(cmd, &trcmd, cmdlen);
- cmd = &trcmd;
- cmdlen = ATAPI_COMMAND_LENGTH;
- }
-
- if (xs->xs_control & XS_CTL_POLL) {
- /* Use sync transfer. XXX Broken! */
- DPRINTF(UDMASS_SCSI, ("umass_scsi_cmd: sync dir=%d\n", dir));
- sc->sc_xfer_flags = USBD_SYNCHRONOUS;
- sc->sc_sync_status = USBD_INVAL;
- sc->transfer(sc, SCSI_LINK_LUN(sc_link), cmd, cmdlen,
- xs->data, xs->datalen, dir, 0, xs);
- sc->sc_xfer_flags = 0;
- DPRINTF(UDMASS_SCSI, ("umass_scsi_cmd: done err=%d\n",
- sc->sc_sync_status));
- switch (sc->sc_sync_status) {
- case USBD_NORMAL_COMPLETION:
- xs->error = XS_NOERROR;
- break;
- case USBD_TIMEOUT:
- xs->error = XS_TIMEOUT;
- break;
- default:
- xs->error = XS_DRIVER_STUFFUP;
- break;
- }
- goto done;
- } else {
- DPRINTF(UDMASS_SCSI, ("umass_scsi_cmd: async dir=%d, cmdlen=%d"
- " datalen=%d\n",
- dir, cmdlen, xs->datalen));
- sc->transfer(sc, SCSI_LINK_LUN(sc_link), cmd, cmdlen,
- xs->data, xs->datalen, dir, umass_scsipi_cb, xs);
- return (SUCCESSFULLY_QUEUED);
- }
-
- /* Return if command finishes early. */
- done:
-#if defined(__NetBSD__)
- xs->xs_status |= XS_STS_DONE;
-#endif
-#if defined(__OpenBSD__)
- xs->flags |= ITSDONE;
-#endif
-
- scsipi_done(xs);
- if (xs->xs_control & XS_CTL_POLL)
- return (COMPLETE);
- else
- return (SUCCESSFULLY_QUEUED);
-}
-
-Static void
-umass_scsipi_minphys(bp)
- struct buf *bp;
-{
- if (bp->b_bcount > UMASS_MAX_TRANSFER_SIZE)
- bp->b_bcount = UMASS_MAX_TRANSFER_SIZE;
- minphys(bp);
-}
-
-int
-umass_scsipi_ioctl(link, cmd, arg, flag, p)
- struct scsipi_link *link;
- u_long cmd;
- caddr_t arg;
- int flag;
- struct proc *p;
-{
- /*struct umass_softc *sc = link->adapter_softc;*/
-
- switch (cmd) {
-#if 0
- case SCBUSIORESET:
- ccb->ccb_h.status = CAM_REQ_INPROG;
- umass_reset(sc, umass_cam_cb, (void *) ccb);
- return (0);
-#endif
- default:
- return (ENOTTY);
- }
-}
-
-Static void
-umass_scsipi_cb(struct umass_softc *sc, void *priv, int residue, int status)
-{
- struct scsipi_xfer *xs = priv;
- struct scsipi_link *sc_link = xs->sc_link;
- int cmdlen;
- int s;
-#ifdef UMASS_DEBUG
- struct timeval tv;
- u_int delta;
- microtime(&tv);
- delta = (tv.tv_sec - sc->tv.tv_sec) * 1000000 + tv.tv_usec - sc->tv.tv_usec;
-#endif
-
- DPRINTF(UDMASS_CMD,("umass_scsipi_cb: at %lu.%06lu, delta=%u: xs=%p residue=%d"
- " status=%d\n", tv.tv_sec, tv.tv_usec, delta, xs, residue, status));
- xs->resid = residue;
-
- switch (status) {
- case STATUS_CMD_OK:
- xs->error = XS_NOERROR;
- break;
-
- case STATUS_CMD_UNKNOWN:
- case STATUS_CMD_FAILED:
- /* fetch sense data */
- memset(&sc->sc_sense_cmd, 0, sizeof(sc->sc_sense_cmd));
- sc->sc_sense_cmd.opcode = REQUEST_SENSE;
- sc->sc_sense_cmd.byte2 = SCSI_LINK_LUN(sc_link) <<
- SCSI_CMD_LUN_SHIFT;
- sc->sc_sense_cmd.length = sizeof(xs->sense);
-
- cmdlen = sizeof(sc->sc_sense_cmd);
- if (sc->proto & PROTO_UFI)
- cmdlen = UFI_COMMAND_LENGTH;
- else if (sc->proto & PROTO_ATAPI)
- cmdlen = ATAPI_COMMAND_LENGTH;
-
- sc->transfer(sc, SCSI_LINK_LUN(sc_link),
- &sc->sc_sense_cmd, cmdlen,
- &xs->sense, sizeof(xs->sense), DIR_IN,
- umass_scsipi_sense_cb, xs);
- return;
-
- case STATUS_WIRE_FAILED:
- xs->error = XS_RESET;
- break;
-
- default:
- panic("%s: Unknown status %d in umass_scsipi_cb\n",
- USBDEVNAME(sc->sc_dev), status);
- }
-
-#if defined(__NetBSD__)
- xs->xs_status |= XS_STS_DONE;
-#endif
-#if defined(__OpenBSD__)
- xs->flags |= ITSDONE;
-#endif
-
- DPRINTF(UDMASS_CMD,("umass_scsipi_cb: at %lu.%06lu: return xs->error="
- "%d, xs->xs_status=0x%x xs->resid=%d\n",
- tv.tv_sec, tv.tv_usec,
- xs->error, xs->xs_status, xs->resid));
-
- s = splbio();
- scsipi_done(xs);
- splx(s);
-}
-
-/*
- * Finalise a completed autosense operation
- */
-Static void
-umass_scsipi_sense_cb(struct umass_softc *sc, void *priv, int residue,
- int status)
-{
- struct scsipi_xfer *xs = priv;
- int s;
- int bytes_received;
-
- DPRINTF(UDMASS_CMD,("umass_scsipi_sense_cb: xs=%p residue=%d "
- "status=%d\n", xs, residue, status));
-
- switch (status) {
- case STATUS_CMD_OK:
- case STATUS_CMD_UNKNOWN:
- /* getting sense data succeeded */
- if ((xs->cmd->opcode == INQUIRY)
- && (xs->resid < xs->datalen)) {
- /* Some drivers return SENSE errors even after INQUIRY
- * The upper layer doesn't like that.
- */
- xs->error = XS_NOERROR;
- break;
- }
-
- bytes_received = sizeof(xs->sense) - residue;
-
- if (bytes_received < 8 ||
- (bytes_received < xs->sense.extra_len + 8))
- xs->error = XS_SHORTSENSE;
- else
- xs->error = XS_SENSE;
-
-#if defined(__OpenBSD__)
- /* Note that this test may need to be revised
- with QIC-157a/SCSI tape drives that return
- ILI, EOM in the high bits of flags.
- */
- if ((xs->sense.error_code & SSD_ERRCODE) == 0x70 &&
- (xs->sense.flags == 0))
- xs->error = XS_NOERROR;
-#endif
-
- break;
- default:
- DPRINTF(UDMASS_SCSI, ("%s: Autosense failed, status %d\n",
- USBDEVNAME(sc->sc_dev), status));
- xs->error = XS_DRIVER_STUFFUP;
- break;
- }
-
-#if defined(__NetBSD__)
- xs->xs_status |= XS_STS_DONE;
-#endif
-#if defined(__OpenBSD__)
- xs->flags |= ITSDONE;
-#endif
-
- DPRINTF(UDMASS_CMD,("umass_scsipi_sense_cb: return xs->error=%d, "
- "xs->xs_status=0x%x xs->resid=%d\n", xs->error, xs->xs_status,
- xs->resid));
-
- s = splbio();
- scsipi_done(xs);
- splx(s);
-}
-
-/*
- * UFI specific functions
- */
-
-Static int
-umass_ufi_transform(struct umass_softc *sc, struct scsipi_generic *cmd,
- int cmdlen, struct scsipi_generic *rcmd, int *rcmdlen)
-{
- *rcmdlen = UFI_COMMAND_LENGTH;
- memset(rcmd, 0, sizeof *rcmd);
-
- /* Handle any quirks */
- if (cmd->opcode == TEST_UNIT_READY
- && (sc->quirks & NO_TEST_UNIT_READY)) {
- /*
- * Some devices do not support this command.
- * Start Stop Unit should give the same results
- */
- DPRINTF(UDMASS_UFI, ("%s: Converted TEST_UNIT_READY "
- "to START_UNIT\n", USBDEVNAME(sc->sc_dev)));
- rcmd->opcode = START_STOP;
- rcmd->bytes[3] = SSS_START;
- return 1;
- }
-
- switch (cmd->opcode) {
- /* Commands of which the format has been verified. They should work. */
- case TEST_UNIT_READY:
- case SCSI_REZERO_UNIT:
- case REQUEST_SENSE:
- case INQUIRY:
- case START_STOP:
- /*case SEND_DIAGNOSTIC: ??*/
- case PREVENT_ALLOW:
- case READ_CAPACITY:
- case READ_BIG:
- case WRITE_BIG:
- case POSITION_TO_ELEMENT: /* SEEK_10 */
- case SCSI_MODE_SELECT_BIG:
- case SCSI_MODE_SENSE_BIG:
- default:
- /* Copy the command into the (zeroed out) destination buffer */
- memcpy(rcmd, cmd, cmdlen);
- return (1); /* success */
-
- /*
- * Other UFI commands: FORMAT_UNIT, MODE_SELECT, READ_FORMAT_CAPACITY,
- * VERIFY, WRITE_AND_VERIFY.
- * These should be checked whether they somehow can be made to fit.
- */
-
- /* These commands are known _not_ to work. They should be converted. */
- case SCSI_READ_COMMAND:
- case SCSI_WRITE_COMMAND:
- case SCSI_MODE_SENSE:
- case SCSI_MODE_SELECT:
- printf("%s: Unsupported UFI command 0x%02x",
- USBDEVNAME(sc->sc_dev), cmd->opcode);
- if (cmdlen == 6)
- printf(", 6 byte command should have been converted");
- printf("\n");
- return (0); /* failure */
- }
-}
-
-
-#if NATAPIBUS > 0
-Static void
-umass_atapi_probedev(atapi, target)
- struct atapibus_softc *atapi;
- int target;
-{
- struct scsipi_link *sc_link;
- struct scsipibus_attach_args sa;
- struct ata_drive_datas *drvp = &atapi->sc_drvs[target];
- char vendor[33], product[65], revision[17];
- struct scsipi_inquiry_data inqbuf;
-
- DPRINTF(UDMASS_SCSI,("umass_atapi_probedev: atapi=%p target=%d\n",
- atapi, target));
-
- if (atapi->sc_link[target])
- return;
-
- sc_link = malloc(sizeof(*sc_link), M_DEVBUF, M_NOWAIT);
- if (sc_link == NULL) {
- printf("%s: can't allocate link for drive %d\n",
- atapi->sc_dev.dv_xname, target);
- return;
- }
- *sc_link = *atapi->adapter_link;
-
- DIF(UDMASS_UPPER, sc_link->flags |= DEBUGLEVEL);
-
- /* Fill generic parts of the link. */
- sc_link->active = 0;
- sc_link->scsipi_atapi.drive = target;
- sc_link->device = &umass_dev;
- TAILQ_INIT(&sc_link->pending_xfers);
-
- DPRINTF(UDMASS_SCSI, ("umass_atapi_probedev: doing inquiry\n"));
- /* Now go ask the device all about itself. */
- memset(&inqbuf, 0, sizeof(inqbuf));
- if (scsipi_inquire(sc_link, &inqbuf, XS_CTL_DISCOVERY) != 0)
- goto bad;
-
- scsipi_strvis(vendor, 33, inqbuf.vendor, 8);
- scsipi_strvis(product, 65, inqbuf.product, 16);
- scsipi_strvis(revision, 17, inqbuf.revision, 4);
-
- sa.sa_sc_link = sc_link;
- sa.sa_inqbuf.type = inqbuf.device;
- sa.sa_inqbuf.removable = inqbuf.dev_qual2 & SID_REMOVABLE ?
- T_REMOV : T_FIXED;
- if (sa.sa_inqbuf.removable)
- sc_link->flags |= SDEV_REMOVABLE;
- /* XXX how? sc_link->scsipi_atapi.cap |= ACAP_LEN;*/
- sa.sa_inqbuf.vendor = vendor;
- sa.sa_inqbuf.product = product;
- sa.sa_inqbuf.revision = revision;
- sa.sa_inqptr = NULL;
-
- drvp->drv_softc = atapi_probedev(atapi, target, sc_link, &sa);
- /* atapi_probedev() frees the scsipi_link when there is no device. */
- return;
-
-bad:
- free(sc_link, M_DEVBUF);
- return;
-}
-#endif
-#endif
diff --git a/sys/dev/usb/umass_isdata.c b/sys/dev/usb/umass_isdata.c
new file mode 100644
index 00000000000..bd5a73562dd
--- /dev/null
+++ b/sys/dev/usb/umass_isdata.c
@@ -0,0 +1,589 @@
+/* $NetBSD: umass_isdata.c,v 1.1 2001/12/24 13:43:25 augustss Exp $ */
+
+/*
+ * TODO:
+ * get ATA registers on any kind of error
+ * implement more commands (what is needed)
+ */
+
+/*
+ * Copyright (c) 2001 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.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: umass_isdata.c,v 1.1 2001/12/24 13:43:25 augustss Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/buf.h>
+#include <sys/device.h>
+#include <sys/proc.h>
+#include <sys/disklabel.h>
+#include <sys/malloc.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+
+#include <dev/usb/umassvar.h>
+#include <dev/usb/umass_isdata.h>
+
+int umass_wd_attach(struct umass_softc *);
+
+#include <dev/ata/atareg.h>
+#include <dev/ata/atavar.h>
+#include <dev/ata/wdvar.h>
+#include <dev/ic/wdcreg.h>
+
+/* XXX move this */
+struct isd200_config {
+ uByte EventNotification;
+ uByte ExternalClock;
+ uByte ATAInitTimeout;
+ uByte ATAMisc1;
+#define ATATiming 0x0f
+#define ATAPIReset 0x10
+#define MasterSlaveSelection 0x20
+#define ATAPICommandBlockSize 0xc0
+ uByte ATAMajorCommand;
+ uByte ATAMinorCommand;
+ uByte ATAMisc2;
+#define LastLUNIdentifier 0x07
+#define DescriptOverride 0x08
+#define ATA3StateSuspend 0x10
+#define SkipDeviceBoot 0x20
+#define ConfigDescriptor2 0x40
+#define InitStatus 0x80
+ uByte ATAMisc3;
+#define SRSTEnable 0x01
+};
+
+struct uisdata_softc {
+ struct umassbus_softc base;
+
+ struct ata_drive_datas sc_drv_data;
+ struct isd200_config sc_isd_config;
+ void *sc_ata_bio;
+ u_long sc_skip;
+};
+
+#undef DPRINTF
+#undef DPRINTFN
+#ifdef UISDATA_DEBUG
+#define DPRINTF(x) if (uisdatadebug) logprintf x
+#define DPRINTFN(n,x) if (uisdatadebug>(n)) logprintf x
+int uisdatadebug = 0;
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n,x)
+#endif
+
+int uisdata_bio(struct ata_drive_datas *, struct ata_bio *);
+int uisdata_bio1(struct ata_drive_datas *, struct ata_bio *);
+void uisdata_reset_channel(struct ata_drive_datas *);
+int uisdata_exec_command(struct ata_drive_datas *, struct wdc_command *);
+int uisdata_get_params(struct ata_drive_datas *, u_int8_t, struct ataparams *);
+int uisdata_addref(struct ata_drive_datas *);
+void uisdata_delref(struct ata_drive_datas *);
+void uisdata_kill_pending(struct ata_drive_datas *);
+
+void uisdata_bio_cb(struct umass_softc *, void *, int, int);
+void uisdata_exec_cb(struct umass_softc *, void *, int, int);
+int uwdprint(void *, const char *);
+
+const struct ata_bustype uisdata_bustype = {
+ SCSIPI_BUSTYPE_ATA,
+ uisdata_bio,
+ uisdata_reset_channel,
+ uisdata_exec_command,
+ uisdata_get_params,
+ uisdata_addref,
+ uisdata_delref,
+ uisdata_kill_pending,
+};
+
+struct ata_cmd {
+ u_int8_t ac_signature0;
+ u_int8_t ac_signature1;
+
+ u_int8_t ac_action_select;
+#define AC_ReadRegisterAccess 0x01
+#define AC_NoDeviceSelectionBit 0x02
+#define AC_NoBSYPollBit 0x04
+#define AC_IgnorePhaseErrorBit 0x08
+#define AC_IgnoreDeviceErrorBit 0x10
+
+ u_int8_t ac_register_select;
+#define AC_SelectAlternateStatus 0x01 /* R */
+#define AC_SelectDeviceControl 0x01 /* W */
+#define AC_SelectError 0x02 /* R */
+#define AC_SelectFeatures 0x02 /* W */
+#define AC_SelectSectorCount 0x04 /* RW */
+#define AC_SelectSectorNumber 0x08 /* RW */
+#define AC_SelectCylinderLow 0x10 /* RW */
+#define AC_SelectCylinderHigh 0x20 /* RW */
+#define AC_SelectDeviceHead 0x40 /* RW */
+#define AC_SelectStatus 0x80 /* R */
+#define AC_SelectCommand 0x80 /* W */
+
+ u_int8_t ac_transfer_blocksize;
+
+ u_int8_t ac_alternate_status;
+#define ac_device_control ac_alternate_status
+ u_int8_t ac_error;
+#define ac_features ac_error
+
+ u_int8_t ac_sector_count;
+ u_int8_t ac_sector_number;
+ u_int8_t ac_cylinder_low;
+ u_int8_t ac_cylinder_high;
+ u_int8_t ac_device_head;
+
+ u_int8_t ac_status;
+#define ac_command ac_status
+
+ u_int8_t ac_reserved[3];
+};
+
+#define ATA_DELAY 10000 /* 10s for a drive I/O */
+
+int
+umass_isdata_attach(struct umass_softc *sc)
+{
+ usb_device_request_t req;
+ usbd_status err;
+ struct ata_device adev;
+ struct uisdata_softc *scbus;
+ struct isd200_config *cf;
+
+ scbus = malloc(sizeof *scbus, M_DEVBUF, M_WAITOK | M_ZERO);
+ sc->bus = &scbus->base;
+ cf = &scbus->sc_isd_config;
+
+ req.bmRequestType = UT_READ_VENDOR_DEVICE;
+ req.bRequest = 0x02;
+ USETW(req.wValue, 0);
+ USETW(req.wIndex, 2);
+ USETW(req.wLength, sizeof *cf);
+
+ err = usbd_do_request(sc->sc_udev, &req, cf);
+ if (err)
+ return (EIO);
+ DPRINTF(("umass_wd_attach info:\n EventNotification=0x%02x "
+ "ExternalClock=0x%02x ATAInitTimeout=0x%02x\n"
+ " ATAMisc1=0x%02x ATAMajorCommand=0x%02x "
+ "ATAMinorCommand=0x%02x\n"
+ " ATAMisc2=0x%02x ATAMisc3=0x%02x\n",
+ cf->EventNotification, cf->ExternalClock, cf->ATAInitTimeout,
+ cf->ATAMisc1, cf->ATAMajorCommand, cf->ATAMinorCommand,
+ cf->ATAMisc2, cf->ATAMisc3));
+
+ memset(&adev, 0, sizeof(struct ata_device));
+ adev.adev_bustype = &uisdata_bustype;
+ adev.adev_channel = 1; /* XXX */
+ adev.adev_openings = 1;
+ adev.adev_drv_data = &scbus->sc_drv_data;
+ scbus->sc_drv_data.drive_flags = DRIVE_ATA;
+ scbus->sc_drv_data.chnl_softc = sc;
+ scbus->base.sc_child = config_found(&sc->sc_dev, &adev, uwdprint);
+
+ return (0);
+}
+
+
+void
+uisdata_bio_cb(struct umass_softc *sc, void *priv, int residue, int status)
+{
+ struct uisdata_softc *scbus = (struct uisdata_softc *)sc->bus;
+ struct ata_bio *ata_bio = priv;
+ int s;
+
+ DPRINTF(("%s: residue=%d status=%d\n", __FUNCTION__, residue, status));
+
+ s = splbio();
+ scbus->sc_ata_bio = NULL;
+ if (status != STATUS_CMD_OK)
+ ata_bio->error = ERR_DF; /* ??? */
+ else
+ ata_bio->error = NOERROR;
+ ata_bio->flags |= ATA_ITSDONE;
+
+ ata_bio->blkdone += ata_bio->nblks;
+ ata_bio->blkno += ata_bio->nblks;
+ ata_bio->bcount -= ata_bio->nbytes;
+ scbus->sc_skip += ata_bio->nbytes;
+ if (residue != 0) {
+ ata_bio->bcount += residue;
+ } else if (ata_bio->bcount > 0) {
+ DPRINTF(("%s: continue\n", __FUNCTION__));
+ (void)uisdata_bio1(&scbus->sc_drv_data, ata_bio); /*XXX save drv*/
+ splx(s);
+ return;
+ }
+
+ if (ata_bio->flags & ATA_POLL) {
+ DPRINTF(("%s: wakeup %p\n", __FUNCTION__, ata_bio));
+ wakeup(ata_bio);
+ } else {
+ wddone(scbus->sc_drv_data.drv_softc);
+ }
+ splx(s);
+}
+
+int
+uisdata_bio(struct ata_drive_datas *drv, struct ata_bio *ata_bio)
+{
+ struct umass_softc *sc = drv->chnl_softc;
+ struct uisdata_softc *scbus = (struct uisdata_softc *)sc->bus;
+
+ scbus->sc_skip = 0;
+ return (uisdata_bio1(drv, ata_bio));
+}
+
+int
+uisdata_bio1(struct ata_drive_datas *drv, struct ata_bio *ata_bio)
+{
+ struct umass_softc *sc = drv->chnl_softc;
+ struct uisdata_softc *scbus = (struct uisdata_softc *)sc->bus;
+ struct isd200_config *cf = &scbus->sc_isd_config;
+ struct ata_cmd ata;
+ u_int16_t cyl;
+ u_int8_t head, sect;
+ int dir;
+ long nbytes;
+ u_int nblks;
+
+ DPRINTF(("%s\n", __FUNCTION__));
+ /* XXX */
+
+ if (ata_bio->flags & ATA_NOSLEEP) {
+ printf("%s: ATA_NOSLEEP not supported\n", __FUNCTION__);
+ ata_bio->error = TIMEOUT;
+ ata_bio->flags |= ATA_ITSDONE;
+ return (WDC_COMPLETE);
+ }
+
+ if (scbus->sc_ata_bio != NULL) {
+ printf("%s: multiple uisdata_bio\n", __FUNCTION__);
+ return (WDC_TRY_AGAIN);
+ } else
+ scbus->sc_ata_bio = ata_bio;
+
+ if (ata_bio->flags & ATA_LBA) {
+ sect = (ata_bio->blkno >> 0) & 0xff;
+ cyl = (ata_bio->blkno >> 8) & 0xffff;
+ head = (ata_bio->blkno >> 24) & 0x0f;
+ head |= WDSD_LBA;
+ } else {
+ int blkno = ata_bio->blkno;
+ sect = blkno % ata_bio->lp->d_nsectors;
+ sect++; /* Sectors begin with 1, not 0. */
+ blkno /= ata_bio->lp->d_nsectors;
+ head = blkno % ata_bio->lp->d_ntracks;
+ blkno /= ata_bio->lp->d_ntracks;
+ cyl = blkno;
+ head |= WDSD_CHS;
+ }
+
+ nbytes = ata_bio->bcount;
+ if (ata_bio->flags & ATA_SINGLE)
+ nblks = 1;
+ else
+ nblks = min(ata_bio->multi, nbytes / ata_bio->lp->d_secsize);
+ nbytes = nblks * ata_bio->lp->d_secsize;
+ ata_bio->nblks = nblks;
+ ata_bio->nbytes = nbytes;
+
+ memset(&ata, 0, sizeof ata);
+ ata.ac_signature0 = cf->ATAMajorCommand;
+ ata.ac_signature1 = cf->ATAMinorCommand;
+ ata.ac_transfer_blocksize = 1;
+ ata.ac_sector_count = nblks;
+ ata.ac_sector_number = sect;
+ ata.ac_cylinder_high = cyl >> 8;
+ ata.ac_cylinder_low = cyl;
+ ata.ac_device_head = head;
+ ata.ac_register_select = AC_SelectSectorCount | AC_SelectSectorNumber |
+ AC_SelectCylinderLow | AC_SelectCylinderHigh | AC_SelectDeviceHead |
+ AC_SelectCommand;
+
+ dir = DIR_NONE;
+ if (ata_bio->bcount != 0) {
+ if (ata_bio->flags & ATA_READ)
+ dir = DIR_IN;
+ else
+ dir = DIR_OUT;
+ }
+
+ if (ata_bio->flags & ATA_READ) {
+ ata.ac_command = WDCC_READ;
+ } else {
+ ata.ac_command = WDCC_WRITE;
+ }
+ DPRINTF(("%s: bno=%d LBA=%d cyl=%d head=%d sect=%d count=%d multi=%d\n",
+ __FUNCTION__, ata_bio->blkno,
+ (ata_bio->flags & ATA_LBA) != 0, cyl, head, sect,
+ ata.ac_sector_count, ata_bio->multi));
+ DPRINTF((" data=%p bcount=%ld, drive=%d\n", ata_bio->databuf,
+ ata_bio->bcount, drv->drive));
+ sc->sc_methods->wire_xfer(sc, drv->drive, &ata, sizeof ata,
+ ata_bio->databuf + scbus->sc_skip, nbytes,
+ dir, ATA_DELAY, uisdata_bio_cb, ata_bio);
+
+ while (ata_bio->flags & ATA_POLL) {
+ DPRINTF(("%s: tsleep %p\n", __FUNCTION__, ata_bio));
+ if (tsleep(ata_bio, PZERO, "uisdatabl", 0)) {
+ ata_bio->error = TIMEOUT;
+ ata_bio->flags |= ATA_ITSDONE;
+ return (WDC_COMPLETE);
+ }
+ }
+
+ return (ata_bio->flags & ATA_ITSDONE) ? WDC_COMPLETE : WDC_QUEUED;
+}
+
+void
+uisdata_reset_channel(struct ata_drive_datas *drv)
+{
+ DPRINTFN(-1,("%s\n", __FUNCTION__));
+ /* XXX what? */
+}
+
+void
+uisdata_exec_cb(struct umass_softc *sc, void *priv, int residue, int status)
+{
+ struct wdc_command *cmd = priv;
+
+ DPRINTF(("%s: status=%d\n", __FUNCTION__, status));
+ if (status != STATUS_CMD_OK)
+ cmd->flags |= AT_DF; /* XXX */
+ cmd->flags |= AT_DONE;
+ if (cmd->flags & (AT_POLL | AT_WAIT)) {
+ DPRINTF(("%s: wakeup %p\n", __FUNCTION__, cmd));
+ wakeup(cmd);
+ }
+}
+
+int
+uisdata_exec_command(struct ata_drive_datas *drv, struct wdc_command *cmd)
+{
+ struct umass_softc *sc = drv->chnl_softc;
+ struct uisdata_softc *scbus = (struct uisdata_softc *)sc->bus;
+ struct isd200_config *cf = &scbus->sc_isd_config;
+ int dir;
+ struct ata_cmd ata;
+
+ DPRINTF(("%s\n", __FUNCTION__));
+ DPRINTF((" r_command=0x%02x timeout=%d flags=0x%x bcount=%d\n",
+ cmd->r_command, cmd->timeout, cmd->flags, cmd->bcount));
+
+ dir = DIR_NONE;
+ if (cmd->bcount != 0) {
+ if (cmd->flags & AT_READ)
+ dir = DIR_IN;
+ else
+ dir = DIR_OUT;
+ }
+
+ if (cmd->bcount > UMASS_MAX_TRANSFER_SIZE) {
+ printf("uisdata_exec_command: large datalen %d\n", cmd->bcount);
+ cmd->flags |= AT_ERROR;
+ goto done;
+ }
+
+ memset(&ata, 0, sizeof ata);
+ ata.ac_signature0 = cf->ATAMajorCommand;
+ ata.ac_signature1 = cf->ATAMinorCommand;
+ ata.ac_transfer_blocksize = 1;
+
+ switch (cmd->r_command) {
+ case WDCC_IDENTIFY:
+ ata.ac_register_select |= AC_SelectCommand;
+ ata.ac_command = WDCC_IDENTIFY;
+ break;
+ default:
+ printf("uisdata_exec_command: bad command 0x%02x\n",
+ cmd->r_command);
+ cmd->flags |= AT_ERROR;
+ goto done;
+ }
+
+ DPRINTF(("%s: execute ATA command 0x%02x, drive=%d\n", __FUNCTION__,
+ ata.ac_command, drv->drive));
+ sc->sc_methods->wire_xfer(sc, drv->drive, &ata,
+ sizeof ata, cmd->data, cmd->bcount, dir,
+ cmd->timeout, uisdata_exec_cb, cmd);
+ if (cmd->flags & (AT_POLL | AT_WAIT)) {
+#if 0
+ if (cmd->flags & AT_POLL)
+ printf("%s: AT_POLL not supported\n", __FUNCTION__);
+#endif
+ DPRINTF(("%s: tsleep %p\n", __FUNCTION__, cmd));
+ if (tsleep(cmd, PZERO, "uisdataex", 0)) {
+ cmd->flags |= AT_ERROR;
+ goto done;
+ }
+ }
+
+done:
+ return (WDC_COMPLETE);
+}
+
+int
+uisdata_addref(struct ata_drive_datas *drv)
+{
+ DPRINTF(("%s\n", __FUNCTION__));
+ /* Nothing to do */
+ return (0);
+}
+
+void
+uisdata_delref(struct ata_drive_datas *drv)
+{
+ DPRINTF(("%s\n", __FUNCTION__));
+ /* Nothing to do */
+}
+
+void
+uisdata_kill_pending(struct ata_drive_datas *drv)
+{
+ struct umass_softc *sc = drv->chnl_softc;
+ struct uisdata_softc *scbus = (struct uisdata_softc *)sc->bus;
+ struct ata_bio *ata_bio = scbus->sc_ata_bio;
+
+ DPRINTFN(-1,("%s\n", __FUNCTION__));
+
+ if (ata_bio == NULL)
+ return;
+ scbus->sc_ata_bio = NULL;
+ ata_bio->flags |= ATA_ITSDONE;
+ ata_bio->error = ERR_NODEV;
+ ata_bio->r_error = WDCE_ABRT;
+ wddone(scbus->sc_drv_data.drv_softc);
+}
+
+int
+uisdata_get_params(struct ata_drive_datas *drvp, u_int8_t flags,
+ struct ataparams *prms)
+{
+ char tb[DEV_BSIZE];
+ struct wdc_command wdc_c;
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+ int i;
+ u_int16_t *p;
+#endif
+
+ DPRINTF(("%s\n", __FUNCTION__));
+
+ memset(tb, 0, DEV_BSIZE);
+ memset(prms, 0, sizeof(struct ataparams));
+ memset(&wdc_c, 0, sizeof(struct wdc_command));
+
+ wdc_c.r_command = WDCC_IDENTIFY;
+ wdc_c.timeout = 1000; /* 1s */
+ wdc_c.flags = AT_READ | flags;
+ wdc_c.data = tb;
+ wdc_c.bcount = DEV_BSIZE;
+ if (uisdata_exec_command(drvp, &wdc_c) != WDC_COMPLETE) {
+ DPRINTF(("uisdata_get_parms: wdc_exec_command failed\n"));
+ return (CMD_AGAIN);
+ }
+ if (wdc_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
+ DPRINTF(("uisdata_get_parms: wdc_c.flags=0x%x\n",
+ wdc_c.flags));
+ return (CMD_ERR);
+ } else {
+ /* Read in parameter block. */
+ memcpy(prms, tb, sizeof(struct ataparams));
+#if BYTE_ORDER == LITTLE_ENDIAN
+ /* XXX copied from ata.c */
+ /*
+ * Shuffle string byte order.
+ * ATAPI Mitsumi and NEC drives don't need this.
+ */
+ if ((prms->atap_config & WDC_CFG_ATAPI_MASK) ==
+ WDC_CFG_ATAPI &&
+ ((prms->atap_model[0] == 'N' &&
+ prms->atap_model[1] == 'E') ||
+ (prms->atap_model[0] == 'F' &&
+ prms->atap_model[1] == 'X')))
+ return 0;
+ for (i = 0; i < sizeof(prms->atap_model); i += 2) {
+ p = (u_short *)(prms->atap_model + i);
+ *p = ntohs(*p);
+ }
+ for (i = 0; i < sizeof(prms->atap_serial); i += 2) {
+ p = (u_short *)(prms->atap_serial + i);
+ *p = ntohs(*p);
+ }
+ for (i = 0; i < sizeof(prms->atap_revision); i += 2) {
+ p = (u_short *)(prms->atap_revision + i);
+ *p = ntohs(*p);
+ }
+#endif
+ return CMD_OK;
+ }
+}
+
+
+/* XXX join with wdc.c routine? */
+int
+uwdprint(void *aux, const char *pnp)
+{
+ //struct ata_device *adev = aux;
+ if (pnp)
+ printf("wd at %s", pnp);
+#if 0
+ printf(" channel %d drive %d", adev->adev_channel,
+ adev->adev_drv_data->drive);
+#endif
+ return (UNCONF);
+}
+
+
+#if 0
+
+int umass_wd_attach(struct umass_softc *);
+
+#if NWD > 0
+ case UMASS_CPROTO_ISD_ATA:
+ return (umass_wd_attach(sc));
+#endif
+
+#endif
diff --git a/sys/dev/usb/umass_isdata.h b/sys/dev/usb/umass_isdata.h
new file mode 100644
index 00000000000..665922192a4
--- /dev/null
+++ b/sys/dev/usb/umass_isdata.h
@@ -0,0 +1,40 @@
+/* $NetBSD: umass_isdata.h,v 1.1 2001/12/24 13:43:25 augustss Exp $ */
+
+/*
+ * Copyright (c) 2001 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.
+ */
+
+int umass_isdata_attach(struct umass_softc *sc);
diff --git a/sys/dev/usb/umass_quirks.c b/sys/dev/usb/umass_quirks.c
new file mode 100644
index 00000000000..5cf42653814
--- /dev/null
+++ b/sys/dev/usb/umass_quirks.c
@@ -0,0 +1,333 @@
+/* $OpenBSD: umass_quirks.c,v 1.1 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: umass_quirks.c,v 1.13 2002/04/22 12:48:40 augustss Exp $ */
+
+/*
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by MAEKAWA Masahide (gehenna@NetBSD.org).
+ *
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/buf.h>
+
+#if defined(__NetBSD__)
+#include <dev/scsipi/scsipi_all.h> /* for scsiconf.h below */
+#include <dev/scsipi/scsiconf.h> /* for quirks defines */
+#endif
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdevs.h>
+
+#include <dev/usb/umassvar.h>
+#include <dev/usb/umass_quirks.h>
+
+Static usbd_status umass_init_insystem(struct umass_softc *);
+Static usbd_status umass_init_shuttle(struct umass_softc *);
+
+Static void umass_fixup_sony(struct umass_softc *);
+Static void umass_fixup_yedata(struct umass_softc *);
+
+Static const struct umass_quirk umass_quirks[] = {
+ { { USB_VENDOR_FUJIPHOTO, USB_PRODUCT_FUJIPHOTO_MASS0100 },
+ UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC,
+ UMASS_QUIRK_NO_START_STOP,
+ PQUIRK_NOTUR | PQUIRK_NOSENSE,
+ UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO,
+ NULL, NULL
+ },
+
+ { { USB_VENDOR_INSYSTEM, USB_PRODUCT_INSYSTEM_USBCABLE },
+ UMASS_WPROTO_CBI, UMASS_CPROTO_ATAPI,
+ UMASS_QUIRK_NO_START_STOP,
+ PQUIRK_NOTUR,
+ UMATCH_VENDOR_PRODUCT,
+ umass_init_insystem, NULL
+ },
+
+ { { USB_VENDOR_IOMEGA, USB_PRODUCT_IOMEGA_ZIP100 },
+ UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC,
+ 0,
+ PQUIRK_NOTUR,
+ UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO,
+ NULL, NULL
+ },
+
+ { { USB_VENDOR_IOMEGA, USB_PRODUCT_IOMEGA_ZIP250 },
+ UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC,
+ 0,
+ PQUIRK_NOTUR,
+ UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO,
+ NULL, NULL
+ },
+
+ { { USB_VENDOR_MICROTECH, USB_PRODUCT_MICROTECH_DPCM },
+ UMASS_WPROTO_CBI, UMASS_CPROTO_ATAPI,
+ 0,
+ 0,
+ UMATCH_VENDOR_PRODUCT,
+ NULL, NULL
+ },
+
+ { { USB_VENDOR_MSYSTEMS, USB_PRODUCT_MSYSTEMS_DISKONKEY },
+ UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC,
+ 0,
+ PQUIRK_NOMODESENSE | PQUIRK_NODOORLOCK | PQUIRK_NOBIGMODESENSE,
+ UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO,
+ NULL, NULL
+ },
+
+ { { USB_VENDOR_OLYMPUS, USB_PRODUCT_OLYMPUS_C1 },
+ UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC,
+ UMASS_QUIRK_WRONG_CSWSIG,
+ 0,
+ UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO,
+ NULL, NULL
+ },
+
+ { { USB_VENDOR_ONSPEC, USB_PRODUCT_ONSPEC_MD2 },
+ UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC,
+ 0,
+ PQUIRK_NOMODESENSE,
+ UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO,
+ NULL, NULL
+ },
+
+ { { USB_VENDOR_ONSPEC, USB_PRODUCT_ONSPEC_MD1II },
+ UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC,
+ UMASS_QUIRK_NO_MAX_LUN | UMASS_QUIRK_NO_START_STOP,
+ PQUIRK_NOMODESENSE,
+ UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO,
+ NULL, NULL
+ },
+
+ { { USB_VENDOR_SCANLOGIC, USB_PRODUCT_SCANLOGIC_SL11R },
+ UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UFI,
+ 0,
+ 0,
+ UMATCH_VENDOR_PRODUCT,
+ NULL, NULL
+ },
+
+ { { USB_VENDOR_SHUTTLE, USB_PRODUCT_SHUTTLE_EUSB },
+ UMASS_WPROTO_CBI_I, UMASS_CPROTO_ATAPI,
+ UMASS_QUIRK_NO_START_STOP,
+ PQUIRK_NOTUR,
+ UMATCH_VENDOR_PRODUCT,
+ umass_init_shuttle, NULL
+ },
+
+ { { USB_VENDOR_SHUTTLE, USB_PRODUCT_SHUTTLE_ZIOMMC },
+ UMASS_WPROTO_CBI_I, UMASS_CPROTO_ATAPI,
+ UMASS_QUIRK_NO_START_STOP,
+ PQUIRK_NOTUR,
+ UMATCH_VENDOR_PRODUCT,
+ NULL, NULL
+ },
+
+ { { USB_VENDOR_SONY, USB_PRODUCT_SONY_MSC },
+ UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC,
+ UMASS_QUIRK_FORCE_SHORT_INQUIRY,
+ 0,
+ UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO,
+ NULL, umass_fixup_sony
+ },
+
+ { { USB_VENDOR_SONY, USB_PRODUCT_ANY },
+ UMASS_WPROTO_UNSPEC, UMASS_CPROTO_RBC,
+ 0,
+ 0,
+ UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO,
+ NULL, umass_fixup_sony
+ },
+
+ { { USB_VENDOR_TEAC, USB_PRODUCT_TEAC_FD05PUB },
+ UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC,
+ 0,
+ PQUIRK_NOMODESENSE,
+ UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO,
+ NULL, NULL
+ },
+
+ { { USB_VENDOR_YANO, USB_PRODUCT_YANO_U640MO },
+ UMASS_WPROTO_CBI_I, UMASS_CPROTO_ATAPI,
+ UMASS_QUIRK_FORCE_SHORT_INQUIRY,
+ 0,
+ UMATCH_VENDOR_PRODUCT,
+ NULL, NULL
+ },
+
+ { { USB_VENDOR_YEDATA, USB_PRODUCT_YEDATA_FLASHBUSTERU },
+ UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UFI,
+ UMASS_QUIRK_RS_NO_CLEAR_UA,
+ PQUIRK_NOMODESENSE,
+ UMATCH_VENDOR_PRODUCT_REV,
+ NULL, umass_fixup_yedata
+ },
+
+ { { USB_VENDOR_MINOLTA, USB_PRODUCT_MINOLTA_S304 },
+ UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC,
+ UMASS_QUIRK_NO_MAX_LUN | UMASS_QUIRK_NO_START_STOP,
+ 0,
+ UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO,
+ NULL, NULL
+ },
+
+ { { USB_VENDOR_MINOLTA, USB_PRODUCT_MINOLTA_X },
+ UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC,
+ UMASS_QUIRK_NO_MAX_LUN | UMASS_QUIRK_NO_START_STOP,
+ 0,
+ UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO,
+ NULL, NULL
+ },
+
+ { { USB_VENDOR_PEN, USB_PRODUCT_PEN_USBDISK },
+ UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC,
+ UMASS_QUIRK_NO_MAX_LUN | UMASS_QUIRK_NO_START_STOP,
+ 0,
+ UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO,
+ NULL, NULL
+ },
+
+ /* InSystem Design ATA over USB devices */
+ { { USB_VENDOR_ATI, USB_PRODUCT_ATI2_205 },
+ UMASS_WPROTO_BBB, UMASS_CPROTO_ISD_ATA,
+ 0,
+ 0,
+ UMATCH_VENDOR_PRODUCT,
+ NULL, NULL
+ },
+ { { USB_VENDOR_INSYSTEM, USB_PRODUCT_INSYSTEM_ATAPI },
+ UMASS_WPROTO_BBB, UMASS_CPROTO_ISD_ATA,
+ 0,
+ 0,
+ UMATCH_VENDOR_PRODUCT,
+ NULL, NULL
+ },
+ { { USB_VENDOR_INSYSTEM, USB_PRODUCT_INSYSTEM_DRIVEV2_5 },
+ UMASS_WPROTO_BBB, UMASS_CPROTO_ISD_ATA,
+ 0,
+ 0,
+ UMATCH_VENDOR_PRODUCT,
+ NULL, NULL
+ },
+ { { USB_VENDOR_INSYSTEM, USB_PRODUCT_INSYSTEM_ADAPTERV2 },
+ UMASS_WPROTO_BBB, UMASS_CPROTO_ISD_ATA,
+ 0,
+ 0,
+ UMATCH_VENDOR_PRODUCT,
+ NULL, NULL
+ },
+ { { USB_VENDOR_SONY, USB_PRODUCT_SONY_DRIVEV2 },
+ UMASS_WPROTO_BBB, UMASS_CPROTO_ISD_ATA,
+ 0,
+ 0,
+ UMATCH_VENDOR_PRODUCT,
+ NULL, NULL
+ },
+};
+
+const struct umass_quirk *
+umass_lookup(u_int16_t vendor, u_int16_t product)
+{
+ return ((const struct umass_quirk *)
+ usb_lookup(umass_quirks, vendor, product));
+}
+
+Static usbd_status
+umass_init_insystem(struct umass_softc *sc)
+{
+ usbd_status err;
+
+ err = usbd_set_interface(sc->sc_iface, 1);
+ if (err) {
+ DPRINTF(UDMASS_USB,
+ ("%s: could not switch to Alt Interface 1\n",
+ USBDEVNAME(sc->sc_dev)));
+ return (err);
+ }
+
+ return (USBD_NORMAL_COMPLETION);
+}
+
+Static usbd_status
+umass_init_shuttle(struct umass_softc *sc)
+{
+ usb_device_request_t req;
+ u_int8_t status[2];
+
+ /* The Linux driver does this */
+ req.bmRequestType = UT_READ_VENDOR_DEVICE;
+ req.bRequest = 1;
+ USETW(req.wValue, 0);
+ USETW(req.wIndex, sc->sc_ifaceno);
+ USETW(req.wLength, sizeof(status));
+
+ return (usbd_do_request(sc->sc_udev, &req, &status));
+}
+
+Static void
+umass_fixup_sony(struct umass_softc *sc)
+{
+ usb_interface_descriptor_t *id;
+
+ id = usbd_get_interface_descriptor(sc->sc_iface);
+ if (id->bInterfaceSubClass == 0xff) {
+ sc->sc_cmd = UMASS_CPROTO_RBC;
+ }
+}
+
+Static void
+umass_fixup_yedata(struct umass_softc *sc)
+{
+ usb_device_descriptor_t *dd;
+
+ dd = usbd_get_device_descriptor(sc->sc_udev);
+
+ /*
+ * Revisions < 1.28 do not handle the interrupt endpoint very well.
+ */
+ if (UGETW(dd->bcdDevice) < 0x128)
+ sc->sc_wire = UMASS_WPROTO_CBI;
+ else
+ sc->sc_wire = UMASS_WPROTO_CBI_I;
+
+ /*
+ * Revisions < 1.28 do not have the TEST UNIT READY command
+ * Revisions == 1.28 have a broken TEST UNIT READY
+ */
+ if (UGETW(dd->bcdDevice) <= 0x128)
+ sc->sc_busquirks |= PQUIRK_NOTUR;
+}
diff --git a/sys/dev/usb/umass_quirks.h b/sys/dev/usb/umass_quirks.h
new file mode 100644
index 00000000000..5348583ba34
--- /dev/null
+++ b/sys/dev/usb/umass_quirks.h
@@ -0,0 +1,62 @@
+/* $OpenBSD: umass_quirks.h,v 1.1 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: umass_quirks.h,v 1.3 2001/12/29 13:46:23 augustss Exp $ */
+
+/*
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by MAEKAWA Masahide (gehenna@NetBSD.org).
+ *
+ * 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.
+ */
+
+
+#ifndef _DEV_USB_UMASS_QUIRKS_H_
+#define _DEV_USB_UMASS_QUIRKS_H_
+
+typedef usbd_status (*umass_init_quirk)(struct umass_softc *);
+typedef void (*umass_fixup_quirk)(struct umass_softc *);
+
+struct umass_quirk {
+ struct usb_devno uq_dev;
+
+ u_int8_t uq_wire;
+ u_int8_t uq_cmd;
+ u_int32_t uq_flags;
+ u_int32_t uq_busquirks;
+ int uq_match;
+
+ umass_init_quirk uq_init;
+ umass_fixup_quirk uq_fixup;
+};
+
+const struct umass_quirk *umass_lookup(u_int16_t, u_int16_t);
+
+#endif /* _DEV_USB_UMASS_QUIRKS_H_ */
diff --git a/sys/dev/usb/umass_scsi.c b/sys/dev/usb/umass_scsi.c
new file mode 100644
index 00000000000..2c1f1c2ba50
--- /dev/null
+++ b/sys/dev/usb/umass_scsi.c
@@ -0,0 +1,488 @@
+/* $OpenBSD: umass_scsi.c,v 1.1 2002/05/07 18:08:04 nate Exp $ */
+/*
+ * Copyright (c) 2001 Nathan L. Binkert
+ * All rights reserved.
+ *
+ * Permission to redistribute, use, copy, and modify this software
+ * without fee is hereby granted, provided that the following
+ * conditions are met:
+ *
+ * 1. This entire notice is included in all source code copies of any
+ * software which is or includes a copy or modification of this
+ * software.
+ * 2. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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) 2001 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.
+ */
+
+#include "atapiscsi.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/buf.h>
+#include <sys/device.h>
+#include <sys/ioctl.h>
+#include <sys/malloc.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+#include <dev/usb/usbdevs.h>
+
+#include <dev/usb/umassvar.h>
+#include <dev/usb/umass_scsi.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+#include <scsi/scsi_disk.h>
+#include <machine/bus.h>
+
+struct umass_scsi_softc {
+ struct umassbus_softc base;
+ struct scsi_link sc_link;
+ struct scsi_adapter sc_adapter;
+
+ usbd_status sc_sync_status;
+ struct scsi_sense sc_sense_cmd;
+};
+
+
+#define SHORT_INQUIRY_LENGTH 36 /* XXX */
+
+#define UMASS_SCSIID_HOST 0x00
+#define UMASS_SCSIID_DEVICE 0x01
+
+#define UMASS_ATAPI_DRIVE 0
+
+int umass_scsi_cmd(struct scsi_xfer *);
+void umass_scsi_minphys(struct buf *);
+int umass_scsi_ioctl(struct scsi_link *, u_long cmd, caddr_t addrp, int flag,
+ struct proc *p);
+
+void umass_scsi_cb(struct umass_softc *sc, void *priv, int residue,
+ int status);
+void umass_scsi_sense_cb(struct umass_softc *sc, void *priv, int residue,
+ int status);
+struct umass_scsi_softc *umass_scsi_setup(struct umass_softc *);
+
+struct scsi_device umass_scsi_dev = { NULL, NULL, NULL, NULL, };
+
+int
+umass_scsi_attach(struct umass_softc *sc)
+{
+ struct umass_scsi_softc *scbus;
+
+ scbus = umass_scsi_setup(sc);
+ scbus->sc_link.adapter_target = UMASS_SCSIID_HOST;
+ scbus->sc_link.luns = sc->maxlun + 1;
+
+ scbus->sc_adapter.scsi_cmd = umass_scsi_cmd;
+ scbus->sc_adapter.scsi_minphys = umass_scsi_minphys;
+ scbus->sc_adapter.ioctl = umass_scsi_ioctl;
+
+ DPRINTF(UDMASS_USB, ("%s: umass_attach_bus: SCSI\n"
+ "sc = 0x%x, scbus = 0x%x\n",
+ USBDEVNAME(sc->sc_dev), sc, scbus));
+
+ scbus->base.sc_child =
+ config_found((struct device *)sc, &scbus->sc_link, scsiprint);
+
+ return (0);
+}
+
+#if NATAPISCSI > 0
+int
+umass_atapi_attach(struct umass_softc *sc)
+{
+ struct umass_scsi_softc *scbus;
+
+ scbus = umass_scsi_setup(sc);
+ scbus->sc_link.adapter_target = UMASS_SCSIID_HOST;
+ scbus->sc_link.luns = 1;
+
+ scbus->sc_adapter.scsi_cmd = umass_scsi_cmd;
+ scbus->sc_adapter.scsi_minphys = umass_scsi_minphys;
+ scbus->sc_adapter.ioctl = umass_scsi_ioctl;
+
+ DPRINTF(UDMASS_USB, ("%s: umass_attach_bus: ATAPI\n"
+ "sc = 0x%x, scbus = 0x%x\n",
+ USBDEVNAME(sc->sc_dev), sc, scbus));
+
+ scbus->base.sc_child =
+ config_found((struct device *)sc, &scbus->sc_link, scsiprint);
+
+ return (0);
+}
+#endif
+
+struct umass_scsi_softc *
+umass_scsi_setup(struct umass_softc *sc)
+{
+ struct umass_scsi_softc *scbus;
+
+ scbus = malloc(sizeof(struct umass_scsi_softc), M_DEVBUF, M_WAITOK);
+ memset(&scbus->sc_link, 0, sizeof(struct scsi_link));
+ memset(&scbus->sc_adapter, 0, sizeof(struct scsi_adapter));
+
+ sc->bus = (struct umassbus_softc *)scbus;
+
+ scbus->sc_link.adapter_buswidth = 2;
+ scbus->sc_link.openings = 1;
+ scbus->sc_link.flags &= ~SDEV_ATAPI;
+ scbus->sc_link.device = &umass_scsi_dev;
+ scbus->sc_link.adapter = &scbus->sc_adapter;
+ scbus->sc_link.adapter_softc = sc;
+ scbus->sc_link.openings = 1;
+
+ return (scbus);
+}
+
+int
+umass_scsi_cmd(struct scsi_xfer *xs)
+{
+ struct scsi_link *sc_link = xs->sc_link;
+ struct umass_softc *sc = sc_link->adapter_softc;
+ struct umass_scsi_softc *scbus = (struct umass_scsi_softc *)sc->bus;
+
+ struct scsi_generic *cmd, trcmd;
+ int cmdlen, dir;
+
+#ifdef UMASS_DEBUG
+ microtime(&sc->tv);
+#endif
+
+ memset(&trcmd, 0, sizeof(trcmd));
+
+ DIF(UDMASS_UPPER, sc_link->flags |= SCSIDEBUG_LEVEL);
+
+ DPRINTF(UDMASS_CMD, ("%s: umass_scsi_cmd: at %lu.%06lu: %d:%d "
+ "xs=%p cmd=0x%02x datalen=%d (quirks=0x%x, poll=%d)\n",
+ USBDEVNAME(sc->sc_dev), sc->tv.tv_sec, sc->tv.tv_usec,
+ sc_link->target, sc_link->lun, xs, xs->cmd->opcode,
+ xs->datalen, sc_link->quirks, xs->flags & SCSI_POLL));
+
+#if defined(USB_DEBUG) && defined(SCSIDEBUG)
+ if (umassdebug & UDMASS_SCSI)
+ show_scsi_xs(xs);
+ else if (umassdebug & ~UDMASS_CMD)
+ show_scsi_cmd(xs);
+#endif
+
+ if (sc->sc_dying) {
+ xs->error = XS_DRIVER_STUFFUP;
+ goto done;
+ }
+
+#if defined(UMASS_DEBUG)
+ if (sc_link->target != UMASS_SCSIID_DEVICE) {
+ DPRINTF(UDMASS_SCSI, ("%s: wrong SCSI ID %d\n",
+ USBDEVNAME(sc->sc_dev), sc_link->target));
+ xs->error = XS_DRIVER_STUFFUP;
+ goto done;
+ }
+#endif
+
+ cmd = xs->cmd;
+ cmdlen = xs->cmdlen;
+
+ if (cmd->opcode == MODE_SENSE &&
+ (sc_link->quirks & SDEV_NOMODESENSE)) {
+ xs->error = XS_TIMEOUT;
+ goto done;
+ }
+
+ if (cmd->opcode == START_STOP &&
+ (sc->sc_quirks & UMASS_QUIRK_NO_START_STOP)) {
+ xs->error = XS_NOERROR;
+ goto done;
+ }
+
+ if (cmd->opcode == INQUIRY &&
+ (sc->sc_quirks & UMASS_QUIRK_FORCE_SHORT_INQUIRY)) {
+ memcpy(&trcmd, cmd, sizeof(trcmd));
+ trcmd.bytes[4] = SHORT_INQUIRY_LENGTH;
+ cmd = &trcmd;
+ }
+
+ dir = DIR_NONE;
+ if (xs->datalen) {
+ switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
+ case SCSI_DATA_IN:
+ dir = DIR_IN;
+ break;
+ case SCSI_DATA_OUT:
+ dir = DIR_OUT;
+ break;
+ }
+ }
+
+ if (xs->datalen > UMASS_MAX_TRANSFER_SIZE) {
+ printf("umass_cmd: large datalen, %d\n", xs->datalen);
+ xs->error = XS_DRIVER_STUFFUP;
+ goto done;
+ }
+
+ if (xs->flags & SCSI_POLL) {
+ /* Use sync transfer. XXX Broken! */
+ DPRINTF(UDMASS_SCSI, ("umass_scsi_cmd: sync dir=%d\n", dir));
+ sc->sc_xfer_flags = USBD_SYNCHRONOUS;
+ scbus->sc_sync_status = USBD_INVAL;
+ sc->sc_methods->wire_xfer(sc, sc_link->lun, cmd, cmdlen,
+ xs->data, xs->datalen, dir,
+ xs->timeout, 0, xs);
+ sc->sc_xfer_flags = 0;
+ DPRINTF(UDMASS_SCSI, ("umass_scsi_cmd: done err=%d\n",
+ scbus->sc_sync_status));
+ switch (scbus->sc_sync_status) {
+ case USBD_NORMAL_COMPLETION:
+ xs->error = XS_NOERROR;
+ break;
+ case USBD_TIMEOUT:
+ xs->error = XS_TIMEOUT;
+ break;
+ default:
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+ }
+ goto done;
+ } else {
+ DPRINTF(UDMASS_SCSI,
+ ("umass_scsi_cmd: async dir=%d, cmdlen=%d"
+ " datalen=%d\n",
+ dir, cmdlen, xs->datalen));
+ sc->sc_methods->wire_xfer(sc, sc_link->lun, cmd, cmdlen,
+ xs->data, xs->datalen, dir,
+ xs->timeout, umass_scsi_cb, xs);
+ return (SUCCESSFULLY_QUEUED);
+ }
+
+ /* Return if command finishes early. */
+ done:
+ xs->flags |= ITSDONE;
+
+ scsi_done(xs);
+ if (xs->flags & SCSI_POLL)
+ return (COMPLETE);
+ else
+ return (SUCCESSFULLY_QUEUED);
+}
+
+void
+umass_scsi_minphys(struct buf *bp)
+{
+ if (bp->b_bcount > UMASS_MAX_TRANSFER_SIZE)
+ bp->b_bcount = UMASS_MAX_TRANSFER_SIZE;
+
+ minphys(bp);
+}
+
+int
+umass_scsi_ioctl(struct scsi_link *link, u_long cmd, caddr_t arg, int flag,
+ struct proc *p)
+{
+#if 0
+ struct umass_softc *sc = link->adapter_softc;
+#endif
+
+ switch (cmd) {
+#if 0
+ case SCBUSIORESET:
+ ccb->ccb_h.status = CAM_REQ_INPROG;
+ umass_reset(sc, umass_cam_cb, (void *) ccb);
+ return (0);
+#endif
+ default:
+ return (ENOTTY);
+ }
+}
+
+void
+umass_scsi_cb(struct umass_softc *sc, void *priv, int residue, int status)
+{
+ struct umass_scsi_softc *scbus = (struct umass_scsi_softc *)sc->bus;
+ struct scsi_xfer *xs = priv;
+ struct scsi_link *link = xs->sc_link;
+ int cmdlen;
+ int s;
+#ifdef UMASS_DEBUG
+ struct timeval tv;
+ u_int delta;
+ microtime(&tv);
+ delta = (tv.tv_sec - sc->tv.tv_sec) * 1000000 +
+ tv.tv_usec - sc->tv.tv_usec;
+#endif
+
+ DPRINTF(UDMASS_CMD,
+ ("umass_scsi_cb: at %lu.%06lu, delta=%u: xs=%p residue=%d"
+ " status=%d\n", tv.tv_sec, tv.tv_usec, delta, xs, residue,
+ status));
+
+ xs->resid = residue;
+
+ switch (status) {
+ case STATUS_CMD_OK:
+ xs->error = XS_NOERROR;
+ break;
+
+ case STATUS_CMD_UNKNOWN:
+ /* we can't issue REQUEST SENSE */
+ if (xs->sc_link->quirks & PQUIRK_NOSENSE) {
+ /*
+ * If no residue and no other USB error,
+ * command succeeded.
+ */
+ if (residue == 0) {
+ xs->error = XS_NOERROR;
+ break;
+ }
+
+ /*
+ * Some devices return a short INQUIRY
+ * response, omitting response data from the
+ * "vendor specific data" on...
+ */
+ if (xs->cmd->opcode == INQUIRY &&
+ residue < xs->datalen) {
+ xs->error = XS_NOERROR;
+ break;
+ }
+
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+ }
+ /* FALLTHROUGH */
+ case STATUS_CMD_FAILED:
+ /* fetch sense data */
+ memset(&scbus->sc_sense_cmd, 0, sizeof(scbus->sc_sense_cmd));
+ scbus->sc_sense_cmd.opcode = REQUEST_SENSE;
+ scbus->sc_sense_cmd.byte2 = link->lun << SCSI_CMD_LUN_SHIFT;
+ scbus->sc_sense_cmd.length = sizeof(xs->sense);
+
+ cmdlen = sizeof(scbus->sc_sense_cmd);
+ if (sc->sc_cmd == UMASS_CPROTO_UFI) /* XXX */
+ cmdlen = UFI_COMMAND_LENGTH;
+ sc->sc_methods->wire_xfer(sc, link->lun,
+ &scbus->sc_sense_cmd, cmdlen,
+ &xs->sense, sizeof(xs->sense),
+ DIR_IN, xs->timeout,
+ umass_scsi_sense_cb, xs);
+ return;
+
+ case STATUS_WIRE_FAILED:
+ xs->error = XS_RESET;
+ break;
+
+ default:
+ panic("%s: Unknown status %d in umass_scsi_cb\n",
+ USBDEVNAME(sc->sc_dev), status);
+ }
+
+ DPRINTF(UDMASS_CMD,("umass_scsi_cb: at %lu.%06lu: return error=%d, "
+ "status=0x%x resid=%d\n",
+ tv.tv_sec, tv.tv_usec,
+ xs->error, xs->status, xs->resid));
+
+ s = splbio();
+ scsi_done(xs);
+ splx(s);
+}
+
+/*
+ * Finalise a completed autosense operation
+ */
+void
+umass_scsi_sense_cb(struct umass_softc *sc, void *priv, int residue,
+ int status)
+{
+ struct scsi_xfer *xs = priv;
+ int s;
+
+ DPRINTF(UDMASS_CMD,("umass_scsi_sense_cb: xs=%p residue=%d "
+ "status=%d\n", xs, residue, status));
+
+ switch (status) {
+ case STATUS_CMD_OK:
+ case STATUS_CMD_UNKNOWN:
+ /* getting sense data succeeded */
+ if (xs->cmd->opcode == INQUIRY && (xs->resid < xs->datalen ||
+ (sc->sc_quirks & UMASS_QUIRK_RS_NO_CLEAR_UA /* XXX */))) {
+ /*
+ * Some drivers return SENSE errors even after INQUIRY.
+ * The upper layer doesn't like that.
+ */
+ xs->error = XS_NOERROR;
+ break;
+ }
+ /* XXX look at residue */
+ if (residue == 0 || residue == 14)/* XXX */
+ xs->error = XS_SENSE;
+ else
+ xs->error = XS_SHORTSENSE;
+ break;
+ default:
+ DPRINTF(UDMASS_SCSI, ("%s: Autosense failed, status %d\n",
+ USBDEVNAME(sc->sc_dev), status));
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+ }
+
+ xs->status |= ITSDONE;
+
+ DPRINTF(UDMASS_CMD,("umass_scsi_sense_cb: return xs->error=%d, "
+ "xs->status=0x%x xs->resid=%d\n", xs->error, xs->status,
+ xs->resid));
+
+ s = splbio();
+ scsi_done(xs);
+ splx(s);
+}
diff --git a/sys/dev/usb/umass_scsi.h b/sys/dev/usb/umass_scsi.h
new file mode 100644
index 00000000000..9237f5d364c
--- /dev/null
+++ b/sys/dev/usb/umass_scsi.h
@@ -0,0 +1,31 @@
+/* $OpenBSD: umass_scsi.h,v 1.1 2002/05/07 18:08:04 nate Exp $ */
+/*
+ * Copyright (c) 2001 Nathan L. Binkert
+ * All rights reserved.
+ *
+ * Permission to redistribute, use, copy, and modify this software
+ * without fee is hereby granted, provided that the following
+ * conditions are met:
+ *
+ * 1. This entire notice is included in all source code copies of any
+ * software which is or includes a copy or modification of this
+ * software.
+ * 2. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ */
+
+int umass_scsi_attach(struct umass_softc *sc);
+int umass_atapi_attach(struct umass_softc *sc);
diff --git a/sys/dev/usb/umass_scsipi.c b/sys/dev/usb/umass_scsipi.c
new file mode 100644
index 00000000000..a37fb3cb425
--- /dev/null
+++ b/sys/dev/usb/umass_scsipi.c
@@ -0,0 +1,636 @@
+/* $NetBSD: umass_scsipi.c,v 1.4 2001/12/31 12:15:21 augustss Exp $ */
+
+/*
+ * Copyright (c) 2001 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.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: umass_scsipi.c,v 1.4 2001/12/31 12:15:21 augustss Exp $");
+
+#include "atapibus.h"
+#include "scsibus.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/buf.h>
+#include <sys/device.h>
+#include <sys/ioctl.h>
+#include <sys/malloc.h>
+
+/* SCSI & ATAPI */
+#include <sys/scsiio.h>
+#include <dev/scsipi/scsi_all.h>
+#include <dev/scsipi/scsipi_all.h>
+#include <dev/scsipi/scsiconf.h>
+
+#include <dev/scsipi/atapiconf.h>
+
+#include <dev/scsipi/scsipi_disk.h>
+#include <dev/scsipi/scsi_disk.h>
+#include <dev/scsipi/scsi_changer.h>
+
+#include <dev/scsipi/atapi_disk.h>
+
+#include <sys/disk.h> /* XXX */
+#include <dev/scsipi/sdvar.h> /* XXX */
+
+/* USB */
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+#include <dev/usb/usbdevs.h>
+
+#include <dev/usb/umassvar.h>
+#include <dev/usb/umass_scsipi.h>
+
+struct umass_scsipi_softc {
+ struct umassbus_softc base;
+
+ struct atapi_adapter sc_atapi_adapter;
+#define sc_adapter sc_atapi_adapter._generic
+ struct scsipi_channel sc_channel;
+ usbd_status sc_sync_status;
+ struct scsipi_sense sc_sense_cmd;
+};
+
+
+#define SHORT_INQUIRY_LENGTH 36 /* XXX */
+
+#define UMASS_SCSIID_HOST 0x00
+#define UMASS_SCSIID_DEVICE 0x01
+
+#define UMASS_ATAPI_DRIVE 0
+
+Static void umass_scsipi_request(struct scsipi_channel *,
+ scsipi_adapter_req_t, void *);
+Static void umass_scsipi_minphys(struct buf *bp);
+Static int umass_scsipi_ioctl(struct scsipi_channel *, u_long,
+ caddr_t, int, usb_proc_ptr);
+Static int umass_scsipi_getgeom(struct scsipi_periph *periph,
+ struct disk_parms *, u_long sectors);
+
+Static void umass_scsipi_cb(struct umass_softc *sc, void *priv,
+ int residue, int status);
+Static void umass_scsipi_sense_cb(struct umass_softc *sc, void *priv,
+ int residue, int status);
+
+Static struct umass_scsipi_softc *umass_scsipi_setup(struct umass_softc *sc);
+
+Static int scsipiprint(void *aux, const char *pnp);
+
+#if NATAPIBUS > 0
+Static void umass_atapi_probe_device(struct atapibus_softc *, int);
+
+const struct scsipi_bustype umass_atapi_bustype = {
+ SCSIPI_BUSTYPE_ATAPI,
+ atapi_scsipi_cmd,
+ atapi_interpret_sense,
+ atapi_print_addr,
+ scsi_kill_pending,
+};
+#endif
+
+
+#if NSCSIBUS > 0
+int
+umass_scsi_attach(struct umass_softc *sc)
+{
+ struct umass_scsipi_softc *scbus;
+
+ scbus = umass_scsipi_setup(sc);
+
+ scbus->sc_channel.chan_bustype = &scsi_bustype;
+ scbus->sc_channel.chan_ntargets = UMASS_SCSIID_DEVICE + 1;
+ scbus->sc_channel.chan_nluns = sc->maxlun + 1;
+ scbus->sc_channel.chan_id = UMASS_SCSIID_HOST;
+ DPRINTF(UDMASS_USB, ("%s: umass_attach_bus: SCSI\n",
+ USBDEVNAME(sc->sc_dev)));
+ scbus->base.sc_child =
+ config_found(&sc->sc_dev, &scbus->sc_channel, scsipiprint);
+
+ return (0);
+}
+#endif
+
+#if NATAPIBUS > 0
+int
+umass_atapi_attach(struct umass_softc *sc)
+{
+ struct umass_scsipi_softc *scbus;
+
+ scbus = umass_scsipi_setup(sc);
+ scbus->sc_atapi_adapter.atapi_probe_device = umass_atapi_probe_device;
+
+ scbus->sc_channel.chan_bustype = &umass_atapi_bustype;
+ scbus->sc_channel.chan_ntargets = 2;
+ scbus->sc_channel.chan_nluns = 1;
+
+ scbus->sc_channel.chan_defquirks |= sc->sc_busquirks;
+ DPRINTF(UDMASS_USB, ("%s: umass_attach_bus: ATAPI\n",
+ USBDEVNAME(sc->sc_dev)));
+ scbus->base.sc_child =
+ config_found(&sc->sc_dev, &scbus->sc_channel, scsipiprint);
+
+ return (0);
+}
+#endif
+
+Static struct umass_scsipi_softc *
+umass_scsipi_setup(struct umass_softc *sc)
+{
+ struct umass_scsipi_softc *scbus;
+
+ scbus = malloc(sizeof *scbus, M_DEVBUF, M_WAITOK | M_ZERO);
+ sc->bus = &scbus->base;
+
+ /* Only use big commands for USB SCSI devices. */
+ sc->sc_busquirks |= PQUIRK_ONLYBIG;
+
+ /* Fill in the adapter. */
+ memset(&scbus->sc_adapter, 0, sizeof(scbus->sc_adapter));
+ scbus->sc_adapter.adapt_dev = &sc->sc_dev;
+ scbus->sc_adapter.adapt_nchannels = 1;
+ scbus->sc_adapter.adapt_request = umass_scsipi_request;
+ scbus->sc_adapter.adapt_minphys = umass_scsipi_minphys;
+ scbus->sc_adapter.adapt_ioctl = umass_scsipi_ioctl;
+ scbus->sc_adapter.adapt_getgeom = umass_scsipi_getgeom;
+
+ /* Fill in the channel. */
+ memset(&scbus->sc_channel, 0, sizeof(scbus->sc_channel));
+ scbus->sc_channel.chan_adapter = &scbus->sc_adapter;
+ scbus->sc_channel.chan_channel = 0;
+ scbus->sc_channel.chan_flags = SCSIPI_CHAN_OPENINGS;
+ scbus->sc_channel.chan_openings = 1;
+ scbus->sc_channel.chan_max_periph = 1;
+ scbus->sc_channel.chan_defquirks |= sc->sc_busquirks;
+
+ return (scbus);
+}
+
+Static int
+scsipiprint(void *aux, const char *pnp)
+{
+ struct scsipi_channel *chan = aux;
+
+ if (chan->chan_bustype->bustype_type == SCSIPI_BUSTYPE_SCSI) {
+#if NSCSIBUS > 0
+ return (scsiprint(aux, pnp));
+#else
+ if (pnp)
+ printf("scsibus at %s", pnp);
+ return (UNCONF);
+#endif
+ } else {
+#if NATAPIBUS > 0
+ return (atapiprint(aux, pnp));
+#else
+ if (pnp)
+ printf("atapibus at %s", pnp);
+ return (UNCONF);
+#endif
+ }
+}
+
+Static void
+umass_scsipi_request(struct scsipi_channel *chan,
+ scsipi_adapter_req_t req, void *arg)
+{
+ struct scsipi_adapter *adapt = chan->chan_adapter;
+ struct scsipi_periph *periph;
+ struct scsipi_xfer *xs;
+ struct umass_softc *sc = (void *)adapt->adapt_dev;
+ struct umass_scsipi_softc *scbus = (struct umass_scsipi_softc *)sc->bus;
+ struct scsipi_generic *cmd, trcmd;
+ int cmdlen;
+ int dir;
+#ifdef UMASS_DEBUG
+ microtime(&sc->tv);
+#endif
+ switch(req) {
+ case ADAPTER_REQ_RUN_XFER:
+ xs = arg;
+ periph = xs->xs_periph;
+ DIF(UDMASS_UPPER, periph->periph_dbflags |= SCSIPI_DEBUG_FLAGS);
+
+ DPRINTF(UDMASS_CMD, ("%s: umass_scsi_cmd: at %lu.%06lu: %d:%d "
+ "xs=%p cmd=0x%02x datalen=%d (quirks=0x%x, poll=%d)\n",
+ USBDEVNAME(sc->sc_dev), sc->tv.tv_sec, sc->tv.tv_usec,
+ periph->periph_target, periph->periph_lun,
+ xs, xs->cmd->opcode, xs->datalen,
+ periph->periph_quirks, xs->xs_control & XS_CTL_POLL));
+#if defined(USB_DEBUG) && defined(SCSIPI_DEBUG)
+ if (umassdebug & UDMASS_SCSI)
+ show_scsipi_xs(xs);
+ else if (umassdebug & ~UDMASS_CMD)
+ show_scsipi_cmd(xs);
+#endif
+
+ if (sc->sc_dying) {
+ xs->error = XS_DRIVER_STUFFUP;
+ goto done;
+ }
+
+#ifdef UMASS_DEBUG
+ if (chan->chan_bustype->bustype_type == SCSIPI_BUSTYPE_ATAPI ?
+ periph->periph_target != UMASS_ATAPI_DRIVE :
+ periph->periph_target != UMASS_SCSIID_DEVICE) {
+ DPRINTF(UDMASS_SCSI, ("%s: wrong SCSI ID %d\n",
+ USBDEVNAME(sc->sc_dev),
+ periph->periph_target));
+ xs->error = XS_DRIVER_STUFFUP;
+ goto done;
+ }
+#endif
+
+ cmd = xs->cmd;
+ cmdlen = xs->cmdlen;
+
+ /* XXX should use transform */
+
+ if (cmd->opcode == START_STOP &&
+ (sc->sc_quirks & UMASS_QUIRK_NO_START_STOP)) {
+ /*printf("%s: START_STOP\n", USBDEVNAME(sc->sc_dev));*/
+ xs->error = XS_NOERROR;
+ goto done;
+ }
+
+ if (cmd->opcode == INQUIRY &&
+ (sc->sc_quirks & UMASS_QUIRK_FORCE_SHORT_INQUIRY)) {
+ /*
+ * some drives wedge when asked for full inquiry
+ * information.
+ */
+ memcpy(&trcmd, cmd, sizeof trcmd);
+ trcmd.bytes[4] = SHORT_INQUIRY_LENGTH;
+ cmd = &trcmd;
+ }
+
+ dir = DIR_NONE;
+ if (xs->datalen) {
+ switch (xs->xs_control &
+ (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
+ case XS_CTL_DATA_IN:
+ dir = DIR_IN;
+ break;
+ case XS_CTL_DATA_OUT:
+ dir = DIR_OUT;
+ break;
+ }
+ }
+
+ if (xs->datalen > UMASS_MAX_TRANSFER_SIZE) {
+ printf("umass_cmd: large datalen, %d\n", xs->datalen);
+ xs->error = XS_DRIVER_STUFFUP;
+ goto done;
+ }
+
+ if (xs->xs_control & XS_CTL_POLL) {
+ /* Use sync transfer. XXX Broken! */
+ DPRINTF(UDMASS_SCSI,
+ ("umass_scsi_cmd: sync dir=%d\n", dir));
+ sc->sc_xfer_flags = USBD_SYNCHRONOUS;
+ scbus->sc_sync_status = USBD_INVAL;
+ sc->sc_methods->wire_xfer(sc, periph->periph_lun, cmd,
+ cmdlen, xs->data,
+ xs->datalen, dir,
+ xs->timeout, 0, xs);
+ sc->sc_xfer_flags = 0;
+ DPRINTF(UDMASS_SCSI, ("umass_scsi_cmd: done err=%d\n",
+ scbus->sc_sync_status));
+ switch (scbus->sc_sync_status) {
+ case USBD_NORMAL_COMPLETION:
+ xs->error = XS_NOERROR;
+ break;
+ case USBD_TIMEOUT:
+ xs->error = XS_TIMEOUT;
+ break;
+ default:
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+ }
+ goto done;
+ } else {
+ DPRINTF(UDMASS_SCSI,
+ ("umass_scsi_cmd: async dir=%d, cmdlen=%d"
+ " datalen=%d\n",
+ dir, cmdlen, xs->datalen));
+ sc->sc_methods->wire_xfer(sc, periph->periph_lun, cmd,
+ cmdlen, xs->data,
+ xs->datalen, dir,
+ xs->timeout,
+ umass_scsipi_cb, xs);
+ return;
+ }
+
+ /* Return if command finishes early. */
+ done:
+ scsipi_done(xs);
+ return;
+ default:
+ /* Not supported, nothing to do. */
+ ;
+ }
+}
+
+Static void
+umass_scsipi_minphys(struct buf *bp)
+{
+#ifdef DIAGNOSTIC
+ if (bp->b_bcount <= 0) {
+ printf("umass_scsipi_minphys count(%ld) <= 0\n",
+ bp->b_bcount);
+ bp->b_bcount = UMASS_MAX_TRANSFER_SIZE;
+ }
+#endif
+ if (bp->b_bcount > UMASS_MAX_TRANSFER_SIZE)
+ bp->b_bcount = UMASS_MAX_TRANSFER_SIZE;
+ minphys(bp);
+}
+
+int
+umass_scsipi_ioctl(struct scsipi_channel *chan, u_long cmd, caddr_t arg,
+ int flag, usb_proc_ptr p)
+{
+ /*struct umass_softc *sc = link->adapter_softc;*/
+ /*struct umass_scsipi_softc *scbus = sc->bus;*/
+
+ switch (cmd) {
+#if 0
+ case SCBUSIORESET:
+ ccb->ccb_h.status = CAM_REQ_INPROG;
+ umass_reset(sc, umass_cam_cb, (void *) ccb);
+ return (0);
+#endif
+ default:
+ return (ENOTTY);
+ }
+}
+
+Static int
+umass_scsipi_getgeom(struct scsipi_periph *periph, struct disk_parms *dp,
+ u_long sectors)
+{
+ struct umass_softc *sc =
+ (void *)periph->periph_channel->chan_adapter->adapt_dev;
+
+ /* If it's not a floppy, we don't know what to do. */
+ if (sc->sc_cmd != UMASS_CPROTO_UFI)
+ return (0);
+
+ switch (sectors) {
+ case 1440:
+ /* Most likely a single density 3.5" floppy. */
+ dp->heads = 2;
+ dp->sectors = 9;
+ dp->cyls = 80;
+ return (1);
+ case 2880:
+ /* Most likely a double density 3.5" floppy. */
+ dp->heads = 2;
+ dp->sectors = 18;
+ dp->cyls = 80;
+ return (1);
+ default:
+ return (0);
+ }
+}
+
+Static void
+umass_scsipi_cb(struct umass_softc *sc, void *priv, int residue, int status)
+{
+ struct umass_scsipi_softc *scbus = (struct umass_scsipi_softc *)sc->bus;
+ struct scsipi_xfer *xs = priv;
+ struct scsipi_periph *periph = xs->xs_periph;
+ int cmdlen;
+ int s;
+#ifdef UMASS_DEBUG
+ struct timeval tv;
+ u_int delta;
+ microtime(&tv);
+ delta = (tv.tv_sec - sc->tv.tv_sec) * 1000000 + tv.tv_usec - sc->tv.tv_usec;
+#endif
+
+ DPRINTF(UDMASS_CMD,("umass_scsipi_cb: at %lu.%06lu, delta=%u: xs=%p residue=%d"
+ " status=%d\n", tv.tv_sec, tv.tv_usec, delta, xs, residue, status));
+
+ xs->resid = residue;
+
+ switch (status) {
+ case STATUS_CMD_OK:
+ xs->error = XS_NOERROR;
+ break;
+
+ case STATUS_CMD_UNKNOWN:
+ /* we can't issue REQUEST SENSE */
+ if (xs->xs_periph->periph_quirks & PQUIRK_NOSENSE) {
+ /*
+ * If no residue and no other USB error,
+ * command succeeded.
+ */
+ if (residue == 0) {
+ xs->error = XS_NOERROR;
+ break;
+ }
+
+ /*
+ * Some devices return a short INQUIRY
+ * response, omitting response data from the
+ * "vendor specific data" on...
+ */
+ if (xs->cmd->opcode == INQUIRY &&
+ residue < xs->datalen) {
+ xs->error = XS_NOERROR;
+ break;
+ }
+
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+ }
+ /* FALLTHROUGH */
+ case STATUS_CMD_FAILED:
+ /* fetch sense data */
+ memset(&scbus->sc_sense_cmd, 0, sizeof(scbus->sc_sense_cmd));
+ scbus->sc_sense_cmd.opcode = REQUEST_SENSE;
+ scbus->sc_sense_cmd.byte2 = periph->periph_lun <<
+ SCSI_CMD_LUN_SHIFT;
+ scbus->sc_sense_cmd.length = sizeof(xs->sense);
+
+ cmdlen = sizeof(scbus->sc_sense_cmd);
+ if (sc->sc_cmd == UMASS_CPROTO_UFI) /* XXX */
+ cmdlen = UFI_COMMAND_LENGTH;
+ sc->sc_methods->wire_xfer(sc, periph->periph_lun,
+ &scbus->sc_sense_cmd, cmdlen,
+ &xs->sense, sizeof(xs->sense),
+ DIR_IN, xs->timeout,
+ umass_scsipi_sense_cb, xs);
+ return;
+
+ case STATUS_WIRE_FAILED:
+ xs->error = XS_RESET;
+ break;
+
+ default:
+ panic("%s: Unknown status %d in umass_scsipi_cb\n",
+ USBDEVNAME(sc->sc_dev), status);
+ }
+
+ DPRINTF(UDMASS_CMD,("umass_scsipi_cb: at %lu.%06lu: return xs->error="
+ "%d, xs->xs_status=0x%x xs->resid=%d\n",
+ tv.tv_sec, tv.tv_usec,
+ xs->error, xs->xs_status, xs->resid));
+
+ s = splbio();
+ scsipi_done(xs);
+ splx(s);
+}
+
+/*
+ * Finalise a completed autosense operation
+ */
+Static void
+umass_scsipi_sense_cb(struct umass_softc *sc, void *priv, int residue,
+ int status)
+{
+ struct scsipi_xfer *xs = priv;
+ int s;
+
+ DPRINTF(UDMASS_CMD,("umass_scsipi_sense_cb: xs=%p residue=%d "
+ "status=%d\n", xs, residue, status));
+
+ switch (status) {
+ case STATUS_CMD_OK:
+ case STATUS_CMD_UNKNOWN:
+ /* getting sense data succeeded */
+ if (xs->cmd->opcode == INQUIRY && (xs->resid < xs->datalen ||
+ (sc->sc_quirks & UMASS_QUIRK_RS_NO_CLEAR_UA /* XXX */))) {
+ /*
+ * Some drivers return SENSE errors even after INQUIRY.
+ * The upper layer doesn't like that.
+ */
+ xs->error = XS_NOERROR;
+ break;
+ }
+ /* XXX look at residue */
+ if (residue == 0 || residue == 14)/* XXX */
+ xs->error = XS_SENSE;
+ else
+ xs->error = XS_SHORTSENSE;
+ break;
+ default:
+ DPRINTF(UDMASS_SCSI, ("%s: Autosense failed, status %d\n",
+ USBDEVNAME(sc->sc_dev), status));
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+ }
+
+ xs->xs_status |= XS_STS_DONE;
+
+ DPRINTF(UDMASS_CMD,("umass_scsipi_sense_cb: return xs->error=%d, "
+ "xs->xs_status=0x%x xs->resid=%d\n", xs->error, xs->xs_status,
+ xs->resid));
+
+ s = splbio();
+ scsipi_done(xs);
+ splx(s);
+}
+
+#if NATAPIBUS > 0
+Static void
+umass_atapi_probe_device(struct atapibus_softc *atapi, int target)
+{
+ struct scsipi_channel *chan = atapi->sc_channel;
+ struct scsipi_periph *periph;
+ struct scsipibus_attach_args sa;
+ char vendor[33], product[65], revision[17];
+ struct scsipi_inquiry_data inqbuf;
+
+ DPRINTF(UDMASS_SCSI,("umass_atapi_probe_device: atapi=%p target=%d\n",
+ atapi, target));
+
+ if (target != UMASS_ATAPI_DRIVE) /* only probe drive 0 */
+ return;
+
+ /* skip if already attached */
+ if (scsipi_lookup_periph(chan, target, 0) != NULL)
+ return;
+
+ periph = scsipi_alloc_periph(M_NOWAIT);
+ if (periph == NULL) {
+ printf("%s: can't allocate link for drive %d\n",
+ atapi->sc_dev.dv_xname, target);
+ return;
+ }
+
+ DIF(UDMASS_UPPER, periph->periph_dbflags |= 1); /* XXX 1 */
+ periph->periph_channel = chan;
+ periph->periph_switch = &atapi_probe_periphsw;
+ periph->periph_target = target;
+ periph->periph_quirks = chan->chan_defquirks;
+
+ DPRINTF(UDMASS_SCSI, ("umass_atapi_probe_device: doing inquiry\n"));
+ /* Now go ask the device all about itself. */
+ memset(&inqbuf, 0, sizeof(inqbuf));
+ if (scsipi_inquire(periph, &inqbuf,
+ XS_CTL_DISCOVERY | XS_CTL_DATA_ONSTACK) != 0) {
+ DPRINTF(UDMASS_SCSI, ("umass_atapi_probe_device: "
+ "scsipi_inquire failed\n"));
+ free(periph, M_DEVBUF);
+ return;
+ }
+
+ scsipi_strvis(vendor, 33, inqbuf.vendor, 8);
+ scsipi_strvis(product, 65, inqbuf.product, 16);
+ scsipi_strvis(revision, 17, inqbuf.revision, 4);
+
+ sa.sa_periph = periph;
+ sa.sa_inqbuf.type = inqbuf.device;
+ sa.sa_inqbuf.removable = inqbuf.dev_qual2 & SID_REMOVABLE ?
+ T_REMOV : T_FIXED;
+ if (sa.sa_inqbuf.removable)
+ periph->periph_flags |= PERIPH_REMOVABLE;
+ sa.sa_inqbuf.vendor = vendor;
+ sa.sa_inqbuf.product = product;
+ sa.sa_inqbuf.revision = revision;
+ sa.sa_inqptr = NULL;
+
+ DPRINTF(UDMASS_SCSI, ("umass_atapi_probedev: doing atapi_probedev on "
+ "'%s' '%s' '%s'\n", vendor, product, revision));
+ atapi_probe_device(atapi, target, periph, &sa);
+ /* atapi_probe_device() frees the periph when there is no device.*/
+}
+#endif
diff --git a/sys/dev/usb/umass_scsipi.h b/sys/dev/usb/umass_scsipi.h
new file mode 100644
index 00000000000..182b50f294b
--- /dev/null
+++ b/sys/dev/usb/umass_scsipi.h
@@ -0,0 +1,41 @@
+/* $NetBSD: umass_scsipi.h,v 1.1 2001/12/24 13:25:53 augustss Exp $ */
+
+/*
+ * Copyright (c) 2001 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.
+ */
+
+int umass_scsi_attach(struct umass_softc *sc);
+int umass_atapi_attach(struct umass_softc *sc);
diff --git a/sys/dev/usb/umassvar.h b/sys/dev/usb/umassvar.h
new file mode 100644
index 00000000000..29e6b4a80cb
--- /dev/null
+++ b/sys/dev/usb/umassvar.h
@@ -0,0 +1,271 @@
+/* $NetBSD: umassvar.h,v 1.15 2002/02/07 13:52:55 augustss Exp $ */
+/*-
+ * Copyright (c) 1999 MAEKAWA Masahide <bishop@rr.iij4u.or.jp>,
+ * Nick Hibma <n_hibma@freebsd.org>
+ * 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.
+ *
+ * $FreeBSD: src/sys/dev/usb/umass.c,v 1.13 2000/03/26 01:39:12 n_hibma Exp $
+ */
+
+#ifdef UMASS_DEBUG
+#define DIF(m, x) if (umassdebug & (m)) do { x ; } while (0)
+#define DPRINTF(m, x) if (umassdebug & (m)) logprintf x
+#define UDMASS_UPPER 0x00008000 /* upper layer */
+#define UDMASS_GEN 0x00010000 /* general */
+#define UDMASS_SCSI 0x00020000 /* scsi */
+#define UDMASS_UFI 0x00040000 /* ufi command set */
+#define UDMASS_8070 0x00080000 /* 8070i command set */
+#define UDMASS_USB 0x00100000 /* USB general */
+#define UDMASS_BBB 0x00200000 /* Bulk-Only transfers */
+#define UDMASS_CBI 0x00400000 /* CBI transfers */
+#define UDMASS_ALL 0xffff0000 /* all of the above */
+
+#define UDMASS_XFER 0x40000000 /* all transfers */
+#define UDMASS_CMD 0x80000000
+
+extern int umassdebug;
+#else
+#define DIF(m, x) /* nop */
+#define DPRINTF(m, x) /* nop */
+#endif
+
+/* Generic definitions */
+
+#define UFI_COMMAND_LENGTH 12
+
+/* Direction for umass_*_transfer */
+#define DIR_NONE 0
+#define DIR_IN 1
+#define DIR_OUT 2
+
+#define MS_TO_TICKS(ms) ((ms) * hz / 1000)
+
+/* Endpoints for umass */
+#define UMASS_BULKIN 0
+#define UMASS_BULKOUT 1
+#define UMASS_INTRIN 2
+#define UMASS_NEP 3
+
+/* Bulk-Only features */
+
+#define UR_BBB_RESET 0xff /* Bulk-Only reset */
+#define UR_BBB_GET_MAX_LUN 0xfe
+
+/* Command Block Wrapper */
+typedef struct {
+ uDWord dCBWSignature;
+#define CBWSIGNATURE 0x43425355
+ uDWord dCBWTag;
+ uDWord dCBWDataTransferLength;
+ uByte bCBWFlags;
+#define CBWFLAGS_OUT 0x00
+#define CBWFLAGS_IN 0x80
+ uByte bCBWLUN;
+ uByte bCDBLength;
+#define CBWCDBLENGTH 16
+ uByte CBWCDB[CBWCDBLENGTH];
+} umass_bbb_cbw_t;
+#define UMASS_BBB_CBW_SIZE 31
+
+/* Command Status Wrapper */
+typedef struct {
+ uDWord dCSWSignature;
+#define CSWSIGNATURE 0x53425355
+#define CSWSIGNATURE_OLYMPUS_C1 0x55425355
+ uDWord dCSWTag;
+ uDWord dCSWDataResidue;
+ uByte bCSWStatus;
+#define CSWSTATUS_GOOD 0x0
+#define CSWSTATUS_FAILED 0x1
+#define CSWSTATUS_PHASE 0x2
+} umass_bbb_csw_t;
+#define UMASS_BBB_CSW_SIZE 13
+
+/* CBI features */
+
+#define UR_CBI_ADSC 0x00
+
+typedef unsigned char umass_cbi_cbl_t[16]; /* Command block */
+
+typedef union {
+ struct {
+ uByte type;
+#define IDB_TYPE_CCI 0x00
+ uByte value;
+#define IDB_VALUE_PASS 0x00
+#define IDB_VALUE_FAIL 0x01
+#define IDB_VALUE_PHASE 0x02
+#define IDB_VALUE_PERSISTENT 0x03
+#define IDB_VALUE_STATUS_MASK 0x03
+ } common;
+
+ struct {
+ uByte asc;
+ uByte ascq;
+ } ufi;
+} umass_cbi_sbl_t;
+
+struct umass_softc; /* see below */
+
+typedef void (*umass_callback)(struct umass_softc *, void *, int, int);
+#define STATUS_CMD_OK 0 /* everything ok */
+#define STATUS_CMD_UNKNOWN 1 /* will have to fetch sense */
+#define STATUS_CMD_FAILED 2 /* transfer was ok, command failed */
+#define STATUS_WIRE_FAILED 3 /* couldn't even get command across */
+
+typedef void (*umass_wire_xfer)(struct umass_softc *, int, void *, int, void *,
+ int, int, u_int, umass_callback, void *);
+typedef void (*umass_wire_reset)(struct umass_softc *, int);
+typedef void (*umass_wire_state)(usbd_xfer_handle, usbd_private_handle,
+ usbd_status);
+
+struct umass_wire_methods {
+ umass_wire_xfer wire_xfer;
+ umass_wire_reset wire_reset;
+ umass_wire_state wire_state;
+};
+
+struct umassbus_softc {
+ device_ptr_t sc_child; /* child device, for detach */
+};
+
+/* the per device structure */
+struct umass_softc {
+ USBBASEDEVICE sc_dev; /* base device */
+ usbd_device_handle sc_udev; /* device */
+ usbd_interface_handle sc_iface; /* interface */
+ int sc_ifaceno; /* interface number */
+
+ u_int8_t sc_epaddr[UMASS_NEP];
+ usbd_pipe_handle sc_pipe[UMASS_NEP];
+ usb_device_request_t sc_req;
+
+ const struct umass_wire_methods *sc_methods;
+
+ u_int8_t sc_wire; /* wire protocol */
+#define UMASS_WPROTO_UNSPEC 0
+#define UMASS_WPROTO_BBB 1
+#define UMASS_WPROTO_CBI 2
+#define UMASS_WPROTO_CBI_I 3
+
+ u_int8_t sc_cmd; /* command protocol */
+#define UMASS_CPROTO_UNSPEC 0
+#define UMASS_CPROTO_SCSI 1
+#define UMASS_CPROTO_ATAPI 2
+#define UMASS_CPROTO_UFI 3
+#define UMASS_CPROTO_RBC 4
+#define UMASS_CPROTO_ISD_ATA 5
+
+ u_int32_t sc_quirks;
+#define UMASS_QUIRK_RS_NO_CLEAR_UA 0x00000002
+#define UMASS_QUIRK_NO_START_STOP 0x00000004
+#define UMASS_QUIRK_FORCE_SHORT_INQUIRY 0x00000008
+#define UMASS_QUIRK_WRONG_CSWSIG 0x00000010
+#define UMASS_QUIRK_NO_MAX_LUN 0x00000020
+
+ u_int32_t sc_busquirks;
+
+ /* Bulk specific variables for transfers in progress */
+ umass_bbb_cbw_t cbw; /* command block wrapper */
+ umass_bbb_csw_t csw; /* command status wrapper*/
+ /* CBI specific variables for transfers in progress */
+ umass_cbi_cbl_t cbl; /* command block */
+ umass_cbi_sbl_t sbl; /* status block */
+
+ /* xfer handles
+ * Most of our operations are initiated from interrupt context, so
+ * we need to avoid using the one that is in use. We want to avoid
+ * allocating them in the interrupt context as well.
+ */
+ /* indices into array below */
+#define XFER_BBB_CBW 0 /* Bulk-Only */
+#define XFER_BBB_DATA 1
+#define XFER_BBB_DCLEAR 2
+#define XFER_BBB_CSW1 3
+#define XFER_BBB_CSW2 4
+#define XFER_BBB_SCLEAR 5
+#define XFER_BBB_RESET1 6
+#define XFER_BBB_RESET2 7
+#define XFER_BBB_RESET3 8
+
+#define XFER_CBI_CB 0 /* CBI */
+#define XFER_CBI_DATA 1
+#define XFER_CBI_STATUS 2
+#define XFER_CBI_DCLEAR 3
+#define XFER_CBI_SCLEAR 4
+#define XFER_CBI_RESET1 5
+#define XFER_CBI_RESET2 6
+#define XFER_CBI_RESET3 7
+
+#define XFER_NR 9 /* maximum number */
+
+ usbd_xfer_handle transfer_xfer[XFER_NR]; /* for ctrl xfers */
+
+ void *data_buffer;
+
+ int transfer_dir; /* data direction */
+ void *transfer_data; /* data buffer */
+ int transfer_datalen; /* (maximum) length */
+ int transfer_actlen; /* actual length */
+ umass_callback transfer_cb; /* callback */
+ void *transfer_priv; /* for callback */
+ int transfer_status;
+
+ int transfer_state;
+#define TSTATE_IDLE 0
+#define TSTATE_BBB_COMMAND 1 /* CBW transfer */
+#define TSTATE_BBB_DATA 2 /* Data transfer */
+#define TSTATE_BBB_DCLEAR 3 /* clear endpt stall */
+#define TSTATE_BBB_STATUS1 4 /* clear endpt stall */
+#define TSTATE_BBB_SCLEAR 5 /* clear endpt stall */
+#define TSTATE_BBB_STATUS2 6 /* CSW transfer */
+#define TSTATE_BBB_RESET1 7 /* reset command */
+#define TSTATE_BBB_RESET2 8 /* in clear stall */
+#define TSTATE_BBB_RESET3 9 /* out clear stall */
+#define TSTATE_CBI_COMMAND 10 /* command transfer */
+#define TSTATE_CBI_DATA 11 /* data transfer */
+#define TSTATE_CBI_STATUS 12 /* status transfer */
+#define TSTATE_CBI_DCLEAR 13 /* clear ep stall */
+#define TSTATE_CBI_SCLEAR 14 /* clear ep stall */
+#define TSTATE_CBI_RESET1 15 /* reset command */
+#define TSTATE_CBI_RESET2 16 /* in clear stall */
+#define TSTATE_CBI_RESET3 17 /* out clear stall */
+#define TSTATE_STATES 18 /* # of states above */
+
+
+ int timeout; /* in msecs */
+
+ u_int8_t maxlun; /* max lun supported */
+
+#ifdef UMASS_DEBUG
+ struct timeval tv;
+#endif
+
+ int sc_xfer_flags;
+ char sc_dying;
+
+ struct umassbus_softc *bus; /* bus dependent data */
+};
+
+#define UMASS_MAX_TRANSFER_SIZE MAXBSIZE
diff --git a/sys/dev/usb/umct.c b/sys/dev/usb/umct.c
new file mode 100644
index 00000000000..954ce542c67
--- /dev/null
+++ b/sys/dev/usb/umct.c
@@ -0,0 +1,631 @@
+/* $OpenBSD: umct.c,v 1.1 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: umct.c,v 1.7 2001/12/17 14:19:39 ichiro Exp $ */
+/*
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Ichiro FUKUHARA (ichiro@ichiro.org).
+ *
+ * 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.
+ */
+
+/*
+ * MCT USB-RS232 Interface Controller
+ * http://www.mct.com.tw/p_u232.html
+ * http://www.dlink.com/products/usb/dsbs25
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/ioctl.h>
+#include <sys/conf.h>
+#include <sys/tty.h>
+#include <sys/file.h>
+#include <sys/select.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+#include <sys/device.h>
+#include <sys/poll.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbcdc.h>
+
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+#include <dev/usb/usbdevs.h>
+#include <dev/usb/usb_quirks.h>
+
+#include <dev/usb/usbdevs.h>
+#include <dev/usb/ucomvar.h>
+
+#include <dev/usb/umct.h>
+
+#ifdef UMCT_DEBUG
+#define DPRINTFN(n, x) if (umctdebug > (n)) logprintf x
+int umctdebug = 0;
+#else
+#define DPRINTFN(n, x)
+#endif
+#define DPRINTF(x) DPRINTFN(0, x)
+
+#define UMCT_CONFIG_INDEX 0
+#define UMCT_IFACE_INDEX 0
+
+struct umct_softc {
+ USBBASEDEVICE sc_dev; /* base device */
+ usbd_device_handle sc_udev; /* USB device */
+ usbd_interface_handle sc_iface; /* interface */
+ int sc_iface_number; /* interface number */
+ u_int16_t sc_product;
+
+ int sc_intr_number; /* interrupt number */
+ usbd_pipe_handle sc_intr_pipe; /* interrupt pipe */
+ u_char *sc_intr_buf; /* interrupt buffer */
+ int sc_isize;
+
+ 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_break; /* set break */
+
+ u_char sc_status;
+
+ device_ptr_t sc_subdev; /* ucom device */
+
+ u_char sc_dying; /* disconnecting */
+
+ u_char sc_lsr; /* Local status register */
+ u_char sc_msr; /* umct status register */
+
+ u_int last_lcr; /* keep lcr register */
+};
+
+/*
+ * These are the maximum number of bytes transferred per frame.
+ * The output buffer size cannot be increased due to the size encoding.
+ */
+#define UMCTIBUFSIZE 256
+#define UMCTOBUFSIZE 256
+
+Static void umct_init(struct umct_softc *);
+Static void umct_set_baudrate(struct umct_softc *, u_int);
+Static void umct_set_lcr(struct umct_softc *, u_int);
+Static void umct_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
+
+Static void umct_set(void *, int, int, int);
+Static void umct_dtr(struct umct_softc *, int);
+Static void umct_rts(struct umct_softc *, int);
+Static void umct_break(struct umct_softc *, int);
+Static void umct_set_line_state(struct umct_softc *);
+Static void umct_get_status(void *, int portno, u_char *lsr, u_char *msr);
+Static int umct_param(void *, int, struct termios *);
+Static int umct_open(void *, int);
+Static void umct_close(void *, int);
+
+struct ucom_methods umct_methods = {
+ umct_get_status,
+ umct_set,
+ umct_param,
+ NULL,
+ umct_open,
+ umct_close,
+ NULL,
+ NULL,
+};
+
+static const struct usb_devno umct_devs[] = {
+ /* MCT USB-232 Interface Products */
+ { USB_VENDOR_MCT, USB_PRODUCT_MCT_USB232 },
+ /* Sitecom USB-232 Products */
+ { USB_VENDOR_MCT, USB_PRODUCT_MCT_SITECOM_USB232 },
+ /* D-Link DU-H3SP USB BAY Hub Products */
+ { USB_VENDOR_MCT, USB_PRODUCT_MCT_DU_H3SP_USB232 },
+};
+#define umct_lookup(v, p) usb_lookup(umct_devs, v, p)
+
+USB_DECLARE_DRIVER(umct);
+
+USB_MATCH(umct)
+{
+ USB_MATCH_START(umct, uaa);
+
+ if (uaa->iface != NULL)
+ return (UMATCH_NONE);
+
+ return (umct_lookup(uaa->vendor, uaa->product) != NULL ?
+ UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
+}
+
+USB_ATTACH(umct)
+{
+ USB_ATTACH_START(umct, sc, uaa);
+ usbd_device_handle dev = uaa->device;
+ usb_config_descriptor_t *cdesc;
+ usb_interface_descriptor_t *id;
+ usb_endpoint_descriptor_t *ed;
+
+ char devinfo[1024];
+ char *devname = USBDEVNAME(sc->sc_dev);
+ usbd_status err;
+ int i, found;
+ struct ucom_attach_args uca;
+
+ usbd_devinfo(dev, 0, devinfo);
+ USB_ATTACH_SETUP;
+ printf("%s: %s\n", devname, devinfo);
+
+ sc->sc_udev = dev;
+ sc->sc_product = uaa->product;
+
+ DPRINTF(("\n\numct attach: sc=%p\n", sc));
+
+ /* initialize endpoints */
+ uca.bulkin = uca.bulkout = -1;
+ sc->sc_intr_number = -1;
+ sc->sc_intr_pipe = NULL;
+
+ /* Move the device into the configured state. */
+ err = usbd_set_config_index(dev, UMCT_CONFIG_INDEX, 1);
+ if (err) {
+ printf("\n%s: failed to set configuration, err=%s\n",
+ devname, usbd_errstr(err));
+ sc->sc_dying = 1;
+ USB_ATTACH_ERROR_RETURN;
+ }
+
+ /* get the config descriptor */
+ cdesc = usbd_get_config_descriptor(sc->sc_udev);
+
+ if (cdesc == NULL) {
+ printf("%s: failed to get configuration descriptor\n",
+ USBDEVNAME(sc->sc_dev));
+ sc->sc_dying = 1;
+ USB_ATTACH_ERROR_RETURN;
+ }
+
+ /* get the interface */
+ err = usbd_device2interface_handle(dev, UMCT_IFACE_INDEX,
+ &sc->sc_iface);
+ if (err) {
+ printf("\n%s: failed to get interface, err=%s\n",
+ devname, usbd_errstr(err));
+ sc->sc_dying = 1;
+ USB_ATTACH_ERROR_RETURN;
+ }
+
+ /* Find the bulk{in,out} and interrupt endpoints */
+
+ id = usbd_get_interface_descriptor(sc->sc_iface);
+ sc->sc_iface_number = id->bInterfaceNumber;
+ found = 0;
+
+ for (i = 0; i < id->bNumEndpoints; i++) {
+ ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
+ if (ed == NULL) {
+ printf("%s: no endpoint descriptor for %d\n",
+ USBDEVNAME(sc->sc_dev), i);
+ sc->sc_dying = 1;
+ USB_ATTACH_ERROR_RETURN;
+ }
+
+ if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
+ UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT &&
+ found == 0) {
+ uca.bulkin = ed->bEndpointAddress;
+ found = 1;
+ } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
+ UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
+ uca.bulkout = ed->bEndpointAddress;
+ } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
+ UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
+ sc->sc_intr_number = ed->bEndpointAddress;
+ sc->sc_isize = UGETW(ed->wMaxPacketSize);
+ }
+ }
+
+ if (uca.bulkin == -1) {
+ printf("%s: Could not find data bulk in\n",
+ USBDEVNAME(sc->sc_dev));
+ sc->sc_dying = 1;
+ USB_ATTACH_ERROR_RETURN;
+ }
+
+ if (uca.bulkout == -1) {
+ printf("%s: Could not find data bulk out\n",
+ USBDEVNAME(sc->sc_dev));
+ sc->sc_dying = 1;
+ USB_ATTACH_ERROR_RETURN;
+ }
+
+ if (sc->sc_intr_number== -1) {
+ printf("%s: Could not find interrupt in\n",
+ USBDEVNAME(sc->sc_dev));
+ sc->sc_dying = 1;
+ USB_ATTACH_ERROR_RETURN;
+ }
+
+ sc->sc_dtr = sc->sc_rts = 0;
+ uca.portno = UCOM_UNK_PORTNO;
+ /* bulkin, bulkout set above */
+ uca.ibufsize = UMCTIBUFSIZE;
+ if (sc->sc_product == USB_PRODUCT_MCT_SITECOM_USB232)
+ uca.obufsize = 16; /* device is broken */
+ else
+ uca.obufsize = UMCTOBUFSIZE;
+ uca.ibufsizepad = UMCTIBUFSIZE;
+ uca.opkthdrlen = 0;
+ uca.device = dev;
+ uca.iface = sc->sc_iface;
+ uca.methods = &umct_methods;
+ uca.arg = sc;
+ uca.info = NULL;
+
+ umct_init(sc);
+
+ usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
+ USBDEV(sc->sc_dev));
+
+ DPRINTF(("umct: in=0x%x out=0x%x intr=0x%x\n",
+ uca.bulkin, uca.bulkout, sc->sc_intr_number ));
+ sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch);
+
+ USB_ATTACH_SUCCESS_RETURN;
+}
+
+USB_DETACH(umct)
+{
+ USB_DETACH_START(umct, sc);
+ int rv = 0;
+
+ DPRINTF(("umct_detach: sc=%p flags=%d\n", sc, flags));
+
+ if (sc->sc_intr_pipe != NULL) {
+ usbd_abort_pipe(sc->sc_intr_pipe);
+ usbd_close_pipe(sc->sc_intr_pipe);
+ free(sc->sc_intr_buf, M_USBDEV);
+ sc->sc_intr_pipe = NULL;
+ }
+
+ sc->sc_dying = 1;
+ if (sc->sc_subdev != NULL) {
+ rv = config_detach(sc->sc_subdev, flags);
+ sc->sc_subdev = NULL;
+ }
+
+ usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
+ USBDEV(sc->sc_dev));
+
+ return (rv);
+}
+
+int
+umct_activate(device_ptr_t self, enum devact act)
+{
+ struct umct_softc *sc = (struct umct_softc *)self;
+ int rv = 0;
+
+ switch (act) {
+ case DVACT_ACTIVATE:
+ return (EOPNOTSUPP);
+ break;
+
+ case DVACT_DEACTIVATE:
+ if (sc->sc_subdev != NULL)
+ rv = config_deactivate(sc->sc_subdev);
+ sc->sc_dying = 1;
+ break;
+ }
+ return (rv);
+}
+
+void
+umct_set_line_state(struct umct_softc *sc)
+{
+ usb_device_request_t req;
+ uByte ls;
+
+ ls = (sc->sc_dtr ? MCR_DTR : 0) |
+ (sc->sc_rts ? MCR_RTS : 0);
+
+ DPRINTF(("umct_set_line_state: DTR=%d,RTS=%d,ls=%02x\n",
+ sc->sc_dtr, sc->sc_rts, ls));
+
+ req.bmRequestType = UMCT_SET_REQUEST;
+ req.bRequest = REQ_SET_MCR;
+ USETW(req.wValue, 0);
+ USETW(req.wIndex, sc->sc_iface_number);
+ USETW(req.wLength, LENGTH_SET_MCR);
+
+ (void)usbd_do_request(sc->sc_udev, &req, &ls);
+}
+
+void
+umct_set(void *addr, int portno, int reg, int onoff)
+{
+ struct umct_softc *sc = addr;
+
+ switch (reg) {
+ case UCOM_SET_DTR:
+ umct_dtr(sc, onoff);
+ break;
+ case UCOM_SET_RTS:
+ umct_rts(sc, onoff);
+ break;
+ case UCOM_SET_BREAK:
+ umct_break(sc, onoff);
+ break;
+ default:
+ break;
+ }
+}
+
+void
+umct_dtr(struct umct_softc *sc, int onoff)
+{
+
+ DPRINTF(("umct_dtr: onoff=%d\n", onoff));
+
+ if (sc->sc_dtr == onoff)
+ return;
+ sc->sc_dtr = onoff;
+
+ umct_set_line_state(sc);
+}
+
+void
+umct_rts(struct umct_softc *sc, int onoff)
+{
+ DPRINTF(("umct_rts: onoff=%d\n", onoff));
+
+ if (sc->sc_rts == onoff)
+ return;
+ sc->sc_rts = onoff;
+
+ umct_set_line_state(sc);
+}
+
+void
+umct_break(struct umct_softc *sc, int onoff)
+{
+ DPRINTF(("umct_break: onoff=%d\n", onoff));
+
+ umct_set_lcr(sc, onoff ? sc->last_lcr | LCR_SET_BREAK :
+ sc->last_lcr);
+}
+
+void
+umct_set_lcr(struct umct_softc *sc, u_int data)
+{
+ usb_device_request_t req;
+ uByte adata;
+
+ adata = data;
+ req.bmRequestType = UMCT_SET_REQUEST;
+ req.bRequest = REQ_SET_LCR;
+ USETW(req.wValue, 0);
+ USETW(req.wIndex, sc->sc_iface_number);
+ USETW(req.wLength, LENGTH_SET_LCR);
+
+ /* XXX should check */
+ (void)usbd_do_request(sc->sc_udev, &req, &adata);
+}
+
+void
+umct_set_baudrate(struct umct_softc *sc, u_int rate)
+{
+ usb_device_request_t req;
+ uDWord arate;
+ u_int val;
+
+ if (sc->sc_product == USB_PRODUCT_MCT_SITECOM_USB232) {
+ switch (rate) {
+ case 300: val = 0x01; break;
+ case 600: val = 0x02; break;
+ case 1200: val = 0x03; break;
+ case 2400: val = 0x04; break;
+ case 4800: val = 0x06; break;
+ case 9600: val = 0x08; break;
+ case 19200: val = 0x09; break;
+ case 38400: val = 0x0a; break;
+ case 57600: val = 0x0b; break;
+ case 115200: val = 0x0c; break;
+ default: val = -1; break;
+ }
+ } else {
+ val = UMCT_BAUD_RATE(rate);
+ }
+ USETDW(arate, val);
+
+ req.bmRequestType = UMCT_SET_REQUEST;
+ req.bRequest = REQ_SET_BAUD_RATE;
+ USETW(req.wValue, 0);
+ USETW(req.wIndex, sc->sc_iface_number);
+ USETW(req.wLength, LENGTH_BAUD_RATE);
+
+ /* XXX should check */
+ (void)usbd_do_request(sc->sc_udev, &req, arate);
+}
+
+void
+umct_init(struct umct_softc *sc)
+{
+ umct_set_baudrate(sc, 9600);
+ umct_set_lcr(sc, LCR_DATA_BITS_8 | LCR_PARITY_NONE | LCR_STOP_BITS_1);
+}
+
+int
+umct_param(void *addr, int portno, struct termios *t)
+{
+ struct umct_softc *sc = addr;
+ u_int data = 0;
+
+ DPRINTF(("umct_param: sc=%p\n", sc));
+
+ DPRINTF(("umct_param: BAUDRATE=%d\n", t->c_ospeed));
+
+ if (ISSET(t->c_cflag, CSTOPB))
+ data |= LCR_STOP_BITS_2;
+ else
+ data |= LCR_STOP_BITS_1;
+ if (ISSET(t->c_cflag, PARENB)) {
+ if (ISSET(t->c_cflag, PARODD))
+ data |= LCR_PARITY_ODD;
+ else
+ data |= LCR_PARITY_EVEN;
+ } else
+ data |= LCR_PARITY_NONE;
+ switch (ISSET(t->c_cflag, CSIZE)) {
+ case CS5:
+ data |= LCR_DATA_BITS_5;
+ break;
+ case CS6:
+ data |= LCR_DATA_BITS_6;
+ break;
+ case CS7:
+ data |= LCR_DATA_BITS_7;
+ break;
+ case CS8:
+ data |= LCR_DATA_BITS_8;
+ break;
+ }
+
+ umct_set_baudrate(sc, t->c_ospeed);
+
+ sc->last_lcr = data;
+ umct_set_lcr(sc, data);
+
+ return (0);
+}
+
+int
+umct_open(void *addr, int portno)
+{
+ struct umct_softc *sc = addr;
+ int err, lcr_data;
+
+ if (sc->sc_dying)
+ return (EIO);
+
+ DPRINTF(("umct_open: sc=%p\n", sc));
+
+ /* initialize LCR */
+ lcr_data = LCR_DATA_BITS_8 | LCR_PARITY_NONE |
+ LCR_STOP_BITS_1;
+ umct_set_lcr(sc, lcr_data);
+
+ if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) {
+ sc->sc_status = 0; /* clear status bit */
+ sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
+ err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_intr_number,
+ USBD_SHORT_XFER_OK, &sc->sc_intr_pipe, sc,
+ sc->sc_intr_buf, sc->sc_isize,
+ umct_intr, USBD_DEFAULT_INTERVAL);
+ if (err) {
+ DPRINTF(("%s: cannot open interrupt pipe (addr %d)\n",
+ USBDEVNAME(sc->sc_dev), sc->sc_intr_number));
+ return (EIO);
+ }
+ }
+
+ return (0);
+}
+
+void
+umct_close(void *addr, int portno)
+{
+ struct umct_softc *sc = addr;
+ int err;
+
+ if (sc->sc_dying)
+ return;
+
+ DPRINTF(("umct_close: close\n"));
+
+ if (sc->sc_intr_pipe != NULL) {
+ err = usbd_abort_pipe(sc->sc_intr_pipe);
+ if (err)
+ printf("%s: abort interrupt pipe failed: %s\n",
+ USBDEVNAME(sc->sc_dev), usbd_errstr(err));
+ err = usbd_close_pipe(sc->sc_intr_pipe);
+ if (err)
+ printf("%s: close interrupt pipe failed: %s\n",
+ USBDEVNAME(sc->sc_dev), usbd_errstr(err));
+ free(sc->sc_intr_buf, M_USBDEV);
+ sc->sc_intr_pipe = NULL;
+ }
+}
+
+void
+umct_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
+{
+ struct umct_softc *sc = priv;
+ u_char *buf = sc->sc_intr_buf;
+ u_char mstatus, lstatus;
+
+ if (sc->sc_dying)
+ return;
+
+ if (status != USBD_NORMAL_COMPLETION) {
+ if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
+ return;
+
+ DPRINTF(("%s: abnormal status: %s\n", USBDEVNAME(sc->sc_dev),
+ usbd_errstr(status)));
+ usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
+ return;
+ }
+
+ DPRINTF(("%s: umct status = MSR:%02x, LSR:%02x\n",
+ USBDEVNAME(sc->sc_dev), buf[0],buf[1]));
+
+ sc->sc_lsr = sc->sc_msr = 0;
+ mstatus = buf[0];
+ lstatus = buf[1];
+ if (ISSET(mstatus, MSR_DSR))
+ sc->sc_msr |= UMSR_DSR;
+ if (ISSET(mstatus, MSR_DCD))
+ sc->sc_msr |= UMSR_DCD;
+ ucom_status_change((struct ucom_softc *)sc->sc_subdev);
+}
+
+void
+umct_get_status(void *addr, int portno, u_char *lsr, u_char *msr)
+{
+ struct umct_softc *sc = addr;
+
+ DPRINTF(("umct_get_status:\n"));
+
+ if (lsr != NULL)
+ *lsr = sc->sc_lsr;
+ if (msr != NULL)
+ *msr = sc->sc_msr;
+}
diff --git a/sys/dev/usb/umct.h b/sys/dev/usb/umct.h
new file mode 100644
index 00000000000..e162280d74c
--- /dev/null
+++ b/sys/dev/usb/umct.h
@@ -0,0 +1,109 @@
+/* $OpenBSD: umct.h,v 1.1 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: umct.h,v 1.1 2001/03/28 18:42:13 ichiro Exp $ */
+/*
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Ichiro FUKUHARA (ichiro@ichiro.org).
+ *
+ * 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.
+ */
+
+/*
+ * Vendor Request Interface
+ */
+#define UMCT_SET_REQUEST 0x40
+#define UMCT_GET_REQUEST 0xc0
+
+#define REQ_SET_BAUD_RATE 5 /* Set Baud Rate Divisor */
+#define LENGTH_BAUD_RATE 4
+
+#define REQ_GET_MSR 2 /* Get Modem Status Register (MSR) */
+#define LENGTH_GET_MSR 1
+
+#define REQ_GET_LCR 6 /* Get Line Control Register (LCR) */
+#define LENGTH_GET_LCR 1
+
+#define REQ_SET_LCR 7 /* Set Line Control Register (LCR) */
+#define LENGTH_SET_LCR 1
+
+#define REQ_SET_MCR 10 /* Set Modem Control Register (MCR) */
+#define LENGTH_SET_MCR 1
+
+/*
+ * Baud rate (divisor)
+ */
+#define UMCT_BAUD_RATE(b) (115200/b)
+
+/*
+ * Line Control Register (LCR)
+ */
+#define LCR_SET_BREAK 0x40
+#define LCR_PARITY_EVEN 0x18
+#define LCR_PARITY_ODD 0x08
+#define LCR_PARITY_NONE 0x00
+#define LCR_DATA_BITS_5 0x00
+#define LCR_DATA_BITS_6 0x01
+#define LCR_DATA_BITS_7 0x02
+#define LCR_DATA_BITS_8 0x03
+#define LCR_STOP_BITS_2 0x04
+#define LCR_STOP_BITS_1 0x00
+
+/*
+ * Modem Control Register (MCR)
+ */
+#define MCR_NONE 0x8
+#define MCR_RTS 0xa
+#define MCR_DTR 0x9
+
+/*
+ * Modem Status Register (MSR)
+ */
+#define MSR_CD 0x80 /* Current CD */
+#define MSR_RI 0x40 /* Current RI */
+#define MSR_DSR 0x20 /* Current DSR */
+#define MSR_CTS 0x10 /* Current CTS */
+#define MSR_DCD 0x08 /* Delta CD */
+#define MSR_DRI 0x04 /* Delta RI */
+#define MSR_DDSR 0x02 /* Delta DSR */
+#define MSR_DCTS 0x01 /* Delta CTS */
+
+/*
+ * Line Status Register (LSR)
+ */
+#define LSR_ERR 0x80 /* OE | PE | FE | BI */
+#define LSR_TEMT 0x40 /* transmit register empty */
+#define LSR_THRE 0x20 /* transmit holding register empty */
+#define LSR_BI 0x10 /* break indicator */
+#define LSR_FE 0x08 /* framing error */
+#define LSR_OE 0x02 /* overrun error */
+#define LSR_PE 0x04 /* parity error */
+#define LSR_OE 0x02 /* overrun error */
+#define LSR_DR 0x01 /* receive data ready */
diff --git a/sys/dev/usb/umidi.c b/sys/dev/usb/umidi.c
new file mode 100644
index 00000000000..09b8df082a8
--- /dev/null
+++ b/sys/dev/usb/umidi.c
@@ -0,0 +1,1374 @@
+/* $OpenBSD: umidi.c,v 1.1 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: umidi.c,v 1.14 2002/03/08 17:24:06 kent Exp $ */
+/*
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Takuya SHIOZAKI (tshiozak@netbsd.org).
+ *
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/ioctl.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/select.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+#include <sys/poll.h>
+#include <sys/lock.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+
+#include <dev/usb/usbdevs.h>
+#include <dev/usb/uaudioreg.h>
+#include <dev/usb/umidireg.h>
+#include <dev/usb/umidivar.h>
+#include <dev/usb/umidi_quirks.h>
+
+#include <dev/midi_if.h>
+
+#ifdef UMIDI_DEBUG
+#define DPRINTF(x) if (umididebug) printf x
+#define DPRINTFN(n,x) if (umididebug >= (n)) printf x
+int umididebug = 0;
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n,x)
+#endif
+
+
+static int umidi_open(void *, int,
+ void (*)(void *, int), void (*)(void *), void *);
+static void umidi_close(void *);
+static int umidi_output(void *, int);
+static void umidi_getinfo(void *, struct midi_info *);
+
+static usbd_status alloc_pipe(struct umidi_endpoint *);
+static void free_pipe(struct umidi_endpoint *);
+
+static usbd_status alloc_all_endpoints(struct umidi_softc *);
+static void free_all_endpoints(struct umidi_softc *);
+
+static usbd_status alloc_all_jacks(struct umidi_softc *);
+static void free_all_jacks(struct umidi_softc *);
+static usbd_status bind_jacks_to_mididev(struct umidi_softc *,
+ struct umidi_jack *,
+ struct umidi_jack *,
+ struct umidi_mididev *);
+static void unbind_jacks_from_mididev(struct umidi_mididev *);
+static void unbind_all_jacks(struct umidi_softc *);
+static usbd_status assign_all_jacks_automatically(struct umidi_softc *);
+static usbd_status open_out_jack(struct umidi_jack *, void *,
+ void (*)(void *));
+static usbd_status open_in_jack(struct umidi_jack *, void *,
+ void (*)(void *, int));
+static void close_out_jack(struct umidi_jack *);
+static void close_in_jack(struct umidi_jack *);
+
+static usbd_status attach_mididev(struct umidi_softc *,
+ struct umidi_mididev *);
+static usbd_status detach_mididev(struct umidi_mididev *, int);
+static usbd_status deactivate_mididev(struct umidi_mididev *);
+static usbd_status alloc_all_mididevs(struct umidi_softc *, int);
+static void free_all_mididevs(struct umidi_softc *);
+static usbd_status attach_all_mididevs(struct umidi_softc *);
+static usbd_status detach_all_mididevs(struct umidi_softc *, int);
+static usbd_status deactivate_all_mididevs(struct umidi_softc *);
+
+#ifdef UMIDI_DEBUG
+static void dump_sc(struct umidi_softc *);
+static void dump_ep(struct umidi_endpoint *);
+static void dump_jack(struct umidi_jack *);
+#endif
+
+static void init_packet(struct umidi_packet *);
+
+static usbd_status start_input_transfer(struct umidi_endpoint *);
+static usbd_status start_output_transfer(struct umidi_endpoint *);
+static int out_jack_output(struct umidi_jack *, int);
+static void in_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
+static void out_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
+static void out_build_packet(int, struct umidi_packet *, uByte);
+
+
+struct midi_hw_if umidi_hw_if = {
+ umidi_open,
+ umidi_close,
+ umidi_output,
+ umidi_getinfo,
+ 0, /* ioctl */
+};
+
+USB_DECLARE_DRIVER(umidi);
+
+USB_MATCH(umidi)
+{
+ USB_MATCH_START(umidi, uaa);
+ usb_interface_descriptor_t *id;
+
+ DPRINTFN(1,("umidi_match\n"));
+
+ if (uaa->iface == NULL)
+ return UMATCH_NONE;
+
+ if (umidi_search_quirk(uaa->vendor, uaa->product, uaa->ifaceno))
+ return UMATCH_IFACECLASS_IFACESUBCLASS;
+
+ id = usbd_get_interface_descriptor(uaa->iface);
+ if (id!=NULL &&
+ id->bInterfaceClass==UICLASS_AUDIO &&
+ id->bInterfaceSubClass==UISUBCLASS_MIDISTREAM)
+ return UMATCH_IFACECLASS_IFACESUBCLASS;
+
+ return UMATCH_NONE;
+}
+
+USB_ATTACH(umidi)
+{
+ usbd_status err;
+ USB_ATTACH_START(umidi, sc, uaa);
+ char devinfo[1024];
+
+ DPRINTFN(1,("umidi_attach\n"));
+
+ usbd_devinfo(uaa->device, 0, devinfo);
+ printf("\n%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo);
+
+ sc->sc_iface = uaa->iface;
+ sc->sc_udev = uaa->device;
+
+ sc->sc_quirk =
+ umidi_search_quirk(uaa->vendor, uaa->product, uaa->ifaceno);
+ printf("%s: ", USBDEVNAME(sc->sc_dev));
+ umidi_print_quirk(sc->sc_quirk);
+
+
+ err = alloc_all_endpoints(sc);
+ if (err!=USBD_NORMAL_COMPLETION) {
+ printf("%s: alloc_all_endpoints failed. (err=%d)\n",
+ USBDEVNAME(sc->sc_dev), err);
+ goto error;
+ }
+ err = alloc_all_jacks(sc);
+ if (err!=USBD_NORMAL_COMPLETION) {
+ free_all_endpoints(sc);
+ printf("%s: alloc_all_jacks failed. (err=%d)\n",
+ USBDEVNAME(sc->sc_dev), err);
+ goto error;
+ }
+ printf("%s: out=%d, in=%d\n",
+ USBDEVNAME(sc->sc_dev),
+ sc->sc_out_num_jacks, sc->sc_in_num_jacks);
+
+ err = assign_all_jacks_automatically(sc);
+ if (err!=USBD_NORMAL_COMPLETION) {
+ unbind_all_jacks(sc);
+ free_all_jacks(sc);
+ free_all_endpoints(sc);
+ printf("%s: assign_all_jacks_automatically failed. (err=%d)\n",
+ USBDEVNAME(sc->sc_dev), err);
+ goto error;
+ }
+ err = attach_all_mididevs(sc);
+ if (err!=USBD_NORMAL_COMPLETION) {
+ free_all_jacks(sc);
+ free_all_endpoints(sc);
+ printf("%s: attach_all_mididevs failed. (err=%d)\n",
+ USBDEVNAME(sc->sc_dev), err);
+ }
+
+#ifdef UMIDI_DEBUG
+ dump_sc(sc);
+#endif
+
+ usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH,
+ sc->sc_udev, USBDEV(sc->sc_dev));
+
+ USB_ATTACH_SUCCESS_RETURN;
+error:
+ printf("%s: disabled.\n", USBDEVNAME(sc->sc_dev));
+ sc->sc_dying = 1;
+ USB_ATTACH_ERROR_RETURN;
+}
+
+int
+umidi_activate(device_ptr_t self, enum devact act)
+{
+ struct umidi_softc *sc = (struct umidi_softc *)self;
+
+ switch (act) {
+ case DVACT_ACTIVATE:
+ DPRINTFN(1,("umidi_activate (activate)\n"));
+
+ return EOPNOTSUPP;
+ break;
+ case DVACT_DEACTIVATE:
+ DPRINTFN(1,("umidi_activate (deactivate)\n"));
+ sc->sc_dying = 1;
+ deactivate_all_mididevs(sc);
+ break;
+ }
+ return 0;
+}
+
+USB_DETACH(umidi)
+{
+ USB_DETACH_START(umidi, sc);
+
+ DPRINTFN(1,("umidi_detach\n"));
+
+ sc->sc_dying = 1;
+ detach_all_mididevs(sc, flags);
+ free_all_mididevs(sc);
+ free_all_jacks(sc);
+ free_all_endpoints(sc);
+
+ usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
+ USBDEV(sc->sc_dev));
+
+ return 0;
+}
+
+
+/*
+ * midi_if stuffs
+ */
+int
+umidi_open(void *addr,
+ int flags,
+ void (*iintr)(void *, int),
+ void (*ointr)(void *),
+ void *arg)
+{
+ struct umidi_mididev *mididev = addr;
+ struct umidi_softc *sc = mididev->sc;
+
+ DPRINTF(("umidi_open: sc=%p\n", sc));
+
+ if (!sc)
+ return ENXIO;
+ if (mididev->opened)
+ return EBUSY;
+ if (sc->sc_dying)
+ return EIO;
+
+ mididev->opened = 1;
+ mididev->flags = flags;
+ if ((mididev->flags & FWRITE) && mididev->out_jack)
+ open_out_jack(mididev->out_jack, arg, ointr);
+ if ((mididev->flags & FREAD) && mididev->in_jack) {
+ open_in_jack(mididev->in_jack, arg, iintr);
+ }
+
+ return 0;
+}
+
+void
+umidi_close(void *addr)
+{
+ int s;
+ struct umidi_mididev *mididev = addr;
+
+ s = splusb();
+ if ((mididev->flags & FWRITE) && mididev->out_jack)
+ close_out_jack(mididev->out_jack);
+ if ((mididev->flags & FREAD) && mididev->in_jack)
+ close_in_jack(mididev->in_jack);
+ mididev->opened = 0;
+ splx(s);
+}
+
+int
+umidi_output(void *addr, int d)
+{
+ struct umidi_mididev *mididev = addr;
+
+ if (!mididev->out_jack || !mididev->opened)
+ return EIO;
+
+ return out_jack_output(mididev->out_jack, d);
+}
+
+void
+umidi_getinfo(void *addr, struct midi_info *mi)
+{
+ struct umidi_mididev *mididev = addr;
+/* struct umidi_softc *sc = mididev->sc; */
+
+ mi->name = "USB MIDI I/F"; /* XXX: model name */
+ mi->props = MIDI_PROP_OUT_INTR;
+ if (mididev->in_jack)
+ mi->props |= MIDI_PROP_CAN_INPUT;
+}
+
+
+/*
+ * each endpoint stuffs
+ */
+
+/* alloc/free pipe */
+static usbd_status
+alloc_pipe(struct umidi_endpoint *ep)
+{
+ struct umidi_softc *sc = ep->sc;
+ usbd_status err;
+
+ DPRINTF(("%s: alloc_pipe %p\n", USBDEVNAME(sc->sc_dev), ep));
+ LIST_INIT(&ep->queue_head);
+ ep->xfer = usbd_alloc_xfer(sc->sc_udev);
+ if (ep->xfer == NULL) {
+ err = USBD_NOMEM;
+ goto quit;
+ }
+ ep->buffer = usbd_alloc_buffer(ep->xfer, UMIDI_PACKET_SIZE);
+ if (ep->buffer == NULL) {
+ usbd_free_xfer(ep->xfer);
+ err = USBD_NOMEM;
+ goto quit;
+ }
+ err = usbd_open_pipe(sc->sc_iface, ep->addr, 0, &ep->pipe);
+ if (err)
+ usbd_free_xfer(ep->xfer);
+quit:
+ return err;
+}
+
+static void
+free_pipe(struct umidi_endpoint *ep)
+{
+ DPRINTF(("%s: free_pipe %p\n", USBDEVNAME(ep->sc->sc_dev), ep));
+ usbd_abort_pipe(ep->pipe);
+ usbd_close_pipe(ep->pipe);
+ usbd_free_xfer(ep->xfer);
+}
+
+
+/* alloc/free the array of endpoint structures */
+
+static usbd_status alloc_all_endpoints_fixed_ep(struct umidi_softc *);
+static usbd_status alloc_all_endpoints_yamaha(struct umidi_softc *);
+static usbd_status alloc_all_endpoints_genuine(struct umidi_softc *);
+
+static usbd_status
+alloc_all_endpoints(struct umidi_softc *sc)
+{
+ usbd_status err;
+ struct umidi_endpoint *ep;
+ int i;
+
+ if (UMQ_ISTYPE(sc, UMQ_TYPE_FIXED_EP)) {
+ err = alloc_all_endpoints_fixed_ep(sc);
+ } else if (UMQ_ISTYPE(sc, UMQ_TYPE_YAMAHA)) {
+ err = alloc_all_endpoints_yamaha(sc);
+ } else {
+ err = alloc_all_endpoints_genuine(sc);
+ }
+ if (err!=USBD_NORMAL_COMPLETION)
+ return err;
+
+ ep = sc->sc_endpoints;
+ for (i=sc->sc_out_num_endpoints+sc->sc_in_num_endpoints; i>0; i--) {
+ err = alloc_pipe(ep++);
+ if (err!=USBD_NORMAL_COMPLETION) {
+ for (; ep!=sc->sc_endpoints; ep--)
+ free_pipe(ep-1);
+ free(sc->sc_endpoints, M_USBDEV);
+ sc->sc_endpoints = sc->sc_out_ep = sc->sc_in_ep = NULL;
+ break;
+ }
+ }
+ return err;
+}
+
+static void
+free_all_endpoints(struct umidi_softc *sc)
+{
+ int i;
+ for (i=0; i<sc->sc_in_num_endpoints+sc->sc_out_num_endpoints; i++)
+ free_pipe(&sc->sc_endpoints[i]);
+ if (sc->sc_endpoints != NULL)
+ free(sc->sc_endpoints, M_USBDEV);
+ sc->sc_endpoints = sc->sc_out_ep = sc->sc_in_ep = NULL;
+}
+
+static usbd_status
+alloc_all_endpoints_fixed_ep(struct umidi_softc *sc)
+{
+ usbd_status err;
+ struct umq_fixed_ep_desc *fp;
+ struct umidi_endpoint *ep;
+ usb_endpoint_descriptor_t *epd;
+ int i;
+
+ fp = umidi_get_quirk_data_from_type(sc->sc_quirk,
+ UMQ_TYPE_FIXED_EP);
+ sc->sc_out_num_jacks = 0;
+ sc->sc_in_num_jacks = 0;
+ sc->sc_out_num_endpoints = fp->num_out_ep;
+ sc->sc_in_num_endpoints = fp->num_in_ep;
+ sc->sc_endpoints = malloc(sizeof(*sc->sc_out_ep)*
+ (sc->sc_out_num_endpoints+
+ sc->sc_in_num_endpoints),
+ M_USBDEV, M_WAITOK);
+ if (!sc->sc_endpoints) {
+ return USBD_NOMEM;
+ }
+ sc->sc_out_ep = sc->sc_out_num_endpoints ? sc->sc_endpoints : NULL;
+ sc->sc_in_ep =
+ sc->sc_in_num_endpoints ?
+ sc->sc_endpoints+sc->sc_out_num_endpoints : NULL;
+
+ ep = &sc->sc_out_ep[0];
+ for (i=0; i<sc->sc_out_num_endpoints; i++) {
+ epd = usbd_interface2endpoint_descriptor(
+ sc->sc_iface,
+ fp->out_ep[i].ep);
+ if (!epd) {
+ printf("%s: cannot get endpoint descriptor(out:%d)\n",
+ USBDEVNAME(sc->sc_dev), fp->out_ep[i].ep);
+ err = USBD_INVAL;
+ goto error;
+ }
+ if (UE_GET_XFERTYPE(epd->bmAttributes)!=UE_BULK ||
+ UE_GET_DIR(epd->bEndpointAddress)!=UE_DIR_OUT) {
+ printf("%s: illegal endpoint(out:%d)\n",
+ USBDEVNAME(sc->sc_dev), fp->out_ep[i].ep);
+ err = USBD_INVAL;
+ goto error;
+ }
+ ep->sc = sc;
+ ep->addr = epd->bEndpointAddress;
+ ep->num_jacks = fp->out_ep[i].num_jacks;
+ sc->sc_out_num_jacks += fp->out_ep[i].num_jacks;
+ ep->num_open = 0;
+ memset(ep->jacks, 0, sizeof(ep->jacks));
+ LIST_INIT(&ep->queue_head);
+ ep++;
+ }
+ ep = &sc->sc_in_ep[0];
+ for (i=0; i<sc->sc_in_num_endpoints; i++) {
+ epd = usbd_interface2endpoint_descriptor(
+ sc->sc_iface,
+ fp->in_ep[i].ep);
+ if (!epd) {
+ printf("%s: cannot get endpoint descriptor(in:%d)\n",
+ USBDEVNAME(sc->sc_dev), fp->in_ep[i].ep);
+ err = USBD_INVAL;
+ goto error;
+ }
+ if (UE_GET_XFERTYPE(epd->bmAttributes)!=UE_BULK ||
+ UE_GET_DIR(epd->bEndpointAddress)!=UE_DIR_IN) {
+ printf("%s: illegal endpoint(in:%d)\n",
+ USBDEVNAME(sc->sc_dev), fp->in_ep[i].ep);
+ err = USBD_INVAL;
+ goto error;
+ }
+ ep->sc = sc;
+ ep->addr = epd->bEndpointAddress;
+ ep->num_jacks = fp->in_ep[i].num_jacks;
+ sc->sc_in_num_jacks += fp->in_ep[i].num_jacks;
+ ep->num_open = 0;
+ memset(ep->jacks, 0, sizeof(ep->jacks));
+ ep++;
+ }
+
+ return USBD_NORMAL_COMPLETION;
+error:
+ free(sc->sc_endpoints, M_USBDEV);
+ sc->sc_endpoints = NULL;
+ return err;
+}
+
+static usbd_status
+alloc_all_endpoints_yamaha(struct umidi_softc *sc)
+{
+ /* This driver currently supports max 1in/1out bulk endpoints */
+ usb_descriptor_t *desc;
+ usb_endpoint_descriptor_t *epd;
+ int out_addr, in_addr, i;
+ int dir;
+ size_t remain, descsize;
+
+ sc->sc_out_num_jacks = sc->sc_in_num_jacks = 0;
+ out_addr = in_addr = 0;
+
+ /* detect endpoints */
+ desc = TO_D(usbd_get_interface_descriptor(sc->sc_iface));
+ for (i=(int)TO_IFD(desc)->bNumEndpoints-1; i>=0; i--) {
+ epd = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
+ if (UE_GET_XFERTYPE(epd->bmAttributes) == UE_BULK) {
+ dir = UE_GET_DIR(epd->bEndpointAddress);
+ if (dir==UE_DIR_OUT && !out_addr)
+ out_addr = epd->bEndpointAddress;
+ else if (dir==UE_DIR_IN && !in_addr)
+ in_addr = epd->bEndpointAddress;
+ }
+ }
+ desc = NEXT_D(desc);
+
+ /* count jacks */
+ if (!(desc->bDescriptorType==UDESC_CS_INTERFACE &&
+ desc->bDescriptorSubtype==UMIDI_MS_HEADER))
+ return USBD_INVAL;
+ remain = (size_t)UGETW(TO_CSIFD(desc)->wTotalLength) -
+ (size_t)desc->bLength;
+ desc = NEXT_D(desc);
+
+ while (remain>=sizeof(usb_descriptor_t)) {
+ descsize = desc->bLength;
+ if (descsize>remain || descsize==0)
+ break;
+ if (desc->bDescriptorType==UDESC_CS_INTERFACE &&
+ remain>=UMIDI_JACK_DESCRIPTOR_SIZE) {
+ if (desc->bDescriptorSubtype==UMIDI_OUT_JACK)
+ sc->sc_out_num_jacks++;
+ else if (desc->bDescriptorSubtype==UMIDI_IN_JACK)
+ sc->sc_in_num_jacks++;
+ }
+ desc = NEXT_D(desc);
+ remain-=descsize;
+ }
+
+ /* validate some parameters */
+ if (sc->sc_out_num_jacks>UMIDI_MAX_EPJACKS)
+ sc->sc_out_num_jacks = UMIDI_MAX_EPJACKS;
+ if (sc->sc_in_num_jacks>UMIDI_MAX_EPJACKS)
+ sc->sc_in_num_jacks = UMIDI_MAX_EPJACKS;
+ if (sc->sc_out_num_jacks && out_addr) {
+ sc->sc_out_num_endpoints = 1;
+ } else {
+ sc->sc_out_num_endpoints = 0;
+ sc->sc_out_num_jacks = 0;
+ }
+ if (sc->sc_in_num_jacks && in_addr) {
+ sc->sc_in_num_endpoints = 1;
+ } else {
+ sc->sc_in_num_endpoints = 0;
+ sc->sc_in_num_jacks = 0;
+ }
+ sc->sc_endpoints = malloc(sizeof(struct umidi_endpoint)*
+ (sc->sc_out_num_endpoints+
+ sc->sc_in_num_endpoints),
+ M_USBDEV, M_WAITOK);
+ if (!sc->sc_endpoints)
+ return USBD_NOMEM;
+ if (sc->sc_out_num_endpoints) {
+ sc->sc_out_ep = sc->sc_endpoints;
+ sc->sc_out_ep->sc = sc;
+ sc->sc_out_ep->addr = out_addr;
+ sc->sc_out_ep->num_jacks = sc->sc_out_num_jacks;
+ sc->sc_out_ep->num_open = 0;
+ memset(sc->sc_out_ep->jacks, 0, sizeof(sc->sc_out_ep->jacks));
+ } else
+ sc->sc_out_ep = NULL;
+
+ if (sc->sc_in_num_endpoints) {
+ sc->sc_in_ep = sc->sc_endpoints+sc->sc_out_num_endpoints;
+ sc->sc_in_ep->sc = sc;
+ sc->sc_in_ep->addr = in_addr;
+ sc->sc_in_ep->num_jacks = sc->sc_in_num_jacks;
+ sc->sc_in_ep->num_open = 0;
+ memset(sc->sc_in_ep->jacks, 0, sizeof(sc->sc_in_ep->jacks));
+ } else
+ sc->sc_in_ep = NULL;
+
+ return USBD_NORMAL_COMPLETION;
+}
+
+static usbd_status
+alloc_all_endpoints_genuine(struct umidi_softc *sc)
+{
+ usb_descriptor_t *desc;
+ int num_ep;
+ size_t remain, descsize;
+ struct umidi_endpoint *p, *q, *lowest, *endep, tmpep;
+ int epaddr;
+
+ desc = TO_D(usbd_get_interface_descriptor(sc->sc_iface));
+ num_ep = TO_IFD(desc)->bNumEndpoints;
+ desc = NEXT_D(desc); /* ifd -> csifd */
+ remain = ((size_t)UGETW(TO_CSIFD(desc)->wTotalLength) -
+ (size_t)desc->bLength);
+ desc = NEXT_D(desc);
+
+ sc->sc_endpoints = p = malloc(sizeof(struct umidi_endpoint)*num_ep,
+ M_USBDEV, M_WAITOK);
+ if (!p)
+ return USBD_NOMEM;
+
+ sc->sc_out_num_jacks = sc->sc_in_num_jacks = 0;
+ sc->sc_out_num_endpoints = sc->sc_in_num_endpoints = 0;
+ epaddr = -1;
+
+ /* get the list of endpoints for midi stream */
+ while (remain>=sizeof(usb_descriptor_t)) {
+ descsize = desc->bLength;
+ if (descsize>remain || descsize==0)
+ break;
+ if (desc->bDescriptorType==UDESC_ENDPOINT &&
+ remain>=USB_ENDPOINT_DESCRIPTOR_SIZE &&
+ UE_GET_XFERTYPE(TO_EPD(desc)->bmAttributes) == UE_BULK) {
+ epaddr = TO_EPD(desc)->bEndpointAddress;
+ } else if (desc->bDescriptorType==UDESC_CS_ENDPOINT &&
+ remain>=UMIDI_CS_ENDPOINT_DESCRIPTOR_SIZE &&
+ epaddr!=-1) {
+ if (num_ep>0) {
+ num_ep--;
+ p->sc = sc;
+ p->addr = epaddr;
+ p->num_jacks = TO_CSEPD(desc)->bNumEmbMIDIJack;
+ if (UE_GET_DIR(epaddr)==UE_DIR_OUT) {
+ sc->sc_out_num_endpoints++;
+ sc->sc_out_num_jacks += p->num_jacks;
+ } else {
+ sc->sc_in_num_endpoints++;
+ sc->sc_in_num_jacks += p->num_jacks;
+ }
+ p++;
+ }
+ } else
+ epaddr = -1;
+ desc = NEXT_D(desc);
+ remain-=descsize;
+ }
+
+ /* sort endpoints */
+ num_ep = sc->sc_out_num_endpoints + sc->sc_in_num_endpoints;
+ p = sc->sc_endpoints;
+ endep = p + num_ep;
+ while (p<endep) {
+ lowest = p;
+ for (q=p+1; q<endep; q++) {
+ if ((UE_GET_DIR(lowest->addr)==UE_DIR_IN &&
+ UE_GET_DIR(q->addr)==UE_DIR_OUT) ||
+ ((UE_GET_DIR(lowest->addr)==
+ UE_GET_DIR(q->addr)) &&
+ (UE_GET_ADDR(lowest->addr)>
+ UE_GET_ADDR(q->addr))))
+ lowest = q;
+ }
+ if (lowest != p) {
+ memcpy((void *)&tmpep, (void *)p, sizeof(tmpep));
+ memcpy((void *)p, (void *)lowest, sizeof(tmpep));
+ memcpy((void *)lowest, (void *)&tmpep, sizeof(tmpep));
+ }
+ p->num_open = 0;
+ p++;
+ }
+
+ sc->sc_out_ep = sc->sc_out_num_endpoints ? sc->sc_endpoints : NULL;
+ sc->sc_in_ep =
+ sc->sc_in_num_endpoints ?
+ sc->sc_endpoints+sc->sc_out_num_endpoints : NULL;
+
+ return USBD_NORMAL_COMPLETION;
+}
+
+
+/*
+ * jack stuffs
+ */
+
+static usbd_status
+alloc_all_jacks(struct umidi_softc *sc)
+{
+ int i, j;
+ struct umidi_endpoint *ep;
+ struct umidi_jack *jack, **rjack;
+
+ /* allocate/initialize structures */
+ sc->sc_jacks =
+ malloc(sizeof(*sc->sc_out_jacks)*(sc->sc_in_num_jacks+
+ sc->sc_out_num_jacks),
+ M_USBDEV, M_WAITOK);
+ if (!sc->sc_jacks)
+ return USBD_NOMEM;
+ sc->sc_out_jacks =
+ sc->sc_out_num_jacks ? sc->sc_jacks : NULL;
+ sc->sc_in_jacks =
+ sc->sc_in_num_jacks ? sc->sc_jacks+sc->sc_out_num_jacks : NULL;
+
+ jack = &sc->sc_out_jacks[0];
+ for (i=0; i<sc->sc_out_num_jacks; i++) {
+ jack->opened = 0;
+ jack->binded = 0;
+ jack->arg = NULL;
+ jack->u.out.intr = NULL;
+ jack->cable_number = i;
+ jack++;
+ }
+ jack = &sc->sc_in_jacks[0];
+ for (i=0; i<sc->sc_in_num_jacks; i++) {
+ jack->opened = 0;
+ jack->binded = 0;
+ jack->arg = NULL;
+ jack->u.in.intr = NULL;
+ jack->cable_number = i;
+ jack++;
+ }
+
+ /* assign each jacks to each endpoints */
+ jack = &sc->sc_out_jacks[0];
+ ep = &sc->sc_out_ep[0];
+ for (i=0; i<sc->sc_out_num_endpoints; i++) {
+ rjack = &ep->jacks[0];
+ for (j=0; j<ep->num_jacks; j++) {
+ *rjack = jack;
+ jack->endpoint = ep;
+ jack++;
+ rjack++;
+ }
+ ep++;
+ }
+ jack = &sc->sc_in_jacks[0];
+ ep = &sc->sc_in_ep[0];
+ for (i=0; i<sc->sc_in_num_endpoints; i++) {
+ rjack = &ep->jacks[0];
+ for (j=0; j<ep->num_jacks; j++) {
+ *rjack = jack;
+ jack->endpoint = ep;
+ jack++;
+ rjack++;
+ }
+ ep++;
+ }
+
+ return USBD_NORMAL_COMPLETION;
+}
+
+static void
+free_all_jacks(struct umidi_softc *sc)
+{
+ int s;
+
+ s = splaudio();
+ if (sc->sc_out_jacks) {
+ free(sc->sc_jacks, M_USBDEV);
+ sc->sc_jacks = sc->sc_in_jacks = sc->sc_out_jacks = NULL;
+ }
+ splx(s);
+}
+
+static usbd_status
+bind_jacks_to_mididev(struct umidi_softc *sc,
+ struct umidi_jack *out_jack,
+ struct umidi_jack *in_jack,
+ struct umidi_mididev *mididev)
+{
+ if ((out_jack && out_jack->binded) || (in_jack && in_jack->binded))
+ return USBD_IN_USE;
+ if (mididev->out_jack || mididev->in_jack)
+ return USBD_IN_USE;
+
+ if (out_jack)
+ out_jack->binded = 1;
+ if (in_jack)
+ in_jack->binded = 1;
+ mididev->in_jack = in_jack;
+ mididev->out_jack = out_jack;
+
+ return USBD_NORMAL_COMPLETION;
+}
+
+static void
+unbind_jacks_from_mididev(struct umidi_mididev *mididev)
+{
+ if ((mididev->flags&FWRITE) && mididev->out_jack)
+ close_out_jack(mididev->out_jack);
+ if ((mididev->flags&FWRITE) && mididev->in_jack)
+ close_in_jack(mididev->in_jack);
+
+ if (mididev->out_jack)
+ mididev->out_jack->binded = 0;
+ if (mididev->in_jack)
+ mididev->in_jack->binded = 0;
+ mididev->out_jack = mididev->in_jack = NULL;
+}
+
+static void
+unbind_all_jacks(struct umidi_softc *sc)
+{
+ int i;
+
+ if (sc->sc_mididevs)
+ for (i=0; i<sc->sc_num_mididevs; i++) {
+ unbind_jacks_from_mididev(&sc->sc_mididevs[i]);
+ }
+}
+
+static usbd_status
+assign_all_jacks_automatically(struct umidi_softc *sc)
+{
+ usbd_status err;
+ int i;
+ struct umidi_jack *out, *in;
+
+ err =
+ alloc_all_mididevs(sc,
+ max(sc->sc_out_num_jacks, sc->sc_in_num_jacks));
+ if (err!=USBD_NORMAL_COMPLETION)
+ return err;
+
+ for (i=0; i<sc->sc_num_mididevs; i++) {
+ out = (i<sc->sc_out_num_jacks) ? &sc->sc_out_jacks[i]:NULL;
+ in = (i<sc->sc_in_num_jacks) ? &sc->sc_in_jacks[i]:NULL;
+ err = bind_jacks_to_mididev(sc, out, in, &sc->sc_mididevs[i]);
+ if (err!=USBD_NORMAL_COMPLETION) {
+ free_all_mididevs(sc);
+ return err;
+ }
+ }
+
+ return USBD_NORMAL_COMPLETION;
+}
+
+static usbd_status
+open_out_jack(struct umidi_jack *jack, void *arg, void (*intr)(void *))
+{
+ struct umidi_endpoint *ep = jack->endpoint;
+
+ if (jack->opened)
+ return USBD_IN_USE;
+
+ jack->arg = arg;
+ jack->u.out.intr = intr;
+ init_packet(&jack->packet);
+ jack->opened = 1;
+ ep->num_open++;
+
+ return USBD_NORMAL_COMPLETION;
+}
+
+static usbd_status
+open_in_jack(struct umidi_jack *jack, void *arg, void (*intr)(void *, int))
+{
+ usbd_status err = USBD_NORMAL_COMPLETION;
+ struct umidi_endpoint *ep = jack->endpoint;
+
+ if (jack->opened)
+ return USBD_IN_USE;
+
+ jack->arg = arg;
+ jack->u.in.intr = intr;
+ jack->opened = 1;
+ if (ep->num_open++==0 && UE_GET_DIR(ep->addr)==UE_DIR_IN) {
+ err = start_input_transfer(ep);
+ if (err!=USBD_NORMAL_COMPLETION) {
+ ep->num_open--;
+ }
+ }
+
+ return err;
+}
+
+static void
+close_out_jack(struct umidi_jack *jack)
+{
+ struct umidi_jack *tail;
+ int s;
+
+ if (jack->opened) {
+ s = splusb();
+ LIST_REMOVE(jack, u.out.queue_entry);
+ if (jack==jack->endpoint->queue_tail) {
+ /* find tail */
+ LIST_FOREACH(tail,
+ &jack->endpoint->queue_head,
+ u.out.queue_entry) {
+ if (!LIST_NEXT(tail, u.out.queue_entry)) {
+ jack->endpoint->queue_tail = tail;
+ }
+ }
+ }
+ splx(s);
+ jack->opened = 0;
+ jack->endpoint->num_open--;
+ }
+}
+
+static void
+close_in_jack(struct umidi_jack *jack)
+{
+ if (jack->opened) {
+ jack->opened = 0;
+ jack->endpoint->num_open--;
+ }
+}
+
+static usbd_status
+attach_mididev(struct umidi_softc *sc, struct umidi_mididev *mididev)
+{
+ if (mididev->sc)
+ return USBD_IN_USE;
+
+ mididev->sc = sc;
+
+ mididev->mdev = midi_attach_mi(&umidi_hw_if, mididev, &sc->sc_dev);
+
+ return USBD_NORMAL_COMPLETION;
+}
+
+static usbd_status
+detach_mididev(struct umidi_mididev *mididev, int flags)
+{
+ if (!mididev->sc)
+ return USBD_NO_ADDR;
+
+ if (mididev->opened) {
+ umidi_close(mididev);
+ }
+ unbind_jacks_from_mididev(mididev);
+
+ if (mididev->mdev)
+ config_detach(mididev->mdev, flags);
+
+ mididev->sc = NULL;
+
+ return USBD_NORMAL_COMPLETION;
+}
+
+static usbd_status
+deactivate_mididev(struct umidi_mididev *mididev)
+{
+ if (mididev->out_jack)
+ mididev->out_jack->binded = 0;
+ if (mididev->in_jack)
+ mididev->in_jack->binded = 0;
+ config_deactivate(mididev->mdev);
+
+ return USBD_NORMAL_COMPLETION;
+}
+
+static usbd_status
+alloc_all_mididevs(struct umidi_softc *sc, int nmidi)
+{
+ sc->sc_num_mididevs = nmidi;
+ sc->sc_mididevs = malloc(sizeof(*sc->sc_mididevs)*nmidi,
+ M_USBDEV, M_WAITOK|M_ZERO);
+ if (!sc->sc_mididevs)
+ return USBD_NOMEM;
+
+ return USBD_NORMAL_COMPLETION;
+}
+
+static void
+free_all_mididevs(struct umidi_softc *sc)
+{
+ sc->sc_num_mididevs = 0;
+ if (sc->sc_mididevs)
+ free(sc->sc_mididevs, M_USBDEV);
+}
+
+static usbd_status
+attach_all_mididevs(struct umidi_softc *sc)
+{
+ usbd_status err;
+ int i;
+
+ if (sc->sc_mididevs)
+ for (i=0; i<sc->sc_num_mididevs; i++) {
+ err = attach_mididev(sc, &sc->sc_mididevs[i]);
+ if (err!=USBD_NORMAL_COMPLETION)
+ return err;
+ }
+
+ return USBD_NORMAL_COMPLETION;
+}
+
+static usbd_status
+detach_all_mididevs(struct umidi_softc *sc, int flags)
+{
+ usbd_status err;
+ int i;
+
+ if (sc->sc_mididevs)
+ for (i=0; i<sc->sc_num_mididevs; i++) {
+ err = detach_mididev(&sc->sc_mididevs[i], flags);
+ if (err!=USBD_NORMAL_COMPLETION)
+ return err;
+ }
+
+ return USBD_NORMAL_COMPLETION;
+}
+
+static usbd_status
+deactivate_all_mididevs(struct umidi_softc *sc)
+{
+ usbd_status err;
+ int i;
+
+ if (sc->sc_mididevs)
+ for (i=0; i<sc->sc_num_mididevs; i++) {
+ err = deactivate_mididev(&sc->sc_mididevs[i]);
+ if (err!=USBD_NORMAL_COMPLETION)
+ return err;
+ }
+
+ return USBD_NORMAL_COMPLETION;
+}
+
+#ifdef UMIDI_DEBUG
+static void
+dump_sc(struct umidi_softc *sc)
+{
+ int i;
+
+ DPRINTFN(10, ("%s: dump_sc\n", USBDEVNAME(sc->sc_dev)));
+ for (i=0; i<sc->sc_out_num_endpoints; i++) {
+ DPRINTFN(10, ("\tout_ep(%p):\n", &sc->sc_out_ep[i]));
+ dump_ep(&sc->sc_out_ep[i]);
+ }
+ for (i=0; i<sc->sc_in_num_endpoints; i++) {
+ DPRINTFN(10, ("\tin_ep(%p):\n", &sc->sc_in_ep[i]));
+ dump_ep(&sc->sc_in_ep[i]);
+ }
+}
+
+static void
+dump_ep(struct umidi_endpoint *ep)
+{
+ int i;
+ for (i=0; i<ep->num_jacks; i++) {
+ DPRINTFN(10, ("\t\tjack(%p):\n", ep->jacks[i]));
+ dump_jack(ep->jacks[i]);
+ }
+}
+static void
+dump_jack(struct umidi_jack *jack)
+{
+ DPRINTFN(10, ("\t\t\tep=%p, mididev=%p\n",
+ jack->endpoint, jack->mididev));
+}
+
+#endif /* UMIDI_DEBUG */
+
+
+
+/*
+ * MUX MIDI PACKET
+ */
+
+static const int packet_length[16] = {
+ /*0*/ -1,
+ /*1*/ -1,
+ /*2*/ 2,
+ /*3*/ 3,
+ /*4*/ 3,
+ /*5*/ 1,
+ /*6*/ 2,
+ /*7*/ 3,
+ /*8*/ 3,
+ /*9*/ 3,
+ /*A*/ 3,
+ /*B*/ 3,
+ /*C*/ 2,
+ /*D*/ 2,
+ /*E*/ 3,
+ /*F*/ 1,
+};
+
+static const struct {
+ int cin;
+ packet_state_t next;
+} packet_0xFX[16] = {
+ /*F0: SysEx */ { 0x04, PS_EXCL_1 },
+ /*F1: MTC */ { 0x02, PS_NORMAL_1OF2 },
+ /*F2: S.POS */ { 0x03, PS_NORMAL_1OF3 },
+ /*F3: S.SEL */ { 0x02, PS_NORMAL_1OF2 },
+ /*F4: UNDEF */ { 0x00, PS_INITIAL },
+ /*F5: UNDEF */ { 0x00, PS_INITIAL },
+ /*F6: Tune */ { 0x0F, PS_END },
+ /*F7: EofEx */ { 0x00, PS_INITIAL },
+ /*F8: Timing */ { 0x0F, PS_END },
+ /*F9: UNDEF */ { 0x00, PS_INITIAL },
+ /*FA: Start */ { 0x0F, PS_END },
+ /*FB: Cont */ { 0x0F, PS_END },
+ /*FC: Stop */ { 0x0F, PS_END },
+ /*FD: UNDEF */ { 0x00, PS_INITIAL },
+ /*FE: ActS */ { 0x0F, PS_END },
+ /*FF: Reset */ { 0x0F, PS_END },
+};
+
+#define GET_CN(p) (((unsigned char)(p)>>4)&0x0F)
+#define GET_CIN(p) ((unsigned char)(p)&0x0F)
+#define MIX_CN_CIN(cn, cin) \
+ ((unsigned char)((((unsigned char)(cn)&0x0F)<<4)| \
+ ((unsigned char)(cin)&0x0F)))
+
+static void
+init_packet(struct umidi_packet *packet)
+{
+ memset(packet->buffer, 0, UMIDI_PACKET_SIZE);
+ packet->state = PS_INITIAL;
+}
+
+static usbd_status
+start_input_transfer(struct umidi_endpoint *ep)
+{
+ usbd_setup_xfer(ep->xfer, ep->pipe,
+ (usbd_private_handle)ep,
+ ep->buffer, UMIDI_PACKET_SIZE,
+ USBD_NO_COPY, USBD_NO_TIMEOUT, in_intr);
+ return usbd_transfer(ep->xfer);
+}
+
+static usbd_status
+start_output_transfer(struct umidi_endpoint *ep)
+{
+ usbd_setup_xfer(ep->xfer, ep->pipe,
+ (usbd_private_handle)ep,
+ ep->buffer, UMIDI_PACKET_SIZE,
+ USBD_NO_COPY, USBD_NO_TIMEOUT, out_intr);
+ return usbd_transfer(ep->xfer);
+}
+
+#ifdef UMIDI_DEBUG
+#define DPR_PACKET(dir, sc, p) \
+if ((unsigned char)(p)->buffer[1]!=0xFE) \
+ DPRINTFN(500, \
+ ("%s: umidi packet(" #dir "): %02X %02X %02X %02X\n", \
+ USBDEVNAME(sc->sc_dev), \
+ (unsigned char)(p)->buffer[0], \
+ (unsigned char)(p)->buffer[1], \
+ (unsigned char)(p)->buffer[2], \
+ (unsigned char)(p)->buffer[3]));
+#else
+#define DPR_PACKET(dir, sc, p)
+#endif
+
+static int
+out_jack_output(struct umidi_jack *out_jack, int d)
+{
+ struct umidi_endpoint *ep = out_jack->endpoint;
+ struct umidi_softc *sc = ep->sc;
+ int error;
+ int s;
+
+ if (sc->sc_dying)
+ return EIO;
+
+ error = 0;
+ if (out_jack->opened) {
+ DPRINTFN(1000, ("umidi_output: ep=%p 0x%02x\n", ep, d));
+ out_build_packet(out_jack->cable_number, &out_jack->packet, d);
+ switch (out_jack->packet.state) {
+ case PS_EXCL_0:
+ case PS_END:
+ DPR_PACKET(out, sc, &out_jack->packet);
+ s = splusb();
+ if (LIST_EMPTY(&ep->queue_head)) {
+ memcpy(ep->buffer,
+ out_jack->packet.buffer,
+ UMIDI_PACKET_SIZE);
+ start_output_transfer(ep);
+ }
+ if (LIST_EMPTY(&ep->queue_head))
+ LIST_INSERT_HEAD(&ep->queue_head,
+ out_jack, u.out.queue_entry);
+ else
+ LIST_INSERT_AFTER(ep->queue_tail,
+ out_jack, u.out.queue_entry);
+ ep->queue_tail = out_jack;
+ splx(s);
+ break;
+ default:
+ error = EINPROGRESS;
+ }
+ } else
+ error = ENODEV;
+
+ return error;
+}
+
+static void
+in_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
+{
+ int cn, len, i;
+ struct umidi_endpoint *ep = (struct umidi_endpoint *)priv;
+ struct umidi_jack *jack;
+
+ if (ep->sc->sc_dying || !ep->num_open)
+ return;
+
+ cn = GET_CN(ep->buffer[0]);
+ len = packet_length[GET_CIN(ep->buffer[0])];
+ jack = ep->jacks[cn];
+ if (cn>=ep->num_jacks || !jack) {
+ DPRINTF(("%s: stray umidi packet (in): %02X %02X %02X %02X\n",
+ USBDEVNAME(ep->sc->sc_dev),
+ (unsigned)ep->buffer[0],
+ (unsigned)ep->buffer[1],
+ (unsigned)ep->buffer[2],
+ (unsigned)ep->buffer[3]));
+ return;
+ }
+ if (!jack->binded || !jack->opened)
+ return;
+ DPR_PACKET(in, ep->sc, &jack->buffer);
+ if (jack->u.in.intr) {
+ for (i=0; i<len; i++) {
+ (*jack->u.in.intr)(jack->arg, ep->buffer[i+1]);
+ }
+ }
+
+ (void)start_input_transfer(ep);
+}
+
+static void
+out_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
+{
+ struct umidi_endpoint *ep = (struct umidi_endpoint *)priv;
+ struct umidi_softc *sc = ep->sc;
+ struct umidi_jack *jack;
+
+ if (sc->sc_dying || !ep->num_open)
+ return;
+
+ jack = LIST_FIRST(&ep->queue_head);
+ if (jack && jack->opened) {
+ LIST_REMOVE(jack, u.out.queue_entry);
+ if (!LIST_EMPTY(&ep->queue_head)) {
+ memcpy(ep->buffer,
+ LIST_FIRST(&ep->queue_head)->packet.buffer,
+ UMIDI_PACKET_SIZE);
+ (void)start_output_transfer(ep);
+ }
+ if (jack->u.out.intr) {
+ (*jack->u.out.intr)(jack->arg);
+ }
+ }
+}
+
+static void
+out_build_packet(int cable_number, struct umidi_packet *packet, uByte in)
+{
+ int cin;
+ uByte prev;
+
+retry:
+ switch (packet->state) {
+ case PS_END:
+ case PS_INITIAL:
+ prev = packet->buffer[1];
+ memset(packet->buffer, 0, UMIDI_PACKET_SIZE);
+ if (in<0x80) {
+ if (prev>=0x80 && prev<0xf0) {
+ /* running status */
+ out_build_packet(cable_number, packet, prev);
+ goto retry;
+ }
+ /* ??? */
+ break;
+ }
+ if (in>=0xf0) {
+ cin=packet_0xFX[in&0x0F].cin;
+ packet->state=packet_0xFX[in&0x0F].next;
+ } else {
+ cin=(unsigned char)in>>4;
+ switch (packet_length[cin]) {
+ case 2:
+ packet->state = PS_NORMAL_1OF2;
+ break;
+ case 3:
+ packet->state = PS_NORMAL_1OF3;
+ break;
+ default:
+ /* ??? */
+ packet->state = PS_INITIAL;
+ }
+ }
+ packet->buffer[0] = MIX_CN_CIN(cable_number, cin);
+ packet->buffer[1] = in;
+ break;
+ case PS_NORMAL_1OF3:
+ if (in>=0x80) { /* ??? */ packet->state = PS_END; break; }
+ packet->buffer[2] = in;
+ packet->state = PS_NORMAL_2OF3;
+ break;
+ case PS_NORMAL_2OF3:
+ if (in>=0x80) { /* ??? */ packet->state = PS_END; break; }
+ packet->buffer[3] = in;
+ packet->state = PS_END;
+ break;
+ case PS_NORMAL_1OF2:
+ if (in>=0x80) { /* ??? */ packet->state = PS_END; break; }
+ packet->buffer[2] = in;
+ packet->state = PS_END;
+ break;
+ case PS_EXCL_0:
+ memset(packet->buffer, 0, UMIDI_PACKET_SIZE);
+ if (in==0xF7) {
+ packet->buffer[0] = MIX_CN_CIN(cable_number, 0x05);
+ packet->buffer[1] = 0xF7;
+ packet->state = PS_END;
+ break;
+ }
+ if (in>=0x80) { /* ??? */ packet->state = PS_END; break; }
+ packet->buffer[1] = in;
+ packet->state = PS_EXCL_1;
+ break;
+ case PS_EXCL_1:
+ if (in==0xF7) {
+ packet->buffer[0] = MIX_CN_CIN(cable_number, 0x06);
+ packet->buffer[2] = 0xF7;
+ packet->state = PS_END;
+ break;
+ }
+ if (in>=0x80) { /* ??? */ packet->state = PS_END; break; }
+ packet->buffer[2] = in;
+ packet->state = PS_EXCL_2;
+ break;
+ case PS_EXCL_2:
+ if (in==0xF7) {
+ packet->buffer[0] = MIX_CN_CIN(cable_number, 0x07);
+ packet->buffer[3] = 0xF7;
+ packet->state = PS_END;
+ break;
+ }
+ if (in>=0x80) { /* ??? */ packet->state = PS_END; break; }
+ packet->buffer[0] = MIX_CN_CIN(cable_number, 0x04);
+ packet->buffer[3] = in;
+ packet->state = PS_EXCL_0;
+ break;
+ default:
+ printf("umidi: ambiguous state.\n");
+ packet->state = PS_INITIAL;
+ goto retry;
+ }
+}
+
diff --git a/sys/dev/usb/umidi_quirks.c b/sys/dev/usb/umidi_quirks.c
new file mode 100644
index 00000000000..a7ae1ee27f4
--- /dev/null
+++ b/sys/dev/usb/umidi_quirks.c
@@ -0,0 +1,215 @@
+/* $OpenBSD: umidi_quirks.c,v 1.1 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: umidi_quirks.c,v 1.3 2001/11/13 06:24:56 lukem Exp $ */
+
+/*
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Takuya SHIOZAKI (tshiozak@netbsd.org).
+ *
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/ioctl.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/select.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+#include <sys/poll.h>
+#include <sys/lock.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+
+#include <dev/usb/usbdevs.h>
+#include <dev/usb/uaudioreg.h>
+#include <dev/usb/umidireg.h>
+#include <dev/usb/umidivar.h>
+#include <dev/usb/umidi_quirks.h>
+
+/*
+ * quirk codes for UMIDI
+ */
+
+#ifdef UMIDIQUIRK_DEBUG
+#define DPRINTF(x) if (umidiquirkdebug) printf x
+#define DPRINTFN(n,x) if (umidiquirkdebug >= (n)) printf x
+int umidiquirkdebug = 1;
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n,x)
+#endif
+
+
+/*
+ * YAMAHA UX-256
+ * --- this is a typical yamaha device, but has a broken descriptor :-<
+ */
+
+UMQ_FIXED_EP_DEF(YAMAHA, YAMAHA_UX256, ANYIFACE, 1, 1) = {
+ /* out */
+ { 0, 16 },
+ /* in */
+ { 1, 8 }
+};
+
+UMQ_DEF(YAMAHA, YAMAHA_UX256, ANYIFACE) = {
+ UMQ_FIXED_EP_REG(YAMAHA, YAMAHA_UX256, ANYIFACE),
+#if 0
+ UMQ_YAMAHA_REG(YAMAHA, ANYPRODUCT, ANYIFACE),
+#endif
+ UMQ_TERMINATOR
+};
+
+
+/*
+ * YAMAHA generic
+ */
+UMQ_DEF(YAMAHA, ANYPRODUCT, ANYIFACE) = {
+ UMQ_YAMAHA_REG(YAMAHA, ANYPRODUCT, ANYIFACE),
+ UMQ_TERMINATOR
+};
+
+
+/*
+ * ROLAND UM-1
+ */
+UMQ_FIXED_EP_DEF(ROLAND, ROLAND_UM1, 2, 1, 1) = {
+ /* out */
+ { 0, 1 },
+ /* in */
+ { 1, 1 }
+};
+
+UMQ_DEF(ROLAND, ROLAND_UM1, 2) = {
+ UMQ_FIXED_EP_REG(ROLAND, ROLAND_UM1, 2),
+ UMQ_TERMINATOR
+};
+
+
+/*
+ * ROLAND UM-880 (native mode)
+ */
+UMQ_FIXED_EP_DEF(ROLAND, ROLAND_UM880N, 0, 1, 1) = {
+ /* out */
+ { 0, 9 },
+ /* in */
+ { 1, 9 }
+};
+
+UMQ_DEF(ROLAND, ROLAND_UM880N, 0) = {
+ UMQ_FIXED_EP_REG(ROLAND, ROLAND_UM880N, 0),
+ UMQ_TERMINATOR
+};
+
+
+
+/*
+ * quirk list
+ */
+struct umidi_quirk umidi_quirklist[] = {
+ UMQ_REG(YAMAHA, YAMAHA_UX256, ANYIFACE),
+ UMQ_REG(YAMAHA, ANYPRODUCT, ANYIFACE),
+ UMQ_REG(ROLAND, ROLAND_UM1, 2),
+ UMQ_REG(ROLAND, ROLAND_UM880N, 0),
+ UMQ_TERMINATOR
+};
+
+
+/*
+ * quirk utilities
+ */
+
+struct umidi_quirk *
+umidi_search_quirk(int vendor, int product, int ifaceno)
+{
+ struct umidi_quirk *p;
+ struct umq_data *q;
+
+ DPRINTF(("umidi_search_quirk: v=%d, p=%d, i=%d\n",
+ vendor, product, ifaceno));
+
+ for (p=&umidi_quirklist[0]; p->vendor; p++) {
+ DPRINTFN(10, ("\tv=%d, p=%d, i=%d",
+ p->vendor, p->product, p->iface));
+ if ((p->vendor==vendor || p->vendor==ANYVENDOR) &&
+ (p->product==product || p->product==ANYPRODUCT) &&
+ (p->iface==ifaceno || p->iface==ANYIFACE)) {
+ DPRINTFN(10, (" found\n"));
+ if (!p->type_mask)
+ /* make quirk mask */
+ for (q=p->quirks; q->type; q++)
+ p->type_mask |= 1<<(q->type-1);
+ return p;
+ }
+ DPRINTFN(10, ("\n"));
+ }
+
+ return NULL;
+}
+
+static char *quirk_name[] = {
+ "NULL",
+ "Fixed Endpoint",
+ "Yamaha Specific",
+};
+
+void
+umidi_print_quirk(struct umidi_quirk *q)
+{
+ struct umq_data *qd;
+ if (q) {
+ printf("(");
+ for (qd=q->quirks; qd->type; qd++)
+ printf("%s%s", quirk_name[qd->type],
+ (qd+1)->type?", ":")\n");
+ } else {
+ printf("(genuine USB-MIDI)\n");
+ }
+}
+
+void *
+umidi_get_quirk_data_from_type(struct umidi_quirk *q, u_int32_t type)
+{
+ struct umq_data *qd;
+ if (q) {
+ for (qd=q->quirks; qd->type; qd++)
+ if (qd->type == type)
+ return qd->data;
+ }
+ return NULL;
+}
diff --git a/sys/dev/usb/umidi_quirks.h b/sys/dev/usb/umidi_quirks.h
new file mode 100644
index 00000000000..ea1f503d756
--- /dev/null
+++ b/sys/dev/usb/umidi_quirks.h
@@ -0,0 +1,120 @@
+/* $OpenBSD: umidi_quirks.h,v 1.1 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: umidi_quirks.h,v 1.2 2001/09/29 22:00:47 tshiozak Exp $ */
+
+/*
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Takuya SHIOZAKI (tshiozak@netbsd.org).
+ *
+ * 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.
+ */
+
+
+/*
+ * quirk code for UMIDI
+ */
+
+#ifndef _DEV_USB_UMIDI_QUIRKS_H_
+#define _DEV_USB_UMIDI_QUIRKS_H_
+
+struct umq_data {
+ int type;
+#define UMQ_TYPE_FIXED_EP 1
+#define UMQ_TYPE_YAMAHA 2
+ void *data;
+};
+
+struct umidi_quirk {
+ int vendor;
+ int product;
+ int iface;
+ struct umq_data *quirks;
+ u_int32_t type_mask;
+};
+#define UMQ_ISTYPE(q, type) \
+ ((q)->sc_quirk && ((q)->sc_quirk->type_mask & (1<<((type)-1))))
+
+#define UMQ_TERMINATOR { 0, }
+#define UMQ_DEF(v, p, i) \
+static struct umq_data umq_##v##_##p##_##i[]
+#define UMQ_REG(v, p, i) \
+ { USB_VENDOR_##v, USB_PRODUCT_##p, i, \
+ umq_##v##_##p##_##i, 0 }
+#define ANYIFACE -1
+#define ANYVENDOR -1
+#define USB_VENDOR_ANYVENDOR ANYVENDOR
+#define ANYPRODUCT -1
+#define USB_PRODUCT_ANYPRODUCT ANYPRODUCT
+
+/*
+ * quirk - fixed port
+ */
+
+struct umq_fixed_ep_endpoint {
+ int ep;
+ int num_jacks;
+};
+struct umq_fixed_ep_desc {
+ int num_out_ep;
+ int num_in_ep;
+ struct umq_fixed_ep_endpoint *out_ep;
+ struct umq_fixed_ep_endpoint *in_ep;
+};
+
+#define UMQ_FIXED_EP_DEF(v, p, i, noep, niep) \
+static struct umq_fixed_ep_endpoint \
+umq_##v##_##p##_##i##_fixed_ep_endpoints[noep+niep]; \
+static struct umq_fixed_ep_desc \
+umq_##v##_##p##_##i##_fixed_ep_desc = { \
+ noep, niep, \
+ &umq_##v##_##p##_##i##_fixed_ep_endpoints[0], \
+ &umq_##v##_##p##_##i##_fixed_ep_endpoints[noep], \
+}; \
+static struct umq_fixed_ep_endpoint \
+umq_##v##_##p##_##i##_fixed_ep_endpoints[noep+niep]
+
+#define UMQ_FIXED_EP_REG(v, p, i) \
+{ UMQ_TYPE_FIXED_EP, (void *)&umq_##v##_##p##_##i##_fixed_ep_desc }
+
+
+/*
+ * quirk - yamaha style midi I/F
+ */
+#define UMQ_YAMAHA_REG(v, p, i) \
+{ UMQ_TYPE_YAMAHA, NULL }
+
+
+/* extern struct umidi_quirk umidi_quirklist[]; */
+struct umidi_quirk *umidi_search_quirk(int, int, int);
+void umidi_print_quirk(struct umidi_quirk *);
+void *umidi_get_quirk_data_from_type(struct umidi_quirk *, u_int32_t);
+
+#endif
diff --git a/sys/dev/usb/umidireg.h b/sys/dev/usb/umidireg.h
new file mode 100644
index 00000000000..f9fd240a1f6
--- /dev/null
+++ b/sys/dev/usb/umidireg.h
@@ -0,0 +1,80 @@
+/* $OpenBSD: umidireg.h,v 1.1 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: umidireg.h,v 1.2 2001/05/28 20:52:06 tshiozak Exp $ */
+/*
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Takuya SHIOZAKI (tshiozak@netbsd.org).
+ *
+ * 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.
+ */
+
+/* Jack Descriptor */
+#define UMIDI_MS_HEADER 0x01
+#define UMIDI_IN_JACK 0x02
+#define UMIDI_OUT_JACK 0x03
+
+/* Jack Type */
+#define UMIDI_EMBEDDED 0x01
+#define UMIDI_EXTERNAL 0x02
+
+typedef struct {
+ uByte bLength;
+ uByte bDescriptorType;
+ uByte bDescriptorSubtype;
+ uWord bcdMSC;
+ uWord wTotalLength;
+} UPACKED umidi_cs_interface_descriptor_t;
+#define UMIDI_CS_INTERFACE_DESCRIPTOR_SIZE 7
+
+typedef struct {
+ uByte bLength;
+ uByte bDescriptorType;
+ uByte bDescriptorSubType;
+ uByte bNumEmbMIDIJack;
+} UPACKED umidi_cs_endpoint_descriptor_t;
+#define UMIDI_CS_ENDPOINT_DESCRIPTOR_SIZE 4
+
+typedef struct {
+ uByte bLength;
+ uByte bDescriptorType;
+ uByte bDescriptorSubtype;
+ uByte bJackType;
+ uByte bJackID;
+} UPACKED umidi_jack_descriptor_t;
+#define UMIDI_JACK_DESCRIPTOR_SIZE 5
+
+
+#define TO_D(p) ((usb_descriptor_t *)(p))
+#define NEXT_D(desc) TO_D((caddr_t)(desc)+(desc)->bLength)
+#define TO_IFD(desc) ((usb_interface_descriptor_t *)(desc))
+#define TO_CSIFD(desc) ((umidi_cs_interface_descriptor_t *)(desc))
+#define TO_EPD(desc) ((usb_endpoint_descriptor_t *)(desc))
+#define TO_CSEPD(desc) ((umidi_cs_endpoint_descriptor_t *)(desc))
diff --git a/sys/dev/usb/umidivar.h b/sys/dev/usb/umidivar.h
new file mode 100644
index 00000000000..d11d69b0303
--- /dev/null
+++ b/sys/dev/usb/umidivar.h
@@ -0,0 +1,138 @@
+/* $OpenBSD: umidivar.h,v 1.1 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: umidivar.h,v 1.3 2001/02/03 18:50:32 tshiozak Exp $ */
+/*
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Takuya SHIOZAKI (tshiozak@netbsd.org).
+ *
+ * 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.
+ */
+
+/* pending MUX-MIDI packet */
+typedef enum {
+ PS_EXCL_0=-2, /* put, and next state is PS_EXCL_0 */
+ PS_END=-1, /* put, and next state is PS_INITIAL */
+ PS_INITIAL=0, /* 0>= : not put, and state is keeped */
+ PS_NORMAL_1OF3=1,
+ PS_NORMAL_2OF3=2,
+ PS_NORMAL_1OF2=3,
+ PS_EXCL_1=4,
+ PS_EXCL_2=5,
+} packet_state_t;
+
+#define UMIDI_PACKET_SIZE 4
+struct umidi_packet {
+ char buffer[UMIDI_PACKET_SIZE];
+ packet_state_t state;
+};
+
+/*
+ * hierarchie
+ *
+ * <-- parent child -->
+ *
+ * umidi(sc) -> endpoint -> jack <- (dynamically assignable) - mididev
+ * ^ | ^ |
+ * +-----+ +-----+
+ */
+
+/* midi device */
+struct umidi_mididev {
+ struct umidi_softc *sc;
+ struct device *mdev;
+ /* */
+ struct umidi_jack *in_jack;
+ struct umidi_jack *out_jack;
+ /* */
+ int opened;
+ int flags;
+};
+
+/* Jack Information */
+struct umidi_jack {
+ struct umidi_endpoint *endpoint;
+ /* */
+ int cable_number;
+ struct umidi_packet packet;
+ void *arg;
+ int binded;
+ int opened;
+ union {
+ struct {
+ void (*intr)(void *);
+ LIST_ENTRY(umidi_jack) queue_entry;
+ } out;
+ struct {
+ void (*intr)(void *, int);
+ } in;
+ } u;
+};
+
+#define UMIDI_MAX_EPJACKS 16
+/* endpoint data */
+struct umidi_endpoint {
+ struct umidi_softc *sc;
+ /* */
+ int addr;
+ usbd_pipe_handle pipe;
+ usbd_xfer_handle xfer;
+ char *buffer;
+ int num_open;
+ int num_jacks;
+ struct umidi_jack *jacks[UMIDI_MAX_EPJACKS];
+ LIST_HEAD(, umidi_jack) queue_head;
+ struct umidi_jack *queue_tail;
+};
+
+/* software context */
+struct umidi_softc {
+ USBBASEDEVICE sc_dev;
+ usbd_device_handle sc_udev;
+ usbd_interface_handle sc_iface;
+ struct umidi_quirk *sc_quirk;
+
+ int sc_dying;
+
+ int sc_out_num_jacks;
+ struct umidi_jack *sc_out_jacks;
+ int sc_in_num_jacks;
+ struct umidi_jack *sc_in_jacks;
+ struct umidi_jack *sc_jacks;
+
+ int sc_num_mididevs;
+ struct umidi_mididev *sc_mididevs;
+
+ int sc_out_num_endpoints;
+ struct umidi_endpoint *sc_out_ep;
+ int sc_in_num_endpoints;
+ struct umidi_endpoint *sc_in_ep;
+ struct umidi_endpoint *sc_endpoints;
+};
diff --git a/sys/dev/usb/umodem.c b/sys/dev/usb/umodem.c
index df2c0ade0c2..9dbd15e2166 100644
--- a/sys/dev/usb/umodem.c
+++ b/sys/dev/usb/umodem.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: umodem.c,v 1.7 2001/05/03 02:20:34 aaron Exp $ */
-/* $NetBSD: umodem.c,v 1.40 2001/03/25 23:02:34 augustss Exp $ */
+/* $OpenBSD: umodem.c,v 1.8 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: umodem.c,v 1.41 2001/11/13 06:24:56 lukem Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -137,7 +137,7 @@ 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, struct proc *);
+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);
@@ -524,7 +524,7 @@ umodem_param(void *addr, int portno, struct termios *t)
int
umodem_ioctl(void *addr, int portno, u_long cmd, caddr_t data, int flag,
- struct proc *p)
+ usb_proc_ptr p)
{
struct umodem_softc *sc = addr;
int error = 0;
diff --git a/sys/dev/usb/ums.c b/sys/dev/usb/ums.c
index 8505da52f67..d2b058ca11e 100644
--- a/sys/dev/usb/ums.c
+++ b/sys/dev/usb/ums.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: ums.c,v 1.6 2001/10/31 04:24:44 nate Exp $ */
-/* $NetBSD: ums.c,v 1.49 2001/10/26 17:58:21 augustss Exp $ */
+/* $OpenBSD: ums.c,v 1.7 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: ums.c,v 1.55 2001/12/31 12:15:22 augustss Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -42,8 +42,6 @@
* HID spec: http://www.usb.org/developers/data/devclass/hid1_1.pdf
*/
-/* XXX complete SPUR_UP change */
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
@@ -64,6 +62,7 @@
#include <dev/usb/usbdi_util.h>
#include <dev/usb/usbdevs.h>
#include <dev/usb/usb_quirks.h>
+#include <dev/usb/uhidev.h>
#include <dev/usb/hid.h>
#include <dev/wscons/wsconsio.h>
@@ -87,18 +86,13 @@ int umsdebug = 0;
#define PS2MBUTMASK x04
#define PS2BUTMASK 0x0f
+#define MAX_BUTTONS 7 /* must not exceed size of sc_buttons */
+
struct ums_softc {
- USBBASEDEVICE sc_dev; /* base device */
- usbd_device_handle sc_udev;
- usbd_interface_handle sc_iface; /* interface */
- usbd_pipe_handle sc_intrpipe; /* interrupt pipe */
- int sc_ep_addr;
-
- u_char *sc_ibuf;
- u_int8_t sc_iid;
- int sc_isize;
+ struct uhidev sc_hdev;
+
struct hid_location sc_loc_x, sc_loc_y, sc_loc_z;
- struct hid_location *sc_loc_btn;
+ struct hid_location sc_loc_btn[MAX_BUTTONS];
int sc_enabled;
@@ -108,7 +102,6 @@ struct ums_softc {
#define UMS_REVZ 0x04 /* Z-axis is reversed */
int nbuttons;
-#define MAX_BUTTONS 31 /* chosen because sc_buttons is u_int32_t */
u_int32_t sc_buttons; /* mouse button status */
struct device *sc_wsmousedev;
@@ -119,11 +112,11 @@ struct ums_softc {
#define MOUSE_FLAGS_MASK (HIO_CONST|HIO_RELATIVE)
#define MOUSE_FLAGS (HIO_RELATIVE)
-Static void ums_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
+Static void ums_intr(struct uhidev *addr, void *ibuf, u_int len);
Static int ums_enable(void *);
Static void ums_disable(void *);
-Static int ums_ioctl(void *, u_long, caddr_t, int, struct proc *);
+Static int ums_ioctl(void *, u_long, caddr_t, int, usb_proc_ptr);
const struct wsmouse_accessops ums_accessops = {
ums_enable,
@@ -136,115 +129,72 @@ USB_DECLARE_DRIVER(ums);
USB_MATCH(ums)
{
USB_MATCH_START(ums, uaa);
- usb_interface_descriptor_t *id;
- int size, ret;
+ struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa;
+ int size;
void *desc;
- usbd_status err;
- if (uaa->iface == NULL)
- return (UMATCH_NONE);
- id = usbd_get_interface_descriptor(uaa->iface);
- if (id == NULL || id->bInterfaceClass != UICLASS_HID)
+ uhidev_get_report_desc(uha->parent, &desc, &size);
+ if (!hid_is_collection(desc, size, uha->reportid,
+ HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE)))
return (UMATCH_NONE);
- err = usbd_read_report_desc(uaa->iface, &desc, &size, M_TEMP);
- if (err)
- return (UMATCH_NONE);
-
- if (hid_is_collection(desc, size,
- HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE)))
- ret = UMATCH_IFACECLASS;
- else
- ret = UMATCH_NONE;
-
- free(desc, M_TEMP);
- return (ret);
+ return (UMATCH_IFACECLASS);
}
USB_ATTACH(ums)
{
USB_ATTACH_START(ums, sc, uaa);
- usbd_interface_handle iface = uaa->iface;
- usb_interface_descriptor_t *id;
- usb_endpoint_descriptor_t *ed;
+ struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa;
struct wsmousedev_attach_args a;
int size;
void *desc;
- usbd_status err;
- char devinfo[1024];
u_int32_t flags, quirks;
int i, wheel;
struct hid_location loc_btn;
-
- sc->sc_udev = uaa->device;
- sc->sc_iface = iface;
- id = usbd_get_interface_descriptor(iface);
- usbd_devinfo(uaa->device, 0, devinfo);
- USB_ATTACH_SETUP;
- printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev),
- devinfo, id->bInterfaceClass, id->bInterfaceSubClass);
- ed = usbd_interface2endpoint_descriptor(iface, 0);
- if (ed == NULL) {
- printf("%s: could not read endpoint descriptor\n",
- USBDEVNAME(sc->sc_dev));
- USB_ATTACH_ERROR_RETURN;
- }
- DPRINTFN(10,("ums_attach: bLength=%d bDescriptorType=%d "
- "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d"
- " bInterval=%d\n",
- ed->bLength, ed->bDescriptorType,
- ed->bEndpointAddress & UE_ADDR,
- UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out",
- ed->bmAttributes & UE_XFERTYPE,
- UGETW(ed->wMaxPacketSize), ed->bInterval));
-
- if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN ||
- (ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) {
- printf("%s: unexpected endpoint\n",
- USBDEVNAME(sc->sc_dev));
- USB_ATTACH_ERROR_RETURN;
- }
+ sc->sc_hdev.sc_intr = ums_intr;
+ sc->sc_hdev.sc_parent = uha->parent;
+ sc->sc_hdev.sc_report_id = uha->reportid;
- quirks = usbd_get_quirks(uaa->device)->uq_flags;
+ quirks = usbd_get_quirks(uha->parent->sc_udev)->uq_flags;
if (quirks & UQ_MS_REVZ)
sc->flags |= UMS_REVZ;
if (quirks & UQ_SPUR_BUT_UP)
sc->flags |= UMS_SPUR_BUT_UP;
- err = usbd_read_report_desc(uaa->iface, &desc, &size, M_TEMP);
- if (err)
- USB_ATTACH_ERROR_RETURN;
+ uhidev_get_report_desc(uha->parent, &desc, &size);
if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X),
- hid_input, &sc->sc_loc_x, &flags)) {
- printf("%s: mouse has no X report\n", USBDEVNAME(sc->sc_dev));
+ uha->reportid, hid_input, &sc->sc_loc_x, &flags)) {
+ printf("\n%s: mouse has no X report\n",
+ USBDEVNAME(sc->sc_hdev.sc_dev));
USB_ATTACH_ERROR_RETURN;
}
if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) {
- printf("%s: X report 0x%04x not supported\n",
- USBDEVNAME(sc->sc_dev), flags);
+ printf("\n%s: X report 0x%04x not supported\n",
+ USBDEVNAME(sc->sc_hdev.sc_dev), flags);
USB_ATTACH_ERROR_RETURN;
}
if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y),
- hid_input, &sc->sc_loc_y, &flags)) {
- printf("%s: mouse has no Y report\n", USBDEVNAME(sc->sc_dev));
+ uha->reportid, hid_input, &sc->sc_loc_y, &flags)) {
+ printf("\n%s: mouse has no Y report\n",
+ USBDEVNAME(sc->sc_hdev.sc_dev));
USB_ATTACH_ERROR_RETURN;
}
if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) {
- printf("%s: Y report 0x%04x not supported\n",
- USBDEVNAME(sc->sc_dev), flags);
+ printf("\n%s: Y report 0x%04x not supported\n",
+ USBDEVNAME(sc->sc_hdev.sc_dev), flags);
USB_ATTACH_ERROR_RETURN;
}
/* Try to guess the Z activator: first check Z, then WHEEL. */
wheel = 0;
if (hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z),
- hid_input, &sc->sc_loc_z, &flags) ||
+ uha->reportid, hid_input, &sc->sc_loc_z, &flags) ||
(wheel = hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP,
HUG_WHEEL),
- hid_input, &sc->sc_loc_z, &flags))) {
+ uha->reportid, hid_input, &sc->sc_loc_z, &flags))) {
if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) {
sc->sc_loc_z.size = 0; /* Bad Z coord, ignore it */
} else {
@@ -258,34 +208,18 @@ USB_ATTACH(ums)
/* figure out the number of buttons */
for (i = 1; i <= MAX_BUTTONS; i++)
if (!hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i),
- hid_input, &loc_btn, 0))
+ uha->reportid, hid_input, &loc_btn, 0))
break;
sc->nbuttons = i - 1;
- 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));
- USB_ATTACH_ERROR_RETURN;
- }
- printf("%s: %d button%s%s\n", USBDEVNAME(sc->sc_dev),
+ printf(": %d button%s%s\n",
sc->nbuttons, sc->nbuttons == 1 ? "" : "s",
sc->flags & UMS_Z ? " and Z dir." : "");
for (i = 1; i <= sc->nbuttons; i++)
hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i),
- hid_input, &sc->sc_loc_btn[i-1], 0);
-
- sc->sc_isize = hid_report_size(desc, size, hid_input, &sc->sc_iid);
- sc->sc_ibuf = malloc(sc->sc_isize, M_USBDEV, M_NOWAIT);
- if (sc->sc_ibuf == NULL) {
- printf("%s: no memory\n", USBDEVNAME(sc->sc_dev));
- free(sc->sc_loc_btn, M_USBDEV);
- USB_ATTACH_ERROR_RETURN;
- }
-
- sc->sc_ep_addr = ed->bEndpointAddress;
- free(desc, M_TEMP);
+ uha->reportid, hid_input,
+ &sc->sc_loc_btn[i-1], 0);
#ifdef USB_DEBUG
DPRINTF(("ums_attach: sc=%p\n", sc));
@@ -300,15 +234,11 @@ USB_ATTACH(ums)
DPRINTF(("ums_attach: B%d\t%d/%d\n",
i, sc->sc_loc_btn[i-1].pos,sc->sc_loc_btn[i-1].size));
}
- DPRINTF(("ums_attach: size=%d, id=%d\n", sc->sc_isize, sc->sc_iid));
#endif
a.accessops = &ums_accessops;
a.accesscookie = sc;
- usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
- USBDEV(sc->sc_dev));
-
sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
USB_ATTACH_SUCCESS_RETURN;
@@ -344,45 +274,21 @@ USB_DETACH(ums)
/* No need to do reference counting of ums, wsmouse has all the goo. */
if (sc->sc_wsmousedev != NULL)
rv = config_detach(sc->sc_wsmousedev, flags);
- if (rv == 0) {
- free(sc->sc_loc_btn, M_USBDEV);
- free(sc->sc_ibuf, M_USBDEV);
- }
-
- usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
- USBDEV(sc->sc_dev));
return (rv);
}
void
-ums_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status)
+ums_intr(struct uhidev *addr, void *ibuf, u_int len)
{
- struct ums_softc *sc = addr;
- u_char *ibuf;
+ struct ums_softc *sc = (struct ums_softc *)addr;
int dx, dy, dz;
u_int32_t buttons = 0;
int i;
int s;
- DPRINTFN(5, ("ums_intr: sc=%p status=%d\n", sc, status));
- DPRINTFN(5, ("ums_intr: data = %02x %02x %02x\n",
- sc->sc_ibuf[0], sc->sc_ibuf[1], sc->sc_ibuf[2]));
-
- if (status == USBD_CANCELLED)
- return;
-
- if (status) {
- DPRINTF(("ums_intr: status=%d\n", status));
- usbd_clear_endpoint_stall_async(sc->sc_intrpipe);
- return;
- }
+ DPRINTFN(5,("ums_intr: len=%d\n", len));
- ibuf = sc->sc_ibuf;
- if (sc->sc_iid != 0) {
- if (*ibuf++ != sc->sc_iid)
- return;
- }
dx = hid_get_data(ibuf, &sc->sc_loc_x);
dy = -hid_get_data(ibuf, &sc->sc_loc_y);
dz = hid_get_data(ibuf, &sc->sc_loc_z);
@@ -410,8 +316,6 @@ ums_enable(void *v)
{
struct ums_softc *sc = v;
- usbd_status err;
-
DPRINTFN(1,("ums_enable: sc=%p\n", sc));
if (sc->sc_dying)
@@ -423,17 +327,7 @@ ums_enable(void *v)
sc->sc_enabled = 1;
sc->sc_buttons = 0;
- /* 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, sc->sc_isize, ums_intr, USBD_DEFAULT_INTERVAL);
- if (err) {
- DPRINTF(("ums_enable: usbd_open_pipe_intr failed, error=%d\n",
- err));
- sc->sc_enabled = 0;
- return (EIO);
- }
- return (0);
+ return (uhidev_open(&sc->sc_hdev));
}
Static void
@@ -449,15 +343,12 @@ ums_disable(void *v)
}
#endif
- /* Disable interrupts. */
- usbd_abort_pipe(sc->sc_intrpipe);
- usbd_close_pipe(sc->sc_intrpipe);
-
sc->sc_enabled = 0;
+ return (uhidev_close(&sc->sc_hdev));
}
Static int
-ums_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
+ums_ioctl(void *v, u_long cmd, caddr_t data, int flag, usb_proc_ptr p)
{
switch (cmd) {
diff --git a/sys/dev/usb/uplcom.c b/sys/dev/usb/uplcom.c
index ffff1e0664c..25d26a8a871 100644
--- a/sys/dev/usb/uplcom.c
+++ b/sys/dev/usb/uplcom.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: uplcom.c,v 1.2 2001/10/31 04:24:44 nate Exp $ */
-/* $NetBSD: uplcom.c,v 1.20 2001/07/31 12:33:11 ichiro Exp $ */
+/* $OpenBSD: uplcom.c,v 1.3 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: uplcom.c,v 1.27 2002/03/16 16:10:19 ichiro Exp $ */
/*
* Copyright (c) 2001 The NetBSD Foundation, Inc.
* All rights reserved.
@@ -131,7 +131,7 @@ Static void uplcom_break(struct uplcom_softc *, int);
Static void uplcom_set_line_state(struct uplcom_softc *);
Static void uplcom_get_status(void *, int portno, u_char *lsr, u_char *msr);
#if TODO
-Static int uplcom_ioctl(void *, int, u_long, caddr_t, int, struct proc *);
+Static int uplcom_ioctl(void *, int, u_long, caddr_t, int, usb_proc_ptr);
#endif
Static int uplcom_param(void *, int, struct termios *);
Static int uplcom_open(void *, int);
@@ -148,10 +148,7 @@ struct ucom_methods uplcom_methods = {
NULL,
};
-static const struct uplcom_product {
- uint16_t vendor;
- uint16_t product;
-} uplcom_products [] = {
+static const struct usb_devno uplcom_devs[] = {
/* I/O DATA USB-RSAQ2 */
{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ2 },
/* I/O DATA USB-RSAQ */
@@ -160,26 +157,28 @@ static const struct uplcom_product {
{ USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC232A },
/* IOGEAR/ATEN UC-232A */
{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303 },
- { 0, 0 }
+ /* ELECOM UC-SGT */
+ { USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT },
+ /* RATOC REX-USB60 */
+ { USB_VENDOR_RATOC, USB_PRODUCT_RATOC_REXUSB60 },
+ /* TDK USB-PHS Adapter UHA6400 */
+ { USB_VENDOR_TDK, USB_PRODUCT_TDK_UHA6400 },
+ /* TDK USB-PDC Adapter UPA9664 */
+ { USB_VENDOR_TDK, USB_PRODUCT_TDK_UPA9664 },
};
+#define uplcom_lookup(v, p) usb_lookup(uplcom_devs, v, p)
USB_DECLARE_DRIVER(uplcom);
USB_MATCH(uplcom)
{
USB_MATCH_START(uplcom, uaa);
- int i;
if (uaa->iface != NULL)
return (UMATCH_NONE);
- for (i = 0; uplcom_products[i].vendor != 0; i++) {
- if (uplcom_products[i].vendor == uaa->vendor &&
- uplcom_products[i].product == uaa->product) {
- return (UMATCH_VENDOR_PRODUCT);
- }
- }
- return (UMATCH_NONE);
+ return (uplcom_lookup(uaa->vendor, uaa->product) != NULL ?
+ UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
}
USB_ATTACH(uplcom)
@@ -715,7 +714,7 @@ uplcom_get_status(void *addr, int portno, u_char *lsr, u_char *msr)
#if TODO
int
uplcom_ioctl(void *addr, int portno, u_long cmd, caddr_t data, int flag,
- struct proc *p)
+ usb_proc_ptr p)
{
struct uplcom_softc *sc = addr;
int error = 0;
diff --git a/sys/dev/usb/urio.c b/sys/dev/usb/urio.c
index 08903978e71..89492aeb019 100644
--- a/sys/dev/usb/urio.c
+++ b/sys/dev/usb/urio.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: urio.c,v 1.6 2001/10/31 04:24:44 nate Exp $ */
-/* $NetBSD: urio.c,v 1.6 2001/09/25 21:08:44 jdolecek Exp $ */
+/* $OpenBSD: urio.c,v 1.7 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: urio.c,v 1.11 2002/02/11 15:11:49 augustss Exp $ */
/*
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@@ -126,6 +126,13 @@ struct urio_softc {
#define URIO_RW_TIMEOUT 4000 /* ms */
+static const struct usb_devno urio_devs[] = {
+ { USB_VENDOR_DIAMOND, USB_PRODUCT_DIAMOND_RIO500USB},
+ { USB_VENDOR_DIAMOND2, USB_PRODUCT_DIAMOND2_RIO600USB},
+ { USB_VENDOR_DIAMOND2, USB_PRODUCT_DIAMOND2_RIO800USB},
+};
+#define urio_lookup(v, p) usb_lookup(urio_devs, v, p)
+
USB_DECLARE_DRIVER(urio);
USB_MATCH(urio)
@@ -137,15 +144,8 @@ USB_MATCH(urio)
if (uaa->iface != NULL)
return (UMATCH_NONE);
- if ( ( uaa->vendor == USB_VENDOR_DIAMOND &&
- uaa->product == USB_PRODUCT_DIAMOND_RIO500USB ) ||
- ( uaa->vendor == USB_VENDOR_DIAMOND2 &&
- ( uaa->product == USB_PRODUCT_DIAMOND2_RIO600USB ||
- uaa->product == USB_PRODUCT_DIAMOND2_RIO800USB ) )
- )
- return (UMATCH_VENDOR_PRODUCT);
- else
- return (UMATCH_NONE);
+ return (urio_lookup(uaa->vendor, uaa->product) != NULL ?
+ UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
}
USB_ATTACH(urio)
@@ -293,7 +293,7 @@ urio_activate(device_ptr_t self, enum devact act)
#endif
int
-urioopen(dev_t dev, int flag, int mode, struct proc *p)
+urioopen(dev_t dev, int flag, int mode, usb_proc_ptr p)
{
struct urio_softc *sc;
usbd_status err;
@@ -326,7 +326,7 @@ urioopen(dev_t dev, int flag, int mode, struct proc *p)
}
int
-urioclose(dev_t dev, int flag, int mode, struct proc *p)
+urioclose(dev_t dev, int flag, int mode, usb_proc_ptr p)
{
struct urio_softc *sc;
USB_GET_SC(urio, URIOUNIT(dev), sc);
@@ -379,7 +379,7 @@ urioread(dev_t dev, struct uio *uio, int flag)
while ((n = min(URIO_BSIZE, uio->uio_resid)) != 0) {
DPRINTFN(1, ("urioread: start transfer %d bytes\n", n));
tn = n;
- err = usbd_bulk_transfer(xfer, sc->sc_in_pipe, 0,
+ err = usbd_bulk_transfer(xfer, sc->sc_in_pipe, USBD_NO_COPY,
URIO_RW_TIMEOUT, bufp, &tn, "uriors");
if (err) {
if (err == USBD_INTERRUPTED)
@@ -441,7 +441,7 @@ uriowrite(dev_t dev, struct uio *uio, int flag)
DPRINTFN(1, ("uriowrite: transfer %d bytes\n", n));
- err = usbd_bulk_transfer(xfer, sc->sc_out_pipe, 0,
+ err = usbd_bulk_transfer(xfer, sc->sc_out_pipe, USBD_NO_COPY,
URIO_RW_TIMEOUT, bufp, &n, "uriowr");
DPRINTFN(2, ("uriowrite: err=%d\n", err));
if (err) {
@@ -468,7 +468,7 @@ uriowrite(dev_t dev, struct uio *uio, int flag)
int
-urioioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
+urioioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, usb_proc_ptr p)
{
struct urio_softc * sc;
int unit = URIOUNIT(dev);
@@ -544,7 +544,7 @@ urioioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
sc->sc_refcnt++;
err = usbd_do_request_flags(sc->sc_udev, &req, ptr, req_flags,
- &req_actlen);
+ &req_actlen, USBD_DEFAULT_TIMEOUT);
if (--sc->sc_refcnt < 0)
usb_detach_wakeup(USBDEV(sc->sc_dev));
@@ -563,7 +563,7 @@ ret:
}
int
-uriopoll(dev_t dev, int events, struct proc *p)
+uriopoll(dev_t dev, int events, usb_proc_ptr p)
{
return (0);
}
diff --git a/sys/dev/usb/usb.c b/sys/dev/usb/usb.c
index 03e769920d3..3cc61c6bb74 100644
--- a/sys/dev/usb/usb.c
+++ b/sys/dev/usb/usb.c
@@ -1,9 +1,8 @@
-/* $OpenBSD: usb.c,v 1.17 2002/05/02 20:08:04 nate Exp $ */
-/* $NetBSD: usb.c,v 1.53 2001/01/23 17:04:30 augustss Exp $ */
-/* $FreeBSD: src/sys/dev/usb/usb.c,v 1.20 1999/11/17 22:33:46 n_hibma Exp $ */
+/* $OpenBSD: usb.c,v 1.18 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: usb.c,v 1.69 2002/04/23 06:34:11 augustss Exp $ */
/*
- * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 2002 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -53,6 +52,7 @@
#include <sys/kthread.h>
#include <sys/proc.h>
#include <sys/conf.h>
+#include <sys/fcntl.h>
#include <sys/poll.h>
#include <sys/select.h>
#include <sys/vnode.h>
@@ -79,7 +79,7 @@ int uhcidebug;
#ifdef OHCI_DEBUG
int ohcidebug;
#endif
-/*
+/*
* 0 - do usual exploration
* 1 - do not use timeout exploration
* >1 - do no exploration
@@ -95,30 +95,31 @@ struct usb_softc {
usbd_bus_handle sc_bus; /* USB controller */
struct usbd_port sc_port; /* dummy port for root hub */
- TAILQ_HEAD(, usb_task) sc_tasks;
- struct proc *sc_event_thread;
-
- struct usb_task sc_exp_task;
+ usb_proc_ptr sc_event_thread;
char sc_dying;
};
+TAILQ_HEAD(, usb_task) usb_all_tasks;
+
cdev_decl(usb);
Static void usb_discover(void *);
Static void usb_create_event_thread(void *);
Static void usb_event_thread(void *);
+Static void usb_task_thread(void *);
+Static usb_proc_ptr usb_task_thread_proc = NULL;
#define USB_MAX_EVENTS 100
struct usb_event_q {
struct usb_event ue;
SIMPLEQ_ENTRY(usb_event_q) next;
};
-Static SIMPLEQ_HEAD(, usb_event_q) usb_events =
+Static SIMPLEQ_HEAD(, usb_event_q) usb_events =
SIMPLEQ_HEAD_INITIALIZER(usb_events);
Static int usb_nevents = 0;
Static struct selinfo usb_selevent;
-Static struct proc *usb_async_proc; /* process that wants USB SIGIO */
+Static usb_proc_ptr usb_async_proc; /* process that wants USB SIGIO */
Static int usb_dev_open = 0;
Static void usb_add_event(int, struct usb_event *);
@@ -140,22 +141,29 @@ USB_ATTACH(usb)
usbd_device_handle dev;
usbd_status err;
int usbrev;
+ int speed;
struct usb_event ue;
-
+
DPRINTF(("usbd_attach\n"));
usbd_init();
sc->sc_bus = aux;
sc->sc_bus->usbctl = sc;
sc->sc_port.power = USB_MAX_POWER;
- TAILQ_INIT(&sc->sc_tasks);
-
- usb_init_task(&sc->sc_exp_task, usb_discover, sc);
usbrev = sc->sc_bus->usbrev;
printf(": USB revision %s", usbrev_str[usbrev]);
- if (usbrev != USBREV_1_0 && usbrev != USBREV_1_1) {
+ 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");
@@ -167,19 +175,34 @@ USB_ATTACH(usb)
ue.u.ue_ctrlr.ue_bus = USBDEVUNIT(sc->sc_dev);
usb_add_event(USB_EVENT_CTRLR_ATTACH, &ue);
- err = usbd_new_device(USBDEV(sc->sc_dev), sc->sc_bus, 0, 0, 0,
+#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.
@@ -188,8 +211,8 @@ USB_ATTACH(usb)
dev->hub->explore(sc->sc_bus->root_hub);
#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)
@@ -206,6 +229,7 @@ void
usb_create_event_thread(void *arg)
{
struct usb_softc *sc = arg;
+ static int created = 0;
if (usb_kthread_create1(usb_event_thread, sc, &sc->sc_event_thread,
"%s", sc->sc_dev.dv_xname)) {
@@ -213,39 +237,47 @@ usb_create_event_thread(void *arg)
sc->sc_dev.dv_xname);
panic("usb_create_event_thread");
}
+ if (!created) {
+ created = 1;
+ TAILQ_INIT(&usb_all_tasks);
+ if (usb_kthread_create1(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 event thread. This function can be
+ * 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)
{
- struct usb_softc *sc = dev->bus->usbctl;
int s;
s = splusb();
if (!task->onqueue) {
- DPRINTFN(2,("usb_add_task: sc=%p task=%p\n", sc, task));
- TAILQ_INSERT_TAIL(&sc->sc_tasks, task, next);
+ 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: sc=%p task=%p on q\n", sc, task));
- wakeup(&sc->sc_tasks);
+ } 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)
{
- struct usb_softc *sc = dev->bus->usbctl;
int s;
s = splusb();
if (task->onqueue) {
- TAILQ_REMOVE(&sc->sc_tasks, task, next);
+ TAILQ_REMOVE(&usb_all_tasks, task, next);
task->onqueue = 0;
}
splx(s);
@@ -255,31 +287,37 @@ void
usb_event_thread(void *arg)
{
struct usb_softc *sc = arg;
- struct usb_task *task;
- int s;
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) {
- s = splusb();
- task = TAILQ_FIRST(&sc->sc_tasks);
- if (task == NULL) {
- tsleep(&sc->sc_tasks, PWAIT, "usbevt", 0);
- task = TAILQ_FIRST(&sc->sc_tasks);
- }
- DPRINTFN(2,("usb_event_thread: woke up task=%p\n", task));
- if (task != NULL && !sc->sc_dying) {
- TAILQ_REMOVE(&sc->sc_tasks, task, next);
- task->onqueue = 0;
- splx(s);
- task->fun(task->arg);
- } else
- splx(s);
+#ifdef USB_DEBUG
+ if (usb_noexplore < 2)
+#endif
+ usb_discover(sc);
+#ifdef USB_DEBUG
+ (void)tsleep(&sc->sc_bus->needs_explore, PWAIT, "usbevt",
+ usb_noexplore ? 0 : hz * 60);
+#else
+ (void)tsleep(&sc->sc_bus->needs_explore, PWAIT, "usbevt",
+ hz * 60);
+#endif
+ DPRINTFN(2,("usb_event_thread: woke up\n"));
}
sc->sc_event_thread = NULL;
@@ -290,6 +328,32 @@ usb_event_thread(void *arg)
kthread_exit(0);
}
+void
+usb_task_thread(void *arg)
+{
+ struct usb_task *task;
+ int s;
+
+ 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();
+ }
+ }
+}
+
int
usbctlprint(void *aux, const char *pnp)
{
@@ -302,7 +366,7 @@ usbctlprint(void *aux, const char *pnp)
#endif /* defined(__NetBSD__) || defined(__OpenBSD__) */
int
-usbopen(dev_t dev, int flag, int mode, struct proc *p)
+usbopen(dev_t dev, int flag, int mode, usb_proc_ptr p)
{
int unit = minor(dev);
struct usb_softc *sc;
@@ -357,7 +421,7 @@ usbread(dev_t dev, struct uio *uio, int flag)
}
int
-usbclose(dev_t dev, int flag, int mode, struct proc *p)
+usbclose(dev_t dev, int flag, int mode, usb_proc_ptr p)
{
int unit = minor(dev);
@@ -370,7 +434,7 @@ usbclose(dev_t dev, int flag, int mode, struct proc *p)
}
int
-usbioctl(dev_t devt, u_long cmd, caddr_t data, int flag, struct proc *p)
+usbioctl(dev_t devt, u_long cmd, caddr_t data, int flag, usb_proc_ptr p)
{
struct usb_softc *sc;
int unit = minor(devt);
@@ -380,7 +444,7 @@ usbioctl(dev_t devt, u_long cmd, caddr_t data, int flag, struct proc *p)
case FIONBIO:
/* All handled in the upper FS layer. */
return (0);
-
+
case FIOASYNC:
if (*(int *)data)
usb_async_proc = p;
@@ -401,6 +465,8 @@ usbioctl(dev_t devt, u_long cmd, caddr_t data, int flag, struct proc *p)
switch (cmd) {
#ifdef USB_DEBUG
case USB_SETDEBUG:
+ if (!(flag & FWRITE))
+ return (EBADF);
usbdebug = ((*(int *)data) & 0x000000ff);
#ifdef UHCI_DEBUG
uhcidebug = ((*(int *)data) & 0x0000ff00) >> 8;
@@ -409,7 +475,7 @@ usbioctl(dev_t devt, u_long cmd, caddr_t data, int flag, struct proc *p)
ohcidebug = ((*(int *)data) & 0x00ff0000) >> 16;
#endif
break;
-#endif
+#endif /* USB_DEBUG */
case USB_REQUEST:
{
struct usb_ctl_request *ur = (void *)data;
@@ -421,10 +487,13 @@ usbioctl(dev_t devt, u_long cmd, caddr_t data, int flag, struct proc *p)
usbd_status err;
int error = 0;
+ if (!(flag & FWRITE))
+ return (EBADF);
+
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) {
@@ -436,7 +505,7 @@ usbioctl(dev_t devt, u_long cmd, caddr_t data, int flag, struct proc *p)
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);
@@ -447,8 +516,8 @@ usbioctl(dev_t devt, u_long cmd, caddr_t data, int flag, struct proc *p)
}
}
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;
@@ -492,21 +561,21 @@ usbioctl(dev_t devt, u_long cmd, caddr_t data, int flag, struct proc *p)
}
int
-usbpoll(dev_t dev, int events, struct proc *p)
+usbpoll(dev_t dev, int events, usb_proc_ptr p)
{
int revents, mask, s;
if (minor(dev) == USB_DEV_MINOR) {
revents = 0;
mask = POLLIN | POLLRDNORM;
-
+
s = splusb();
if (events & mask && usb_nevents > 0)
revents |= events & mask;
if (revents == 0 && events & mask)
selrecord(p, &usb_selevent);
splx(s);
-
+
return (revents);
} else {
return (ENXIO);
@@ -524,7 +593,7 @@ usb_discover(void *v)
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.
@@ -540,7 +609,7 @@ usb_needs_explore(usbd_device_handle dev)
{
DPRINTFN(2,("usb_needs_explore\n"));
dev->bus->needs_explore = 1;
- usb_add_task(dev, &dev->bus->usbctl->sc_exp_task);
+ wakeup(&dev->bus->needs_explore);
}
/* Called at splusb() */
@@ -552,6 +621,13 @@ usb_get_next_event(struct usb_event *ue)
if (usb_nevents <= 0)
return (0);
ueq = SIMPLEQ_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);
free(ueq, M_USBDEV);
@@ -574,7 +650,7 @@ 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),
+ strncpy(ue.u.ue_driver.ue_devname, USBDEVPTRNAME(dev),
sizeof ue.u.ue_driver.ue_devname);
usb_add_event(type, &ue);
}
@@ -607,10 +683,26 @@ usb_add_event(int type, struct usb_event *uep)
psignal(usb_async_proc, SIGIO);
splx(s);
}
+
void
-usb_schedsoftintr(struct usbd_bus *bus)
+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 (!usb_callout_pending(bus->softi))
+ usb_callout(bus->softi, 0, bus->methods->soft_intr,
+ bus);
+#endif /* __HAVE_GENERIC_SOFT_INTERRUPTS */
+ }
+#else
bus->methods->soft_intr(bus);
+#endif /* USB_USE_SOFTINTR */
}
int
@@ -627,7 +719,8 @@ usb_activate(device_ptr_t self, enum devact act)
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]);
}
@@ -647,12 +740,12 @@ usb_detach(device_ptr_t self, int flags)
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) {
- wakeup(&sc->sc_tasks);
+ 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",
USBDEVNAME(sc->sc_dev));
@@ -661,6 +754,17 @@ usb_detach(device_ptr_t self, int flags)
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
+ usb_uncallout(sc->sc_bus->softi, bus->methods->soft_intr, bus);
+#endif
+#endif
+
ue.u.ue_ctrlr.ue_bus = USBDEVUNIT(sc->sc_dev);
usb_add_event(USB_EVENT_CTRLR_DETACH, &ue);
diff --git a/sys/dev/usb/usb.h b/sys/dev/usb/usb.h
index 0a3e39cfae3..c5dc2e8a72a 100644
--- a/sys/dev/usb/usb.h
+++ b/sys/dev/usb/usb.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: usb.h,v 1.15 2002/05/02 20:08:04 nate Exp $ */
-/* $NetBSD: usb.h,v 1.52 2001/07/23 15:17:50 nathanw Exp $ */
+/* $OpenBSD: usb.h,v 1.16 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: usb.h,v 1.65 2002/02/26 10:27:49 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usb.h,v 1.14 1999/11/17 22:33:46 n_hibma Exp $ */
/*
@@ -48,23 +48,18 @@
#if defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/ioctl.h>
+#endif
+#if defined(__FreeBSD__)
+/* 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 */
+#endif
#if defined(_KERNEL)
#include <dev/usb/usb_port.h>
#endif /* _KERNEL */
-#elif defined(__FreeBSD__)
-#if defined(KERNEL)
-#include <sys/malloc.h>
-
-MALLOC_DECLARE(M_USB);
-MALLOC_DECLARE(M_USBDEV);
-MALLOC_DECLARE(M_USBHC);
-
-#include <dev/usb/usb_port.h>
-#endif /* KERNEL */
-#endif /* __FreeBSD__ */
-
+#define USB_STACK_VERSION 2
#define USB_MAX_DEVICES 128
#define USB_START_ADDR 0
@@ -159,6 +154,10 @@ typedef struct {
#define UDESC_STRING 0x03
#define UDESC_INTERFACE 0x04
#define UDESC_ENDPOINT 0x05
+#define UDESC_DEVICE_QUALIFIER 0x06
+#define UDESC_OTHER_SPEED_CONFIGURATION 0x07
+#define UDESC_INTERFACE_POWER 0x08
+#define UDESC_OTG 0x09
#define UDESC_CS_DEVICE 0x21 /* class specific */
#define UDESC_CS_CONFIG 0x22
#define UDESC_CS_STRING 0x23
@@ -175,9 +174,13 @@ typedef struct {
/* Feature numbers */
#define UF_ENDPOINT_HALT 0
#define UF_DEVICE_REMOTE_WAKEUP 1
+#define UF_TEST_MODE 2
#define USB_MAX_IPACKET 8 /* maximum size of the initial packet */
+#define USB_2_MAX_CTRL_PACKET 64
+#define USB_2_MAX_BULK_PACKET 512
+
typedef struct {
uByte bLength;
uByte bDescriptorType;
@@ -188,6 +191,8 @@ typedef struct {
uByte bLength;
uByte bDescriptorType;
uWord bcdUSB;
+#define UD_USB_2_0 0x0200
+#define UD_IS_USB2(d) (UGETW((d)->bcdUSB) >= UD_USB_2_0)
uByte bDeviceClass;
uByte bDeviceSubClass;
uByte bDeviceProtocol;
@@ -269,6 +274,10 @@ typedef struct {
/* Hub specific request */
#define UR_GET_BUS_STATE 0x02
+#define UR_CLEAR_TT_BUFFER 0x08
+#define UR_RESET_TT 0x09
+#define UR_GET_TT_STATE 0x0a
+#define UR_STOP_TT 0x0b
/* Hub features */
#define UHF_C_HUB_LOCAL_POWER 0
@@ -285,21 +294,29 @@ typedef struct {
#define UHF_C_PORT_SUSPEND 18
#define UHF_C_PORT_OVER_CURRENT 19
#define UHF_C_PORT_RESET 20
+#define UHF_PORT_TEST 21
+#define UHF_PORT_INDICATOR 22
typedef struct {
uByte bDescLength;
uByte bDescriptorType;
uByte bNbrPorts;
uWord wHubCharacteristics;
-#define UHD_PWR 0x03
-#define UHD_PWR_GANGED 0x00
-#define UHD_PWR_INDIVIDUAL 0x01
-#define UHD_PWR_NO_SWITCH 0x02
-#define UHD_COMPOUND 0x04
-#define UHD_OC 0x18
-#define UHD_OC_GLOBAL 0x00
-#define UHD_OC_INDIVIDUAL 0x08
-#define UHD_OC_NONE 0x10
+#define UHD_PWR 0x0003
+#define UHD_PWR_GANGED 0x0000
+#define UHD_PWR_INDIVIDUAL 0x0001
+#define UHD_PWR_NO_SWITCH 0x0002
+#define UHD_COMPOUND 0x0004
+#define UHD_OC 0x0018
+#define UHD_OC_GLOBAL 0x0000
+#define UHD_OC_INDIVIDUAL 0x0008
+#define UHD_OC_NONE 0x0010
+#define UHD_TT_THINK 0x0060
+#define UHD_TT_THINK_8 0x0000
+#define UHD_TT_THINK_16 0x0020
+#define UHD_TT_THINK_24 0x0040
+#define UHD_TT_THINK_32 0x0060
+#define UHD_PORT_IND 0x0080
uByte bPwrOn2PwrGood; /* delay in 2 ms units */
#define UHD_PWRON_FACTOR 2
uByte bHubContrCurrent;
@@ -311,6 +328,32 @@ typedef struct {
#define USB_HUB_DESCRIPTOR_SIZE 9 /* includes deprecated PortPowerCtrlMask */
typedef struct {
+ uByte bLength;
+ uByte bDescriptorType;
+ uWord bcdUSB;
+ uByte bDeviceClass;
+ uByte bDeviceSubClass;
+ uByte bDeviceProtocol;
+ uByte bMaxPacketSize0;
+ uByte bNumConfigurations;
+ uByte bReserved;
+} UPACKED usb_device_qualifier_t;
+#define USB_DEVICE_QUALIFIER_SIZE 10
+
+typedef struct {
+ uByte bLength;
+ uByte bDescriptorType;
+ uByte bmAttributes;
+#define UOTG_SRP 0x01
+#define UOTG_HNP 0x02
+} UPACKED usb_otg_descriptor_t;
+
+/* OTG feature selectors */
+#define UOTG_B_HNP_ENABLE 3
+#define UOTG_A_HNP_SUPPORT 4
+#define UOTG_A_ALT_HNP_SUPPORT 5
+
+typedef struct {
uWord wStatus;
/* Device status flags */
#define UDS_SELF_POWERED 0x0001
@@ -335,6 +378,9 @@ typedef struct {
#define UPS_RESET 0x0010
#define UPS_PORT_POWER 0x0100
#define UPS_LOW_SPEED 0x0200
+#define UPS_HIGH_SPEED 0x0400
+#define UPS_PORT_TEST 0x0800
+#define UPS_PORT_INDICATOR 0x1000
uWord wPortChange;
#define UPS_C_CONNECT_STATUS 0x0001
#define UPS_C_PORT_ENABLED 0x0002
@@ -349,6 +395,9 @@ typedef struct {
#define UDCLASS_HID 0x00
#define UDCLASS_HUB 0x09
#define UDSUBCLASS_HUB 0
+#define UDPROTO_FSHUB 0
+#define UDPROTO_HSHUBSTT 1
+#define UDPROTO_HSHUBMTT 2
#define UDCLASS_MASS 0x00
/* Interface class codes */
@@ -390,11 +439,14 @@ typedef struct {
#define UISUBCLASS_SCSI 6
#define UIPROTO_MASS_CBI_I 0
#define UIPROTO_MASS_CBI 1
-#define UIPROTO_MASS_BBB 2
-#define UIPROTO_MASS_BBB_P 80 /* 'P' for the Iomega Zip drive */
+#define UIPROTO_MASS_BBB_OLD 2 /* Not in the spec anymore */
+#define UIPROTO_MASS_BBB 80 /* 'P' for the Iomega Zip drive */
#define UICLASS_HUB 0x09
#define UISUBCLASS_HUB 0
+#define UIPROTO_FSHUB 0
+#define UIPROTO_HSHUBSTT 0 /* Yes, same as previous */
+#define UIPROTO_HSHUBMTT 1
#define UICLASS_CDC_DATA 0x0a
#define UISUBCLASS_DATA 0
@@ -415,6 +467,10 @@ typedef struct {
#define UICLASS_FIRM_UPD 0x0c
#define UICLASS_APPL_SPEC 0xfe
+#define UISUBCLASS_FIRMWARE_DOWNLOAD 1
+#define UISUBCLASS_IRDA 2
+#define UIPROTO_IRDA 0
+
#define UICLASS_VENDOR 0xff
@@ -430,6 +486,7 @@ typedef struct {
#if 0
/* These are the values from the spec. */
#define USB_PORT_RESET_DELAY 10 /* ms */
+#define USB_PORT_ROOT_RESET_DELAY 50 /* ms */
#define USB_PORT_RESET_SETTLE 10 /* ms */
#define USB_PORT_POWERUP_DELAY 100 /* ms */
#define USB_SET_ADDRESS_SETTLE 2 /* ms */
@@ -440,8 +497,9 @@ typedef struct {
#else
/* Allow for marginal (i.e. non-conforming) devices. */
#define USB_PORT_RESET_DELAY 50 /* ms */
+#define USB_PORT_ROOT_RESET_DELAY 250 /* ms */
#define USB_PORT_RESET_RECOVERY 50 /* ms */
-#define USB_PORT_POWERUP_DELAY 200 /* 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 */
@@ -533,7 +591,10 @@ struct usb_device_info {
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];
@@ -563,6 +624,7 @@ struct usb_event {
#define USB_EVENT_DRIVER_ATTACH 5
#define USB_EVENT_DRIVER_DETACH 6
#define USB_EVENT_IS_ATTACH(n) ((n) == USB_EVENT_CTRLR_ATTACH || (n) == USB_EVENT_DEVICE_ATTACH || (n) == USB_EVENT_DRIVER_ATTACH)
+#define USB_EVENT_IS_DETACH(n) ((n) == USB_EVENT_CTRLR_DETACH || (n) == USB_EVENT_DEVICE_DETACH || (n) == USB_EVENT_DRIVER_DETACH)
struct timespec ue_time;
union {
struct {
@@ -588,6 +650,7 @@ struct usb_event {
#define USB_SET_IMMED _IOW ('U', 22, int)
#define USB_GET_REPORT _IOWR('U', 23, struct usb_ctl_report)
#define USB_SET_REPORT _IOW ('U', 24, struct usb_ctl_report)
+#define USB_GET_REPORT_ID _IOR ('U', 25, int)
/* Generic USB device */
#define USB_GET_CONFIG _IOR ('U', 100, int)
diff --git a/sys/dev/usb/usb_port.h b/sys/dev/usb/usb_port.h
index 9f84d83ac07..66ceaddaf3f 100644
--- a/sys/dev/usb/usb_port.h
+++ b/sys/dev/usb/usb_port.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: usb_port.h,v 1.35 2002/05/06 23:07:26 nate Exp $ */
-/* $NetBSD: usb_port.h,v 1.44 2001/05/14 20:35:29 bouyer Exp $ */
+/* $OpenBSD: usb_port.h,v 1.36 2002/05/07 18:08:04 nate 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.21 1999/11/17 22:33:47 n_hibma Exp $ */
/*
@@ -57,6 +57,7 @@
#ifdef USB_DEBUG
#define UKBD_DEBUG 1
+#define UHIDEV_DEBUG 1
#define UHID_DEBUG 1
#define OHCI_DEBUG 1
#define UGEN_DEBUG 1
@@ -65,26 +66,36 @@
#define ULPT_DEBUG 1
#define UCOM_DEBUG 1
#define UPLCOM_DEBUG 1
+#define UMCT_DEBUG 1
#define UMODEM_DEBUG 1
#define UAUDIO_DEBUG 1
#define AUE_DEBUG 1
#define CUE_DEBUG 1
#define KUE_DEBUG 1
+#define URL_DEBUG 1
#define UMASS_DEBUG 1
#define UVISOR_DEBUG 1
#define UPL_DEBUG 1
#define UZCOM_DEBUG 1
#define URIO_DEBUG 1
#define UFTDI_DEBUG 1
-#define UMCT_DEBUG 1
#define USCANNER_DEBUG 1
#define USSCANNER_DEBUG 1
+#define EHCI_DEBUG 1
+#define UIRDA_DEBUG 1
+#define USTIR_DEBUG 1
+#define UISDATA_DEBUG 1
+#define UDSBR_DEBUG 1
#define Static
#else
#define Static static
#endif
-#define SCSI_MODE_SENSE MODE_SENSE
+#define SCSI_MODE_SENSE MODE_SENSE
+
+#define UMASS_ATAPISTR "atapibus"
+
+typedef struct proc *usb_proc_ptr;
typedef struct device *device_ptr_t;
#define USBBASEDEVICE struct device
@@ -104,8 +115,11 @@ typedef struct device *device_ptr_t;
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_callout_pending(h) callout_pending(&(h))
#define usb_uncallout(h, f, d) callout_stop(&(h))
+#define usb_lockmgr(l, f, sl, p) lockmgr((l), (f), (sl))
+
#define usb_kthread_create1 kthread_create1
#define usb_kthread_create kthread_create
@@ -133,21 +147,13 @@ struct cfattach __CONCAT(dname,_ca) = { \
}
#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_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 = \
@@ -161,10 +167,7 @@ __CONCAT(dname,_attach)(parent, self, aux) \
#define USB_ATTACH_SETUP printf("\n")
#define USB_DETACH(dname) \
-int \
-__CONCAT(dname,_detach)(self, flags) \
- struct device *self; \
- int flags;
+int __CONCAT(dname,_detach)(struct device *self, int flags)
#define USB_DETACH_START(dname, sc) \
struct __CONCAT(dname,_softc) *sc = \
@@ -184,12 +187,17 @@ __CONCAT(dname,_detach)(self, flags) \
(config_found_sm(parent, args, print, sub))
#elif defined(__OpenBSD__)
-#include <sys/timeout.h>
/*
* OpenBSD
*/
+#include <sys/timeout.h>
+
+#define USB_USE_SOFTINTR
+
+#define USB_DEBUG
#ifdef USB_DEBUG
#define UKBD_DEBUG 1
+#define UHIDEV_DEBUG 1
#define UHID_DEBUG 1
#define OHCI_DEBUG 1
#define UGEN_DEBUG 1
@@ -197,6 +205,8 @@ __CONCAT(dname,_detach)(self, flags) \
#define UHUB_DEBUG 1
#define ULPT_DEBUG 1
#define UCOM_DEBUG 1
+#define UPLCOM_DEBUG 1
+#define UMCT_DEBUG 1
#define UMODEM_DEBUG 1
#define UAUDIO_DEBUG 1
#define AUE_DEBUG 1
@@ -208,33 +218,49 @@ __CONCAT(dname,_detach)(self, flags) \
#define UZCOM_DEBUG 1
#define URIO_DEBUG 1
#define UFTDI_DEBUG 1
-#define UMCT_DEBUG 1
#define USCANNER_DEBUG 1
#define USSCANNER_DEBUG 1
+#define EHCI_DEBUG 1
+#define UISDATA_DEBUG 1
+#define UDSBR_DEBUG 1
#endif
#define Static
+#define UMASS_ATAPISTR "atapiscsi"
+
+/* periph_quirks */
+#define PQUIRK_AUTOSAVE 0x00000001 /* do implicit SAVE POINTERS */
+#define PQUIRK_NOSYNC 0x00000002 /* does not grok SDTR */
+#define PQUIRK_NOWIDE 0x00000004 /* does not grok WDTR */
+#define PQUIRK_NOTAG 0x00000008 /* does not grok tagged cmds */
+#define PQUIRK_NOLUNS 0x00000010 /* DTWT with LUNs */
+#define PQUIRK_FORCELUNS 0x00000020 /* prehistoric device groks
+ LUNs */
+#define PQUIRK_NOMODESENSE 0x00000040 /* device doesn't do MODE SENSE
+ properly */
+#define PQUIRK_NOSTARTUNIT 0x00000080 /* do not issue START UNIT */
+#define PQUIRK_NOSYNCCACHE 0x00000100 /* do not issue SYNC CACHE */
+#define PQUIRK_CDROM 0x00000200 /* device is a CD-ROM, no
+ matter what else it claims */
+#define PQUIRK_LITTLETOC 0x00000400 /* audio TOC is little-endian */
+#define PQUIRK_NOCAPACITY 0x00000800 /* no READ CD CAPACITY */
+#define PQUIRK_NOTUR 0x00001000 /* no TEST UNIT READY */
+#define PQUIRK_NODOORLOCK 0x00002000 /* can't lock door */
+#define PQUIRK_NOSENSE 0x00004000 /* can't REQUEST SENSE */
+#define PQUIRK_ONLYBIG 0x00008000 /* only use SCSI_{R,W}_BIG */
+#define PQUIRK_BYTE5_ZERO 0x00010000 /* byte5 in capacity is wrong */
+#define PQUIRK_NO_FLEX_PAGE 0x00020000 /* does not support flex geom
+ page */
+#define PQUIRK_NOBIGMODESENSE 0x00040000 /* has no big mode-sense op */
+#define PQUIRK_CAP_SYNC 0x00080000 /* SCSI1 device with sync op */
+
+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 show_scsipi_xs show_scsi_xs
-#define show_scsipi_cmd show_scsi_cmd
-#define xs_control flags
-#define xs_status status
+#define UHIDBUSCF_REPORTID -1
+#define UHIDBUSCF_REPORTID_DEFAULT -1
#define bswap32(x) swap32(x)
#define bswap16(x) swap16(x)
@@ -301,6 +327,7 @@ typedef struct timeout usb_callout_t;
#define usb_callout_init(h)
#define usb_callout(h, t, f, d) \
{ timeout_set(&(h), (f), (d)); timeout_add(&(h), (t)); }
+#define usb_callout_pending(h) timeout_pending(&(h))
#define usb_uncallout(h, f, d) timeout_del(&(h))
#define usb_lockmgr(l, f, sl, p) lockmgr((l), (f), (sl), (p))
@@ -381,6 +408,15 @@ __CONCAT(dname,_detach)(self, flags) \
#include "opt_usb.h"
+#if defined(_KERNEL)
+#include <sys/malloc.h>
+
+MALLOC_DECLARE(M_USB);
+MALLOC_DECLARE(M_USBDEV);
+MALLOC_DECLARE(M_USBHC);
+
+#endif
+
#define Static
#define USBVERBOSE
@@ -395,14 +431,15 @@ __CONCAT(dname,_detach)(self, flags) \
#define DECLARE_USB_DMA_T typedef void * usb_dma_t
+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 usb_kthread_create1(function, sc, priv, string, name)
-#define usb_kthread_create(create_function, sc)
-#define usb_kthread_exit(err)
+#define kthread_create1(f, s, p, a0, a1) \
+ kthread_create((f), (s), (p), RFHIGHPID, (a0), (a1))
typedef struct callout_handle usb_callout_t;
#define usb_callout_init(h) callout_handle_init(&(h))
@@ -416,6 +453,8 @@ typedef struct callout_handle usb_callout_t;
#define powerhook_disestablish(hdl)
#define PWR_RESUME 0
+#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) \
diff --git a/sys/dev/usb/usb_quirks.c b/sys/dev/usb/usb_quirks.c
index 31e003798b8..0abf050b1a6 100644
--- a/sys/dev/usb/usb_quirks.c
+++ b/sys/dev/usb/usb_quirks.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: usb_quirks.c,v 1.10 2001/10/31 04:24:44 nate Exp $ */
-/* $NetBSD: usb_quirks.c,v 1.38 2001/04/15 10:26:36 augustss Exp $ */
+/* $OpenBSD: usb_quirks.c,v 1.11 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: usb_quirks.c,v 1.39 2001/11/13 06:24:56 lukem Exp $ */
/* $FreeBSD: src/sys/dev/usb/usb_quirks.c,v 1.13 1999/11/17 22:33:47 n_hibma Exp $ */
/*
@@ -74,8 +74,6 @@ Static const struct usbd_quirk_entry {
{ USB_VENDOR_ALCOR2, USB_PRODUCT_ALCOR2_KBD_HUB, 0x001, { UQ_SPUR_BUT_UP }},
{ USB_VENDOR_MCT, USB_PRODUCT_MCT_HUB0100, 0x102, { UQ_BUS_POWERED }},
{ USB_VENDOR_MCT, USB_PRODUCT_MCT_USB232, 0x102, { UQ_BUS_POWERED }},
- { USB_VENDOR_MCT, USB_PRODUCT_MCT_SITECOM_USB232, 0x102, { UQ_BUS_POWERED }},
- { USB_VENDOR_MCT, USB_PRODUCT_MCT_DU_H3SP_USB232, 0x102, { UQ_BUS_POWERED }},
{ USB_VENDOR_METRICOM, USB_PRODUCT_METRICOM_RICOCHET_GS,
0x100, { UQ_ASSUME_CM_OVER_DATA | UQ_NO_STRINGS }},
{ USB_VENDOR_TI, USB_PRODUCT_TI_UTUSB41, 0x110, { UQ_POWER_CLAIM }},
diff --git a/sys/dev/usb/usb_subr.c b/sys/dev/usb/usb_subr.c
index 4883a38aa17..66cb1fd6248 100644
--- a/sys/dev/usb/usb_subr.c
+++ b/sys/dev/usb/usb_subr.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: usb_subr.c,v 1.19 2002/05/02 20:08:04 nate Exp $ */
-/* $NetBSD: usb_subr.c,v 1.87 2001/08/15 00:04:59 augustss Exp $ */
+/* $OpenBSD: usb_subr.c,v 1.20 2002/05/07 18:08:04 nate Exp $ */
+/* $NetBSD: usb_subr.c,v 1.98 2002/02/20 20:30:13 christos Exp $ */
/* $FreeBSD: src/sys/dev/usb/usb_subr.c,v 1.18 1999/11/17 22:33:47 n_hibma Exp $ */
/*
@@ -352,6 +352,9 @@ usbd_reset_port(usbd_device_handle dev, int port, usb_port_status_t *ps)
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);
@@ -475,13 +478,36 @@ usbd_fill_iface_data(usbd_device_handle dev, int ifaceidx, int altidx)
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;
}
@@ -725,7 +751,6 @@ usbd_setup_pipe(usbd_device_handle dev, usbd_interface_handle iface,
p->repeat = 0;
p->interval = ival;
SIMPLEQ_INIT(&p->queue);
- usb_callout_init(p->abort_handle);
err = dev->bus->methods->open_pipe(p);
if (err) {
DPRINTFN(-1,("usbd_setup_pipe: endpoint=0x%x failed, error="
@@ -745,6 +770,7 @@ usbd_setup_pipe(usbd_device_handle dev, usbd_interface_handle iface,
void
usbd_kill_pipe(usbd_pipe_handle pipe)
{
+ usbd_abort_pipe(pipe);
pipe->methods->close(pipe);
pipe->endpoint->refcnt--;
free(pipe, M_USB);
@@ -927,16 +953,17 @@ usbd_probe_and_attach(device_ptr_t parent, usbd_device_handle dev,
*/
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;
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",
@@ -947,7 +974,7 @@ usbd_new_device(device_ptr_t parent, usbd_bus_handle bus, int depth,
dev = malloc(sizeof *dev, M_USB, M_NOWAIT);
if (dev == NULL)
return (USBD_NOMEM);
- memset(dev, 0, sizeof(*dev));
+ memset(dev, 0, sizeof *dev);
dev->bus = bus;
@@ -965,9 +992,15 @@ usbd_new_device(device_ptr_t parent, usbd_bus_handle bus, int depth,
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;
@@ -996,11 +1029,22 @@ usbd_new_device(device_ptr_t parent, usbd_bus_handle bus, int depth,
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));
+ dev->speed));
if (dd->bDescriptorType != UDESC_DEVICE) {
/* Illegal device descriptor */
@@ -1203,7 +1247,7 @@ usbd_fill_deviceinfo(usbd_device_handle dev, struct usb_device_info *di,
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] &&
@@ -1306,13 +1350,7 @@ usb_disconnect_port(struct usbd_port *up, device_ptr_t parent)
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
-
}
}
diff --git a/sys/dev/usb/usbdevs.h b/sys/dev/usb/usbdevs.h
index 8a81bd55e82..875ba4dfa7a 100644
--- a/sys/dev/usb/usbdevs.h
+++ b/sys/dev/usb/usbdevs.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: usbdevs.h,v 1.43 2002/04/01 21:36:16 nate Exp $ */
+/* $OpenBSD: usbdevs.h,v 1.44 2002/05/07 18:08:05 nate Exp $ */
/*
* THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
diff --git a/sys/dev/usb/usbdevs_data.h b/sys/dev/usb/usbdevs_data.h
index 1e84ae19099..e7096569e4c 100644
--- a/sys/dev/usb/usbdevs_data.h
+++ b/sys/dev/usb/usbdevs_data.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: usbdevs_data.h,v 1.43 2002/04/01 21:36:16 nate Exp $ */
+/* $OpenBSD: usbdevs_data.h,v 1.44 2002/05/07 18:08:05 nate Exp $ */
/*
* THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
diff --git a/sys/dev/usb/usbdi.c b/sys/dev/usb/usbdi.c
index 002fa3767f5..856a20cd905 100644
--- a/sys/dev/usb/usbdi.c
+++ b/sys/dev/usb/usbdi.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: usbdi.c,v 1.16 2002/05/02 20:08:04 nate Exp $ */
-/* $NetBSD: usbdi.c,v 1.81 2001/04/17 00:05:33 augustss Exp $ */
+/* $OpenBSD: usbdi.c,v 1.17 2002/05/07 18:08:05 nate Exp $ */
+/* $NetBSD: usbdi.c,v 1.99 2002/02/28 04:49:16 thorpej Exp $ */
/* $FreeBSD: src/sys/dev/usb/usbdi.c,v 1.28 1999/11/17 22:33:49 n_hibma Exp $ */
/*
@@ -79,10 +79,10 @@ extern int usbdebug;
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);
+ (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_nbuses = 0;
@@ -109,7 +109,42 @@ usbd_xfer_isread(usbd_xfer_handle xfer)
}
#ifdef USB_DEBUG
-void usbd_dump_queue(usbd_pipe_handle pipe);
+void
+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)
{
@@ -122,6 +157,21 @@ usbd_dump_queue(usbd_pipe_handle pipe)
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
@@ -221,12 +271,6 @@ usbd_close_pipe(usbd_pipe_handle pipe)
LIST_REMOVE(pipe, next);
pipe->endpoint->refcnt--;
pipe->methods->close(pipe);
-#if defined(__NetBSD__) && defined(DIAGNOSTIC)
- if (callout_pending(&pipe->abort_handle)) {
- callout_stop(&pipe->abort_handle);
- printf("usbd_close_pipe: abort_handle pending");
- }
-#endif
if (pipe->intrxfer != NULL)
usbd_free_xfer(pipe->intrxfer);
free(pipe, M_USB);
@@ -315,9 +359,13 @@ usbd_alloc_buffer(usbd_xfer_handle xfer, u_int32_t size)
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));
}
@@ -512,7 +560,7 @@ usbd_clear_endpoint_stall(usbd_pipe_handle pipe)
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);
@@ -551,7 +599,6 @@ usbd_clear_endpoint_stall_async(usbd_pipe_handle pipe)
return (err);
}
-void usbd_clear_endpoint_toggle(usbd_pipe_handle pipe); /* XXXXX */
void
usbd_clear_endpoint_toggle(usbd_pipe_handle pipe)
{
@@ -580,12 +627,11 @@ usbd_interface_count(usbd_device_handle dev, u_int8_t *count)
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
@@ -719,6 +765,13 @@ usb_transfer_complete(usbd_xfer_handle xfer)
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) {
@@ -758,6 +811,7 @@ usb_transfer_complete(usbd_xfer_handle xfer)
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);
}
@@ -811,6 +865,14 @@ usb_insert_transfer(usbd_xfer_handle xfer)
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)
@@ -861,20 +923,22 @@ usbd_start_next(usbd_pipe_handle pipe)
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)
+ 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));
+ data, flags, actlen, timo));
}
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)
+ usb_device_request_t *req, void *data, u_int16_t flags, int *actlen,
+ u_int32_t timeout)
{
usbd_xfer_handle xfer;
usbd_status err;
@@ -893,7 +957,7 @@ usbd_do_request_flags_pipe(usbd_device_handle dev, usbd_pipe_handle pipe,
xfer = usbd_alloc_xfer(dev);
if (xfer == NULL)
return (USBD_NOMEM);
- usbd_setup_default_xfer(xfer, dev, 0, USBD_DEFAULT_TIMEOUT, req,
+ usbd_setup_default_xfer(xfer, dev, 0, timeout, req,
data, UGETW(req->wLength), flags, 0);
xfer->pipe = pipe;
err = usbd_sync_transfer(xfer);
@@ -1024,6 +1088,9 @@ usbd_set_polling(usbd_device_handle dev, int on)
dev->bus->use_polling++;
else
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);
}
@@ -1068,7 +1135,7 @@ usb_match_device(const struct usb_devno *tbl, u_int nentries, u_int sz,
if (tbl->ud_vendor == vendor &&
(tproduct == product || tproduct == USB_PRODUCT_ANY))
return (tbl);
- tbl = (struct usb_devno *)((char *)tbl + sz);
+ tbl = (const struct usb_devno *)((const char *)tbl + sz);
}
return (NULL);
}
diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h
index 517287ea75d..0a571b0bcee 100644
--- a/sys/dev/usb/usbdi.h
+++ b/sys/dev/usb/usbdi.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: usbdi.h,v 1.14 2002/04/01 21:47:07 nate Exp $ */
-/* $NetBSD: usbdi.h,v 1.53 2001/08/15 00:04:59 augustss Exp $ */
+/* $OpenBSD: usbdi.h,v 1.15 2002/05/07 18:08:05 nate Exp $ */
+/* $NetBSD: usbdi.h,v 1.61 2002/02/11 15:20:23 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usbdi.h,v 1.18 1999/11/17 22:33:49 n_hibma Exp $ */
/*
@@ -48,25 +48,25 @@ typedef void *usbd_private_handle;
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_status;
@@ -117,16 +117,17 @@ usb_endpoint_descriptor_t *usbd_interface2endpoint_descriptor
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);
+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,
@@ -139,10 +140,11 @@ 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 *);
+ 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);
+ 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);
@@ -150,7 +152,7 @@ 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, int);
+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,
@@ -267,14 +269,15 @@ struct usb_attach_arg {
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 */
diff --git a/sys/dev/usb/usbdi_util.c b/sys/dev/usb/usbdi_util.c
index 3109bde4fac..cfe02dfea0f 100644
--- a/sys/dev/usb/usbdi_util.c
+++ b/sys/dev/usb/usbdi_util.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: usbdi_util.c,v 1.11 2001/10/31 04:24:45 nate Exp $ */
-/* $NetBSD: usbdi_util.c,v 1.35 2001/10/26 17:58:21 augustss Exp $ */
+/* $OpenBSD: usbdi_util.c,v 1.12 2002/05/07 18:08:05 nate Exp $ */
+/* $NetBSD: usbdi_util.c,v 1.39 2001/12/27 11:24:42 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usbdi_util.c,v 1.14 1999/11/17 22:33:50 n_hibma Exp $ */
/*
@@ -220,6 +220,25 @@ usbd_set_port_feature(usbd_device_handle dev, int port, int sel)
return (usbd_do_request(dev, &req, 0));
}
+usbd_status
+usbd_get_protocol(usbd_interface_handle iface, u_int8_t *report)
+{
+ usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface);
+ usbd_device_handle dev;
+ usb_device_request_t req;
+
+ DPRINTFN(4, ("usbd_get_protocol: iface=%p, endpt=%d\n",
+ iface, id->bInterfaceNumber));
+ if (id == NULL)
+ return (USBD_IOERROR);
+ usbd_interface2device_handle(iface, &dev);
+ req.bmRequestType = UT_READ_CLASS_INTERFACE;
+ req.bRequest = UR_GET_PROTOCOL;
+ USETW(req.wValue, 0);
+ USETW(req.wIndex, id->bInterfaceNumber);
+ USETW(req.wLength, 1);
+ return (usbd_do_request(dev, &req, report));
+}
usbd_status
usbd_set_protocol(usbd_interface_handle iface, int report)
@@ -227,15 +246,12 @@ usbd_set_protocol(usbd_interface_handle iface, int report)
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);
@@ -251,14 +267,11 @@ usbd_set_report(usbd_interface_handle iface, int type, int id, void *data,
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);
@@ -268,20 +281,17 @@ usbd_set_report(usbd_interface_handle iface, int type, int id, void *data,
}
usbd_status
-usbd_set_report_async(usbd_interface_handle iface, int type, int id, void *data,
- int len)
+usbd_set_report_async(usbd_interface_handle iface, int type, int id,
+ void *data, int len)
{
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);
@@ -297,14 +307,11 @@ usbd_get_report(usbd_interface_handle iface, int type, int id, void *data,
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_get_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_READ_CLASS_INTERFACE;
req.bRequest = UR_GET_REPORT;
USETW2(req.wValue, type, id);
@@ -319,14 +326,11 @@ usbd_set_idle(usbd_interface_handle iface, int duration, int id)
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);
@@ -357,13 +361,10 @@ usbd_get_hid_descriptor(usbd_interface_handle ifc)
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;
@@ -388,9 +389,7 @@ usbd_read_report_desc(usbd_interface_handle ifc, void **descp, int *sizep,
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);
@@ -482,3 +481,21 @@ usb_detach_wakeup(device_ptr_t dv)
DPRINTF(("usb_detach_wakeup: for %s\n", USBDEVPTRNAME(dv)));
wakeup(dv);
}
+
+usb_descriptor_t *
+usb_find_desc(usbd_device_handle dev, int type)
+{
+ usb_descriptor_t *desc;
+ usb_config_descriptor_t *cd = usbd_get_config_descriptor(dev);
+ uByte *p = (uByte *)cd;
+ uByte *end = p + UGETW(cd->wTotalLength);
+
+ while (p < end) {
+ desc = (usb_descriptor_t *)p;
+ if (desc->bDescriptorType == type)
+ return (desc);
+ p += desc->bLength;
+ }
+
+ return (NULL);
+}
diff --git a/sys/dev/usb/usbdi_util.h b/sys/dev/usb/usbdi_util.h
index 224cb714787..6bca3e54e7c 100644
--- a/sys/dev/usb/usbdi_util.h
+++ b/sys/dev/usb/usbdi_util.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: usbdi_util.h,v 1.8 2001/10/31 04:24:45 nate Exp $ */
-/* $NetBSD: usbdi_util.h,v 1.23 2001/10/26 17:58:22 augustss Exp $ */
+/* $OpenBSD: usbdi_util.h,v 1.9 2002/05/07 18:08:05 nate Exp $ */
+/* $NetBSD: usbdi_util.h,v 1.27 2002/03/17 18:02:53 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usbdi_util.h,v 1.9 1999/11/17 22:33:50 n_hibma Exp $ */
/*
@@ -53,8 +53,9 @@ 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_device_status(usbd_device_handle, usb_status_t *);
usbd_status usbd_get_hub_status(usbd_device_handle, usb_hub_status_t *);
+usbd_status usbd_get_protocol(usbd_interface_handle dev, u_int8_t *report);
usbd_status usbd_set_protocol(usbd_interface_handle dev, int report);
usbd_status usbd_get_report_descriptor(usbd_device_handle dev, int ifcno,
int size, void *d);
@@ -84,3 +85,4 @@ usbd_status usbd_bulk_transfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe,
void usb_detach_wait(device_ptr_t);
void usb_detach_wakeup(device_ptr_t);
+usb_descriptor_t *usb_find_desc(usbd_device_handle dev, int type);
diff --git a/sys/dev/usb/usbdivar.h b/sys/dev/usb/usbdivar.h
index 9d81200a6ff..d5e53c3e0f1 100644
--- a/sys/dev/usb/usbdivar.h
+++ b/sys/dev/usb/usbdivar.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: usbdivar.h,v 1.14 2001/10/31 04:24:45 nate Exp $ */
-/* $NetBSD: usbdivar.h,v 1.63 2001/01/21 19:00:06 augustss Exp $ */
+/* $OpenBSD: usbdivar.h,v 1.15 2002/05/07 18:08:05 nate Exp $ */
+/* $NetBSD: usbdivar.h,v 1.69 2001/12/27 18:43:46 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usbdivar.h,v 1.11 1999/11/17 22:33:51 n_hibma Exp $ */
/*
@@ -80,7 +80,7 @@ struct usbd_port {
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 */
};
@@ -117,13 +117,11 @@ struct usbd_bus {
#define USBREV_2_0 4
#define USBREV_STR { "unknown", "pre 1.0", "1.0", "1.1", "2.0" }
-#if 0
#ifdef USB_USE_SOFTINTR
#ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
void *soft; /* soft interrupt cookie */
#else
- struct callout softi;
-#endif
+ usb_callout_t softi;
#endif
#endif
@@ -138,13 +136,15 @@ struct usbd_device {
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 */
@@ -179,8 +179,6 @@ struct usbd_pipe {
char repeat;
int interval;
- usb_callout_t abort_handle;
-
/* Filled by HC driver. */
struct usbd_pipe_methods *methods;
};
@@ -199,7 +197,8 @@ struct usbd_xfer {
#ifdef DIAGNOSTIC
u_int32_t busy_free;
#define XFER_FREE 0x46524545
-#define XFER_BUSY 0x42555357
+#define XFER_BUSY 0x42555359
+#define XFER_ONQU 0x4f4e5155
#endif
/* For control pipe */
@@ -228,6 +227,14 @@ struct usbd_xfer {
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);
diff --git a/sys/dev/usb/usbhid.h b/sys/dev/usb/usbhid.h
index 86c7948ccee..cd27fb55643 100644
--- a/sys/dev/usb/usbhid.h
+++ b/sys/dev/usb/usbhid.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: usbhid.h,v 1.4 2000/11/08 18:10:39 aaron Exp $ */
-/* $NetBSD: usbhid.h,v 1.9 2000/09/03 19:09:14 augustss Exp $ */
+/* $OpenBSD: usbhid.h,v 1.5 2002/05/07 18:08:05 nate Exp $ */
+/* $NetBSD: usbhid.h,v 1.11 2001/12/28 00:20:24 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usbhid.h,v 1.7 1999/11/17 22:33:51 n_hibma Exp $ */
/*
@@ -165,12 +165,25 @@ typedef struct usb_hid_descriptor {
#define HUD_ERASER 0x0045
#define HUD_TABLET_PICK 0x0046
-#define HID_USAGE2(p,u) (((p) << 16) | u)
+/* Usages LEDs */
+#define HUD_LED_NUM_LOCK 0x0001
+#define HUD_LED_CAPS_LOCK 0x0002
+#define HUD_LED_SCROLL_LOCK 0x0003
+#define HUD_LED_COMPOSE 0x0004
+#define HUD_LED_KANA 0x0005
+
+#define HID_USAGE2(p, u) (((p) << 16) | u)
+#define HID_GET_USAGE(u) ((u) & 0xffff)
+#define HID_GET_USAGE_PAGE(u) (((u) >> 16) & 0xffff)
#define UHID_INPUT_REPORT 0x01
#define UHID_OUTPUT_REPORT 0x02
#define UHID_FEATURE_REPORT 0x03
+#define HCOLL_PHYSICAL 0
+#define HCOLL_APPLICATION 1
+#define HCOLL_LOGICAL 2
+
/* Bits in the input/output/feature items */
#define HIO_CONST 0x001
#define HIO_VARIABLE 0x002
diff --git a/sys/dev/usb/uscanner.c b/sys/dev/usb/uscanner.c
index a9973e43a53..dad8296523e 100644
--- a/sys/dev/usb/uscanner.c
+++ b/sys/dev/usb/uscanner.c
@@ -1,6 +1,5 @@
-/* $OpenBSD: uscanner.c,v 1.5 2002/01/03 22:23:43 deraadt Exp $ */
-/* $NetBSD: uscanner.c,v 1.18 2001/10/11 12:05:10 augustss Exp $ */
-/* $FreeBSD$ */
+/* $OpenBSD: uscanner.c,v 1.6 2002/05/07 18:08:05 nate Exp $ */
+/* $NetBSD: uscanner.c,v 1.27 2002/02/11 10:09:14 augustss Exp $ */
/*
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@@ -56,7 +55,11 @@
#endif
#include <sys/tty.h>
#include <sys/file.h>
+#if defined(__FreeBSD__) && __FreeBSD_version >= 500014
+#include <sys/selinfo.h>
+#else
#include <sys/select.h>
+#endif
#include <sys/proc.h>
#include <sys/vnode.h>
#include <sys/poll.h>
@@ -77,104 +80,128 @@ int uscannerdebug = 0;
#define DPRINTFN(n,x)
#endif
+struct uscan_info {
+ struct usb_devno devno;
+ u_int flags;
+#define USC_KEEP_OPEN 1
+};
+
/* Table of scanners that may work with this driver. */
-static const struct scanner_id {
- uint16_t vendor;
- uint16_t product;
-} scanner_ids [] = {
- /* Acer Peripherals */
- { USB_VENDOR_ACERP, USB_PRODUCT_ACERP_ACERSCAN_320U },
- { USB_VENDOR_ACERP, USB_PRODUCT_ACERP_ACERSCAN_640U },
- { USB_VENDOR_ACERP, USB_PRODUCT_ACERP_ACERSCAN_620U },
- { USB_VENDOR_ACERP, USB_PRODUCT_ACERP_ACERSCAN_C310U },
-
- /* AGFA */
- { USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCAN1212U },
- { USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCAN1212U2 },
- { USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCANTOUCH },
-
- /* Kye */
- { USB_VENDOR_KYE, USB_PRODUCT_KYE_VIVIDPRO },
-
- /* HP */
- { USB_VENDOR_HP, USB_PRODUCT_HP_3300C },
- { USB_VENDOR_HP, USB_PRODUCT_HP_3400CSE },
- { USB_VENDOR_HP, USB_PRODUCT_HP_4100C },
- { USB_VENDOR_HP, USB_PRODUCT_HP_4200C },
- { USB_VENDOR_HP, USB_PRODUCT_HP_S20 },
- { USB_VENDOR_HP, USB_PRODUCT_HP_5200C },
+static const struct uscan_info uscanner_devs[] = {
+ /* Acer Peripherals */
+ {{ USB_VENDOR_ACERP, USB_PRODUCT_ACERP_ACERSCAN_320U }, 0 },
+ {{ USB_VENDOR_ACERP, USB_PRODUCT_ACERP_ACERSCAN_640U }, 0 },
+ {{ USB_VENDOR_ACERP, USB_PRODUCT_ACERP_ACERSCAN_620U }, 0 },
+ {{ USB_VENDOR_ACERP, USB_PRODUCT_ACERP_ACERSCAN_C310U }, 0 },
+
+ /* AGFA */
+ {{ USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCAN1236U }, 0 },
+ {{ USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCAN1212U }, 0 },
+ {{ USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCAN1212U2 }, 0 },
+ {{ USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCANTOUCH }, 0 },
+ {{ USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCANE40 }, 0 },
+ {{ USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCANE50 }, 0 },
+ {{ USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCANE20 }, 0 },
+ {{ USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCANE25 }, 0 },
+ {{ USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCANE26 }, 0 },
+ {{ USB_VENDOR_AGFA, USB_PRODUCT_AGFA_SNAPSCANE52 }, 0 },
+
+ /* Avision */
+ {{ USB_VENDOR_AVISION, USB_PRODUCT_AVISION_1200U }, 0 },
+
+ /* Canon */
+ {{ USB_VENDOR_CANON, USB_PRODUCT_CANON_N656U }, 0 },
+
+ /* Kye */
+ {{ USB_VENDOR_KYE, USB_PRODUCT_KYE_VIVIDPRO }, 0 },
+
+ /* HP */
+ {{ USB_VENDOR_HP, USB_PRODUCT_HP_3300C }, 0 },
+ {{ USB_VENDOR_HP, USB_PRODUCT_HP_3400CSE }, 0 },
+ {{ USB_VENDOR_HP, USB_PRODUCT_HP_4100C }, 0 },
+ {{ USB_VENDOR_HP, USB_PRODUCT_HP_4200C }, 0 },
+ {{ USB_VENDOR_HP, USB_PRODUCT_HP_4300C }, 0 },
+ {{ USB_VENDOR_HP, USB_PRODUCT_HP_S20 }, 0 },
+ {{ USB_VENDOR_HP, USB_PRODUCT_HP_5200C }, 0 },
#if 0
- { USB_VENDOR_HP, USB_PRODUCT_HP_5300C },
+ /* Handled by usscanner */
+ {{ USB_VENDOR_HP, USB_PRODUCT_HP_5300C }, 0 },
#endif
- { USB_VENDOR_HP, USB_PRODUCT_HP_6200C },
- { USB_VENDOR_HP, USB_PRODUCT_HP_6300C },
-
- /* Avision */
- { USB_VENDOR_AVISION, USB_PRODUCT_AVISION_1200U },
+ {{ USB_VENDOR_HP, USB_PRODUCT_HP_6200C }, 0 },
+ {{ USB_VENDOR_HP, USB_PRODUCT_HP_6300C }, 0 },
#if 0
- /* Microtek */
- { USB_VENDOR_SCANLOGIC, USB_PRODUCT_SCANLOGIC_336CX },
- { USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_X6U },
- { USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_336CX },
- { USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_336CX2 },
- { USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_C6 },
- { USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_V6USL },
- { USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_V6USL2 },
- { USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_V6UL },
+ /* XXX Should be handled by usscanner */
+ /* Microtek */
+ {{ USB_VENDOR_SCANLOGIC, USB_PRODUCT_SCANLOGIC_336CX }, 0 },
+ {{ USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_X6U }, 0 },
+ {{ USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_336CX }, 0 },
+ {{ USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_336CX2 }, 0 },
+ {{ USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_C6 }, 0 },
+ {{ USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_V6USL }, 0 },
+ {{ USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_V6USL2 }, 0 },
+ {{ USB_VENDOR_MICROTEK, USB_PRODUCT_MICROTEK_V6UL }, 0 },
#endif
- /* Mustek */
- { USB_VENDOR_MUSTEK, USB_PRODUCT_MUSTEK_1200CU },
- { USB_VENDOR_NATIONAL, USB_PRODUCT_NATIONAL_BEARPAW1200 },
- { USB_VENDOR_NATIONAL, USB_PRODUCT_MUSTEK_600CU },
- { USB_VENDOR_NATIONAL, USB_PRODUCT_MUSTEK_1200USB },
- { USB_VENDOR_NATIONAL, USB_PRODUCT_MUSTEK_1200UB },
-
- /* Primax */
- { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2X300 },
- { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2E300 },
- { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2300 },
- { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2E3002 },
- { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_9600 },
- { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_600U },
- { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_19200 },
- { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_1200U },
- { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G600 },
- { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_636I },
- { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2600 },
- { USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2E600 },
-
- /* Epson */
- { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_636 },
- { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_610 },
- { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1200 },
- { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1240 },
- { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1600 },
- { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1640 },
- { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_640U },
- { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1650 },
-
- /* UMAX */
- { USB_VENDOR_UMAX, USB_PRODUCT_UMAX_ASTRA1220U },
- { USB_VENDOR_UMAX, USB_PRODUCT_UMAX_ASTRA1236U },
- { USB_VENDOR_UMAX, USB_PRODUCT_UMAX_ASTRA2000U },
- { USB_VENDOR_UMAX, USB_PRODUCT_UMAX_ASTRA2200U },
- { USB_VENDOR_UMAX, USB_PRODUCT_UMAX_ASTRA3400 },
-
- /* Visioneer */
- { USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_5300 },
- { USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_7600 },
- { USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_6100 },
- { USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_6200 },
- { USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_8100 },
- { USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_8600 },
-
- /* Canon */
- { USB_VENDOR_CANON, USB_PRODUCT_CANON_N656U },
-
- { 0, 0 }
+ /* Mustek */
+ {{ USB_VENDOR_MUSTEK, USB_PRODUCT_MUSTEK_1200CU }, 0 },
+ {{ USB_VENDOR_MUSTEK, USB_PRODUCT_MUSTEK_BEARPAW1200F }, 0 },
+ {{ USB_VENDOR_MUSTEK, USB_PRODUCT_MUSTEK_600USB }, 0 },
+ {{ USB_VENDOR_MUSTEK, USB_PRODUCT_MUSTEK_600CU }, 0 },
+ {{ USB_VENDOR_MUSTEK, USB_PRODUCT_MUSTEK_1200USB }, 0 },
+ {{ USB_VENDOR_MUSTEK, USB_PRODUCT_MUSTEK_1200UB }, 0 },
+ {{ USB_VENDOR_MUSTEK, USB_PRODUCT_MUSTEK_1200USBPLUS }, 0 },
+ {{ USB_VENDOR_MUSTEK, USB_PRODUCT_MUSTEK_1200CUPLUS }, 0 },
+
+ /* National */
+ {{ USB_VENDOR_NATIONAL, USB_PRODUCT_NATIONAL_BEARPAW1200 }, 0 },
+ {{ USB_VENDOR_NATIONAL, USB_PRODUCT_NATIONAL_BEARPAW2400 }, 0 },
+
+ /* Primax */
+ {{ USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2X300 }, 0 },
+ {{ USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2E300 }, 0 },
+ {{ USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2300 }, 0 },
+ {{ USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2E3002 }, 0 },
+ {{ USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_9600 }, 0 },
+ {{ USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_600U }, 0 },
+ {{ USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_19200 }, 0 },
+ {{ USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_1200U }, 0 },
+ {{ USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G600 }, 0 },
+ {{ USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_636I }, 0 },
+ {{ USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2600 }, 0 },
+ {{ USB_VENDOR_PRIMAX, USB_PRODUCT_PRIMAX_G2E600 }, 0 },
+
+ /* Epson */
+ {{ USB_VENDOR_EPSON, USB_PRODUCT_EPSON_636 }, 0 },
+ {{ USB_VENDOR_EPSON, USB_PRODUCT_EPSON_610 }, 0 },
+ {{ USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1200 }, 0 },
+ {{ USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1240 }, 0 },
+ {{ USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1600 }, 0 },
+ {{ USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1640 }, 0 },
+ {{ USB_VENDOR_EPSON, USB_PRODUCT_EPSON_640U }, 0 },
+ {{ USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1650 }, 0 },
+ {{ USB_VENDOR_EPSON, USB_PRODUCT_EPSON_GT9700F }, USC_KEEP_OPEN },
+
+ /* UMAX */
+ {{ 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_ASTRA2200U }, 0 },
+ {{ USB_VENDOR_UMAX, USB_PRODUCT_UMAX_ASTRA3400 }, 0 },
+
+ /* Visioneer */
+ {{ USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_5300 }, 0 },
+ {{ USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_7600 }, 0 },
+ {{ USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_6100 }, 0 },
+ {{ USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_6200 }, 0 },
+ {{ USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_8100 }, 0 },
+ {{ USB_VENDOR_VISIONEER, USB_PRODUCT_VISIONEER_8600 }, 0 },
+
+ /* Ultima */
+ {{ USB_VENDOR_ULTIMA, USB_PRODUCT_ULTIMA_1200UBPLUS }, 0 },
+
};
+#define uscanner_lookup(v, p) ((const struct uscan_info *)usb_lookup(uscanner_devs, v, p))
#define USCANNER_BUFFERSIZE 1024
@@ -183,6 +210,8 @@ struct uscanner_softc {
usbd_device_handle sc_udev;
usbd_interface_handle sc_iface;
+ u_int sc_dev_flags;
+
usbd_pipe_handle sc_bulkin_pipe;
int sc_bulkin;
usbd_xfer_handle sc_bulkin_xfer;
@@ -229,7 +258,9 @@ Static struct cdevsw uscanner_cdevsw = {
/* dump */ nodump,
/* psize */ nopsize,
/* flags */ 0,
+#if !defined(__FreeBSD__) || (__FreeBSD__ < 5)
/* bmaj */ -1
+#endif
};
#endif
@@ -244,19 +275,12 @@ USB_DECLARE_DRIVER(uscanner);
USB_MATCH(uscanner)
{
USB_MATCH_START(uscanner, uaa);
- int i;
if (uaa->iface != NULL)
return UMATCH_NONE;
- for (i = 0; scanner_ids[i].vendor != 0; i++) {
- if (scanner_ids[i].vendor == uaa->vendor &&
- scanner_ids[i].product == uaa->product) {
- return (UMATCH_VENDOR_PRODUCT);
- }
- }
-
- return (UMATCH_NONE);
+ return (uscanner_lookup(uaa->vendor, uaa->product) != NULL ?
+ UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
}
USB_ATTACH(uscanner)
@@ -272,6 +296,8 @@ USB_ATTACH(uscanner)
USB_ATTACH_SETUP;
printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo);
+ sc->sc_dev_flags = uscanner_lookup(uaa->vendor, uaa->product)->flags;
+
sc->sc_udev = uaa->device;
err = usbd_set_config_no(uaa->device, 1, 1); /* XXX */
@@ -335,11 +361,7 @@ USB_ATTACH(uscanner)
}
int
-uscanneropen(dev, flag, mode, p)
- dev_t dev;
- int flag;
- int mode;
- struct proc *p;
+uscanneropen(dev_t dev, int flag, int mode, usb_proc_ptr p)
{
struct uscanner_softc *sc;
int unit = USCANNERUNIT(dev);
@@ -366,21 +388,25 @@ uscanneropen(dev, flag, mode, p)
sc->sc_bulkout_bufferlen = USCANNER_BUFFERSIZE;
/* We have decided on which endpoints to use, now open the pipes */
- err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin,
- USBD_EXCLUSIVE_USE, &sc->sc_bulkin_pipe);
- if (err) {
- printf("%s: cannot open bulk-in pipe (addr %d)\n",
- USBDEVNAME(sc->sc_dev), sc->sc_bulkin);
- uscanner_do_close(sc);
- return (EIO);
+ if (sc->sc_bulkin_pipe == NULL) {
+ err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin,
+ USBD_EXCLUSIVE_USE, &sc->sc_bulkin_pipe);
+ if (err) {
+ printf("%s: cannot open bulk-in pipe (addr %d)\n",
+ USBDEVNAME(sc->sc_dev), sc->sc_bulkin);
+ uscanner_do_close(sc);
+ return (EIO);
+ }
}
- err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout,
- USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
- if (err) {
- printf("%s: cannot open bulk-out pipe (addr %d)\n",
- USBDEVNAME(sc->sc_dev), sc->sc_bulkout);
- uscanner_do_close(sc);
- return (EIO);
+ if (sc->sc_bulkout_pipe == NULL) {
+ err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout,
+ USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
+ if (err) {
+ printf("%s: cannot open bulk-out pipe (addr %d)\n",
+ USBDEVNAME(sc->sc_dev), sc->sc_bulkout);
+ uscanner_do_close(sc);
+ return (EIO);
+ }
}
sc->sc_bulkin_xfer = usbd_alloc_xfer(sc->sc_udev);
@@ -398,11 +424,7 @@ uscanneropen(dev, flag, mode, p)
}
int
-uscannerclose(dev, flag, mode, p)
- dev_t dev;
- int flag;
- int mode;
- struct proc *p;
+uscannerclose(dev_t dev, int flag, int mode, usb_proc_ptr p)
{
struct uscanner_softc *sc;
@@ -435,15 +457,17 @@ uscanner_do_close(struct uscanner_softc *sc)
sc->sc_bulkout_xfer = NULL;
}
- if (sc->sc_bulkin_pipe) {
- usbd_abort_pipe(sc->sc_bulkin_pipe);
- usbd_close_pipe(sc->sc_bulkin_pipe);
- sc->sc_bulkin_pipe = NULL;
- }
- if (sc->sc_bulkout_pipe) {
- usbd_abort_pipe(sc->sc_bulkout_pipe);
- usbd_close_pipe(sc->sc_bulkout_pipe);
- sc->sc_bulkout_pipe = NULL;
+ if (!(sc->sc_dev_flags & USC_KEEP_OPEN)) {
+ if (sc->sc_bulkin_pipe != NULL) {
+ usbd_abort_pipe(sc->sc_bulkin_pipe);
+ usbd_close_pipe(sc->sc_bulkin_pipe);
+ sc->sc_bulkin_pipe = NULL;
+ }
+ if (sc->sc_bulkout_pipe != NULL) {
+ usbd_abort_pipe(sc->sc_bulkout_pipe);
+ usbd_close_pipe(sc->sc_bulkout_pipe);
+ sc->sc_bulkout_pipe = NULL;
+ }
}
if (sc->sc_bulkin_buffer) {
@@ -459,10 +483,7 @@ uscanner_do_close(struct uscanner_softc *sc)
}
Static int
-uscanner_do_read(sc, uio, flag)
- struct uscanner_softc *sc;
- struct uio *uio;
- int flag;
+uscanner_do_read(struct uscanner_softc *sc, struct uio *uio, int flag)
{
u_int32_t n, tn;
usbd_status err;
@@ -481,7 +502,7 @@ uscanner_do_read(sc, uio, flag)
sc->sc_bulkin_xfer, sc->sc_bulkin_pipe,
USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT,
sc->sc_bulkin_buffer, &tn,
- "uscannerrb");
+ "uscnrb");
if (err) {
if (err == USBD_INTERRUPTED)
error = EINTR;
@@ -501,10 +522,7 @@ uscanner_do_read(sc, uio, flag)
}
int
-uscannerread(dev, uio, flag)
- dev_t dev;
- struct uio *uio;
- int flag;
+uscannerread(dev_t dev, struct uio *uio, int flag)
{
struct uscanner_softc *sc;
int error;
@@ -520,10 +538,7 @@ uscannerread(dev, uio, flag)
}
Static int
-uscanner_do_write(sc, uio, flag)
- struct uscanner_softc *sc;
- struct uio *uio;
- int flag;
+uscanner_do_write(struct uscanner_softc *sc, struct uio *uio, int flag)
{
u_int32_t n;
int error = 0;
@@ -543,7 +558,7 @@ uscanner_do_write(sc, uio, flag)
sc->sc_bulkout_xfer, sc->sc_bulkout_pipe,
0, USBD_NO_TIMEOUT,
sc->sc_bulkout_buffer, &n,
- "uscannerwb");
+ "uscnwb");
if (err) {
if (err == USBD_INTERRUPTED)
error = EINTR;
@@ -557,10 +572,7 @@ uscanner_do_write(sc, uio, flag)
}
int
-uscannerwrite(dev, uio, flag)
- dev_t dev;
- struct uio *uio;
- int flag;
+uscannerwrite(dev_t dev, struct uio *uio, int flag)
{
struct uscanner_softc *sc;
int error;
@@ -576,9 +588,7 @@ uscannerwrite(dev, uio, flag)
#if defined(__NetBSD__) || defined(__OpenBSD__)
int
-uscanner_activate(self, act)
- device_ptr_t self;
- enum devact act;
+uscanner_activate(device_ptr_t self, enum devact act)
{
struct uscanner_softc *sc = (struct uscanner_softc *)self;
@@ -613,11 +623,12 @@ USB_DETACH(uscanner)
#endif
sc->sc_dying = 1;
+ sc->sc_dev_flags = 0; /* make close really close device */
/* Abort all pipes. Causes processes waiting for transfer to wake. */
- if (sc->sc_bulkin_pipe)
+ if (sc->sc_bulkin_pipe != NULL)
usbd_abort_pipe(sc->sc_bulkin_pipe);
- if (sc->sc_bulkout_pipe)
+ if (sc->sc_bulkout_pipe != NULL)
usbd_abort_pipe(sc->sc_bulkout_pipe);
s = splusb();
@@ -652,10 +663,7 @@ USB_DETACH(uscanner)
}
int
-uscannerpoll(dev, events, p)
- dev_t dev;
- int events;
- struct proc *p;
+uscannerpoll(dev_t dev, int events, usb_proc_ptr p)
{
struct uscanner_softc *sc;
int revents = 0;
@@ -677,7 +685,7 @@ uscannerpoll(dev, events, p)
}
int
-uscannerioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
+uscannerioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, usb_proc_ptr p)
{
return (EINVAL);
}
diff --git a/sys/dev/usb/usscanner.c b/sys/dev/usb/usscanner.c
index 68c1b7921f5..1d7a368d709 100644
--- a/sys/dev/usb/usscanner.c
+++ b/sys/dev/usb/usscanner.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: usscanner.c,v 1.3 2001/05/03 02:20:35 aaron Exp $ */
+/* $OpenBSD: usscanner.c,v 1.4 2002/05/07 18:08:05 nate Exp $ */
/* $NetBSD: usscanner.c,v 1.6 2001/01/23 14:04:14 augustss Exp $ */
/*
@@ -89,6 +89,22 @@ int usscannerdebug = 0;
#define DPRINTFN(n,x)
#endif
+#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 show_scsipi_xs show_scsi_xs
+#define show_scsipi_cmd show_scsi_cmd
+#define xs_control flags
+#define xs_status status
+#define XS_STS_DONE ITSDONE
+#define XS_CTL_POLL SCSI_POLL
#define USSCANNER_CONFIG_NO 1
#define USSCANNER_IFACE_IDX 0
diff --git a/sys/dev/usb/uvisor.c b/sys/dev/usb/uvisor.c
index a0a45c54ddd..e44687355f9 100644
--- a/sys/dev/usb/uvisor.c
+++ b/sys/dev/usb/uvisor.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: uvisor.c,v 1.3 2001/05/03 02:20:35 aaron Exp $ */
-/* $NetBSD: uvisor.c,v 1.11 2001/01/23 21:56:17 augustss Exp $ */
+/* $OpenBSD: uvisor.c,v 1.4 2002/05/07 18:08:05 nate Exp $ */
+/* $NetBSD: uvisor.c,v 1.14 2002/02/27 23:00:03 augustss Exp $ */
/*
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@@ -104,7 +104,6 @@ struct uvisor_connection_info {
};
#define UVISOR_CONNECTION_INFO_SIZE 18
-
/* struct uvisor_connection_info.connection[x].port_function_id defines: */
#define UVISOR_FUNCTION_GENERIC 0x00
#define UVISOR_FUNCTION_DEBUGGER 0x01
@@ -112,6 +111,12 @@ struct uvisor_connection_info {
#define UVISOR_FUNCTION_CONSOLE 0x03
#define UVISOR_FUNCTION_REMOTE_FILE_SYS 0x04
+/*
+ * Unknown PalmOS stuff.
+ */
+#define UVISOR_GET_PALM_INFORMATION 0x04
+#define UVISOR_GET_PALM_INFORMATION_LEN 0x14
+
#define UVISORIBUFSIZE 1024
#define UVISOROBUFSIZE 1024
@@ -124,6 +129,8 @@ struct uvisor_softc {
device_ptr_t sc_subdevs[UVISOR_MAX_CONN];
int sc_numcon;
+ u_int16_t sc_flags;
+
u_char sc_dying;
};
@@ -144,6 +151,21 @@ struct ucom_methods uvisor_methods = {
NULL,
};
+struct uvisor_type {
+ struct usb_devno uv_dev;
+ u_int16_t uv_flags;
+#define PALM4 0x0001
+};
+static const struct uvisor_type uvisor_devs[] = {
+ {{ USB_VENDOR_HANDSPRING, USB_PRODUCT_HANDSPRING_VISOR }, 0 },
+ {{ USB_VENDOR_PALM, USB_PRODUCT_PALM_M500 }, PALM4 },
+ {{ USB_VENDOR_PALM, USB_PRODUCT_PALM_M505 }, PALM4 },
+ {{ USB_VENDOR_PALM, USB_PRODUCT_PALM_M125 }, PALM4 },
+ {{ USB_VENDOR_SONY, USB_PRODUCT_SONY_CLIE_40 }, PALM4 },
+/* {{ USB_VENDOR_SONY, USB_PRODUCT_SONY_CLIE_25 }, PALM4 },*/
+};
+#define uvisor_lookup(v, p) ((struct uvisor_type *)usb_lookup(uvisor_devs, v, p))
+
USB_DECLARE_DRIVER(uvisor);
USB_MATCH(uvisor)
@@ -156,11 +178,8 @@ USB_MATCH(uvisor)
DPRINTFN(20,("uvisor: vendor=0x%x, product=0x%x\n",
uaa->vendor, uaa->product));
- if (uaa->vendor == USB_VENDOR_HANDSPRING &&
- uaa->product == USB_PRODUCT_HANDSPRING_VISOR)
- return (UMATCH_VENDOR_PRODUCT);
-
- return (UMATCH_NONE);
+ return (uvisor_lookup(uaa->vendor, uaa->product) != NULL ?
+ UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
}
USB_ATTACH(uvisor)
@@ -198,6 +217,8 @@ USB_ATTACH(uvisor)
USB_ATTACH_SETUP;
printf("%s: %s\n", devname, devinfo);
+ sc->sc_flags = uvisor_lookup(uaa->vendor, uaa->product)->uv_flags;
+
id = usbd_get_interface_descriptor(iface);
sc->sc_udev = dev;
@@ -330,6 +351,7 @@ uvisor_init(struct uvisor_softc *sc, struct uvisor_connection_info *ci)
usb_device_request_t req;
int actlen;
uWord avail;
+ char buffer[256];
DPRINTF(("uvisor_init: getting connection info\n"));
req.bmRequestType = UT_READ_VENDOR_ENDPOINT;
@@ -338,10 +360,30 @@ uvisor_init(struct uvisor_softc *sc, struct uvisor_connection_info *ci)
USETW(req.wIndex, 0);
USETW(req.wLength, UVISOR_CONNECTION_INFO_SIZE);
err = usbd_do_request_flags(sc->sc_udev, &req, ci,
- USBD_SHORT_XFER_OK, &actlen);
+ USBD_SHORT_XFER_OK, &actlen, USBD_DEFAULT_TIMEOUT);
if (err)
return (err);
+ if (sc->sc_flags & PALM4) {
+ /* Palm OS 4.0 Hack */
+ req.bmRequestType = UT_READ_VENDOR_ENDPOINT;
+ req.bRequest = UVISOR_GET_PALM_INFORMATION;
+ USETW(req.wValue, 0);
+ USETW(req.wIndex, 0);
+ USETW(req.wLength, UVISOR_GET_PALM_INFORMATION_LEN);
+ err = usbd_do_request(sc->sc_udev, &req, buffer);
+ if (err)
+ return (err);
+ req.bmRequestType = UT_READ_VENDOR_ENDPOINT;
+ req.bRequest = UVISOR_GET_PALM_INFORMATION;
+ USETW(req.wValue, 0);
+ USETW(req.wIndex, 0);
+ USETW(req.wLength, UVISOR_GET_PALM_INFORMATION_LEN);
+ err = usbd_do_request(sc->sc_udev, &req, buffer);
+ if (err)
+ return (err);
+ }
+
DPRINTF(("uvisor_init: getting available bytes\n"));
req.bmRequestType = UT_READ_VENDOR_ENDPOINT;
req.bRequest = UVISOR_REQUEST_BYTES_AVAILABLE;
@@ -374,5 +416,5 @@ uvisor_close(void *addr, int portno)
USETW(req.wIndex, 0);
USETW(req.wLength, UVISOR_CONNECTION_INFO_SIZE);
(void)usbd_do_request_flags(sc->sc_udev, &req, &coninfo,
- USBD_SHORT_XFER_OK, &actlen);
+ USBD_SHORT_XFER_OK, &actlen, USBD_DEFAULT_TIMEOUT);
}