summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authorthompsa <thompsa@FreeBSD.org>2010-01-06 22:14:05 +0000
committerthompsa <thompsa@FreeBSD.org>2010-01-06 22:14:05 +0000
commitf9e6c6a249caaf137a522b43d20cd40c4d8611c3 (patch)
tree54c711c0bb9a6b4a61ebef1a9c10d5d4a4a96c58 /sys/dev
parentc6572afc18dd829baa4b852e6c8478d4f3d10095 (diff)
downloadFreeBSD-src-f9e6c6a249caaf137a522b43d20cd40c4d8611c3.zip
FreeBSD-src-f9e6c6a249caaf137a522b43d20cd40c4d8611c3.tar.gz
Improve u3g device ejecting by providing additional methods for the eject
command in the usb_msctest routines, as well as a general tidyup. This now properly ejects the ZTE MF636, Option Gi0322 and Novatel MC950D devices I have on my desk.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/usb/serial/u3g.c231
-rw-r--r--sys/dev/usb/usb_device.c2
-rw-r--r--sys/dev/usb/usb_msctest.c258
-rw-r--r--sys/dev/usb/usb_msctest.h13
4 files changed, 283 insertions, 221 deletions
diff --git a/sys/dev/usb/serial/u3g.c b/sys/dev/usb/serial/u3g.c
index 5b61948..5d2c81c 100644
--- a/sys/dev/usb/serial/u3g.c
+++ b/sys/dev/usb/serial/u3g.c
@@ -86,10 +86,14 @@ SYSCTL_INT(_hw_usb_u3g, OID_AUTO, debug, CTLFLAG_RW,
#define U3GSP_HSPA 6
#define U3GSP_MAX 7
-#define U3GFL_HUAWEI_INIT 0x0001 /* Init command required */
-#define U3GFL_SCSI_EJECT 0x0002 /* SCSI eject command required */
-#define U3GFL_SIERRA_INIT 0x0004 /* Init command required */
-#define U3GFL_SAEL_M460_INIT 0x0008 /* Init device */
+#define U3GINIT_HUAWEI 1 /* Requires Huawei init command */
+#define U3GINIT_SIERRA 2 /* Requires Sierra init command */
+#define U3GINIT_SCSIEJECT 3 /* Requires SCSI eject command */
+#define U3GINIT_REZERO 4 /* Requires SCSI rezero command */
+#define U3GINIT_ZTESTOR 5 /* Requires ZTE SCSI command */
+#define U3GINIT_CMOTECH 6 /* Requires CMOTECH SCSI command */
+#define U3GINIT_WAIT 7 /* Device reappears after a delay */
+#define U3GINIT_SAEL_M460 8 /* Requires vendor init */
enum {
U3G_BULK_WR,
@@ -192,6 +196,7 @@ static const struct usb_device_id u3g_devs[] = {
U3G_DEV(ANYDATA, ADU_E100X, 0),
U3G_DEV(AXESSTEL, DATAMODEM, 0),
U3G_DEV(CMOTECH, CDMA_MODEM1, 0),
+ U3G_DEV(CMOTECH, CGU628, U3GINIT_CMOTECH),
U3G_DEV(DELL, U5500, 0),
U3G_DEV(DELL, U5505, 0),
U3G_DEV(DELL, U5510, 0),
@@ -211,73 +216,73 @@ static const struct usb_device_id u3g_devs[] = {
U3G_DEV(DLINK3, DWM652, 0),
U3G_DEV(HP, EV2200, 0),
U3G_DEV(HP, HS2300, 0),
- U3G_DEV(HUAWEI, E1401, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1402, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1403, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1404, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1405, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1406, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1407, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1408, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1409, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E140A, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E140B, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E140D, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E140E, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E140F, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1410, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1411, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1412, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1413, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1414, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1415, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1416, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1417, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1418, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1419, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E141A, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E141B, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E141C, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E141D, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E141E, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E141F, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1420, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1421, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1422, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1423, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1424, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1425, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1426, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1427, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1428, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1429, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E142A, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E142B, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E142C, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E142D, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E142E, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E142F, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1430, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1431, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1432, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1433, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1434, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1435, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1436, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1437, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1438, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E1439, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E143A, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E143B, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E143C, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E143D, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E143E, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E143F, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E14AC, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E180V, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E220, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, E220BIS, U3GFL_HUAWEI_INIT),
- U3G_DEV(HUAWEI, MOBILE, U3GFL_HUAWEI_INIT),
+ U3G_DEV(HUAWEI, E1401, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1402, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1403, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1404, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1405, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1406, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1407, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1408, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1409, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E140A, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E140B, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E140D, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E140E, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E140F, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1410, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1411, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1412, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1413, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1414, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1415, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1416, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1417, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1418, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1419, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E141A, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E141B, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E141C, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E141D, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E141E, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E141F, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1420, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1421, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1422, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1423, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1424, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1425, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1426, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1427, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1428, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1429, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E142A, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E142B, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E142C, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E142D, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E142E, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E142F, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1430, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1431, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1432, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1433, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1434, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1435, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1436, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1437, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1438, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E1439, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E143A, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E143B, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E143C, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E143D, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E143E, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E143F, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E14AC, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E180V, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E220, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, E220BIS, U3GINIT_HUAWEI),
+ U3G_DEV(HUAWEI, MOBILE, U3GINIT_HUAWEI),
U3G_DEV(KYOCERA2, CDMA_MSM_K, 0),
U3G_DEV(KYOCERA2, KPC680, 0),
U3G_DEV(MERLIN, V620, 0),
@@ -294,7 +299,7 @@ static const struct usb_device_id u3g_devs[] = {
U3G_DEV(NOVATEL, U727_2, 0),
U3G_DEV(NOVATEL, U740, 0),
U3G_DEV(NOVATEL, U740_2, 0),
- U3G_DEV(NOVATEL, U760, U3GFL_SCSI_EJECT),
+ U3G_DEV(NOVATEL, U760, U3GINIT_SCSIEJECT),
U3G_DEV(NOVATEL, U870, 0),
U3G_DEV(NOVATEL, V620, 0),
U3G_DEV(NOVATEL, V640, 0),
@@ -338,7 +343,7 @@ static const struct usb_device_id u3g_devs[] = {
U3G_DEV(QUALCOMMINC, AC2726, 0),
U3G_DEV(QUALCOMMINC, AC8700, 0),
U3G_DEV(QUALCOMMINC, AC8710, 0),
- U3G_DEV(QUALCOMMINC, CDMA_MSM, U3GFL_SCSI_EJECT),
+ U3G_DEV(QUALCOMMINC, CDMA_MSM, U3GINIT_SCSIEJECT),
U3G_DEV(QUALCOMMINC, E0002, 0),
U3G_DEV(QUALCOMMINC, E0003, 0),
U3G_DEV(QUALCOMMINC, E0004, 0),
@@ -405,7 +410,6 @@ static const struct usb_device_id u3g_devs[] = {
U3G_DEV(QUALCOMMINC, E2003, 0),
U3G_DEV(QUALCOMMINC, MF626, 0),
U3G_DEV(QUALCOMMINC, MF628, 0),
- U3G_DEV(QUALCOMMINC, ZTE_STOR, U3GFL_SCSI_EJECT),
U3G_DEV(QUANTA, GKE, 0),
U3G_DEV(QUANTA, GLE, 0),
U3G_DEV(QUANTA, GLX, 0),
@@ -466,7 +470,7 @@ static const struct usb_device_id u3g_devs[] = {
U3G_DEV(SIERRA, MINI5725, 0),
U3G_DEV(SIERRA, T11, 0),
U3G_DEV(SIERRA, T598, 0),
- U3G_DEV(SILABS, SAEL, U3GFL_SAEL_M460_INIT),
+ U3G_DEV(SILABS, SAEL, U3GINIT_SAEL_M460),
U3G_DEV(STELERA, C105, 0),
U3G_DEV(STELERA, E1003, 0),
U3G_DEV(STELERA, E1004, 0),
@@ -492,12 +496,14 @@ static const struct usb_device_id u3g_devs[] = {
U3G_DEV(TOSHIBA, HSDPA, 0),
U3G_DEV(YISO, C893, 0),
/* Autoinstallers */
- U3G_DEV(NOVATEL, ZEROCD, U3GFL_SCSI_EJECT),
- U3G_DEV(SIERRA, TRUINSTALL, U3GFL_SIERRA_INIT),
+ U3G_DEV(NOVATEL, ZEROCD, U3GINIT_SCSIEJECT),
+ U3G_DEV(OPTION, GTICON322, U3GINIT_REZERO),
+ U3G_DEV(QUALCOMMINC, ZTE_STOR, U3GINIT_ZTESTOR),
+ U3G_DEV(SIERRA, TRUINSTALL, U3GINIT_SIERRA),
#undef U3G_DEV
};
-static void
+static int
u3g_sierra_init(struct usb_device *udev)
{
struct usb_device_request req;
@@ -512,10 +518,10 @@ u3g_sierra_init(struct usb_device *udev)
NULL, 0, NULL, USB_MS_HZ)) {
/* ignore any errors */
}
- return;
+ return (0);
}
-static void
+static int
u3g_huawei_init(struct usb_device *udev)
{
struct usb_device_request req;
@@ -530,7 +536,7 @@ u3g_huawei_init(struct usb_device *udev)
NULL, 0, NULL, USB_MS_HZ)) {
/* ignore any errors */
}
- return;
+ return (0);
}
static void
@@ -625,7 +631,7 @@ u3g_test_autoinst(void *arg, struct usb_device *udev,
{
struct usb_interface *iface;
struct usb_interface_descriptor *id;
- uint32_t flags;
+ int error;
if (uaa->dev_state != UAA_DEV_READY)
return;
@@ -636,25 +642,41 @@ u3g_test_autoinst(void *arg, struct usb_device *udev,
id = iface->idesc;
if (id == NULL || id->bInterfaceClass != UICLASS_MASS)
return;
- if (usbd_lookup_id_by_uaa(u3g_devs, sizeof(u3g_devs), uaa)) {
- /* no device match */
- return;
+ if (usbd_lookup_id_by_uaa(u3g_devs, sizeof(u3g_devs), uaa))
+ return; /* no device match */
+
+ switch (USB_GET_DRIVER_INFO(uaa)) {
+ case U3GINIT_HUAWEI:
+ error = u3g_huawei_init(udev);
+ break;
+ case U3GINIT_SCSIEJECT:
+ error = usb_msc_eject(udev, 0, MSC_EJECT_STOPUNIT);
+ break;
+ case U3GINIT_REZERO:
+ error = usb_msc_eject(udev, 0, MSC_EJECT_REZERO);
+ break;
+ case U3GINIT_ZTESTOR:
+ error = usb_msc_eject(udev, 0, MSC_EJECT_ZTESTOR);
+ break;
+ case U3GINIT_CMOTECH:
+ error = usb_msc_eject(udev, 0, MSC_EJECT_CMOTECH);
+ break;
+ case U3GINIT_SIERRA:
+ error = u3g_sierra_init(udev);
+ break;
+ case U3GINIT_WAIT:
+ /* Just pretend we ejected, the card will timeout */
+ error = 0;
+ break;
+ default:
+ /* no 3G eject quirks */
+ error = EOPNOTSUPP;
+ break;
}
- flags = USB_GET_DRIVER_INFO(uaa);
-
- if (flags & U3GFL_HUAWEI_INIT) {
- u3g_huawei_init(udev);
- } else if (flags & U3GFL_SCSI_EJECT) {
- if (usb_test_autoinstall(udev, 0, 1) != 0)
- return;
- } else if (flags & U3GFL_SIERRA_INIT) {
- u3g_sierra_init(udev);
- } else {
- /* no quirks */
- return;
+ if (error == 0) {
+ /* success, mark the udev as disappearing */
+ uaa->dev_state = UAA_DEV_EJECTING;
}
- uaa->dev_state = UAA_DEV_EJECTING;
- return; /* success */
}
static int
@@ -701,15 +723,14 @@ u3g_attach(device_t dev)
struct usb_interface *iface;
struct usb_interface_descriptor *id;
uint32_t iface_valid;
- int error, flags, nports;
+ int error, type, nports;
int ep, n;
uint8_t i;
DPRINTF("sc=%p\n", sc);
- flags = USB_GET_DRIVER_INFO(uaa);
-
- if (flags & U3GFL_SAEL_M460_INIT)
+ type = USB_GET_DRIVER_INFO(uaa);
+ if (type == U3GINIT_SAEL_M460)
u3g_sael_m460_init(uaa->device);
/* copy in USB config */
@@ -781,8 +802,8 @@ u3g_attach(device_t dev)
DPRINTF("ucom_attach failed\n");
goto detach;
}
- if (sc->sc_numports > 1)
- device_printf(dev, "Found %u ports.\n", sc->sc_numports);
+ device_printf(dev, "Found %u port%s.\n", sc->sc_numports,
+ sc->sc_numports > 1 ? "s":"");
return (0);
detach:
diff --git a/sys/dev/usb/usb_device.c b/sys/dev/usb/usb_device.c
index a80c130..5aef59d 100644
--- a/sys/dev/usb/usb_device.c
+++ b/sys/dev/usb/usb_device.c
@@ -1805,7 +1805,7 @@ repeat_set_config:
* Try to figure out if we have an
* auto-install disk there:
*/
- if (usb_test_autoinstall(udev, 0, 0) == 0) {
+ if (usb_iface_is_cdrom(udev, 0)) {
DPRINTFN(0, "Found possible auto-install "
"disk (trying next config)\n");
config_index++;
diff --git a/sys/dev/usb/usb_msctest.c b/sys/dev/usb/usb_msctest.c
index 61df5f1..99aff3f 100644
--- a/sys/dev/usb/usb_msctest.c
+++ b/sys/dev/usb/usb_msctest.c
@@ -67,8 +67,7 @@
#include <dev/usb/usb_device.h>
#include <dev/usb/usb_request.h>
#include <dev/usb/usb_util.h>
-
-#include <dev/usb/usb.h>
+#include <dev/usb/quirk/usb_quirk.h>
enum {
ST_COMMAND,
@@ -86,7 +85,18 @@ enum {
DIR_NONE,
};
+#define SCSI_INQ_LEN 0x24
+static uint8_t scsi_test_unit_ready[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static uint8_t scsi_inquiry[] = { 0x12, 0x00, 0x00, 0x00, SCSI_INQ_LEN, 0x00 };
+static uint8_t scsi_rezero_init[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static uint8_t scsi_start_stop_unit[] = { 0x1b, 0x00, 0x00, 0x00, 0x02, 0x00 };
+static uint8_t scsi_ztestor_eject[] = { 0x85, 0x01, 0x01, 0x01, 0x18, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x00, 0x00 };
+static uint8_t scsi_cmotech_eject[] = { 0xff, 0x52, 0x44, 0x45, 0x56, 0x43,
+ 0x48, 0x47 };
+
#define BULK_SIZE 64 /* dummy */
+#define ERR_CSW_FAILED -1
/* Command Block Wrapper */
struct bbb_cbw {
@@ -134,8 +144,8 @@ struct bbb_transfer {
uint8_t dir;
uint8_t lun;
uint8_t state;
- uint8_t error;
uint8_t status_try;
+ int error;
uint8_t buffer[256];
};
@@ -147,6 +157,15 @@ static usb_callback_t bbb_data_write_callback;
static usb_callback_t bbb_data_wr_cs_callback;
static usb_callback_t bbb_status_callback;
+static void bbb_done(struct bbb_transfer *, int);
+static void bbb_transfer_start(struct bbb_transfer *, uint8_t);
+static void bbb_data_clear_stall_callback(struct usb_xfer *, uint8_t,
+ uint8_t);
+static uint8_t bbb_command_start(struct bbb_transfer *, uint8_t, uint8_t,
+ void *, size_t, void *, size_t, usb_timeout_t);
+static struct bbb_transfer *bbb_attach(struct usb_device *, uint8_t);
+static void bbb_detach(struct bbb_transfer *);
+
static const struct usb_config bbb_config[ST_MAX] = {
[ST_COMMAND] = {
@@ -208,25 +227,9 @@ static const struct usb_config bbb_config[ST_MAX] = {
};
static void
-bbb_done(struct bbb_transfer *sc, uint8_t error)
+bbb_done(struct bbb_transfer *sc, int error)
{
- struct usb_xfer *xfer;
-
- xfer = sc->xfer[sc->state];
- /* verify the error code */
-
- if (error) {
- switch (USB_GET_STATE(xfer)) {
- case USB_ST_SETUP:
- case USB_ST_TRANSFERRED:
- error = 1;
- break;
- default:
- error = 2;
- break;
- }
- }
sc->error = error;
sc->state = ST_COMMAND;
sc->status_try = 1;
@@ -253,7 +256,7 @@ bbb_data_clear_stall_callback(struct usb_xfer *xfer,
bbb_transfer_start(sc, next_xfer);
break;
default:
- bbb_done(sc, 1);
+ bbb_done(sc, USB_ERR_STALLED);
break;
}
}
@@ -291,7 +294,7 @@ bbb_command_callback(struct usb_xfer *xfer, usb_error_t error)
break;
default: /* Error */
- bbb_done(sc, 1);
+ bbb_done(sc, error);
break;
}
}
@@ -333,7 +336,7 @@ bbb_data_read_callback(struct usb_xfer *xfer, usb_error_t error)
default: /* Error */
if (error == USB_ERR_CANCELLED) {
- bbb_done(sc, 1);
+ bbb_done(sc, error);
} else {
bbb_transfer_start(sc, ST_DATA_RD_CS);
}
@@ -385,7 +388,7 @@ bbb_data_write_callback(struct usb_xfer *xfer, usb_error_t error)
default: /* Error */
if (error == USB_ERR_CANCELLED) {
- bbb_done(sc, 1);
+ bbb_done(sc, error);
} else {
bbb_transfer_start(sc, ST_DATA_WR_CS);
}
@@ -415,11 +418,11 @@ bbb_status_callback(struct usb_xfer *xfer, usb_error_t error)
/* very simple status check */
if (actlen < sizeof(sc->csw)) {
- bbb_done(sc, 1);/* error */
+ bbb_done(sc, USB_ERR_SHORT_XFER);
} else if (sc->csw.bCSWStatus == CSWSTATUS_GOOD) {
- bbb_done(sc, 0);/* success */
+ bbb_done(sc, 0); /* success */
} else {
- bbb_done(sc, 1);/* error */
+ bbb_done(sc, ERR_CSW_FAILED); /* error */
}
break;
@@ -429,11 +432,11 @@ bbb_status_callback(struct usb_xfer *xfer, usb_error_t error)
break;
default:
- DPRINTFN(0, "Failed to read CSW: %s, try %d\n",
+ DPRINTF("Failed to read CSW: %s, try %d\n",
usbd_errstr(error), sc->status_try);
if (error == USB_ERR_CANCELLED || sc->status_try) {
- bbb_done(sc, 1);
+ bbb_done(sc, error);
} else {
sc->status_try = 1;
bbb_transfer_start(sc, ST_DATA_RD_CS);
@@ -451,7 +454,7 @@ bbb_status_callback(struct usb_xfer *xfer, usb_error_t error)
*------------------------------------------------------------------------*/
static uint8_t
bbb_command_start(struct bbb_transfer *sc, uint8_t dir, uint8_t lun,
- void *data_ptr, usb_size_t data_len, uint8_t cmd_len,
+ void *data_ptr, size_t data_len, void *cmd_ptr, size_t cmd_len,
usb_timeout_t data_timeout)
{
sc->lun = lun;
@@ -461,54 +464,46 @@ 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->data_ptr = data_ptr;
sc->cmd_len = cmd_len;
+ bzero(&sc->cbw.CBWCDB, sizeof(sc->cbw.CBWCDB));
+ bcopy(cmd_ptr, &sc->cbw.CBWCDB, cmd_len);
+ DPRINTFN(1, "SCSI cmd = %*D\n", cmd_len, &sc->cbw.CBWCDB, ":");
+ mtx_lock(&sc->mtx);
usbd_transfer_start(sc->xfer[sc->state]);
while (usbd_transfer_pending(sc->xfer[sc->state])) {
cv_wait(&sc->cv, &sc->mtx);
}
+ mtx_unlock(&sc->mtx);
return (sc->error);
}
-/*------------------------------------------------------------------------*
- * usb_test_autoinstall
- *
- * Return values:
- * 0: This interface is an auto install disk (CD-ROM)
- * Else: Not an auto install disk.
- *------------------------------------------------------------------------*/
-usb_error_t
-usb_test_autoinstall(struct usb_device *udev, uint8_t iface_index,
- uint8_t do_eject)
+static struct bbb_transfer *
+bbb_attach(struct usb_device *udev, uint8_t iface_index)
{
struct usb_interface *iface;
struct usb_interface_descriptor *id;
- usb_error_t err;
- uint8_t timeout;
- uint8_t sid_type;
struct bbb_transfer *sc;
+ usb_error_t err;
- if (udev == NULL) {
- return (USB_ERR_INVAL);
- }
iface = usbd_get_iface(udev, iface_index);
- if (iface == NULL) {
- return (USB_ERR_INVAL);
- }
+ if (iface == NULL)
+ return (NULL);
+
id = iface->idesc;
- if (id == NULL) {
- return (USB_ERR_INVAL);
- }
- if (id->bInterfaceClass != UICLASS_MASS) {
- return (USB_ERR_INVAL);
- }
+ if (id == NULL || id->bInterfaceClass != UICLASS_MASS)
+ return (NULL);
+
switch (id->bInterfaceSubClass) {
case UISUBCLASS_SCSI:
case UISUBCLASS_UFI:
+ case UISUBCLASS_SFF8020I:
+ case UISUBCLASS_SFF8070I:
break;
default:
- return (USB_ERR_INVAL);
+ return (NULL);
}
switch (id->bInterfaceProtocol) {
@@ -516,75 +511,112 @@ usb_test_autoinstall(struct usb_device *udev, uint8_t iface_index,
case UIPROTO_MASS_BBB:
break;
default:
- return (USB_ERR_INVAL);
+ return (NULL);
}
sc = malloc(sizeof(*sc), M_USB, M_WAITOK | M_ZERO);
- if (sc == NULL) {
- return (USB_ERR_NOMEM);
- }
mtx_init(&sc->mtx, "USB autoinstall", NULL, MTX_DEF);
cv_init(&sc->cv, "WBBB");
- err = usbd_transfer_setup(udev,
- &iface_index, sc->xfer, bbb_config,
+ err = usbd_transfer_setup(udev, &iface_index, sc->xfer, bbb_config,
ST_MAX, sc, &sc->mtx);
-
if (err) {
- goto done;
+ bbb_detach(sc);
+ return (NULL);
}
- mtx_lock(&sc->mtx);
-
- timeout = 4; /* tries */
-
-repeat_inquiry:
-
- sc->cbw.CBWCDB[0] = 0x12; /* INQUIRY */
- sc->cbw.CBWCDB[1] = 0;
- sc->cbw.CBWCDB[2] = 0;
- sc->cbw.CBWCDB[3] = 0;
- sc->cbw.CBWCDB[4] = 0x24; /* length */
- sc->cbw.CBWCDB[5] = 0;
- err = bbb_command_start(sc, DIR_IN, 0,
- sc->buffer, 0x24, 6, USB_MS_HZ);
-
- if ((sc->actlen != 0) && (err == 0)) {
- sid_type = sc->buffer[0] & 0x1F;
- if (sid_type == 0x05) {
- /* CD-ROM */
- if (do_eject) {
- /* 0: opcode: SCSI START/STOP */
- sc->cbw.CBWCDB[0] = 0x1b;
- /* 1: byte2: Not immediate */
- sc->cbw.CBWCDB[1] = 0x00;
- /* 2..3: reserved */
- sc->cbw.CBWCDB[2] = 0x00;
- sc->cbw.CBWCDB[3] = 0x00;
- /* 4: Load/Eject command */
- sc->cbw.CBWCDB[4] = 0x02;
- /* 5: control */
- sc->cbw.CBWCDB[5] = 0x00;
- err = bbb_command_start(sc, DIR_OUT, 0,
- NULL, 0, 6, USB_MS_HZ);
-
- DPRINTFN(0, "Eject CD command "
- "status: %s\n", usbd_errstr(err));
- }
- err = 0;
- goto done;
- }
- } else if ((err != 2) && --timeout) {
- usb_pause_mtx(&sc->mtx, hz);
- goto repeat_inquiry;
- }
- err = USB_ERR_INVAL;
- goto done;
+ return (sc);
+}
-done:
- mtx_unlock(&sc->mtx);
+static void
+bbb_detach(struct bbb_transfer *sc)
+{
usbd_transfer_unsetup(sc->xfer, ST_MAX);
mtx_destroy(&sc->mtx);
cv_destroy(&sc->cv);
free(sc, M_USB);
- return (err);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_iface_is_cdrom
+ *
+ * Return values:
+ * 1: This interface is an auto install disk (CD-ROM)
+ * 0: Not an auto install disk.
+ *------------------------------------------------------------------------*/
+int
+usb_iface_is_cdrom(struct usb_device *udev, uint8_t iface_index)
+{
+ struct bbb_transfer *sc;
+ usb_error_t err;
+ uint8_t timeout, is_cdrom;
+ uint8_t sid_type;
+
+ sc = bbb_attach(udev, iface_index);
+ if (sc == NULL)
+ return (0);
+
+ is_cdrom = 0;
+ timeout = 4; /* tries */
+ while (--timeout) {
+ err = bbb_command_start(sc, DIR_IN, 0, sc->buffer,
+ SCSI_INQ_LEN, &scsi_inquiry, sizeof(scsi_inquiry),
+ USB_MS_HZ);
+
+ if (err == 0 && sc->actlen > 0) {
+ sid_type = sc->buffer[0] & 0x1F;
+ if (sid_type == 0x05)
+ is_cdrom = 1;
+ break;
+ } else if (err != ERR_CSW_FAILED)
+ break; /* non retryable error */
+ usb_pause_mtx(NULL, hz);
+ }
+ bbb_detach(sc);
+ return (is_cdrom);
+}
+
+usb_error_t
+usb_msc_eject(struct usb_device *udev, uint8_t iface_index, int method)
+{
+ struct bbb_transfer *sc;
+ usb_error_t err;
+
+ sc = bbb_attach(udev, iface_index);
+ 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,
+ &scsi_test_unit_ready, sizeof(scsi_test_unit_ready),
+ USB_MS_HZ);
+ DPRINTF("Test unit ready status: %s\n", usbd_errstr(err));
+ err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
+ &scsi_start_stop_unit, sizeof(scsi_start_stop_unit),
+ USB_MS_HZ);
+ break;
+ case MSC_EJECT_REZERO:
+ err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
+ &scsi_rezero_init, sizeof(scsi_rezero_init),
+ USB_MS_HZ);
+ break;
+ case MSC_EJECT_ZTESTOR:
+ err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
+ &scsi_ztestor_eject, sizeof(scsi_ztestor_eject),
+ USB_MS_HZ);
+ break;
+ case MSC_EJECT_CMOTECH:
+ err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
+ &scsi_cmotech_eject, sizeof(scsi_cmotech_eject),
+ USB_MS_HZ);
+ break;
+ default:
+ printf("usb_msc_eject: unknown eject method (%d)\n", method);
+ break;
+ }
+ DPRINTF("Eject CD command status: %s\n", usbd_errstr(err));
+
+ bbb_detach(sc);
+ return (0);
}
diff --git a/sys/dev/usb/usb_msctest.h b/sys/dev/usb/usb_msctest.h
index 44fa20d..2310bba 100644
--- a/sys/dev/usb/usb_msctest.h
+++ b/sys/dev/usb/usb_msctest.h
@@ -27,7 +27,16 @@
#ifndef _USB_MSCTEST_H_
#define _USB_MSCTEST_H_
-usb_error_t usb_test_autoinstall(struct usb_device *udev,
- uint8_t iface_index, uint8_t do_eject);
+enum {
+ MSC_EJECT_STOPUNIT,
+ MSC_EJECT_REZERO,
+ MSC_EJECT_ZTESTOR,
+ MSC_EJECT_CMOTECH
+};
+
+int usb_iface_is_cdrom(struct usb_device *udev,
+ uint8_t iface_index);
+usb_error_t usb_msc_eject(struct usb_device *udev,
+ uint8_t iface_index, int method);
#endif /* _USB_MSCTEST_H_ */
OpenPOWER on IntegriCloud