Add support for DYMO LabelWriter PnP.

MFC after:		2 weeks
This commit is contained in:
Hans Petter Selasky 2015-05-07 12:54:27 +00:00
parent d667b90d53
commit 415bcd89a6
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=282577
7 changed files with 178 additions and 34 deletions

View File

@ -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

View File

@ -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",
};
/*------------------------------------------------------------------------*

View File

@ -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
};

View File

@ -1343,6 +1343,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) {

View File

@ -181,6 +181,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);
@ -188,7 +189,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] = {
@ -251,6 +252,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)
{
@ -471,6 +485,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
*
@ -506,13 +561,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;
#if USB_HAVE_MSCTEST_DETACH
uint8_t do_unlock;
@ -535,22 +622,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);
@ -560,22 +664,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);
}
@ -604,7 +713,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);
@ -660,7 +769,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);
@ -829,7 +938,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);
@ -889,6 +998,21 @@ usb_msc_eject(struct usb_device *udev, uint8_t iface_index, int method)
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);
}
usb_error_t
usb_msc_read_10(struct usb_device *udev, uint8_t iface_index,
uint32_t lba, uint32_t blocks, void *buffer)
@ -908,7 +1032,7 @@ usb_msc_read_10(struct usb_device *udev, uint8_t iface_index,
cmd[8] = blocks;
cmd[9] = 0;
sc = bbb_attach(udev, iface_index);
sc = bbb_attach(udev, iface_index, UICLASS_MASS);
if (sc == NULL)
return (USB_ERR_INVAL);
@ -939,7 +1063,7 @@ usb_msc_write_10(struct usb_device *udev, uint8_t iface_index,
cmd[8] = blocks;
cmd[9] = 0;
sc = bbb_attach(udev, iface_index);
sc = bbb_attach(udev, iface_index, UICLASS_MASS);
if (sc == NULL)
return (USB_ERR_INVAL);
@ -958,7 +1082,7 @@ usb_msc_read_capacity(struct usb_device *udev, uint8_t iface_index,
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);

View File

@ -52,5 +52,7 @@ usb_error_t usb_msc_write_10(struct usb_device *udev,
usb_error_t usb_msc_read_capacity(struct usb_device *udev,
uint8_t iface_index, uint32_t *lba_last,
uint32_t *block_size);
usb_error_t usb_dymo_eject(struct usb_device *udev,
uint8_t iface_index);
#endif /* _USB_MSCTEST_H_ */

View File

@ -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
@ -1694,6 +1695,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