mirror of
https://git.hardenedbsd.org/hardenedbsd/HardenedBSD.git
synced 2024-11-26 10:53:39 +01:00
Add support for DYMO LabelWriter PnP.
MFC after: 2 weeks
This commit is contained in:
parent
d667b90d53
commit
415bcd89a6
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=282577
@ -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
|
||||
|
@ -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",
|
||||
};
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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_ */
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user