diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2013-11-06 16:20:21 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2013-11-11 10:08:08 +0100 |
commit | 66659ff1ad6831b0ea7425fa6ecd8a8687523658 (patch) | |
tree | 48e22b475fa8854128e0861a33fed6f78c8094b5 /freebsd/sys/dev/usb | |
parent | Define __GLOBL1() and __GLOBL() (diff) | |
download | rtems-libbsd-66659ff1ad6831b0ea7425fa6ecd8a8687523658.tar.bz2 |
Update to FreeBSD 9.2
Diffstat (limited to 'freebsd/sys/dev/usb')
26 files changed, 621 insertions, 349 deletions
diff --git a/freebsd/sys/dev/usb/controller/ehci.c b/freebsd/sys/dev/usb/controller/ehci.c index 18864431..456aff61 100644 --- a/freebsd/sys/dev/usb/controller/ehci.c +++ b/freebsd/sys/dev/usb/controller/ehci.c @@ -96,7 +96,7 @@ static int ehcinohighspeed = 0; static int ehciiaadbug = 0; static int ehcilostintrbug = 0; -SYSCTL_NODE(_hw_usb, OID_AUTO, ehci, CTLFLAG_RW, 0, "USB ehci"); +static SYSCTL_NODE(_hw_usb, OID_AUTO, ehci, CTLFLAG_RW, 0, "USB ehci"); SYSCTL_INT(_hw_usb_ehci, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN, &ehcidebug, 0, "Debug level"); TUNABLE_INT("hw.usb.ehci.debug", &ehcidebug); @@ -334,14 +334,18 @@ ehci_init(ehci_softc_t *sc) sc->sc_noport = EHCI_HCS_N_PORTS(sparams); sc->sc_bus.usbrev = USB_REV_2_0; - /* Reset the controller */ - DPRINTF("%s: resetting\n", device_get_nameunit(sc->sc_bus.bdev)); + if (!(sc->sc_flags & EHCI_SCFLG_DONTRESET)) { + /* Reset the controller */ + DPRINTF("%s: resetting\n", + device_get_nameunit(sc->sc_bus.bdev)); - err = ehci_hcreset(sc); - if (err) { - device_printf(sc->sc_bus.bdev, "reset timeout\n"); - return (err); + err = ehci_hcreset(sc); + if (err) { + device_printf(sc->sc_bus.bdev, "reset timeout\n"); + return (err); + } } + /* * use current frame-list-size selection 0: 1024*4 bytes 1: 512*4 * bytes 2: 256*4 bytes 3: unknown diff --git a/freebsd/sys/dev/usb/controller/ehci.h b/freebsd/sys/dev/usb/controller/ehci.h index a64d48a0..f718a8a7 100644 --- a/freebsd/sys/dev/usb/controller/ehci.h +++ b/freebsd/sys/dev/usb/controller/ehci.h @@ -345,6 +345,8 @@ typedef struct ehci_softc { #define EHCI_SCFLG_TT 0x0020 /* transaction translator present */ #define EHCI_SCFLG_LOSTINTRBUG 0x0040 /* workaround for VIA / ATI chipsets */ #define EHCI_SCFLG_IAADBUG 0x0080 /* workaround for nVidia chipsets */ +#define EHCI_SCFLG_DONTRESET 0x0100 /* don't reset ctrl. in ehci_init() */ +#define EHCI_SCFLG_DONEINIT 0x1000 /* ehci_init() has been called. */ uint8_t sc_offs; /* offset to operational registers */ uint8_t sc_doorbell_disable; /* set on doorbell failure */ diff --git a/freebsd/sys/dev/usb/controller/ohci.c b/freebsd/sys/dev/usb/controller/ohci.c index 94e94fd9..42129a8e 100644 --- a/freebsd/sys/dev/usb/controller/ohci.c +++ b/freebsd/sys/dev/usb/controller/ohci.c @@ -82,7 +82,7 @@ __FBSDID("$FreeBSD$"); #ifdef USB_DEBUG static int ohcidebug = 0; -SYSCTL_NODE(_hw_usb, OID_AUTO, ohci, CTLFLAG_RW, 0, "USB ohci"); +static SYSCTL_NODE(_hw_usb, OID_AUTO, ohci, CTLFLAG_RW, 0, "USB ohci"); SYSCTL_INT(_hw_usb_ohci, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN, &ohcidebug, 0, "ohci debug level"); TUNABLE_INT("hw.usb.ohci.debug", &ohcidebug); diff --git a/freebsd/sys/dev/usb/controller/usb_controller.c b/freebsd/sys/dev/usb/controller/usb_controller.c index 3f9c8742..37f79364 100644 --- a/freebsd/sys/dev/usb/controller/usb_controller.c +++ b/freebsd/sys/dev/usb/controller/usb_controller.c @@ -81,7 +81,7 @@ static void usb_attach_sub(device_t, struct usb_bus *); #ifdef USB_DEBUG static int usb_ctrl_debug = 0; -SYSCTL_NODE(_hw_usb, OID_AUTO, ctrl, CTLFLAG_RW, 0, "USB controller"); +static SYSCTL_NODE(_hw_usb, OID_AUTO, ctrl, CTLFLAG_RW, 0, "USB controller"); SYSCTL_INT(_hw_usb_ctrl, OID_AUTO, debug, CTLFLAG_RW, &usb_ctrl_debug, 0, "Debug level"); #endif @@ -889,3 +889,28 @@ usb_bus_mem_free_all(struct usb_bus *bus, usb_bus_mem_cb_t *cb) mtx_destroy(&bus->bus_mtx); } + +/* convenience wrappers */ +void +usb_proc_explore_mwait(struct usb_device *udev, void *pm1, void *pm2) +{ + usb_proc_mwait(&udev->bus->explore_proc, pm1, pm2); +} + +void * +usb_proc_explore_msignal(struct usb_device *udev, void *pm1, void *pm2) +{ + return (usb_proc_msignal(&udev->bus->explore_proc, pm1, pm2)); +} + +void +usb_proc_explore_lock(struct usb_device *udev) +{ + USB_BUS_LOCK(udev->bus); +} + +void +usb_proc_explore_unlock(struct usb_device *udev) +{ + USB_BUS_UNLOCK(udev->bus); +} diff --git a/freebsd/sys/dev/usb/controller/xhcireg.h b/freebsd/sys/dev/usb/controller/xhcireg.h new file mode 100644 index 00000000..85d989a6 --- /dev/null +++ b/freebsd/sys/dev/usb/controller/xhcireg.h @@ -0,0 +1,221 @@ +/* $FreeBSD$ */ + +/*- + * Copyright (c) 2010 Hans Petter Selasky. 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. + */ + +#ifndef _XHCIREG_H_ +#define _XHCIREG_H_ + +/* XHCI PCI config registers */ +#define PCI_XHCI_CBMEM 0x10 /* configuration base MEM */ +#define PCI_XHCI_USBREV 0x60 /* RO USB protocol revision */ +#define PCI_USB_REV_3_0 0x30 /* USB 3.0 */ +#define PCI_XHCI_FLADJ 0x61 /* RW frame length adjust */ + +#define PCI_XHCI_INTEL_XUSB2PR 0xD0 /* Intel USB2 Port Routing */ +#define PCI_XHCI_INTEL_USB3_PSSEN 0xD8 /* Intel USB3 Port SuperSpeed Enable */ + +/* XHCI capability registers */ +#define XHCI_CAPLENGTH 0x00 /* RO capability */ +#define XHCI_RESERVED 0x01 /* Reserved */ +#define XHCI_HCIVERSION 0x02 /* RO Interface version number */ +#define XHCI_HCIVERSION_0_9 0x0090 /* xHCI version 0.9 */ +#define XHCI_HCIVERSION_1_0 0x0100 /* xHCI version 1.0 */ +#define XHCI_HCSPARAMS1 0x04 /* RO structual parameters 1 */ +#define XHCI_HCS1_DEVSLOT_MAX(x)((x) & 0xFF) +#define XHCI_HCS1_IRQ_MAX(x) (((x) >> 8) & 0x3FF) +#define XHCI_HCS1_N_PORTS(x) (((x) >> 24) & 0xFF) +#define XHCI_HCSPARAMS2 0x08 /* RO structual parameters 2 */ +#define XHCI_HCS2_IST(x) ((x) & 0xF) +#define XHCI_HCS2_ERST_MAX(x) (((x) >> 4) & 0xF) +#define XHCI_HCS2_SPR(x) (((x) >> 24) & 0x1) +#define XHCI_HCS2_SPB_MAX(x) (((x) >> 27) & 0x7F) +#define XHCI_HCSPARAMS3 0x0C /* RO structual parameters 3 */ +#define XHCI_HCS3_U1_DEL(x) ((x) & 0xFF) +#define XHCI_HCS3_U2_DEL(x) (((x) >> 16) & 0xFFFF) +#define XHCI_HCSPARAMS0 0x10 /* RO capability parameters */ +#define XHCI_HCS0_AC64(x) ((x) & 0x1) /* 64-bit capable */ +#define XHCI_HCS0_BNC(x) (((x) >> 1) & 0x1) /* BW negotiation */ +#define XHCI_HCS0_CSZ(x) (((x) >> 2) & 0x1) /* context size */ +#define XHCI_HCS0_PPC(x) (((x) >> 3) & 0x1) /* port power control */ +#define XHCI_HCS0_PIND(x) (((x) >> 4) & 0x1) /* port indicators */ +#define XHCI_HCS0_LHRC(x) (((x) >> 5) & 0x1) /* light HC reset */ +#define XHCI_HCS0_LTC(x) (((x) >> 6) & 0x1) /* latency tolerance msg */ +#define XHCI_HCS0_NSS(x) (((x) >> 7) & 0x1) /* no secondary sid */ +#define XHCI_HCS0_PSA_SZ_MAX(x) (((x) >> 12) & 0xF) /* max pri. stream array size */ +#define XHCI_HCS0_XECP(x) (((x) >> 16) & 0xFFFF) /* extended capabilities pointer */ +#define XHCI_DBOFF 0x14 /* RO doorbell offset */ +#define XHCI_RTSOFF 0x18 /* RO runtime register space offset */ + +/* XHCI operational registers. Offset given by XHCI_CAPLENGTH register */ +#define XHCI_USBCMD 0x00 /* XHCI command */ +#define XHCI_CMD_RS 0x00000001 /* RW Run/Stop */ +#define XHCI_CMD_HCRST 0x00000002 /* RW Host Controller Reset */ +#define XHCI_CMD_INTE 0x00000004 /* RW Interrupter Enable */ +#define XHCI_CMD_HSEE 0x00000008 /* RW Host System Error Enable */ +#define XHCI_CMD_LHCRST 0x00000080 /* RO/RW Light Host Controller Reset */ +#define XHCI_CMD_CSS 0x00000100 /* RW Controller Save State */ +#define XHCI_CMD_CRS 0x00000200 /* RW Controller Restore State */ +#define XHCI_CMD_EWE 0x00000400 /* RW Enable Wrap Event */ +#define XHCI_CMD_EU3S 0x00000800 /* RW Enable U3 MFINDEX Stop */ +#define XHCI_USBSTS 0x04 /* XHCI status */ +#define XHCI_STS_HCH 0x00000001 /* RO - Host Controller Halted */ +#define XHCI_STS_HSE 0x00000004 /* RW - Host System Error */ +#define XHCI_STS_EINT 0x00000008 /* RW - Event Interrupt */ +#define XHCI_STS_PCD 0x00000010 /* RW - Port Change Detect */ +#define XHCI_STS_SSS 0x00000100 /* RO - Save State Status */ +#define XHCI_STS_RSS 0x00000200 /* RO - Restore State Status */ +#define XHCI_STS_SRE 0x00000400 /* RW - Save/Restore Error */ +#define XHCI_STS_CNR 0x00000800 /* RO - Controller Not Ready */ +#define XHCI_STS_HCE 0x00001000 /* RO - Host Controller Error */ +#define XHCI_PAGESIZE 0x08 /* XHCI page size mask */ +#define XHCI_PAGESIZE_4K 0x00000001 /* 4K Page Size */ +#define XHCI_PAGESIZE_8K 0x00000002 /* 8K Page Size */ +#define XHCI_PAGESIZE_16K 0x00000004 /* 16K Page Size */ +#define XHCI_PAGESIZE_32K 0x00000008 /* 32K Page Size */ +#define XHCI_PAGESIZE_64K 0x00000010 /* 64K Page Size */ +#define XHCI_DNCTRL 0x14 /* XHCI device notification control */ +#define XHCI_DNCTRL_MASK(n) (1U << (n)) +#define XHCI_CRCR_LO 0x18 /* XHCI command ring control */ +#define XHCI_CRCR_LO_RCS 0x00000001 /* RW - consumer cycle state */ +#define XHCI_CRCR_LO_CS 0x00000002 /* RW - command stop */ +#define XHCI_CRCR_LO_CA 0x00000004 /* RW - command abort */ +#define XHCI_CRCR_LO_CRR 0x00000008 /* RW - command ring running */ +#define XHCI_CRCR_LO_MASK 0x0000000F +#define XHCI_CRCR_HI 0x1C /* XHCI command ring control */ +#define XHCI_DCBAAP_LO 0x30 /* XHCI dev context BA pointer */ +#define XHCI_DCBAAP_HI 0x34 /* XHCI dev context BA pointer */ +#define XHCI_CONFIG 0x38 +#define XHCI_CONFIG_SLOTS_MASK 0x000000FF /* RW - number of device slots enabled */ + +/* XHCI port status registers */ +#define XHCI_PORTSC(n) (0x3F0 + (0x10 * (n))) /* XHCI port status */ +#define XHCI_PS_CCS 0x00000001 /* RO - current connect status */ +#define XHCI_PS_PED 0x00000002 /* RW - port enabled / disabled */ +#define XHCI_PS_OCA 0x00000008 /* RO - over current active */ +#define XHCI_PS_PR 0x00000010 /* RW - port reset */ +#define XHCI_PS_PLS_GET(x) (((x) >> 5) & 0xF) /* RW - port link state */ +#define XHCI_PS_PLS_SET(x) (((x) & 0xF) << 5) /* RW - port link state */ +#define XHCI_PS_PP 0x00000200 /* RW - port power */ +#define XHCI_PS_SPEED_GET(x) (((x) >> 10) & 0xF) /* RO - port speed */ +#define XHCI_PS_PIC_GET(x) (((x) >> 14) & 0x3) /* RW - port indicator */ +#define XHCI_PS_PIC_SET(x) (((x) & 0x3) << 14) /* RW - port indicator */ +#define XHCI_PS_LWS 0x00010000 /* RW - port link state write strobe */ +#define XHCI_PS_CSC 0x00020000 /* RW - connect status change */ +#define XHCI_PS_PEC 0x00040000 /* RW - port enable/disable change */ +#define XHCI_PS_WRC 0x00080000 /* RW - warm port reset change */ +#define XHCI_PS_OCC 0x00100000 /* RW - over-current change */ +#define XHCI_PS_PRC 0x00200000 /* RW - port reset change */ +#define XHCI_PS_PLC 0x00400000 /* RW - port link state change */ +#define XHCI_PS_CEC 0x00800000 /* RW - config error change */ +#define XHCI_PS_CAS 0x01000000 /* RO - cold attach status */ +#define XHCI_PS_WCE 0x02000000 /* RW - wake on connect enable */ +#define XHCI_PS_WDE 0x04000000 /* RW - wake on disconnect enable */ +#define XHCI_PS_WOE 0x08000000 /* RW - wake on over-current enable */ +#define XHCI_PS_DR 0x40000000 /* RO - device removable */ +#define XHCI_PS_WPR 0x80000000U /* RW - warm port reset */ +#define XHCI_PS_CLEAR 0x80FF01FFU /* command bits */ + +#define XHCI_PORTPMSC(n) (0x3F4 + (0x10 * (n))) /* XHCI status and control */ +#define XHCI_PM3_U1TO_GET(x) (((x) >> 0) & 0xFF) /* RW - U1 timeout */ +#define XHCI_PM3_U1TO_SET(x) (((x) & 0xFF) << 0) /* RW - U1 timeout */ +#define XHCI_PM3_U2TO_GET(x) (((x) >> 8) & 0xFF) /* RW - U2 timeout */ +#define XHCI_PM3_U2TO_SET(x) (((x) & 0xFF) << 8) /* RW - U2 timeout */ +#define XHCI_PM3_FLA 0x00010000 /* RW - Force Link PM Accept */ +#define XHCI_PM2_L1S_GET(x) (((x) >> 0) & 0x7) /* RO - L1 status */ +#define XHCI_PM2_RWE 0x00000008 /* RW - remote wakup enable */ +#define XHCI_PM2_HIRD_GET(x) (((x) >> 4) & 0xF) /* RW - host initiated resume duration */ +#define XHCI_PM2_HIRD_SET(x) (((x) & 0xF) << 4) /* RW - host initiated resume duration */ +#define XHCI_PM2_L1SLOT_GET(x) (((x) >> 8) & 0xFF) /* RW - L1 device slot */ +#define XHCI_PM2_L1SLOT_SET(x) (((x) & 0xFF) << 8) /* RW - L1 device slot */ +#define XHCI_PM2_HLE 0x00010000 /* RW - hardware LPM enable */ +#define XHCI_PORTLI(n) (0x3F8 + (0x10 * (n))) /* XHCI port link info */ +#define XHCI_PLI3_ERR_GET(x) (((x) >> 0) & 0xFFFF) /* RO - port link errors */ +#define XHCI_PORTRSV(n) (0x3FC + (0x10 * (n))) /* XHCI port reserved */ + +/* XHCI runtime registers. Offset given by XHCI_CAPLENGTH + XHCI_RTSOFF registers */ +#define XHCI_MFINDEX 0x0000 /* RO - microframe index */ +#define XHCI_MFINDEX_GET(x) ((x) & 0x3FFF) +#define XHCI_IMAN(n) (0x0020 + (0x20 * (n))) /* XHCI interrupt management */ +#define XHCI_IMAN_INTR_PEND 0x00000001 /* RW - interrupt pending */ +#define XHCI_IMAN_INTR_ENA 0x00000002 /* RW - interrupt enable */ +#define XHCI_IMOD(n) (0x0024 + (0x20 * (n))) /* XHCI interrupt moderation */ +#define XHCI_IMOD_IVAL_GET(x) (((x) >> 0) & 0xFFFF) /* 250ns unit */ +#define XHCI_IMOD_IVAL_SET(x) (((x) & 0xFFFF) << 0) /* 250ns unit */ +#define XHCI_IMOD_ICNT_GET(x) (((x) >> 16) & 0xFFFF) /* 250ns unit */ +#define XHCI_IMOD_ICNT_SET(x) (((x) & 0xFFFF) << 16) /* 250ns unit */ +#define XHCI_IMOD_DEFAULT 0x000003E8U /* 8000 IRQ/second */ +#define XHCI_ERSTSZ(n) (0x0028 + (0x20 * (n))) /* XHCI event ring segment table size */ +#define XHCI_ERSTS_GET(x) ((x) & 0xFFFF) +#define XHCI_ERSTS_SET(x) ((x) & 0xFFFF) +#define XHCI_ERSTBA_LO(n) (0x0030 + (0x20 * (n))) /* XHCI event ring segment table BA */ +#define XHCI_ERSTBA_HI(n) (0x0034 + (0x20 * (n))) /* XHCI event ring segment table BA */ +#define XHCI_ERDP_LO(n) (0x0038 + (0x20 * (n))) /* XHCI event ring dequeue pointer */ +#define XHCI_ERDP_LO_SINDEX(x) ((x) & 0x7) /* RO - dequeue segment index */ +#define XHCI_ERDP_LO_BUSY 0x00000008 /* RW - event handler busy */ +#define XHCI_ERDP_HI(n) (0x003C + (0x20 * (n))) /* XHCI event ring dequeue pointer */ + +/* XHCI doorbell registers. Offset given by XHCI_CAPLENGTH + XHCI_DBOFF registers */ +#define XHCI_DOORBELL(n) (0x0000 + (4 * (n))) +#define XHCI_DB_TARGET_GET(x) ((x) & 0xFF) /* RW - doorbell target */ +#define XHCI_DB_TARGET_SET(x) ((x) & 0xFF) /* RW - doorbell target */ +#define XHCI_DB_SID_GET(x) (((x) >> 16) & 0xFFFF) /* RW - doorbell stream ID */ +#define XHCI_DB_SID_SET(x) (((x) & 0xFFFF) << 16) /* RW - doorbell stream ID */ + +/* XHCI legacy support */ +#define XHCI_XECP_ID(x) ((x) & 0xFF) +#define XHCI_XECP_NEXT(x) (((x) >> 8) & 0xFF) +#define XHCI_XECP_BIOS_SEM 0x0002 +#define XHCI_XECP_OS_SEM 0x0003 + +/* XHCI capability ID's */ +#define XHCI_ID_USB_LEGACY 0x0001 +#define XHCI_ID_PROTOCOLS 0x0002 +#define XHCI_ID_POWER_MGMT 0x0003 +#define XHCI_ID_VIRTUALIZATION 0x0004 +#define XHCI_ID_MSG_IRQ 0x0005 +#define XHCI_ID_USB_LOCAL_MEM 0x0006 + +/* XHCI register R/W wrappers */ +#define XREAD1(sc, what, a) \ + bus_space_read_1((sc)->sc_io_tag, (sc)->sc_io_hdl, \ + (a) + (sc)->sc_##what##_off) +#define XREAD2(sc, what, a) \ + bus_space_read_2((sc)->sc_io_tag, (sc)->sc_io_hdl, \ + (a) + (sc)->sc_##what##_off) +#define XREAD4(sc, what, a) \ + bus_space_read_4((sc)->sc_io_tag, (sc)->sc_io_hdl, \ + (a) + (sc)->sc_##what##_off) +#define XWRITE1(sc, what, a, x) \ + bus_space_write_1((sc)->sc_io_tag, (sc)->sc_io_hdl, \ + (a) + (sc)->sc_##what##_off, (x)) +#define XWRITE2(sc, what, a, x) \ + bus_space_write_2((sc)->sc_io_tag, (sc)->sc_io_hdl, \ + (a) + (sc)->sc_##what##_off, (x)) +#define XWRITE4(sc, what, a, x) \ + bus_space_write_4((sc)->sc_io_tag, (sc)->sc_io_hdl, \ + (a) + (sc)->sc_##what##_off, (x)) + +#endif /* _XHCIREG_H_ */ diff --git a/freebsd/sys/dev/usb/quirk/usb_quirk.c b/freebsd/sys/dev/usb/quirk/usb_quirk.c index 2df2de5e..9042c166 100644 --- a/freebsd/sys/dev/usb/quirk/usb_quirk.c +++ b/freebsd/sys/dev/usb/quirk/usb_quirk.c @@ -96,6 +96,7 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = { USB_QUIRK(SILICONPORTALS, YAPPHONE, 0x100, 0x100, UQ_AU_INP_ASYNC), USB_QUIRK(LOGITECH, UN53B, 0x0000, 0xffff, UQ_NO_STRINGS), USB_QUIRK(ELSA, MODEM1, 0x0000, 0xffff, UQ_CFG_INDEX_1), + USB_QUIRK(PLANEX2, MZKUE150N, 0x0000, 0xffff, UQ_CFG_INDEX_1), /* Quirks for printer devices */ USB_QUIRK(HP, 895C, 0x0000, 0xffff, UQ_BROKEN_BIDIR), USB_QUIRK(HP, 880C, 0x0000, 0xffff, UQ_BROKEN_BIDIR), @@ -127,6 +128,8 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = { /* MS keyboards do weird things */ USB_QUIRK(MICROSOFT, NATURAL4000, 0x0000, 0xFFFF, UQ_KBD_BOOTPROTO), USB_QUIRK(MICROSOFT, WLINTELLIMOUSE, 0x0000, 0xffff, UQ_MS_LEADING_BYTE), + /* Quirk for Corsair Vengeance K60 keyboard */ + USB_QUIRK(CORSAIR, K60, 0x0000, 0xffff, UQ_KBD_BOOTPROTO), /* umodem(4) device quirks */ USB_QUIRK(METRICOM, RICOCHET_GS, 0x100, 0x100, UQ_ASSUME_CM_OVER_DATA), USB_QUIRK(SANYO, SCP4900, 0x000, 0x000, UQ_ASSUME_CM_OVER_DATA), @@ -254,6 +257,7 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = { USB_QUIRK(MICROTECH, DPCM, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_CBI, UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_TEST_UNIT_READY, UQ_MSC_NO_START_STOP), + USB_QUIRK(MICRON, REALSSD, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE), USB_QUIRK(MICROTECH, SCSIDB25, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB, UQ_MSC_FORCE_PROTO_SCSI), USB_QUIRK(MICROTECH, SCSIHD50, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB, @@ -391,6 +395,7 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = { UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_GETMAXLUN), USB_QUIRK(SONY, PORTABLE_HDD_V2, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB, UQ_MSC_FORCE_PROTO_SCSI), + USB_QUIRK(STMICRO, ST72682, 0x0000, 0xffff, UQ_MSC_NO_PREVENT_ALLOW), USB_QUIRK(SUPERTOP, IDE, 0x0000, 0xffff, UQ_MSC_IGNORE_RESIDUE, UQ_MSC_NO_SYNC_CACHE), USB_QUIRK(TAUGA, CAMERAMATE, 0x0000, 0xffff, UQ_MSC_FORCE_PROTO_SCSI), @@ -443,6 +448,9 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = { USB_QUIRK(MEIZU, M6_SL, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB, UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_INQUIRY, UQ_MSC_NO_SYNC_CACHE), + USB_QUIRK(TOSHIBA, TRANSMEMORY, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE), + USB_QUIRK(VIALABS, USB30SATABRIDGE, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE), + /* Non-standard USB MIDI devices */ USB_QUIRK(ROLAND, UM1, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS), USB_QUIRK(ROLAND, SC8850, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS), @@ -460,7 +468,13 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = { USB_QUIRK(ROLAND, SD20, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS), USB_QUIRK(ROLAND, SD80, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS), USB_QUIRK(ROLAND, UA700, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS), + USB_QUIRK(EGO, M4U, 0x0000, 0xffff, UQ_SINGLE_CMD_MIDI), + USB_QUIRK(LOGILINK, U2M, 0x0000, 0xffff, UQ_SINGLE_CMD_MIDI), USB_QUIRK(MEDELI, DD305, 0x0000, 0xffff, UQ_SINGLE_CMD_MIDI, UQ_MATCH_VENDOR_ONLY), + USB_QUIRK(REDOCTANE, GHMIDI, 0x0000, 0xffff, UQ_SINGLE_CMD_MIDI), + USB_QUIRK(TEXTECH, U2M_1, 0x0000, 0xffff, UQ_SINGLE_CMD_MIDI), + USB_QUIRK(TEXTECH, U2M_2, 0x0000, 0xffff, UQ_SINGLE_CMD_MIDI), + USB_QUIRK(WCH2, U2M, 0x0000, 0xffff, UQ_SINGLE_CMD_MIDI), /* Non-standard USB AUDIO devices */ USB_QUIRK(MAUDIO, FASTTRACKULTRA, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS), @@ -514,6 +528,7 @@ static const char *usb_quirk_str[USB_QUIRK_MAX] = { [UQ_MSC_NO_GETMAXLUN] = "UQ_MSC_NO_GETMAXLUN", [UQ_MSC_NO_INQUIRY] = "UQ_MSC_NO_INQUIRY", [UQ_MSC_NO_INQUIRY_EVPD] = "UQ_MSC_NO_INQUIRY_EVPD", + [UQ_MSC_NO_PREVENT_ALLOW] = "UQ_MSC_NO_PREVENT_ALLOW", [UQ_MSC_NO_SYNC_CACHE] = "UQ_MSC_NO_SYNC_CACHE", [UQ_MSC_SHUTTLE_INIT] = "UQ_MSC_SHUTTLE_INIT", [UQ_MSC_ALT_IFACE_1] = "UQ_MSC_ALT_IFACE_1", diff --git a/freebsd/sys/dev/usb/quirk/usb_quirk.h b/freebsd/sys/dev/usb/quirk/usb_quirk.h index f2c10dd8..32a60a10 100644 --- a/freebsd/sys/dev/usb/quirk/usb_quirk.h +++ b/freebsd/sys/dev/usb/quirk/usb_quirk.h @@ -75,6 +75,7 @@ enum { UQ_MSC_NO_GETMAXLUN, /* does not support get max LUN */ UQ_MSC_NO_INQUIRY, /* fake generic inq response */ UQ_MSC_NO_INQUIRY_EVPD, /* does not support inq EVPD */ + UQ_MSC_NO_PREVENT_ALLOW, /* does not support medium removal */ UQ_MSC_NO_SYNC_CACHE, /* does not support sync cache */ UQ_MSC_SHUTTLE_INIT, /* requires Shuttle init sequence */ UQ_MSC_ALT_IFACE_1, /* switch to alternate interface 1 */ diff --git a/freebsd/sys/dev/usb/storage/umass.c b/freebsd/sys/dev/usb/storage/umass.c index d3d2040f..76a1fcb6 100644 --- a/freebsd/sys/dev/usb/storage/umass.c +++ b/freebsd/sys/dev/usb/storage/umass.c @@ -139,14 +139,6 @@ __FBSDID("$FreeBSD$"); #include <cam/cam_periph.h> -#define UMASS_EXT_BUFFER -#ifdef UMASS_EXT_BUFFER -/* this enables loading of virtual buffers into DMA */ -#define UMASS_USB_FLAGS .ext_buffer=1, -#else -#define UMASS_USB_FLAGS -#endif - #ifdef USB_DEBUG #define DIF(m, x) \ do { \ @@ -173,19 +165,21 @@ __FBSDID("$FreeBSD$"); #define UDMASS_CBI 0x00400000 /* CBI transfers */ #define UDMASS_WIRE (UDMASS_BBB|UDMASS_CBI) #define UDMASS_ALL 0xffff0000 /* all of the above */ -static int umass_debug = 0; +static int umass_debug; +static int umass_throttle; -SYSCTL_NODE(_hw_usb, OID_AUTO, umass, CTLFLAG_RW, 0, "USB umass"); +static SYSCTL_NODE(_hw_usb, OID_AUTO, umass, CTLFLAG_RW, 0, "USB umass"); SYSCTL_INT(_hw_usb_umass, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN, &umass_debug, 0, "umass debug level"); TUNABLE_INT("hw.usb.umass.debug", &umass_debug); +SYSCTL_INT(_hw_usb_umass, OID_AUTO, throttle, CTLFLAG_RW | CTLFLAG_TUN, + &umass_throttle, 0, "Forced delay between commands in milliseconds"); +TUNABLE_INT("hw.usb.umass.throttle", &umass_throttle); #else #define DIF(...) do { } while (0) #define DPRINTF(...) do { } while (0) #endif -#define UMASS_GONE ((struct umass_softc *)1) - #define UMASS_BULK_SIZE (1 << 17) #define UMASS_CBI_DIAGNOSTIC_CMDLEN 12 /* bytes */ #define UMASS_MAX_CMDLEN MAX(12, CAM_MAX_CDBLEN) /* bytes */ @@ -373,6 +367,8 @@ typedef uint8_t (umass_transform_t)(struct umass_softc *sc, uint8_t *cmd_ptr, * result. */ #define NO_SYNCHRONIZE_CACHE 0x4000 + /* Device does not support 'PREVENT/ALLOW MEDIUM REMOVAL'. */ +#define NO_PREVENT_ALLOW 0x8000 struct umass_softc { @@ -545,7 +541,7 @@ static struct usb_config umass_bbb_config[UMASS_T_BBB_MAX] = { .endpoint = UE_ADDR_ANY, .direction = UE_DIR_IN, .bufsize = UMASS_BULK_SIZE, - .flags = {.proxy_buffer = 1,.short_xfer_ok = 1, UMASS_USB_FLAGS}, + .flags = {.proxy_buffer = 1,.short_xfer_ok = 1,.ext_buffer=1,}, .callback = &umass_t_bbb_data_read_callback, .timeout = 0, /* overwritten later */ }, @@ -564,7 +560,7 @@ static struct usb_config umass_bbb_config[UMASS_T_BBB_MAX] = { .endpoint = UE_ADDR_ANY, .direction = UE_DIR_OUT, .bufsize = UMASS_BULK_SIZE, - .flags = {.proxy_buffer = 1,.short_xfer_ok = 1, UMASS_USB_FLAGS}, + .flags = {.proxy_buffer = 1,.short_xfer_ok = 1,.ext_buffer=1,}, .callback = &umass_t_bbb_data_write_callback, .timeout = 0, /* overwritten later */ }, @@ -637,7 +633,7 @@ static struct usb_config umass_cbi_config[UMASS_T_CBI_MAX] = { .endpoint = UE_ADDR_ANY, .direction = UE_DIR_IN, .bufsize = UMASS_BULK_SIZE, - .flags = {.proxy_buffer = 1,.short_xfer_ok = 1, UMASS_USB_FLAGS}, + .flags = {.proxy_buffer = 1,.short_xfer_ok = 1,.ext_buffer=1,}, .callback = &umass_t_cbi_data_read_callback, .timeout = 0, /* overwritten later */ }, @@ -656,7 +652,7 @@ static struct usb_config umass_cbi_config[UMASS_T_CBI_MAX] = { .endpoint = UE_ADDR_ANY, .direction = UE_DIR_OUT, .bufsize = UMASS_BULK_SIZE, - .flags = {.proxy_buffer = 1,.short_xfer_ok = 1, UMASS_USB_FLAGS}, + .flags = {.proxy_buffer = 1,.short_xfer_ok = 1,.ext_buffer=1,}, .callback = &umass_t_cbi_data_write_callback, .timeout = 0, /* overwritten later */ }, @@ -845,6 +841,8 @@ umass_probe_proto(device_t dev, struct usb_attach_arg *uaa) quirks |= NO_INQUIRY; if (usb_test_quirk(uaa, UQ_MSC_NO_INQUIRY_EVPD)) quirks |= NO_INQUIRY_EVPD; + if (usb_test_quirk(uaa, UQ_MSC_NO_PREVENT_ALLOW)) + quirks |= NO_PREVENT_ALLOW; if (usb_test_quirk(uaa, UQ_MSC_NO_SYNC_CACHE)) quirks |= NO_SYNCHRONIZE_CACHE; if (usb_test_quirk(uaa, UQ_MSC_SHUTTLE_INIT)) @@ -891,7 +889,7 @@ umass_attach(device_t dev) struct usb_attach_arg *uaa = device_get_ivars(dev); struct umass_probe_proto temp = umass_probe_proto(dev, uaa); struct usb_interface_descriptor *id; - int32_t err; + int err; /* * NOTE: the softc struct is cleared in device_set_driver. @@ -1004,6 +1002,24 @@ umass_attach(device_t dev) "transfers, %s\n", usbd_errstr(err)); goto detach; } +#ifdef USB_DEBUG + if (umass_throttle > 0) { + uint8_t x; + int iv; + + iv = umass_throttle; + + if (iv < 1) + iv = 1; + else if (iv > 8000) + iv = 8000; + + for (x = 0; x != UMASS_T_MAX; x++) { + if (sc->sc_xfer[x] != NULL) + usbd_xfer_set_interval(sc->sc_xfer[x], iv); + } + } +#endif sc->sc_transform = (sc->sc_proto & UMASS_PROTO_SCSI) ? &umass_scsi_transform : (sc->sc_proto & UMASS_PROTO_UFI) ? &umass_ufi_transform : @@ -1058,14 +1074,16 @@ umass_detach(device_t dev) usbd_transfer_unsetup(sc->sc_xfer, UMASS_T_MAX); -#if (__FreeBSD_version >= 700037) mtx_lock(&sc->sc_mtx); -#endif + + /* cancel any leftover CCB's */ + + umass_cancel_ccb(sc); + umass_cam_detach_sim(sc); -#if (__FreeBSD_version >= 700037) mtx_unlock(&sc->sc_mtx); -#endif + mtx_destroy(&sc->sc_mtx); return (0); /* success */ @@ -1206,7 +1224,6 @@ umass_t_bbb_reset1_callback(struct usb_xfer *xfer, usb_error_t error) default: /* Error */ umass_tr_error(xfer, error); return; - } } @@ -1245,7 +1262,6 @@ tr_transferred: default: /* Error */ umass_tr_error(xfer, error); return; - } } @@ -1331,7 +1347,6 @@ umass_t_bbb_command_callback(struct usb_xfer *xfer, usb_error_t error) default: /* Error */ umass_tr_error(xfer, error); return; - } } @@ -1340,19 +1355,12 @@ umass_t_bbb_data_read_callback(struct usb_xfer *xfer, usb_error_t error) { struct umass_softc *sc = usbd_xfer_softc(xfer); uint32_t max_bulk = usbd_xfer_max_len(xfer); -#ifndef UMASS_EXT_BUFFER - struct usb_page_cache *pc; -#endif int actlen, sumlen; usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: -#ifndef UMASS_EXT_BUFFER - pc = usbd_xfer_get_frame(xfer, 0); - usbd_copy_out(pc, 0, sc->sc_transfer.data_ptr, actlen); -#endif sc->sc_transfer.data_rem -= actlen; sc->sc_transfer.data_ptr += actlen; sc->sc_transfer.actlen += actlen; @@ -1374,12 +1382,9 @@ umass_t_bbb_data_read_callback(struct usb_xfer *xfer, usb_error_t error) } usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout); -#ifdef UMASS_EXT_BUFFER usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr, max_bulk); -#else - usbd_xfer_set_frame_len(xfer, 0, max_bulk); -#endif + usbd_transfer_submit(xfer); return; @@ -1390,7 +1395,6 @@ umass_t_bbb_data_read_callback(struct usb_xfer *xfer, usb_error_t error) umass_transfer_start(sc, UMASS_T_BBB_DATA_RD_CS); } return; - } } @@ -1406,9 +1410,6 @@ umass_t_bbb_data_write_callback(struct usb_xfer *xfer, usb_error_t error) { struct umass_softc *sc = usbd_xfer_softc(xfer); uint32_t max_bulk = usbd_xfer_max_len(xfer); -#ifndef UMASS_EXT_BUFFER - struct usb_page_cache *pc; -#endif int actlen, sumlen; usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); @@ -1436,14 +1437,8 @@ umass_t_bbb_data_write_callback(struct usb_xfer *xfer, usb_error_t error) } usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout); -#ifdef UMASS_EXT_BUFFER usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr, max_bulk); -#else - pc = usbd_xfer_get_frame(xfer, 0); - usbd_copy_in(pc, 0, sc->sc_transfer.data_ptr, max_bulk); - usbd_xfer_set_frame_len(xfer, 0, max_bulk); -#endif usbd_transfer_submit(xfer); return; @@ -1455,7 +1450,6 @@ umass_t_bbb_data_write_callback(struct usb_xfer *xfer, usb_error_t error) umass_transfer_start(sc, UMASS_T_BBB_DATA_WR_CS); } return; - } } @@ -1581,7 +1575,6 @@ tr_error: umass_transfer_start(sc, UMASS_T_BBB_DATA_RD_CS); } return; - } } @@ -1612,8 +1605,7 @@ umass_command_start(struct umass_softc *sc, uint8_t dir, if (sc->sc_xfer[sc->sc_last_xfer_index]) { usbd_transfer_start(sc->sc_xfer[sc->sc_last_xfer_index]); } else { - ccb->ccb_h.status = CAM_TID_INVALID; - xpt_done(ccb); + umass_cancel_ccb(sc); } } @@ -1733,7 +1725,6 @@ umass_t_cbi_reset1_callback(struct usb_xfer *xfer, usb_error_t error) else umass_transfer_start(sc, UMASS_T_CBI_RESET2); break; - } } @@ -1788,7 +1779,6 @@ tr_transferred: default: /* Error */ umass_tr_error(xfer, error); break; - } } @@ -1878,19 +1868,12 @@ umass_t_cbi_data_read_callback(struct usb_xfer *xfer, usb_error_t error) { struct umass_softc *sc = usbd_xfer_softc(xfer); uint32_t max_bulk = usbd_xfer_max_len(xfer); -#ifndef UMASS_EXT_BUFFER - struct usb_page_cache *pc; -#endif int actlen, sumlen; usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: -#ifndef UMASS_EXT_BUFFER - pc = usbd_xfer_get_frame(xfer, 0); - usbd_copy_out(pc, 0, sc->sc_transfer.data_ptr, actlen); -#endif sc->sc_transfer.data_rem -= actlen; sc->sc_transfer.data_ptr += actlen; sc->sc_transfer.actlen += actlen; @@ -1912,12 +1895,9 @@ umass_t_cbi_data_read_callback(struct usb_xfer *xfer, usb_error_t error) } usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout); -#ifdef UMASS_EXT_BUFFER usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr, max_bulk); -#else - usbd_xfer_set_frame_len(xfer, 0, max_bulk); -#endif + usbd_transfer_submit(xfer); break; @@ -1929,7 +1909,6 @@ umass_t_cbi_data_read_callback(struct usb_xfer *xfer, usb_error_t error) umass_transfer_start(sc, UMASS_T_CBI_DATA_RD_CS); } break; - } } @@ -1945,9 +1924,6 @@ umass_t_cbi_data_write_callback(struct usb_xfer *xfer, usb_error_t error) { struct umass_softc *sc = usbd_xfer_softc(xfer); uint32_t max_bulk = usbd_xfer_max_len(xfer); -#ifndef UMASS_EXT_BUFFER - struct usb_page_cache *pc; -#endif int actlen, sumlen; usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); @@ -1975,14 +1951,8 @@ umass_t_cbi_data_write_callback(struct usb_xfer *xfer, usb_error_t error) } usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout); -#ifdef UMASS_EXT_BUFFER usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr, max_bulk); -#else - pc = usbd_xfer_get_frame(xfer, 0); - usbd_copy_in(pc, 0, sc->sc_transfer.data_ptr, max_bulk); - usbd_xfer_set_frame_len(xfer, 0, max_bulk); -#endif usbd_transfer_submit(xfer); break; @@ -1995,7 +1965,6 @@ umass_t_cbi_data_write_callback(struct usb_xfer *xfer, usb_error_t error) umass_transfer_start(sc, UMASS_T_CBI_DATA_WR_CS); } break; - } } @@ -2097,7 +2066,6 @@ tr_setup: usbd_errstr(error)); umass_tr_error(xfer, error); break; - } } @@ -2126,9 +2094,7 @@ umass_cam_attach_sim(struct umass_softc *sc) DEVNAME_SIM, sc /* priv */ , sc->sc_unit /* unit number */ , -#if (__FreeBSD_version >= 700037) &sc->sc_mtx /* mutex */ , -#endif 1 /* maximum device openings */ , 0 /* maximum tagged device openings */ , devq); @@ -2138,27 +2104,15 @@ umass_cam_attach_sim(struct umass_softc *sc) return (ENOMEM); } -#if (__FreeBSD_version >= 700037) mtx_lock(&sc->sc_mtx); -#endif -#if (__FreeBSD_version >= 700048) - if (xpt_bus_register(sc->sc_sim, sc->sc_dev, sc->sc_unit) != CAM_SUCCESS) { + if (xpt_bus_register(sc->sc_sim, sc->sc_dev, + sc->sc_unit) != CAM_SUCCESS) { mtx_unlock(&sc->sc_mtx); return (ENOMEM); } -#else - if (xpt_bus_register(sc->sc_sim, sc->sc_unit) != CAM_SUCCESS) { -#if (__FreeBSD_version >= 700037) - mtx_unlock(&sc->sc_mtx); -#endif - return (ENOMEM); - } -#endif - -#if (__FreeBSD_version >= 700037) mtx_unlock(&sc->sc_mtx); -#endif + return (0); } @@ -2186,7 +2140,7 @@ umass_cam_detach_sim(struct umass_softc *sc) if (sc->sc_sim != NULL) { if (xpt_bus_deregister(cam_sim_path(sc->sc_sim))) { /* accessing the softc is not possible after this */ - sc->sc_sim->softc = UMASS_GONE; + sc->sc_sim->softc = NULL; cam_sim_free(sc->sc_sim, /* free_devq */ TRUE); } else { panic("%s: CAM layer is busy\n", @@ -2205,68 +2159,11 @@ umass_cam_action(struct cam_sim *sim, union ccb *ccb) { struct umass_softc *sc = (struct umass_softc *)sim->softc; - if (sc == UMASS_GONE || - (sc != NULL && !usbd_device_attached(sc->sc_udev))) { + if (sc == NULL) { ccb->ccb_h.status = CAM_SEL_TIMEOUT; xpt_done(ccb); return; } - if (sc) { -#if (__FreeBSD_version < 700037) - mtx_lock(&sc->sc_mtx); -#endif - } - /* - * 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) { - DPRINTF(sc, UDMASS_GEN, "%s:%d:%d:%d:func_code 0x%04x: " - "Invalid target (target needed)\n", - DEVNAME_SIM, cam_sim_path(sc->sc_sim), - 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); - goto done; - } - 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(sc, UDMASS_SCSI, "%s:%d:%d:%d:func_code 0x%04x: " - "Invalid target (no wildcard)\n", - DEVNAME_SIM, cam_sim_path(sc->sc_sim), - 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); - goto done; - } - break; - default: - /* XXX Hm, we should check the input parameters */ - break; - } /* Perform the requested action */ switch (ccb->ccb_h.func_code) { @@ -2353,17 +2250,20 @@ umass_cam_action(struct cam_sim *sim, union ccb *ccb) */ if ((sc->sc_quirks & (NO_INQUIRY_EVPD | NO_INQUIRY)) && (sc->sc_transfer.cmd_data[1] & SI_EVPD)) { - struct scsi_sense_data *sense; - - sense = &ccb->csio.sense_data; - bzero(sense, sizeof(*sense)); - sense->error_code = SSD_CURRENT_ERROR; - sense->flags = SSD_KEY_ILLEGAL_REQUEST; - sense->add_sense_code = 0x24; - sense->extra_len = 10; + + scsi_set_sense_data(&ccb->csio.sense_data, + /*sense_format*/ SSD_TYPE_NONE, + /*current_error*/ 1, + /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, + /*asc*/ 0x24, + /*ascq*/ 0x00, + /*extra args*/ SSD_ELEM_NONE); ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; - ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | - CAM_AUTOSNS_VALID; + ccb->ccb_h.status = + CAM_SCSI_STATUS_ERROR | + CAM_AUTOSNS_VALID | + CAM_DEV_QFRZN; + xpt_freeze_devq(ccb->ccb_h.path, 1); xpt_done(ccb); goto done; } @@ -2382,6 +2282,13 @@ umass_cam_action(struct cam_sim *sim, union ccb *ccb) if (sc->sc_quirks & FORCE_SHORT_INQUIRY) { ccb->csio.dxfer_len = SHORT_INQUIRY_LENGTH; } + } else if (sc->sc_transfer.cmd_data[0] == PREVENT_ALLOW) { + if (sc->sc_quirks & NO_PREVENT_ALLOW) { + ccb->csio.scsi_status = SCSI_STATUS_OK; + ccb->ccb_h.status = CAM_REQ_CMP; + xpt_done(ccb); + goto done; + } } else if (sc->sc_transfer.cmd_data[0] == SYNCHRONIZE_CACHE) { if (sc->sc_quirks & NO_SYNCHRONIZE_CACHE) { ccb->csio.scsi_status = SCSI_STATUS_OK; @@ -2418,12 +2325,11 @@ umass_cam_action(struct cam_sim *sim, union ccb *ccb) strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); cpi->unit_number = cam_sim_unit(sim); cpi->bus_id = sc->sc_unit; -#if (__FreeBSD_version >= 700025) cpi->protocol = PROTO_SCSI; cpi->protocol_version = SCSI_REV_2; cpi->transport = XPORT_USB; cpi->transport_version = 0; -#endif + if (sc == NULL) { cpi->base_transfer_speed = 0; cpi->max_lun = 0; @@ -2475,16 +2381,12 @@ umass_cam_action(struct cam_sim *sim, union ccb *ccb) cam_sim_path(sc->sc_sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun); -#if (__FreeBSD_version >= 700025) cts->protocol = PROTO_SCSI; cts->protocol_version = SCSI_REV_2; cts->transport = XPORT_USB; cts->transport_version = 0; cts->xport_specific.valid = 0; -#else - cts->valid = 0; - cts->flags = 0; /* no disconnection, tagging */ -#endif + ccb->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); break; @@ -2529,11 +2431,6 @@ umass_cam_action(struct cam_sim *sim, union ccb *ccb) } done: -#if (__FreeBSD_version < 700037) - if (sc) { - mtx_unlock(&sc->sc_mtx); - } -#endif return; } @@ -2542,7 +2439,7 @@ umass_cam_poll(struct cam_sim *sim) { struct umass_softc *sc = (struct umass_softc *)sim->softc; - if (sc == UMASS_GONE) + if (sc == NULL) return; DPRINTF(sc, UDMASS_SCSI, "CAM poll\n"); @@ -2628,7 +2525,8 @@ umass_cam_cb(struct umass_softc *sc, union ccb *ccb, uint32_t residue, * recovered. We return an error to CAM and let CAM * retry the command if necessary. */ - ccb->ccb_h.status = CAM_REQ_CMP_ERR; + xpt_freeze_devq(ccb->ccb_h.path, 1); + ccb->ccb_h.status = CAM_REQ_CMP_ERR | CAM_DEV_QFRZN; xpt_done(ccb); break; } @@ -2642,12 +2540,17 @@ umass_cam_sense_cb(struct umass_softc *sc, union ccb *ccb, uint32_t residue, uint8_t status) { uint8_t *cmd; - uint8_t key; switch (status) { case STATUS_CMD_OK: case STATUS_CMD_UNKNOWN: - case STATUS_CMD_FAILED: + case STATUS_CMD_FAILED: { + int key, sense_len; + + ccb->csio.sense_resid = residue; + sense_len = ccb->csio.sense_len - ccb->csio.sense_resid; + key = scsi_get_sense_key(&ccb->csio.sense_data, sense_len, + /*show_errors*/ 1); if (ccb->csio.ccb_h.flags & CAM_CDB_POINTER) { cmd = (uint8_t *)(ccb->csio.cdb_io.cdb_ptr); @@ -2655,8 +2558,6 @@ umass_cam_sense_cb(struct umass_softc *sc, union ccb *ccb, uint32_t residue, cmd = (uint8_t *)(ccb->csio.cdb_io.cdb_bytes); } - key = (ccb->csio.sense_data.flags & SSD_KEY); - /* * Getting sense data always succeeds (apart from wire * failures): @@ -2688,8 +2589,9 @@ umass_cam_sense_cb(struct umass_softc *sc, union ccb *ccb, uint32_t residue, * usual. */ + xpt_freeze_devq(ccb->ccb_h.path, 1); ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR - | CAM_AUTOSNS_VALID; + | CAM_AUTOSNS_VALID | CAM_DEV_QFRZN; ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; #if 0 @@ -2700,34 +2602,40 @@ umass_cam_sense_cb(struct umass_softc *sc, union ccb *ccb, uint32_t residue, /* the rest of the command was filled in at attach */ - if (umass_std_transform(sc, ccb, + if ((sc->sc_transform)(sc, &sc->cam_scsi_test_unit_ready.opcode, - sizeof(sc->cam_scsi_test_unit_ready))) { + sizeof(sc->cam_scsi_test_unit_ready)) == 1) { umass_command_start(sc, DIR_NONE, NULL, 0, ccb->ccb_h.timeout, &umass_cam_quirk_cb, ccb); + break; } - break; } else { - ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR - | CAM_AUTOSNS_VALID; - ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; + xpt_freeze_devq(ccb->ccb_h.path, 1); + if (key >= 0) { + ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR + | CAM_AUTOSNS_VALID | CAM_DEV_QFRZN; + ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; + } else + ccb->ccb_h.status = CAM_AUTOSENSE_FAIL + | CAM_DEV_QFRZN; } xpt_done(ccb); break; - + } default: DPRINTF(sc, UDMASS_SCSI, "Autosense failed, " "status %d\n", status); - ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; + xpt_freeze_devq(ccb->ccb_h.path, 1); + ccb->ccb_h.status = CAM_AUTOSENSE_FAIL | CAM_DEV_QFRZN; xpt_done(ccb); } } /* * This completion code just handles the fact that we sent a test-unit-ready - * after having previously failed a READ CAPACITY with CHECK_COND. Even - * though this command succeeded, we have to tell CAM to retry. + * after having previously failed a READ CAPACITY with CHECK_COND. The CCB + * status for CAM is already set earlier. */ static void umass_cam_quirk_cb(struct umass_softc *sc, union ccb *ccb, uint32_t residue, @@ -2736,9 +2644,6 @@ umass_cam_quirk_cb(struct umass_softc *sc, union ccb *ccb, uint32_t residue, DPRINTF(sc, UDMASS_SCSI, "Test unit ready " "returned status %d\n", status); - ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR - | CAM_AUTOSNS_VALID; - ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; xpt_done(ccb); } @@ -3027,7 +2932,8 @@ umass_std_transform(struct umass_softc *sc, union ccb *ccb, xpt_done(ccb); return (0); } else if (retval == 0) { - ccb->ccb_h.status = CAM_REQ_INVALID; + xpt_freeze_devq(ccb->ccb_h.path, 1); + ccb->ccb_h.status = CAM_REQ_INVALID | CAM_DEV_QFRZN; xpt_done(ccb); return (0); } diff --git a/freebsd/sys/dev/usb/usb.h b/freebsd/sys/dev/usb/usb.h index 2f216d27..9492d491 100644 --- a/freebsd/sys/dev/usb/usb.h +++ b/freebsd/sys/dev/usb/usb.h @@ -223,7 +223,8 @@ typedef struct usb_device_request usb_device_request_t; #define UR_RESET_TT 0x09 #define UR_GET_TT_STATE 0x0a #define UR_STOP_TT 0x0b -#define UR_SET_HUB_DEPTH 0x0c +#define UR_SET_AND_TEST 0x0c /* USB 2.0 only */ +#define UR_SET_HUB_DEPTH 0x0c /* USB 3.0 only */ #define USB_SS_HUB_DEPTH_MAX 5 #define UR_GET_PORT_ERR_COUNT 0x0d @@ -246,6 +247,7 @@ typedef struct usb_device_request usb_device_request_t; #define UHF_PORT_LINK_STATE 5 #define UHF_PORT_POWER 8 #define UHF_PORT_LOW_SPEED 9 +#define UHF_PORT_L1 10 #define UHF_C_PORT_CONNECTION 16 #define UHF_C_PORT_ENABLE 17 #define UHF_C_PORT_SUSPEND 18 @@ -253,6 +255,7 @@ typedef struct usb_device_request usb_device_request_t; #define UHF_C_PORT_RESET 20 #define UHF_PORT_TEST 21 #define UHF_PORT_INDICATOR 22 +#define UHF_C_PORT_L1 23 /* SuperSpeed HUB specific features */ #define UHF_PORT_U1_TIMEOUT 23 @@ -322,7 +325,12 @@ struct usb_devcap_usb2ext_descriptor { uByte bDescriptorType; uByte bDevCapabilityType; uDWord bmAttributes; -#define USB_V2EXT_LPM 0x02 +#define USB_V2EXT_LPM (1U << 1) +#define USB_V2EXT_BESL_SUPPORTED (1U << 2) +#define USB_V2EXT_BESL_BASELINE_VALID (1U << 3) +#define USB_V2EXT_BESL_DEEP_VALID (1U << 4) +#define USB_V2EXT_BESL_BASELINE_GET(x) (((x) >> 8) & 0xF) +#define USB_V2EXT_BESL_DEEP_GET(x) (((x) >> 12) & 0xF) } __packed; typedef struct usb_devcap_usb2ext_descriptor usb_devcap_usb2ext_descriptor_t; @@ -669,6 +677,7 @@ struct usb_port_status { #define UPS_SUSPEND 0x0004 #define UPS_OVERCURRENT_INDICATOR 0x0008 #define UPS_RESET 0x0010 +#define UPS_PORT_L1 0x0020 /* USB 2.0 only */ /* The link-state bits are valid for Super-Speed USB HUBs */ #define UPS_PORT_LINK_STATE_GET(x) (((x) >> 5) & 0xF) #define UPS_PORT_LINK_STATE_SET(x) (((x) & 0xF) << 5) @@ -699,7 +708,8 @@ struct usb_port_status { #define UPS_C_SUSPEND 0x0004 #define UPS_C_OVERCURRENT_INDICATOR 0x0008 #define UPS_C_PORT_RESET 0x0010 -#define UPS_C_BH_PORT_RESET 0x0020 +#define UPS_C_PORT_L1 0x0020 /* USB 2.0 only */ +#define UPS_C_BH_PORT_RESET 0x0020 /* USB 3.0 only */ #define UPS_C_PORT_LINK_STATE 0x0040 #define UPS_C_PORT_CONFIG_ERROR 0x0080 } __packed; diff --git a/freebsd/sys/dev/usb/usb_dev.c b/freebsd/sys/dev/usb/usb_dev.c index 7ca10d7b..7697b64c 100644 --- a/freebsd/sys/dev/usb/usb_dev.c +++ b/freebsd/sys/dev/usb/usb_dev.c @@ -83,7 +83,7 @@ #ifdef USB_DEBUG static int usb_fifo_debug = 0; -SYSCTL_NODE(_hw_usb, OID_AUTO, dev, CTLFLAG_RW, 0, "USB device"); +static SYSCTL_NODE(_hw_usb, OID_AUTO, dev, CTLFLAG_RW, 0, "USB device"); SYSCTL_INT(_hw_usb_dev, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN, &usb_fifo_debug, 0, "Debug Level"); TUNABLE_INT("hw.usb.dev.debug", &usb_fifo_debug); @@ -770,7 +770,7 @@ usb_fifo_close(struct usb_fifo *f, int fflags) /* check if a thread wants SIGIO */ if (f->async_p != NULL) { PROC_LOCK(f->async_p); - psignal(f->async_p, SIGIO); + kern_psignal(f->async_p, SIGIO); PROC_UNLOCK(f->async_p); f->async_p = NULL; } @@ -844,7 +844,7 @@ usb_open(struct cdev *dev, int fflags, int devtype, struct thread *td) struct usb_cdev_privdata *cpd; int err, ep; - DPRINTFN(2, "%s fflags=0x%08x\n", dev->si_name, fflags); + DPRINTFN(2, "%s fflags=0x%08x\n", devtoname(dev), fflags); KASSERT(fflags & (FREAD|FWRITE), ("invalid open flags")); if (((fflags & FREAD) && !(pd->mode & FREAD)) || @@ -1584,7 +1584,7 @@ usb_fifo_wakeup(struct usb_fifo *f) } if (f->async_p != NULL) { PROC_LOCK(f->async_p); - psignal(f->async_p, SIGIO); + kern_psignal(f->async_p, SIGIO); PROC_UNLOCK(f->async_p); } } diff --git a/freebsd/sys/dev/usb/usb_device.c b/freebsd/sys/dev/usb/usb_device.c index 3a58158d..78ae3d8c 100644 --- a/freebsd/sys/dev/usb/usb_device.c +++ b/freebsd/sys/dev/usb/usb_device.c @@ -2431,77 +2431,6 @@ usbd_get_device_index(struct usb_device *udev) } #if USB_HAVE_DEVCTL -/*------------------------------------------------------------------------* - * usb_notify_addq - * - * This function will generate events for dev. - *------------------------------------------------------------------------*/ -#ifndef BURN_BRIDGES -static void -usb_notify_addq_compat(const char *type, struct usb_device *udev) -{ - char *data = NULL; - const char *ntype; - struct malloc_type *mt; - const size_t buf_size = 512; - - /* Convert notify type */ - if (strcmp(type, "ATTACH") == 0) - ntype = "+"; - else if (strcmp(type, "DETACH") == 0) - ntype = "-"; - else - return; - - mtx_lock(&malloc_mtx); - mt = malloc_desc2type("bus"); /* XXX M_BUS */ - mtx_unlock(&malloc_mtx); - if (mt == NULL) - return; - - data = malloc(buf_size, mt, M_NOWAIT); - if (data == NULL) - return; - - /* String it all together. */ - snprintf(data, buf_size, - "%s" -#if USB_HAVE_UGEN - "%s " -#endif - "at port=%u " - "vendor=0x%04x " - "product=0x%04x " - "devclass=0x%02x " - "devsubclass=0x%02x " - "sernum=\"%s\" " - "release=0x%04x " -#if USB_HAVE_UGEN - "on %s\n" -#endif - "", - ntype, -#if USB_HAVE_UGEN - udev->ugen_name, -#endif - udev->port_no, - UGETW(udev->ddesc.idVendor), - UGETW(udev->ddesc.idProduct), - udev->ddesc.bDeviceClass, - udev->ddesc.bDeviceSubClass, - usb_get_serial(udev), - UGETW(udev->ddesc.bcdDevice) -#if USB_HAVE_UGEN - , udev->parent_hub != NULL ? - udev->parent_hub->ugen_name : - device_get_nameunit(device_get_parent(udev->bus->bdev)) -#endif - ); - - devctl_queue_data(data); -} -#endif - static void usb_notify_addq(const char *type, struct usb_device *udev) { @@ -2509,10 +2438,6 @@ usb_notify_addq(const char *type, struct usb_device *udev) struct sbuf *sb; int i; -#ifndef BURN_BRIDGES - usb_notify_addq_compat(type, udev); -#endif - /* announce the device */ sb = sbuf_new_auto(); sbuf_printf(sb, diff --git a/freebsd/sys/dev/usb/usb_device.h b/freebsd/sys/dev/usb/usb_device.h index 03ddf1e6..8e13e3de 100644 --- a/freebsd/sys/dev/usb/usb_device.h +++ b/freebsd/sys/dev/usb/usb_device.h @@ -215,6 +215,7 @@ struct usb_device { uint16_t power; /* mA the device uses */ uint16_t langid; /* language for strings */ + uint16_t autoQuirk[USB_MAX_AUTO_QUIRK]; /* dynamic quirks */ uint8_t address; /* device addess */ uint8_t device_index; /* device index in "bus->devices" */ @@ -257,8 +258,6 @@ struct usb_device { uint32_t clear_stall_errors; /* number of clear-stall failures */ - uint16_t autoQuirk[USB_MAX_AUTO_QUIRK]; /* dynamic quirks */ - union usb_device_scratch scratch; }; diff --git a/freebsd/sys/dev/usb/usb_freebsd.h b/freebsd/sys/dev/usb/usb_freebsd.h index 8f9bb4c6..06369a25 100644 --- a/freebsd/sys/dev/usb/usb_freebsd.h +++ b/freebsd/sys/dev/usb/usb_freebsd.h @@ -48,7 +48,15 @@ #define USB_TD_GET_PROC(td) (td)->td_proc #define USB_PROC_GET_GID(td) (td)->p_pgid +#if (!defined(USB_HOST_ALIGN)) || (USB_HOST_ALIGN <= 0) +/* Use default value. */ +#undef USB_HOST_ALIGN #define USB_HOST_ALIGN 8 /* bytes, must be power of two */ +#endif +/* Sanity check for USB_HOST_ALIGN: Verify power of two. */ +#if ((-USB_HOST_ALIGN) & USB_HOST_ALIGN) != USB_HOST_ALIGN +#error "USB_HOST_ALIGN is not power of two." +#endif #define USB_FS_ISOC_UFRAME_MAX 4 /* exclusive unit */ #define USB_BUS_MAX 256 /* units */ #define USB_MAX_DEVICES 128 /* units */ diff --git a/freebsd/sys/dev/usb/usb_generic.c b/freebsd/sys/dev/usb/usb_generic.c index 361ee2ef..a0b7f007 100644 --- a/freebsd/sys/dev/usb/usb_generic.c +++ b/freebsd/sys/dev/usb/usb_generic.c @@ -128,7 +128,7 @@ struct usb_fifo_methods usb_ugen_methods = { #ifdef USB_DEBUG static int ugen_debug = 0; -SYSCTL_NODE(_hw_usb, OID_AUTO, ugen, CTLFLAG_RW, 0, "USB generic"); +static SYSCTL_NODE(_hw_usb, OID_AUTO, ugen, CTLFLAG_RW, 0, "USB generic"); SYSCTL_INT(_hw_usb_ugen, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN, &ugen_debug, 0, "Debug level"); TUNABLE_INT("hw.usb.ugen.debug", &ugen_debug); @@ -1833,6 +1833,17 @@ ugen_get_power_mode(struct usb_fifo *f) } static int +ugen_get_power_usage(struct usb_fifo *f) +{ + struct usb_device *udev = f->udev; + + if (udev == NULL) + return (0); + + return (udev->power); +} + +static int ugen_do_port_feature(struct usb_fifo *f, uint8_t port_no, uint8_t set, uint16_t feature) { @@ -2194,6 +2205,10 @@ ugen_ioctl_post(struct usb_fifo *f, u_long cmd, void *addr, int fflags) *u.pint = ugen_get_power_mode(f); break; + case USB_GET_POWER_USAGE: + *u.pint = ugen_get_power_usage(f); + break; + case USB_SET_PORT_ENABLE: error = ugen_do_port_feature(f, *u.pint, 1, UHF_PORT_ENABLE); diff --git a/freebsd/sys/dev/usb/usb_hid.c b/freebsd/sys/dev/usb/usb_hid.c index 86fa27b0..737237bd 100644 --- a/freebsd/sys/dev/usb/usb_hid.c +++ b/freebsd/sys/dev/usb/usb_hid.c @@ -847,3 +847,79 @@ usbd_req_get_hid_desc(struct usb_device *udev, struct mtx *mtx, } return (USB_ERR_NORMAL_COMPLETION); } + +/*------------------------------------------------------------------------* + * hid_is_mouse + * + * This function will decide if a USB descriptor belongs to a USB mouse. + * + * Return values: + * Zero: Not a USB mouse. + * Else: Is a USB mouse. + *------------------------------------------------------------------------*/ +int +hid_is_mouse(const void *d_ptr, uint16_t d_len) +{ + struct hid_data *hd; + struct hid_item hi; + int mdepth; + int found; + + hd = hid_start_parse(d_ptr, d_len, 1 << hid_input); + if (hd == NULL) + return (0); + + mdepth = 0; + found = 0; + + while (hid_get_item(hd, &hi)) { + switch (hi.kind) { + case hid_collection: + if (mdepth != 0) + mdepth++; + else if (hi.collection == 1 && + hi.usage == + HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE)) + mdepth++; + break; + case hid_endcollection: + if (mdepth != 0) + mdepth--; + break; + case hid_input: + if (mdepth == 0) + break; + if (hi.usage == + HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X) && + (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE) + found++; + if (hi.usage == + HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y) && + (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE) + found++; + break; + default: + break; + } + } + hid_end_parse(hd); + return (found); +} + +/*------------------------------------------------------------------------* + * hid_is_keyboard + * + * This function will decide if a USB descriptor belongs to a USB keyboard. + * + * Return values: + * Zero: Not a USB keyboard. + * Else: Is a USB keyboard. + *------------------------------------------------------------------------*/ +int +hid_is_keyboard(const void *d_ptr, uint16_t d_len) +{ + if (hid_is_collection(d_ptr, d_len, + HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD))) + return (1); + return (0); +} diff --git a/freebsd/sys/dev/usb/usb_hub.c b/freebsd/sys/dev/usb/usb_hub.c index 97b3a4dd..2dee6784 100644 --- a/freebsd/sys/dev/usb/usb_hub.c +++ b/freebsd/sys/dev/usb/usb_hub.c @@ -78,7 +78,7 @@ #ifdef USB_DEBUG static int uhub_debug = 0; -SYSCTL_NODE(_hw_usb, OID_AUTO, uhub, CTLFLAG_RW, 0, "USB HUB"); +static SYSCTL_NODE(_hw_usb, OID_AUTO, uhub, CTLFLAG_RW, 0, "USB HUB"); SYSCTL_INT(_hw_usb_uhub, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN, &uhub_debug, 0, "Debug level"); TUNABLE_INT("hw.usb.uhub.debug", &uhub_debug); diff --git a/freebsd/sys/dev/usb/usb_ioctl.h b/freebsd/sys/dev/usb/usb_ioctl.h index 9af6ee5c..9e66bd5a 100644 --- a/freebsd/sys/dev/usb/usb_ioctl.h +++ b/freebsd/sys/dev/usb/usb_ioctl.h @@ -270,7 +270,8 @@ struct usb_gen_quirk { #define USB_IFACE_DRIVER_DETACH _IOW ('U', 125, int) #define USB_GET_PLUGTIME _IOR ('U', 126, uint32_t) #define USB_READ_DIR _IOW ('U', 127, struct usb_read_dir) -/* 128 - 135 unused */ +/* 128 - 134 unused */ +#define USB_GET_POWER_USAGE _IOR ('U', 135, int) #define USB_SET_TX_FORCE_SHORT _IOW ('U', 136, int) #define USB_SET_TX_TIMEOUT _IOW ('U', 137, int) #define USB_GET_TX_FRAME_SIZE _IOR ('U', 138, int) diff --git a/freebsd/sys/dev/usb/usb_msctest.c b/freebsd/sys/dev/usb/usb_msctest.c index 5e8eebb3..fcb9f026 100644 --- a/freebsd/sys/dev/usb/usb_msctest.c +++ b/freebsd/sys/dev/usb/usb_msctest.c @@ -64,7 +64,6 @@ #include <dev/usb/usb_transfer.h> #include <dev/usb/usb_msctest.h> #include <dev/usb/usb_debug.h> -#include <dev/usb/usb_busdma.h> #include <dev/usb/usb_device.h> #include <dev/usb/usb_request.h> #include <dev/usb/usb_util.h> @@ -106,6 +105,8 @@ static uint8_t scsi_sync_cache[] = { 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static uint8_t scsi_request_sense[] = { 0x03, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static uint8_t scsi_read_capacity[] = { 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; #define BULK_SIZE 64 /* dummy */ #define ERR_CSW_FAILED -1 @@ -481,7 +482,7 @@ bbb_command_start(struct bbb_transfer *sc, uint8_t dir, uint8_t lun, sc->cmd_len = cmd_len; memset(&sc->cbw.CBWCDB, 0, sizeof(sc->cbw.CBWCDB)); memcpy(&sc->cbw.CBWCDB, cmd_ptr, cmd_len); - DPRINTFN(1, "SCSI cmd = %*D\n", (int)cmd_len, &sc->cbw.CBWCDB, ":"); + DPRINTFN(1, "SCSI cmd = %*D\n", (int)cmd_len, (char *)sc->cbw.CBWCDB, ":"); mtx_lock(&sc->mtx); usbd_transfer_start(sc->xfer[sc->state]); @@ -650,7 +651,7 @@ usb_msc_auto_quirk(struct usb_device *udev, uint8_t iface_index) } is_no_direct = 1; - for (timeout = 4; timeout; timeout--) { + for (timeout = 4; timeout != 0; timeout--) { err = bbb_command_start(sc, DIR_IN, 0, sc->buffer, SCSI_INQ_LEN, &scsi_inquiry, sizeof(scsi_inquiry), USB_MS_HZ); @@ -660,8 +661,11 @@ usb_msc_auto_quirk(struct usb_device *udev, uint8_t iface_index) if (sid_type == 0x00) is_no_direct = 0; break; - } else if (err != ERR_CSW_FAILED) - break; /* non retryable error */ + } else if (err != ERR_CSW_FAILED) { + DPRINTF("Device is not responding " + "properly to SCSI INQUIRY command.\n"); + goto error; /* non retryable error */ + } usb_pause_mtx(NULL, hz); } @@ -679,7 +683,9 @@ usb_msc_auto_quirk(struct usb_device *udev, uint8_t iface_index) if (err != ERR_CSW_FAILED) goto error; } + timeout = 1; +retry_sync_cache: err = bbb_command_start(sc, DIR_IN, 0, NULL, 0, &scsi_sync_cache, sizeof(scsi_sync_cache), USB_MS_HZ); @@ -692,6 +698,42 @@ usb_msc_auto_quirk(struct usb_device *udev, uint8_t iface_index) DPRINTF("Device doesn't handle synchronize cache\n"); usbd_add_dynamic_quirk(udev, UQ_MSC_NO_SYNC_CACHE); + + } else { + + /* + * Certain Kingston memory sticks fail the first + * read capacity after a synchronize cache command + * has been issued. Disable the synchronize cache + * command for such devices. + */ + + err = bbb_command_start(sc, DIR_IN, 0, sc->buffer, 8, + &scsi_read_capacity, sizeof(scsi_read_capacity), + USB_MS_HZ); + + if (err != 0) { + if (err != ERR_CSW_FAILED) + goto error; + + err = bbb_command_start(sc, DIR_IN, 0, sc->buffer, 8, + &scsi_read_capacity, sizeof(scsi_read_capacity), + USB_MS_HZ); + + if (err == 0) { + if (timeout--) + goto retry_sync_cache; + + DPRINTF("Device most likely doesn't " + "handle synchronize cache\n"); + + usbd_add_dynamic_quirk(udev, + UQ_MSC_NO_SYNC_CACHE); + } else { + if (err != ERR_CSW_FAILED) + goto error; + } + } } /* clear sense status of any failed commands on the device */ diff --git a/freebsd/sys/dev/usb/usb_process.c b/freebsd/sys/dev/usb/usb_process.c index fb422df4..59b26567 100644 --- a/freebsd/sys/dev/usb/usb_process.c +++ b/freebsd/sys/dev/usb/usb_process.c @@ -69,17 +69,13 @@ static int usb_pcount; #define USB_THREAD_CREATE(f, s, p, ...) \ kproc_kthread_add((f), (s), &usbproc, (p), RFHIGHPID, \ 0, "usb", __VA_ARGS__) -#if (__FreeBSD_version >= 900000) #define USB_THREAD_SUSPEND_CHECK() kthread_suspend_check() -#else -#define USB_THREAD_SUSPEND_CHECK() kthread_suspend_check(curthread) -#endif #define USB_THREAD_SUSPEND(p) kthread_suspend(p,0) #define USB_THREAD_EXIT(err) kthread_exit() #else #define USB_THREAD_CREATE(f, s, p, ...) \ kthread_create((f), (s), (p), RFHIGHPID, 0, __VA_ARGS__) -#define USB_THREAD_SUSPEND_CHECK() kthread_suspend_check(curproc) +#define USB_THREAD_SUSPEND_CHECK() kthread_suspend_check() #define USB_THREAD_SUSPEND(p) kthread_suspend(p,0) #define USB_THREAD_EXIT(err) kthread_exit(err) #endif @@ -87,7 +83,7 @@ static int usb_pcount; #ifdef USB_DEBUG static int usb_proc_debug; -SYSCTL_NODE(_hw_usb, OID_AUTO, proc, CTLFLAG_RW, 0, "USB process"); +static SYSCTL_NODE(_hw_usb, OID_AUTO, proc, CTLFLAG_RW, 0, "USB process"); SYSCTL_INT(_hw_usb_proc, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN, &usb_proc_debug, 0, "Debug level"); TUNABLE_INT("hw.usb.proc.debug", &usb_proc_debug); diff --git a/freebsd/sys/dev/usb/usb_process.h b/freebsd/sys/dev/usb/usb_process.h index 23cf6607..9b1a8534 100644 --- a/freebsd/sys/dev/usb/usb_process.h +++ b/freebsd/sys/dev/usb/usb_process.h @@ -42,6 +42,7 @@ /* structure prototypes */ struct usb_proc_msg; +struct usb_device; /* * The following structure defines the USB process. @@ -79,4 +80,9 @@ void usb_proc_free(struct usb_process *up); void *usb_proc_msignal(struct usb_process *up, void *pm0, void *pm1); void usb_proc_rewakeup(struct usb_process *up); +void usb_proc_explore_mwait(struct usb_device *, void *, void *); +void *usb_proc_explore_msignal(struct usb_device *, void *, void *); +void usb_proc_explore_lock(struct usb_device *); +void usb_proc_explore_unlock(struct usb_device *); + #endif /* _USB_PROCESS_H_ */ diff --git a/freebsd/sys/dev/usb/usb_request.c b/freebsd/sys/dev/usb/usb_request.c index 2897cadb..167a7228 100644 --- a/freebsd/sys/dev/usb/usb_request.c +++ b/freebsd/sys/dev/usb/usb_request.c @@ -2158,3 +2158,57 @@ usbd_req_set_port_link_state(struct usb_device *udev, struct mtx *mtx, USETW(req.wLength, 0); return (usbd_do_request(udev, mtx, &req, 0)); } + +/*------------------------------------------------------------------------* + * usbd_req_set_lpm_info + * + * USB 2.0 specific request for Link Power Management. + * + * Returns: + * 0: Success + * USB_ERR_PENDING_REQUESTS: NYET + * USB_ERR_TIMEOUT: TIMEOUT + * USB_ERR_STALL: STALL + * Else: Failure + *------------------------------------------------------------------------*/ +usb_error_t +usbd_req_set_lpm_info(struct usb_device *udev, struct mtx *mtx, + uint8_t port, uint8_t besl, uint8_t addr, uint8_t rwe) +{ + struct usb_device_request req; + usb_error_t err; + uint8_t buf[1]; + + req.bmRequestType = UT_WRITE_CLASS_OTHER; + req.bRequest = UR_SET_AND_TEST; + USETW(req.wValue, UHF_PORT_L1); + req.wIndex[0] = (port & 0xF) | ((besl & 0xF) << 4); + req.wIndex[1] = (addr & 0x7F) | (rwe ? 0x80 : 0x00); + USETW(req.wLength, sizeof(buf)); + + /* set default value in case of short transfer */ + buf[0] = 0x00; + + err = usbd_do_request(udev, mtx, &req, buf); + if (err) + return (err); + + switch (buf[0]) { + case 0x00: /* SUCCESS */ + break; + case 0x10: /* NYET */ + err = USB_ERR_PENDING_REQUESTS; + break; + case 0x11: /* TIMEOUT */ + err = USB_ERR_TIMEOUT; + break; + case 0x30: /* STALL */ + err = USB_ERR_STALLED; + break; + default: /* reserved */ + err = USB_ERR_IOERROR; + break; + } + return (err); +} + diff --git a/freebsd/sys/dev/usb/usb_request.h b/freebsd/sys/dev/usb/usb_request.h index 74823af2..5fcedd5e 100644 --- a/freebsd/sys/dev/usb/usb_request.h +++ b/freebsd/sys/dev/usb/usb_request.h @@ -91,5 +91,7 @@ usb_error_t usbd_req_clear_tt_buffer(struct usb_device *udev, struct mtx *mtx, uint8_t port, uint8_t addr, uint8_t type, uint8_t endpoint); usb_error_t usbd_req_set_port_link_state(struct usb_device *udev, struct mtx *mtx, uint8_t port, uint8_t link_state); +usb_error_t usbd_req_set_lpm_info(struct usb_device *udev, struct mtx *mtx, + uint8_t port, uint8_t besl, uint8_t addr, uint8_t rwe); #endif /* _USB_REQUEST_H_ */ diff --git a/freebsd/sys/dev/usb/usb_transfer.c b/freebsd/sys/dev/usb/usb_transfer.c index d3d41709..b2528186 100644 --- a/freebsd/sys/dev/usb/usb_transfer.c +++ b/freebsd/sys/dev/usb/usb_transfer.c @@ -2206,7 +2206,7 @@ usbd_callback_wrapper(struct usb_xfer_queue *pq) struct usb_xfer_root *info = xfer->xroot; USB_BUS_LOCK_ASSERT(info->bus, MA_OWNED); - if (!mtx_owned(info->xfer_mtx)) { + if (!mtx_owned(info->xfer_mtx) && !SCHEDULER_STOPPED()) { /* * Cases that end up here: * @@ -3179,14 +3179,14 @@ usbd_transfer_poll(struct usb_xfer **ppxfer, uint16_t max) /* make sure that the BUS mutex is not locked */ drop_bus = 0; - while (mtx_owned(&xroot->udev->bus->bus_mtx)) { + while (mtx_owned(&xroot->udev->bus->bus_mtx) && !SCHEDULER_STOPPED()) { mtx_unlock(&xroot->udev->bus->bus_mtx); drop_bus++; } /* make sure that the transfer mutex is not locked */ drop_xfer = 0; - while (mtx_owned(xroot->xfer_mtx)) { + while (mtx_owned(xroot->xfer_mtx) && !SCHEDULER_STOPPED()) { mtx_unlock(xroot->xfer_mtx); drop_xfer++; } diff --git a/freebsd/sys/dev/usb/usb_util.c b/freebsd/sys/dev/usb/usb_util.c index 5c56da87..24558b84 100644 --- a/freebsd/sys/dev/usb/usb_util.c +++ b/freebsd/sys/dev/usb/usb_util.c @@ -60,31 +60,6 @@ #include <dev/usb/usb_bus.h> /*------------------------------------------------------------------------* - * device_delete_all_children - delete all children of a device - *------------------------------------------------------------------------*/ -#ifndef device_delete_all_children -int -device_delete_all_children(device_t dev) -{ - device_t *devlist; - int devcount; - int error; - - error = device_get_children(dev, &devlist, &devcount); - if (error == 0) { - while (devcount-- > 0) { - error = device_delete_child(dev, devlist[devcount]); - if (error) { - break; - } - } - free(devlist, M_TEMP); - } - return (error); -} -#endif - -/*------------------------------------------------------------------------* * device_set_usb_desc * * This function can be called at probe or attach to set the USB @@ -150,33 +125,21 @@ device_set_usb_desc(device_t dev) * * This function will delay the code by the passed number of system * ticks. The passed mutex "mtx" will be dropped while waiting, if - * "mtx" is not NULL. + * "mtx" is different from NULL. *------------------------------------------------------------------------*/ void -usb_pause_mtx(struct mtx *mtx, int _ticks) +usb_pause_mtx(struct mtx *mtx, int timo) { if (mtx != NULL) mtx_unlock(mtx); - if (cold) { - /* convert to milliseconds */ - _ticks = (_ticks * 1000) / hz; - /* convert to microseconds, rounded up */ - _ticks = (_ticks + 1) * 1000; - DELAY(_ticks); - - } else { + /* + * Add one tick to the timeout so that we don't return too + * early! Note that pause() will assert that the passed + * timeout is positive and non-zero! + */ + pause("USBWAIT", timo + 1); - /* - * Add one to the number of ticks so that we don't return - * too early! - */ - _ticks++; - - if (pause("USBWAIT", _ticks)) { - /* ignore */ - } - } if (mtx != NULL) mtx_lock(mtx); } diff --git a/freebsd/sys/dev/usb/usb_util.h b/freebsd/sys/dev/usb/usb_util.h index 35abeddd..7e52404f 100644 --- a/freebsd/sys/dev/usb/usb_util.h +++ b/freebsd/sys/dev/usb/usb_util.h @@ -27,7 +27,6 @@ #ifndef _USB_UTIL_H_ #define _USB_UTIL_H_ -int device_delete_all_children(device_t dev); uint8_t usb_make_str_desc(void *ptr, uint16_t max_len, const char *s); void usb_printbcd(char *p, uint16_t p_len, uint16_t bcd); void usb_trim_spaces(char *p); diff --git a/freebsd/sys/dev/usb/usbhid.h b/freebsd/sys/dev/usb/usbhid.h index f40232aa..f6c447ca 100644 --- a/freebsd/sys/dev/usb/usbhid.h +++ b/freebsd/sys/dev/usb/usbhid.h @@ -242,5 +242,7 @@ struct usb_hid_descriptor *hid_get_descriptor_from_usb( usb_error_t usbd_req_get_hid_desc(struct usb_device *udev, struct mtx *mtx, void **descp, uint16_t *sizep, struct malloc_type *mem, uint8_t iface_index); +int hid_is_mouse(const void *d_ptr, uint16_t d_len); +int hid_is_keyboard(const void *d_ptr, uint16_t d_len); #endif /* _KERNEL */ #endif /* _USB_HID_H_ */ |