diff options
author | hselasky <hselasky@FreeBSD.org> | 2015-05-21 06:47:20 +0000 |
---|---|---|
committer | hselasky <hselasky@FreeBSD.org> | 2015-05-21 06:47:20 +0000 |
commit | baf0162e34b888f6d76595ac158d06d34336fec8 (patch) | |
tree | 851ef2869e95ab4757e17879da561c939b3cf88b | |
parent | e136fd019b14c4cac4794e97f3304d39a7e87584 (diff) | |
download | FreeBSD-src-baf0162e34b888f6d76595ac158d06d34336fec8.zip FreeBSD-src-baf0162e34b888f6d76595ac158d06d34336fec8.tar.gz |
MFC r282577:
Add support for DYMO LabelWriter PnP.
-rw-r--r-- | share/man/man4/usb_quirk.4 | 5 | ||||
-rw-r--r-- | sys/dev/usb/quirk/usb_quirk.c | 4 | ||||
-rw-r--r-- | sys/dev/usb/quirk/usb_quirk.h | 1 | ||||
-rw-r--r-- | sys/dev/usb/usb_device.c | 6 | ||||
-rw-r--r-- | sys/dev/usb/usb_msctest.c | 185 | ||||
-rw-r--r-- | sys/dev/usb/usb_msctest.h | 2 | ||||
-rw-r--r-- | sys/dev/usb/usbdevs | 4 |
7 files changed, 176 insertions, 31 deletions
diff --git a/share/man/man4/usb_quirk.4 b/share/man/man4/usb_quirk.4 index eb45eaa..5b3f01c 100644 --- a/share/man/man4/usb_quirk.4 +++ b/share/man/man4/usb_quirk.4 @@ -16,7 +16,7 @@ .\" .\" $FreeBSD$ .\" -.Dd April 21, 2013 +.Dd May 7, 2015 .Dt USB_QUIRK 4 .Os .Sh NAME @@ -170,6 +170,9 @@ ejects after Huawei SCSI command .It UQ_MSC_EJECT_TCT ejects after TCT SCSI command .Dv 0x06f504025270 +.It UQ_MSC_DYMO_EJECT +ejects after HID command +.Dv 0x1b5a01 .El .Pp See diff --git a/sys/dev/usb/quirk/usb_quirk.c b/sys/dev/usb/quirk/usb_quirk.c index e0c5db7..3cfaef0 100644 --- a/sys/dev/usb/quirk/usb_quirk.c +++ b/sys/dev/usb/quirk/usb_quirk.c @@ -523,6 +523,9 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = { USB_QUIRK(FEIYA, DUMMY, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE, UQ_MATCH_VENDOR_ONLY), USB_QUIRK(REALTEK, DUMMY, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE, UQ_MATCH_VENDOR_ONLY), USB_QUIRK(INITIO, DUMMY, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE, UQ_MATCH_VENDOR_ONLY), + + /* DYMO LabelManager Pnp */ + USB_QUIRK(DYMO, LABELMANAGERPNP, 0x0000, 0xffff, UQ_MSC_DYMO_EJECT), }; #undef USB_QUIRK_VP #undef USB_QUIRK @@ -592,6 +595,7 @@ static const char *usb_quirk_str[USB_QUIRK_MAX] = { [UQ_BAD_MIDI] = "UQ_BAD_MIDI", [UQ_AU_VENDOR_CLASS] = "UQ_AU_VENDOR_CLASS", [UQ_SINGLE_CMD_MIDI] = "UQ_SINGLE_CMD_MIDI", + [UQ_MSC_DYMO_EJECT] = "UQ_MSC_DYMO_EJECT", }; /*------------------------------------------------------------------------* diff --git a/sys/dev/usb/quirk/usb_quirk.h b/sys/dev/usb/quirk/usb_quirk.h index c2e9501..7010916 100644 --- a/sys/dev/usb/quirk/usb_quirk.h +++ b/sys/dev/usb/quirk/usb_quirk.h @@ -108,6 +108,7 @@ enum { UQ_BAD_MIDI, /* device claims MIDI class, but isn't */ UQ_AU_VENDOR_CLASS, /* audio device uses vendor and not audio class */ UQ_SINGLE_CMD_MIDI, /* at most one command per USB packet */ + UQ_MSC_DYMO_EJECT, /* ejects Dymo MSC device */ USB_QUIRK_MAX }; diff --git a/sys/dev/usb/usb_device.c b/sys/dev/usb/usb_device.c index 44314aa..c3936f6 100644 --- a/sys/dev/usb/usb_device.c +++ b/sys/dev/usb/usb_device.c @@ -1346,6 +1346,12 @@ usb_probe_and_attach(struct usb_device *udev, uint8_t iface_index) */ if (iface_index == USB_IFACE_INDEX_ANY) { + if (usb_test_quirk(&uaa, UQ_MSC_DYMO_EJECT) != 0 && + usb_dymo_eject(udev, 0) == 0) { + /* success, mark the udev as disappearing */ + uaa.dev_state = UAA_DEV_EJECTING; + } + EVENTHANDLER_INVOKE(usb_dev_configured, udev, &uaa); if (uaa.dev_state != UAA_DEV_READY) { diff --git a/sys/dev/usb/usb_msctest.c b/sys/dev/usb/usb_msctest.c index 13d7330..23d9d8a 100644 --- a/sys/dev/usb/usb_msctest.c +++ b/sys/dev/usb/usb_msctest.c @@ -177,6 +177,7 @@ static usb_callback_t bbb_data_rd_cs_callback; 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 usb_callback_t bbb_raw_write_callback; static void bbb_done(struct bbb_transfer *, int); static void bbb_transfer_start(struct bbb_transfer *, uint8_t); @@ -184,7 +185,7 @@ static void bbb_data_clear_stall_callback(struct usb_xfer *, uint8_t, uint8_t); static int 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 struct bbb_transfer *bbb_attach(struct usb_device *, uint8_t, uint8_t); static void bbb_detach(struct bbb_transfer *); static const struct usb_config bbb_config[ST_MAX] = { @@ -247,6 +248,19 @@ static const struct usb_config bbb_config[ST_MAX] = { }, }; +static const struct usb_config bbb_raw_config[1] = { + + [0] = { + .type = UE_BULK_INTR, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_OUT, + .bufsize = SCSI_MAX_LEN, + .flags = {.ext_buffer = 1,.proxy_buffer = 1,}, + .callback = &bbb_raw_write_callback, + .timeout = 1 * USB_MS_HZ, /* 1 second */ + }, +}; + static void bbb_done(struct bbb_transfer *sc, int error) { @@ -467,6 +481,47 @@ bbb_status_callback(struct usb_xfer *xfer, usb_error_t error) } } +static void +bbb_raw_write_callback(struct usb_xfer *xfer, usb_error_t error) +{ + struct bbb_transfer *sc = usbd_xfer_softc(xfer); + usb_frlength_t max_bulk = usbd_xfer_max_len(xfer); + int actlen, sumlen; + + usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); + + switch (USB_GET_STATE(xfer)) { + case USB_ST_TRANSFERRED: + sc->data_rem -= actlen; + sc->data_ptr += actlen; + sc->actlen += actlen; + + if (actlen < sumlen) { + /* short transfer */ + sc->data_rem = 0; + } + case USB_ST_SETUP: + DPRINTF("max_bulk=%d, data_rem=%d\n", + max_bulk, sc->data_rem); + + if (sc->data_rem == 0) { + bbb_done(sc, 0); + break; + } + if (max_bulk > sc->data_rem) { + max_bulk = sc->data_rem; + } + usbd_xfer_set_timeout(xfer, sc->data_timeout); + usbd_xfer_set_frame_data(xfer, 0, sc->data_ptr, max_bulk); + usbd_transfer_submit(xfer); + break; + + default: /* Error */ + bbb_done(sc, error); + break; + } +} + /*------------------------------------------------------------------------* * bbb_command_start - execute a SCSI command synchronously * @@ -502,13 +557,45 @@ bbb_command_start(struct bbb_transfer *sc, uint8_t dir, uint8_t lun, return (sc->error); } +/*------------------------------------------------------------------------* + * bbb_raw_write - write a raw BULK message synchronously + * + * Return values + * 0: Success + * Else: Failure + *------------------------------------------------------------------------*/ +static int +bbb_raw_write(struct bbb_transfer *sc, const void *data_ptr, size_t data_len, + usb_timeout_t data_timeout) +{ + sc->data_ptr = __DECONST(void *, data_ptr); + sc->data_len = data_len; + sc->data_rem = data_len; + sc->data_timeout = (data_timeout + USB_MS_HZ); + sc->actlen = 0; + sc->error = 0; + + DPRINTFN(1, "BULK DATA = %*D\n", (int)data_len, + (const char *)data_ptr, ":"); + + mtx_lock(&sc->mtx); + usbd_transfer_start(sc->xfer[0]); + while (usbd_transfer_pending(sc->xfer[0])) + cv_wait(&sc->cv, &sc->mtx); + mtx_unlock(&sc->mtx); + return (sc->error); +} + static struct bbb_transfer * -bbb_attach(struct usb_device *udev, uint8_t iface_index) +bbb_attach(struct usb_device *udev, uint8_t iface_index, + uint8_t bInterfaceClass) { struct usb_interface *iface; struct usb_interface_descriptor *id; + const struct usb_config *pconfig; struct bbb_transfer *sc; usb_error_t err; + int nconfig; uint8_t do_unlock; /* Prevent re-enumeration */ @@ -528,22 +615,39 @@ bbb_attach(struct usb_device *udev, uint8_t iface_index) return (NULL); id = iface->idesc; - if (id == NULL || id->bInterfaceClass != UICLASS_MASS) + if (id == NULL || id->bInterfaceClass != bInterfaceClass) return (NULL); - switch (id->bInterfaceSubClass) { - case UISUBCLASS_SCSI: - case UISUBCLASS_UFI: - case UISUBCLASS_SFF8020I: - case UISUBCLASS_SFF8070I: + switch (id->bInterfaceClass) { + case UICLASS_MASS: + switch (id->bInterfaceSubClass) { + case UISUBCLASS_SCSI: + case UISUBCLASS_UFI: + case UISUBCLASS_SFF8020I: + case UISUBCLASS_SFF8070I: + break; + default: + return (NULL); + } + switch (id->bInterfaceProtocol) { + case UIPROTO_MASS_BBB_OLD: + case UIPROTO_MASS_BBB: + break; + default: + return (NULL); + } + pconfig = bbb_config; + nconfig = ST_MAX; break; - default: - return (NULL); - } - - switch (id->bInterfaceProtocol) { - case UIPROTO_MASS_BBB_OLD: - case UIPROTO_MASS_BBB: + case UICLASS_HID: + switch (id->bInterfaceSubClass) { + case 0: + break; + default: + return (NULL); + } + pconfig = bbb_raw_config; + nconfig = 1; break; default: return (NULL); @@ -553,22 +657,27 @@ bbb_attach(struct usb_device *udev, uint8_t iface_index) 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, - ST_MAX, sc, &sc->mtx); + err = usbd_transfer_setup(udev, &iface_index, sc->xfer, pconfig, + nconfig, sc, &sc->mtx); if (err) { bbb_detach(sc); return (NULL); } - /* store pointer to DMA buffers */ - sc->buffer = usbd_xfer_get_frame_buffer( - sc->xfer[ST_DATA_RD], 0); - sc->buffer_size = - usbd_xfer_max_len(sc->xfer[ST_DATA_RD]); - sc->cbw = usbd_xfer_get_frame_buffer( - sc->xfer[ST_COMMAND], 0); - sc->csw = usbd_xfer_get_frame_buffer( - sc->xfer[ST_STATUS], 0); - + switch (id->bInterfaceClass) { + case UICLASS_MASS: + /* store pointer to DMA buffers */ + sc->buffer = usbd_xfer_get_frame_buffer( + sc->xfer[ST_DATA_RD], 0); + sc->buffer_size = + usbd_xfer_max_len(sc->xfer[ST_DATA_RD]); + sc->cbw = usbd_xfer_get_frame_buffer( + sc->xfer[ST_COMMAND], 0); + sc->csw = usbd_xfer_get_frame_buffer( + sc->xfer[ST_STATUS], 0); + break; + default: + break; + } return (sc); } @@ -597,7 +706,7 @@ usb_iface_is_cdrom(struct usb_device *udev, uint8_t iface_index) uint8_t sid_type; int err; - sc = bbb_attach(udev, iface_index); + sc = bbb_attach(udev, iface_index, UICLASS_MASS); if (sc == NULL) return (0); @@ -653,7 +762,7 @@ usb_msc_auto_quirk(struct usb_device *udev, uint8_t iface_index) uint8_t sid_type; int err; - sc = bbb_attach(udev, iface_index); + sc = bbb_attach(udev, iface_index, UICLASS_MASS); if (sc == NULL) return (0); @@ -822,7 +931,7 @@ 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); + sc = bbb_attach(udev, iface_index, UICLASS_MASS); if (sc == NULL) return (USB_ERR_INVAL); @@ -881,3 +990,19 @@ usb_msc_eject(struct usb_device *udev, uint8_t iface_index, int method) bbb_detach(sc); return (0); } + +usb_error_t +usb_dymo_eject(struct usb_device *udev, uint8_t iface_index) +{ + static const uint8_t data[3] = { 0x1b, 0x5a, 0x01 }; + struct bbb_transfer *sc; + usb_error_t err; + + sc = bbb_attach(udev, iface_index, UICLASS_HID); + if (sc == NULL) + return (USB_ERR_INVAL); + err = bbb_raw_write(sc, data, sizeof(data), USB_MS_HZ); + bbb_detach(sc); + return (err); +} + diff --git a/sys/dev/usb/usb_msctest.h b/sys/dev/usb/usb_msctest.h index 4f64f84..a14f424 100644 --- a/sys/dev/usb/usb_msctest.h +++ b/sys/dev/usb/usb_msctest.h @@ -43,5 +43,7 @@ usb_error_t usb_msc_eject(struct usb_device *udev, uint8_t iface_index, int method); usb_error_t usb_msc_auto_quirk(struct usb_device *udev, uint8_t iface_index); +usb_error_t usb_dymo_eject(struct usb_device *udev, + uint8_t iface_index); #endif /* _USB_MSCTEST_H_ */ diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs index ea2c11d..c9606c8 100644 --- a/sys/dev/usb/usbdevs +++ b/sys/dev/usb/usbdevs @@ -452,6 +452,7 @@ vendor GLOBESPAN 0x0915 Globespan vendor CONCORDCAMERA 0x0919 Concord Camera vendor GARMIN 0x091e Garmin International vendor GOHUBS 0x0921 GoHubs +vendor DYMO 0x0922 DYMO vendor XEROX 0x0924 Xerox vendor BIOMETRIC 0x0929 American Biometric Company vendor TOSHIBA 0x0930 Toshiba @@ -1670,6 +1671,9 @@ product DRESDENELEKTRONIK WIRELESSHANDHELDTERMINAL 0x0004 Wireless Handheld Ter product DRESDENELEKTRONIK DE_RFNODE 0x001c deRFnode product DRESDENELEKTRONIK LEVELSHIFTERSTICKLOWCOST 0x0022 Levelshifter Stick Low Cost +/* DYMO */ +product DYMO LABELMANAGERPNP 0x1001 DYMO LabelManager PnP + /* Dynastream Innovations */ product DYNASTREAM ANTDEVBOARD 0x1003 ANT dev board product DYNASTREAM ANT2USB 0x1004 ANT2USB |