summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/dev/usb
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2015-04-08 15:37:49 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2015-05-20 09:58:21 +0200
commit165dd8ea1256d71d6a4f52c0a66dcc2799ef8f99 (patch)
treec42072a99573d4d7cc03b2263e2c0c6d53f9c691 /freebsd/sys/dev/usb
parentrtems-bsd-chunk: Include missing header file (diff)
downloadrtems-libbsd-165dd8ea1256d71d6a4f52c0a66dcc2799ef8f99.tar.bz2
Update to FreeBSD Stable/9 2015-04-08
Diffstat (limited to 'freebsd/sys/dev/usb')
-rw-r--r--freebsd/sys/dev/usb/controller/ehci.c4
-rw-r--r--freebsd/sys/dev/usb/controller/usb_controller.c49
-rw-r--r--freebsd/sys/dev/usb/controller/xhcireg.h2
-rw-r--r--freebsd/sys/dev/usb/quirk/usb_quirk.c37
-rw-r--r--freebsd/sys/dev/usb/quirk/usb_quirk.h1
-rw-r--r--freebsd/sys/dev/usb/usb_bus.h7
-rw-r--r--freebsd/sys/dev/usb/usb_busdma.h4
-rw-r--r--freebsd/sys/dev/usb/usb_core.h1
-rw-r--r--freebsd/sys/dev/usb/usb_dev.c33
-rw-r--r--freebsd/sys/dev/usb/usb_device.c117
-rw-r--r--freebsd/sys/dev/usb/usb_device.h1
-rw-r--r--freebsd/sys/dev/usb/usb_dynamic.c2
-rw-r--r--freebsd/sys/dev/usb/usb_freebsd.h2
-rw-r--r--freebsd/sys/dev/usb/usb_generic.c9
-rw-r--r--freebsd/sys/dev/usb/usb_hub.c14
-rw-r--r--freebsd/sys/dev/usb/usb_msctest.c38
-rw-r--r--freebsd/sys/dev/usb/usb_msctest.h1
-rw-r--r--freebsd/sys/dev/usb/usb_process.c4
-rw-r--r--freebsd/sys/dev/usb/usb_request.c2
-rw-r--r--freebsd/sys/dev/usb/usb_transfer.c31
20 files changed, 248 insertions, 111 deletions
diff --git a/freebsd/sys/dev/usb/controller/ehci.c b/freebsd/sys/dev/usb/controller/ehci.c
index 730fd666..3eb63c60 100644
--- a/freebsd/sys/dev/usb/controller/ehci.c
+++ b/freebsd/sys/dev/usb/controller/ehci.c
@@ -214,7 +214,7 @@ ehci_reset(ehci_softc_t *sc)
return (0);
}
}
- device_printf(sc->sc_bus.bdev, "Reset timeout\n");
+ device_printf(sc->sc_bus.bdev, "reset timeout\n");
return (USB_ERR_IOERROR);
}
@@ -289,7 +289,7 @@ ehci_init_sub(struct ehci_softc *sc)
}
}
if (hcr) {
- device_printf(sc->sc_bus.bdev, "Run timeout\n");
+ device_printf(sc->sc_bus.bdev, "run timeout\n");
return (USB_ERR_IOERROR);
}
return (USB_ERR_NORMAL_COMPLETION);
diff --git a/freebsd/sys/dev/usb/controller/usb_controller.c b/freebsd/sys/dev/usb/controller/usb_controller.c
index c0fda652..90e09bb5 100644
--- a/freebsd/sys/dev/usb/controller/usb_controller.c
+++ b/freebsd/sys/dev/usb/controller/usb_controller.c
@@ -58,6 +58,7 @@
#include <dev/usb/usb_busdma.h>
#include <dev/usb/usb_dynamic.h>
#include <dev/usb/usb_device.h>
+#include <dev/usb/usb_dev.h>
#include <dev/usb/usb_hub.h>
#include <dev/usb/usb_controller.h>
@@ -130,7 +131,7 @@ DRIVER_MODULE(usbus, xhci, usb_driver, usb_devclass, 0, 0);
/* Device Only Drivers */
DRIVER_MODULE(usbus, at91_udp, usb_driver, usb_devclass, 0, 0);
DRIVER_MODULE(usbus, musbotg, usb_driver, usb_devclass, 0, 0);
-DRIVER_MODULE(usbus, uss820, usb_driver, usb_devclass, 0, 0);
+DRIVER_MODULE(usbus, uss820dci, usb_driver, usb_devclass, 0, 0);
/*------------------------------------------------------------------------*
* usb_probe
@@ -213,6 +214,11 @@ usb_detach(device_t dev)
usb_proc_mwait(&bus->explore_proc,
&bus->detach_msg[0], &bus->detach_msg[1]);
+#if USB_HAVE_UGEN
+ /* Wait for cleanup to complete */
+ usb_proc_mwait(&bus->explore_proc,
+ &bus->cleanup_msg[0], &bus->cleanup_msg[1]);
+#endif
USB_BUS_UNLOCK(bus);
/* Get rid of USB callback processes */
@@ -324,7 +330,7 @@ usb_shutdown(device_t dev)
return (0);
}
- device_printf(bus->bdev, "Controller shutdown\n");
+ DPRINTF("%s: Controller shutdown\n", device_get_nameunit(bus->bdev));
USB_BUS_LOCK(bus);
#ifndef __rtems__
@@ -338,7 +344,8 @@ usb_shutdown(device_t dev)
#endif /* __rtems__ */
USB_BUS_UNLOCK(bus);
- device_printf(bus->bdev, "Controller shutdown complete\n");
+ DPRINTF("%s: Controller shutdown complete\n",
+ device_get_nameunit(bus->bdev));
return (0);
}
@@ -624,6 +631,32 @@ usb_bus_shutdown(struct usb_proc_msg *pm)
USB_BUS_LOCK(bus);
}
+/*------------------------------------------------------------------------*
+ * usb_bus_cleanup
+ *
+ * This function is used to cleanup leftover USB character devices.
+ *------------------------------------------------------------------------*/
+#if USB_HAVE_UGEN
+static void
+usb_bus_cleanup(struct usb_proc_msg *pm)
+{
+ struct usb_bus *bus;
+ struct usb_fs_privdata *pd;
+
+ bus = ((struct usb_bus_msg *)pm)->bus;
+
+ while ((pd = LIST_FIRST(&bus->pd_cleanup_list)) != NULL) {
+
+ LIST_REMOVE(pd, pd_next);
+ USB_BUS_UNLOCK(bus);
+
+ usb_destroy_dev_sync(pd);
+
+ USB_BUS_LOCK(bus);
+ }
+}
+#endif
+
static void
usb_power_wdog(void *arg)
{
@@ -804,6 +837,14 @@ usb_attach_sub(device_t dev, struct usb_bus *bus)
bus->shutdown_msg[1].hdr.pm_callback = &usb_bus_shutdown;
bus->shutdown_msg[1].bus = bus;
+#if USB_HAVE_UGEN
+ LIST_INIT(&bus->pd_cleanup_list);
+ bus->cleanup_msg[0].hdr.pm_callback = &usb_bus_cleanup;
+ bus->cleanup_msg[0].bus = bus;
+ bus->cleanup_msg[1].hdr.pm_callback = &usb_bus_cleanup;
+ bus->cleanup_msg[1].bus = bus;
+#endif
+
/* Create USB explore and callback processes */
if (usb_proc_create(&bus->giant_callback_proc,
@@ -901,7 +942,7 @@ usb_bus_mem_alloc_all(struct usb_bus *bus, bus_dma_tag_t dmat,
#if USB_HAVE_BUSDMA
usb_dma_tag_setup(bus->dma_parent_tag, bus->dma_tags,
- dmat, &bus->bus_mtx, NULL, 32, USB_BUS_DMA_TAG_MAX);
+ dmat, &bus->bus_mtx, NULL, bus->dma_bits, USB_BUS_DMA_TAG_MAX);
#endif
if ((bus->devices_max > USB_MAX_DEVICES) ||
(bus->devices_max < USB_MIN_DEVICES) ||
diff --git a/freebsd/sys/dev/usb/controller/xhcireg.h b/freebsd/sys/dev/usb/controller/xhcireg.h
index bd1d635c..a0b73971 100644
--- a/freebsd/sys/dev/usb/controller/xhcireg.h
+++ b/freebsd/sys/dev/usb/controller/xhcireg.h
@@ -35,7 +35,9 @@
#define PCI_XHCI_FLADJ 0x61 /* RW frame length adjust */
#define PCI_XHCI_INTEL_XUSB2PR 0xD0 /* Intel USB2 Port Routing */
+#define PCI_XHCI_INTEL_USB2PRM 0xD4 /* Intel USB2 Port Routing Mask */
#define PCI_XHCI_INTEL_USB3_PSSEN 0xD8 /* Intel USB3 Port SuperSpeed Enable */
+#define PCI_XHCI_INTEL_USB3PRM 0xDC /* Intel USB3 Port Routing Mask */
/* XHCI capability registers */
#define XHCI_CAPLENGTH 0x00 /* RO capability */
diff --git a/freebsd/sys/dev/usb/quirk/usb_quirk.c b/freebsd/sys/dev/usb/quirk/usb_quirk.c
index 2f7ea792..7447ea80 100644
--- a/freebsd/sys/dev/usb/quirk/usb_quirk.c
+++ b/freebsd/sys/dev/usb/quirk/usb_quirk.c
@@ -61,7 +61,7 @@
MODULE_DEPEND(usb_quirk, usb, 1, 1, 1);
MODULE_VERSION(usb_quirk, 1);
-#define USB_DEV_QUIRKS_MAX 256
+#define USB_DEV_QUIRKS_MAX 384
#define USB_SUB_QUIRKS_MAX 8
struct usb_quirk_entry {
@@ -132,6 +132,8 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = {
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),
+ /* Quirk for Corsair Vengeance K70 keyboard */
+ USB_QUIRK(CORSAIR, K70, 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),
@@ -252,6 +254,7 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = {
USB_QUIRK(LEXAR, CF_READER, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_INQUIRY),
USB_QUIRK(LEXAR, JUMPSHOT, 0x0000, 0xffff, UQ_MSC_FORCE_PROTO_SCSI),
+ USB_QUIRK(LEXAR, JUMPDRIVE, 0x0000, 0xffff, UQ_MSC_NO_INQUIRY),
USB_QUIRK(LOGITEC, LDR_H443SU2, 0x0000, 0xffff, UQ_MSC_FORCE_PROTO_SCSI),
USB_QUIRK(LOGITEC, LDR_H443U2, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI,),
@@ -436,8 +439,28 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = {
USB_QUIRK(WESTERN, MYBOOK, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_INQUIRY_EVPD,
UQ_MSC_NO_SYNC_CACHE),
- USB_QUIRK(WESTERN, MYPASSWORD, 0x0000, 0xffff, UQ_MSC_FORCE_SHORT_INQ),
- USB_QUIRK(WESTERN, MYPASSPORT, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
+ USB_QUIRK(WESTERN, MYPASSPORT_00, 0x0000, 0xffff, UQ_MSC_FORCE_SHORT_INQ),
+ USB_QUIRK(WESTERN, MYPASSPORT_01, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
+ USB_QUIRK(WESTERN, MYPASSPORT_02, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
+ USB_QUIRK(WESTERN, MYPASSPORT_03, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
+ USB_QUIRK(WESTERN, MYPASSPORT_04, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
+ USB_QUIRK(WESTERN, MYPASSPORT_05, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
+ USB_QUIRK(WESTERN, MYPASSPORT_06, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
+ USB_QUIRK(WESTERN, MYPASSPORT_07, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
+ USB_QUIRK(WESTERN, MYPASSPORT_08, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
+ USB_QUIRK(WESTERN, MYPASSPORT_09, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
+ USB_QUIRK(WESTERN, MYPASSPORT_10, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
+ USB_QUIRK(WESTERN, MYPASSPORT_11, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
+ USB_QUIRK(WESTERN, MYPASSPORTES_00, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
+ USB_QUIRK(WESTERN, MYPASSPORTES_01, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
+ USB_QUIRK(WESTERN, MYPASSPORTES_02, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
+ USB_QUIRK(WESTERN, MYPASSPORTES_03, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
+ USB_QUIRK(WESTERN, MYPASSPORTES_04, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
+ USB_QUIRK(WESTERN, MYPASSPORTES_05, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
+ USB_QUIRK(WESTERN, MYPASSPORTES_06, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
+ USB_QUIRK(WESTERN, MYPASSPORTES_07, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
+ USB_QUIRK(WESTERN, MYPASSPORTES_08, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
+ USB_QUIRK(WESTERN, MYPASSPORTES_09, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
USB_QUIRK(WINMAXGROUP, FLASH64MC, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_INQUIRY),
USB_QUIRK(YANO, FW800HD, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
@@ -458,10 +481,11 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = {
UQ_MSC_FORCE_PROTO_ATAPI),
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(TOSHIBA, TRANSMEMORY, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE,
+ UQ_MSC_NO_PREVENT_ALLOW),
USB_QUIRK(VIALABS, USB30SATABRIDGE, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
-
+ USB_QUIRK(QUALCOMMINC, ZTE_MF730M, 0x0000, 0xffff, UQ_MSC_NO_GETMAXLUN,
+ UQ_MSC_NO_INQUIRY, UQ_CFG_INDEX_0),
/* 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),
@@ -565,6 +589,7 @@ static const char *usb_quirk_str[USB_QUIRK_MAX] = {
[UQ_MSC_EJECT_WAIT] = "UQ_MSC_EJECT_WAIT",
[UQ_MSC_EJECT_SAEL_M460] = "UQ_MSC_EJECT_SAEL_M460",
[UQ_MSC_EJECT_HUAWEISCSI] = "UQ_MSC_EJECT_HUAWEISCSI",
+ [UQ_MSC_EJECT_HUAWEISCSI2] = "UQ_MSC_EJECT_HUAWEISCSI2",
[UQ_MSC_EJECT_TCT] = "UQ_MSC_EJECT_TCT",
[UQ_BAD_MIDI] = "UQ_BAD_MIDI",
[UQ_AU_VENDOR_CLASS] = "UQ_AU_VENDOR_CLASS",
diff --git a/freebsd/sys/dev/usb/quirk/usb_quirk.h b/freebsd/sys/dev/usb/quirk/usb_quirk.h
index 32a60a10..bddc2c55 100644
--- a/freebsd/sys/dev/usb/quirk/usb_quirk.h
+++ b/freebsd/sys/dev/usb/quirk/usb_quirk.h
@@ -103,6 +103,7 @@ enum {
UQ_MSC_EJECT_WAIT, /* wait for the device to eject */
UQ_MSC_EJECT_SAEL_M460, /* ejects after Sael USB commands */
UQ_MSC_EJECT_HUAWEISCSI, /* ejects after Huawei SCSI command */
+ UQ_MSC_EJECT_HUAWEISCSI2, /* ejects after Huawei SCSI 2 command */
UQ_MSC_EJECT_TCT, /* ejects after TCT SCSI command */
UQ_BAD_MIDI, /* device claims MIDI class, but isn't */
diff --git a/freebsd/sys/dev/usb/usb_bus.h b/freebsd/sys/dev/usb/usb_bus.h
index 702f623d..0a7350c9 100644
--- a/freebsd/sys/dev/usb/usb_bus.h
+++ b/freebsd/sys/dev/usb/usb_bus.h
@@ -27,6 +27,8 @@
#ifndef _USB_BUS_H_
#define _USB_BUS_H_
+struct usb_fs_privdata;
+
/*
* The following structure defines the USB explore message sent to the USB
* explore process.
@@ -75,6 +77,10 @@ struct usb_bus {
struct usb_bus_msg resume_msg[2];
struct usb_bus_msg reset_msg[2];
struct usb_bus_msg shutdown_msg[2];
+#if USB_HAVE_UGEN
+ struct usb_bus_msg cleanup_msg[2];
+ LIST_HEAD(,usb_fs_privdata) pd_cleanup_list;
+#endif
/*
* This mutex protects the USB hardware:
*/
@@ -106,6 +112,7 @@ struct usb_bus {
uint8_t devices_max; /* maximum number of USB devices */
uint8_t do_probe; /* set if USB should be re-probed */
uint8_t no_explore; /* don't explore USB ports */
+ uint8_t dma_bits; /* number of DMA address lines */
};
#endif /* _USB_BUS_H_ */
diff --git a/freebsd/sys/dev/usb/usb_busdma.h b/freebsd/sys/dev/usb/usb_busdma.h
index 6b6e4039..ee420bc6 100644
--- a/freebsd/sys/dev/usb/usb_busdma.h
+++ b/freebsd/sys/dev/usb/usb_busdma.h
@@ -60,7 +60,7 @@ typedef void (usb_dma_callback_t)(struct usb_dma_parent_tag *udpt);
*/
struct usb_page {
#if USB_HAVE_BUSDMA
- bus_size_t physaddr;
+ bus_addr_t physaddr;
void *buffer; /* non Kernel Virtual Address */
#endif
};
@@ -73,7 +73,7 @@ struct usb_page {
struct usb_page_search {
void *buffer;
#if USB_HAVE_BUSDMA
- bus_size_t physaddr;
+ bus_addr_t physaddr;
#endif
usb_size_t length;
};
diff --git a/freebsd/sys/dev/usb/usb_core.h b/freebsd/sys/dev/usb/usb_core.h
index 48e5ee83..287e69f2 100644
--- a/freebsd/sys/dev/usb/usb_core.h
+++ b/freebsd/sys/dev/usb/usb_core.h
@@ -97,6 +97,7 @@ struct usb_xfer_flags_int {
* sent */
uint8_t control_act:1; /* set if control transfer is active */
uint8_t control_stall:1; /* set if control transfer should be stalled */
+ uint8_t control_did_data:1; /* set if control DATA has been transferred */
uint8_t short_frames_ok:1; /* filtered version */
uint8_t short_xfer_ok:1; /* filtered version */
diff --git a/freebsd/sys/dev/usb/usb_dev.c b/freebsd/sys/dev/usb/usb_dev.c
index 3ff064ee..ce107cf3 100644
--- a/freebsd/sys/dev/usb/usb_dev.c
+++ b/freebsd/sys/dev/usb/usb_dev.c
@@ -292,11 +292,15 @@ error:
usbd_enum_unlock(cpd->udev);
if (crd->is_uref) {
- cpd->udev->refcount--;
- cv_broadcast(&cpd->udev->ref_cv);
+ if (--(cpd->udev->refcount) == 0)
+ cv_broadcast(&cpd->udev->ref_cv);
}
mtx_unlock(&usb_ref_lock);
DPRINTFN(2, "fail\n");
+
+ /* clear all refs */
+ memset(crd, 0, sizeof(*crd));
+
return (USB_ERR_INVAL);
}
@@ -360,8 +364,8 @@ usb_unref_device(struct usb_cdev_privdata *cpd,
}
if (crd->is_uref) {
crd->is_uref = 0;
- cpd->udev->refcount--;
- cv_broadcast(&cpd->udev->ref_cv);
+ if (--(cpd->udev->refcount) == 0)
+ cv_broadcast(&cpd->udev->ref_cv);
}
mtx_unlock(&usb_ref_lock);
}
@@ -587,12 +591,12 @@ usb_fifo_free(struct usb_fifo *f)
/* decrease refcount */
f->refcount--;
- /* prevent any write flush */
- f->flag_iserror = 1;
/* need to wait until all callers have exited */
while (f->refcount != 0) {
mtx_unlock(&usb_ref_lock); /* avoid LOR */
mtx_lock(f->priv_mtx);
+ /* prevent write flush, if any */
+ f->flag_iserror = 1;
/* get I/O thread out of any sleep state */
if (f->flag_sleeping) {
f->flag_sleeping = 0;
@@ -1092,8 +1096,8 @@ usb_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int fflag, struct thread*
goto done;
if (usb_usb_ref_device(cpd, &refs)) {
- err = ENXIO;
- goto done;
+ /* we lost the reference */
+ return (ENXIO);
}
err = (f->methods->f_ioctl_post) (f, cmd, addr, fflags);
@@ -1116,9 +1120,8 @@ usb_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int fflag, struct thread*
while (usb_ref_device(cpd, &refs, 1 /* need uref */)) {
if (usb_ref_device(cpd, &refs, 0)) {
- /* device no longer exits */
- err = ENXIO;
- goto done;
+ /* device no longer exists */
+ return (ENXIO);
}
usb_unref_device(cpd, &refs);
usb_pause_mtx(NULL, hz / 128);
@@ -1410,9 +1413,9 @@ usb_read(struct cdev *dev, struct uio *uio, int ioflag)
return (err);
err = usb_ref_device(cpd, &refs, 0 /* no uref */ );
- if (err) {
+ if (err)
return (ENXIO);
- }
+
fflags = cpd->fflags;
f = refs.rxfifo;
@@ -1536,9 +1539,9 @@ usb_write(struct cdev *dev, struct uio *uio, int ioflag)
return (err);
err = usb_ref_device(cpd, &refs, 0 /* no uref */ );
- if (err) {
+ if (err)
return (ENXIO);
- }
+
fflags = cpd->fflags;
f = refs.txfifo;
diff --git a/freebsd/sys/dev/usb/usb_device.c b/freebsd/sys/dev/usb/usb_device.c
index e18c32df..8e0144cc 100644
--- a/freebsd/sys/dev/usb/usb_device.c
+++ b/freebsd/sys/dev/usb/usb_device.c
@@ -437,60 +437,28 @@ usb_endpoint_foreach(struct usb_device *udev, struct usb_endpoint *ep)
}
/*------------------------------------------------------------------------*
- * usb_wait_pending_ref_locked
+ * usb_wait_pending_refs
*
* This function will wait for any USB references to go away before
- * returning and disable further USB device refcounting on the
- * specified USB device. This function is used when detaching a USB
- * device.
+ * returning. This function is used before freeing a USB device.
*------------------------------------------------------------------------*/
static void
-usb_wait_pending_ref_locked(struct usb_device *udev)
+usb_wait_pending_refs(struct usb_device *udev)
{
#if USB_HAVE_UGEN
- const uint16_t refcount =
- usb_proc_is_called_from(
- &udev->bus->explore_proc) ? 1 : 2;
-
- DPRINTF("Refcount = %d\n", (int)refcount);
+ DPRINTF("Refcount = %d\n", (int)udev->refcount);
+ mtx_lock(&usb_ref_lock);
+ udev->refcount--;
while (1) {
/* wait for any pending references to go away */
- mtx_lock(&usb_ref_lock);
- if (udev->refcount == refcount) {
- /* prevent further refs being taken */
+ if (udev->refcount == 0) {
+ /* prevent further refs being taken, if any */
udev->refcount = USB_DEV_REF_MAX;
- mtx_unlock(&usb_ref_lock);
break;
}
- usbd_enum_unlock(udev);
cv_wait(&udev->ref_cv, &usb_ref_lock);
- mtx_unlock(&usb_ref_lock);
- (void) usbd_enum_lock(udev);
}
-#endif
-}
-
-/*------------------------------------------------------------------------*
- * usb_ref_restore_locked
- *
- * This function will restore the reference count value after a call
- * to "usb_wait_pending_ref_locked()".
- *------------------------------------------------------------------------*/
-static void
-usb_ref_restore_locked(struct usb_device *udev)
-{
-#if USB_HAVE_UGEN
- const uint16_t refcount =
- usb_proc_is_called_from(
- &udev->bus->explore_proc) ? 1 : 2;
-
- DPRINTF("Refcount = %d\n", (int)refcount);
-
- /* restore reference count and wakeup waiters, if any */
- mtx_lock(&usb_ref_lock);
- udev->refcount = refcount;
- cv_broadcast(&udev->ref_cv);
mtx_unlock(&usb_ref_lock);
#endif
}
@@ -844,9 +812,6 @@ usb_config_parse(struct usb_device *udev, uint8_t iface_index, uint8_t cmd)
/* find maximum number of endpoints */
if (ep_max < temp)
ep_max = temp;
-
- /* optimalisation */
- id = (struct usb_interface_descriptor *)ed;
}
}
@@ -1100,10 +1065,12 @@ usb_detach_device_sub(struct usb_device *udev, device_t *ppdev,
*/
*ppdev = NULL;
- device_printf(dev, "at %s, port %d, addr %d "
- "(disconnected)\n",
- device_get_nameunit(udev->parent_dev),
- udev->port_no, udev->address);
+ if (!rebooting) {
+ device_printf(dev, "at %s, port %d, addr %d "
+ "(disconnected)\n",
+ device_get_nameunit(udev->parent_dev),
+ udev->port_no, udev->address);
+ }
if (device_is_attached(dev)) {
if (udev->flags.peer_suspended) {
@@ -1156,9 +1123,6 @@ usb_detach_device(struct usb_device *udev, uint8_t iface_index,
sx_assert(&udev->enum_sx, SA_LOCKED);
- /* wait for pending refs to go away */
- usb_wait_pending_ref_locked(udev);
-
/*
* First detach the child to give the child's detach routine a
* chance to detach the sub-devices in the correct order.
@@ -1185,8 +1149,6 @@ usb_detach_device(struct usb_device *udev, uint8_t iface_index,
usb_detach_device_sub(udev, &iface->subdev,
&iface->pnpinfo, flag);
}
-
- usb_ref_restore_locked(udev);
}
/*------------------------------------------------------------------------*
@@ -1999,14 +1961,46 @@ usb_make_dev(struct usb_device *udev, const char *devname, int ep,
}
void
+usb_destroy_dev_sync(struct usb_fs_privdata *pd)
+{
+ DPRINTFN(1, "Destroying device at ugen%d.%d\n",
+ pd->bus_index, pd->dev_index);
+
+ /*
+ * Destroy character device synchronously. After this
+ * all system calls are returned. Can block.
+ */
+ destroy_dev(pd->cdev);
+
+ free(pd, M_USBDEV);
+}
+
+void
usb_destroy_dev(struct usb_fs_privdata *pd)
{
+ struct usb_bus *bus;
+
if (pd == NULL)
return;
- destroy_dev(pd->cdev);
+ mtx_lock(&usb_ref_lock);
+ bus = devclass_get_softc(usb_devclass_ptr, pd->bus_index);
+ mtx_unlock(&usb_ref_lock);
- free(pd, M_USBDEV);
+ if (bus == NULL) {
+ usb_destroy_dev_sync(pd);
+ return;
+ }
+
+ /* make sure we can re-use the device name */
+ delist_dev(pd->cdev);
+
+ USB_BUS_LOCK(bus);
+ LIST_INSERT_HEAD(&bus->pd_cleanup_list, pd, pd_next);
+ /* get cleanup going */
+ usb_proc_msignal(&bus->explore_proc,
+ &bus->cleanup_msg[0], &bus->cleanup_msg[1]);
+ USB_BUS_UNLOCK(bus);
}
static void
@@ -2115,8 +2109,10 @@ usb_free_device(struct usb_device *udev, uint8_t flag)
#endif
#if USB_HAVE_UGEN
- printf("%s: <%s> at %s (disconnected)\n", udev->ugen_name,
- usb_get_manufacturer(udev), device_get_nameunit(bus->bdev));
+ if (!rebooting) {
+ printf("%s: <%s> at %s (disconnected)\n", udev->ugen_name,
+ usb_get_manufacturer(udev), device_get_nameunit(bus->bdev));
+ }
/* Destroy UGEN symlink, if any */
if (udev->ugen_symlink) {
@@ -2155,6 +2151,9 @@ usb_free_device(struct usb_device *udev, uint8_t flag)
&udev->cs_msg[0], &udev->cs_msg[1]);
USB_BUS_UNLOCK(udev->bus);
+ /* wait for all references to go away */
+ usb_wait_pending_refs(udev);
+
sx_destroy(&udev->enum_sx);
sx_destroy(&udev->sr_sx);
@@ -2640,14 +2639,8 @@ usb_fifo_free_wrap(struct usb_device *udev,
/* no need to free this FIFO */
continue;
}
- /* wait for pending refs to go away */
- usb_wait_pending_ref_locked(udev);
-
/* free this FIFO */
usb_fifo_free(f);
-
- /* restore refcount */
- usb_ref_restore_locked(udev);
}
}
#endif
diff --git a/freebsd/sys/dev/usb/usb_device.h b/freebsd/sys/dev/usb/usb_device.h
index 361f5c3c..309bd057 100644
--- a/freebsd/sys/dev/usb/usb_device.h
+++ b/freebsd/sys/dev/usb/usb_device.h
@@ -281,6 +281,7 @@ struct usb_device *usb_alloc_device(device_t parent_dev, struct usb_bus *bus,
struct usb_fs_privdata *usb_make_dev(struct usb_device *, const char *,
int, int, int, uid_t, gid_t, int);
void usb_destroy_dev(struct usb_fs_privdata *);
+void usb_destroy_dev_sync(struct usb_fs_privdata *);
#endif
usb_error_t usb_probe_and_attach(struct usb_device *udev,
uint8_t iface_index);
diff --git a/freebsd/sys/dev/usb/usb_dynamic.c b/freebsd/sys/dev/usb/usb_dynamic.c
index 32ff5e6a..65c9a7d7 100644
--- a/freebsd/sys/dev/usb/usb_dynamic.c
+++ b/freebsd/sys/dev/usb/usb_dynamic.c
@@ -66,7 +66,7 @@ usb_temp_setup_by_index_t *usb_temp_setup_by_index_p = &usb_temp_setup_by_index_
usb_temp_unsetup_t *usb_temp_unsetup_p = &usb_temp_unsetup_w;
usb_test_quirk_t *usb_test_quirk_p = &usb_test_quirk_w;
usb_quirk_ioctl_t *usb_quirk_ioctl_p = &usb_quirk_ioctl_w;
-devclass_t usb_devclass_ptr = NULL;
+devclass_t usb_devclass_ptr;
static usb_error_t
usb_temp_setup_by_index_w(struct usb_device *udev, uint16_t index)
diff --git a/freebsd/sys/dev/usb/usb_freebsd.h b/freebsd/sys/dev/usb/usb_freebsd.h
index 4cd1758a..ed2c6bba 100644
--- a/freebsd/sys/dev/usb/usb_freebsd.h
+++ b/freebsd/sys/dev/usb/usb_freebsd.h
@@ -73,7 +73,7 @@
#define USB_EP0_BUFSIZE 1024 /* bytes */
#define USB_CS_RESET_LIMIT 20 /* failures = 20 * 50 ms = 1sec */
-#define USB_MAX_AUTO_QUIRK 4 /* maximum number of dynamic quirks */
+#define USB_MAX_AUTO_QUIRK 8 /* maximum number of dynamic quirks */
typedef uint32_t usb_timeout_t; /* milliseconds */
typedef uint32_t usb_frlength_t; /* bytes */
diff --git a/freebsd/sys/dev/usb/usb_generic.c b/freebsd/sys/dev/usb/usb_generic.c
index e1fc141f..d6172908 100644
--- a/freebsd/sys/dev/usb/usb_generic.c
+++ b/freebsd/sys/dev/usb/usb_generic.c
@@ -1839,14 +1839,13 @@ ugen_get_port_path(struct usb_fifo *f, struct usb_device_port_path *dpp)
if (nlevel > USB_DEVICE_PORT_PATH_MAX)
goto error;
+ /* store total level of ports */
+ dpp->udp_port_level = nlevel;
+
/* store port index array */
next = udev;
while (next->parent_hub != NULL) {
- nlevel--;
-
- dpp->udp_port_no[nlevel] = next->port_no;
- dpp->udp_port_level = nlevel;
-
+ dpp->udp_port_no[--nlevel] = next->port_no;
next = next->parent_hub;
}
return (0); /* success */
diff --git a/freebsd/sys/dev/usb/usb_hub.c b/freebsd/sys/dev/usb/usb_hub.c
index 9b3bd076..0c62ee08 100644
--- a/freebsd/sys/dev/usb/usb_hub.c
+++ b/freebsd/sys/dev/usb/usb_hub.c
@@ -603,7 +603,6 @@ uhub_reattach_port(struct uhub_softc *sc, uint8_t portno)
DPRINTF("reattaching port %d\n", portno);
- err = 0;
timeout = 0;
udev = sc->sc_udev;
child = usb_bus_port_get_device(udev->bus,
@@ -1595,6 +1594,7 @@ uhub_child_location_string(device_t parent, device_t child,
struct uhub_softc *sc;
struct usb_hub *hub;
struct hub_result res;
+ char *ugen_name;
if (!device_is_attached(parent)) {
if (buflen)
@@ -1614,10 +1614,16 @@ uhub_child_location_string(device_t parent, device_t child,
}
goto done;
}
- snprintf(buf, buflen, "bus=%u hubaddr=%u port=%u devaddr=%u interface=%u",
+#if USB_HAVE_UGEN
+ ugen_name = res.udev->ugen_name;
+#else
+ ugen_name = "?";
+#endif
+ snprintf(buf, buflen, "bus=%u hubaddr=%u port=%u devaddr=%u interface=%u"
+ " ugen=%s",
(res.udev->parent_hub != NULL) ? res.udev->parent_hub->device_index : 0,
res.portno, device_get_unit(res.udev->bus->bdev),
- res.udev->device_index, res.iface_index);
+ res.udev->device_index, res.iface_index, ugen_name);
done:
mtx_unlock(&Giant);
@@ -1659,7 +1665,7 @@ uhub_child_pnpinfo_string(device_t parent, device_t child,
"release=0x%04x "
"mode=%s "
"intclass=0x%02x intsubclass=0x%02x "
- "intprotocol=0x%02x " "%s%s",
+ "intprotocol=0x%02x" "%s%s",
UGETW(res.udev->ddesc.idVendor),
UGETW(res.udev->ddesc.idProduct),
res.udev->ddesc.bDeviceClass,
diff --git a/freebsd/sys/dev/usb/usb_msctest.c b/freebsd/sys/dev/usb/usb_msctest.c
index 4d28346c..19accddf 100644
--- a/freebsd/sys/dev/usb/usb_msctest.c
+++ b/freebsd/sys/dev/usb/usb_msctest.c
@@ -100,6 +100,9 @@ static uint8_t scsi_cmotech_eject[] = { 0xff, 0x52, 0x44, 0x45, 0x56, 0x43,
static uint8_t scsi_huawei_eject[] = { 0x11, 0x06, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };
+static uint8_t scsi_huawei_eject2[] = { 0x11, 0x06, 0x20, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00 };
static uint8_t scsi_tct_eject[] = { 0x06, 0xf5, 0x04, 0x02, 0x52, 0x70 };
static uint8_t scsi_sync_cache[] = { 0x35, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };
@@ -107,6 +110,8 @@ 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 };
+static uint8_t scsi_prevent_removal[] = { 0x1e, 0, 0, 0, 1, 0 };
+static uint8_t scsi_allow_removal[] = { 0x1e, 0, 0, 0, 0, 0 };
#define BULK_SIZE 64 /* dummy */
#define ERR_CSW_FAILED -1
@@ -479,6 +484,7 @@ bbb_command_start(struct bbb_transfer *sc, uint8_t dir, uint8_t lun,
sc->data_rem = data_len;
sc->data_timeout = (data_timeout + USB_MS_HZ);
sc->actlen = 0;
+ sc->error = 0;
sc->cmd_len = cmd_len;
memset(&sc->cbw->CBWCDB, 0, sizeof(sc->cbw->CBWCDB));
memcpy(&sc->cbw->CBWCDB, cmd_ptr, cmd_len);
@@ -689,10 +695,28 @@ usb_msc_auto_quirk(struct usb_device *udev, uint8_t iface_index)
USB_MS_HZ);
if (err != 0) {
+ if (err != ERR_CSW_FAILED)
+ goto error;
+ DPRINTF("Test unit ready failed\n");
+ }
+
+ err = bbb_command_start(sc, DIR_OUT, 0, NULL, 0,
+ &scsi_prevent_removal, sizeof(scsi_prevent_removal),
+ USB_MS_HZ);
+
+ if (err == 0) {
+ err = bbb_command_start(sc, DIR_OUT, 0, NULL, 0,
+ &scsi_allow_removal, sizeof(scsi_allow_removal),
+ USB_MS_HZ);
+ }
+ if (err != 0) {
if (err != ERR_CSW_FAILED)
goto error;
+ DPRINTF("Device doesn't handle prevent and allow removal\n");
+ usbd_add_dynamic_quirk(udev, UQ_MSC_NO_PREVENT_ALLOW);
}
+
timeout = 1;
retry_sync_cache:
@@ -708,7 +732,6 @@ retry_sync_cache:
DPRINTF("Device doesn't handle synchronize cache\n");
usbd_add_dynamic_quirk(udev, UQ_MSC_NO_SYNC_CACHE);
-
} else {
/*
@@ -782,6 +805,7 @@ error:
DPRINTF("Device did not respond, enabling all quirks\n");
usbd_add_dynamic_quirk(udev, UQ_MSC_NO_SYNC_CACHE);
+ usbd_add_dynamic_quirk(udev, UQ_MSC_NO_PREVENT_ALLOW);
usbd_add_dynamic_quirk(udev, UQ_MSC_NO_TEST_UNIT_READY);
/* Need to re-enumerate the device */
@@ -800,7 +824,6 @@ usb_msc_eject(struct usb_device *udev, uint8_t iface_index, int method)
if (sc == NULL)
return (USB_ERR_INVAL);
- err = 0;
switch (method) {
case MSC_EJECT_STOPUNIT:
err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
@@ -831,6 +854,11 @@ usb_msc_eject(struct usb_device *udev, uint8_t iface_index, int method)
&scsi_huawei_eject, sizeof(scsi_huawei_eject),
USB_MS_HZ);
break;
+ case MSC_EJECT_HUAWEI2:
+ err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
+ &scsi_huawei_eject2, sizeof(scsi_huawei_eject2),
+ USB_MS_HZ);
+ break;
case MSC_EJECT_TCT:
/*
* TCTMobile needs DIR_IN flag. To get it, we
@@ -841,9 +869,11 @@ usb_msc_eject(struct usb_device *udev, uint8_t iface_index, int method)
sizeof(scsi_tct_eject), USB_MS_HZ);
break;
default:
- printf("usb_msc_eject: unknown eject method (%d)\n", method);
- break;
+ DPRINTF("Unknown eject method (%d)\n", method);
+ bbb_detach(sc);
+ return (USB_ERR_INVAL);
}
+
DPRINTF("Eject CD command status: %s\n", usbd_errstr(err));
bbb_detach(sc);
diff --git a/freebsd/sys/dev/usb/usb_msctest.h b/freebsd/sys/dev/usb/usb_msctest.h
index e4a717fe..4f64f842 100644
--- a/freebsd/sys/dev/usb/usb_msctest.h
+++ b/freebsd/sys/dev/usb/usb_msctest.h
@@ -33,6 +33,7 @@ enum {
MSC_EJECT_ZTESTOR,
MSC_EJECT_CMOTECH,
MSC_EJECT_HUAWEI,
+ MSC_EJECT_HUAWEI2,
MSC_EJECT_TCT,
};
diff --git a/freebsd/sys/dev/usb/usb_process.c b/freebsd/sys/dev/usb/usb_process.c
index d36df36e..a5426e1e 100644
--- a/freebsd/sys/dev/usb/usb_process.c
+++ b/freebsd/sys/dev/usb/usb_process.c
@@ -26,8 +26,6 @@
* SUCH DAMAGE.
*/
-#define USB_DEBUG_VAR usb_proc_debug
-
#include <sys/stdint.h>
#include <sys/stddef.h>
#include <rtems/bsd/sys/param.h>
@@ -51,6 +49,8 @@
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdi_util.h>
#include <dev/usb/usb_process.h>
+
+#define USB_DEBUG_VAR usb_proc_debug
#include <dev/usb/usb_debug.h>
#include <dev/usb/usb_util.h>
diff --git a/freebsd/sys/dev/usb/usb_request.c b/freebsd/sys/dev/usb/usb_request.c
index e9137bd2..6f9d7b12 100644
--- a/freebsd/sys/dev/usb/usb_request.c
+++ b/freebsd/sys/dev/usb/usb_request.c
@@ -806,8 +806,6 @@ usbd_req_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port)
/* check for errors */
if (err)
goto done;
-#ifdef USB_DEBUG
-#endif
n = 0;
while (1) {
/* wait for the device to recover from reset */
diff --git a/freebsd/sys/dev/usb/usb_transfer.c b/freebsd/sys/dev/usb/usb_transfer.c
index 205a72f7..ab5558e1 100644
--- a/freebsd/sys/dev/usb/usb_transfer.c
+++ b/freebsd/sys/dev/usb/usb_transfer.c
@@ -945,7 +945,8 @@ usbd_transfer_setup(struct usb_device *udev,
#if USB_HAVE_BUSDMA
usb_dma_tag_setup(&info->dma_parent_tag,
parm->dma_tag_p, udev->bus->dma_parent_tag[0].tag,
- xfer_mtx, &usb_bdma_done_event, 32, parm->dma_tag_max);
+ xfer_mtx, &usb_bdma_done_event, udev->bus->dma_bits,
+ parm->dma_tag_max);
#endif
info->bus = udev->bus;
@@ -1374,6 +1375,29 @@ usbd_control_transfer_init(struct usb_xfer *xfer)
}
/*------------------------------------------------------------------------*
+ * usbd_control_transfer_did_data
+ *
+ * This function returns non-zero if a control endpoint has
+ * transferred the first DATA packet after the SETUP packet.
+ * Else it returns zero.
+ *------------------------------------------------------------------------*/
+static uint8_t
+usbd_control_transfer_did_data(struct usb_xfer *xfer)
+{
+ struct usb_device_request req;
+
+ /* SETUP packet is not yet sent */
+ if (xfer->flags_int.control_hdr != 0)
+ return (0);
+
+ /* copy out the USB request header */
+ usbd_copy_out(xfer->frbuffers, 0, &req, sizeof(req));
+
+ /* compare remainder to the initial value */
+ return (xfer->flags_int.control_rem != UGETW(req.wLength));
+}
+
+/*------------------------------------------------------------------------*
* usbd_setup_ctrl_transfer
*
* This function handles initialisation of control transfers. Control
@@ -1478,6 +1502,11 @@ usbd_setup_ctrl_transfer(struct usb_xfer *xfer)
len = (xfer->sumlen - sizeof(struct usb_device_request));
}
+ /* update did data flag */
+
+ xfer->flags_int.control_did_data =
+ usbd_control_transfer_did_data(xfer);
+
/* check if there is a length mismatch */
if (len > xfer->flags_int.control_rem) {