Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (21 commits)
  USB: musb: fix srp sysfs entry deletion
  USB: musb: resume suspended root hub on disconnect
  USB: musb: use right poll limit for low speed devices
  USB: musb: be careful with 64K+ transfer lengths, host side
  USB: musb: fix data toggle saving with shared FIFO
  USB: musb: host endpoint_disable() oops fixes
  USB: musb: fix urb_dequeue() method
  USB: musb: fix musb_host_tx() for shared endpoint FIFO
  USB: musb: be careful with 64K+ transfer lengths (gadget side)
  usb: musb: make Davinci *work* in mainline
  USB: usb_get_string should check the descriptor type
  USB: gadget: fix build error in omap_apollon_2420_defconfig
  USB: g_file_storage: automatically disable stalls under Atmel
  USB: usb-storage: add IGNORE_RESIDUE flag for Genesys Logic adapters
  USB: Quirk for Hummingbird huc56s / Conexant ACM modem
  USB: serial: add support for second revision of Ericsson F3507G WWAN card
  USB: cdc-acm: add usb id for motomagx phones
  USB: option: add BenQ 3g modem information
  usb: gadget: obex: select correct ep descriptors
  USB: EHCI: slow down ITD reuse
  ...
This commit is contained in:
Linus Torvalds 2009-02-27 16:49:26 -08:00
commit 3c4f1158cd
19 changed files with 176 additions and 75 deletions

View file

@ -311,6 +311,9 @@ evm_u35_setup(struct i2c_client *client, int gpio, unsigned ngpio, void *c)
gpio_request(gpio + 7, "nCF_SEL");
gpio_direction_output(gpio + 7, 1);
/* irlml6401 sustains over 3A, switches 5V in under 8 msec */
setup_usb(500, 8);
return 0;
}
@ -417,9 +420,6 @@ static __init void davinci_evm_init(void)
platform_add_devices(davinci_evm_devices,
ARRAY_SIZE(davinci_evm_devices));
evm_init_i2c();
/* irlml6401 sustains over 3A, switches 5V in under 8 msec */
setup_usb(500, 8);
}
static __init void davinci_evm_irq_init(void)

View file

@ -230,6 +230,11 @@ static struct clk davinci_clks[] = {
.rate = &commonrate,
.lpsc = DAVINCI_LPSC_GPIO,
},
{
.name = "usb",
.rate = &commonrate,
.lpsc = DAVINCI_LPSC_USB,
},
{
.name = "AEMIFCLK",
.rate = &commonrate,

View file

@ -47,6 +47,7 @@ static struct musb_hdrc_platform_data usb_data = {
#elif defined(CONFIG_USB_MUSB_HOST)
.mode = MUSB_HOST,
#endif
.clock = "usb",
.config = &musb_config,
};

View file

@ -1376,6 +1376,15 @@ static struct usb_device_id acm_ids[] = {
{ USB_DEVICE(0x0572, 0x1324), /* Conexant USB MODEM RD02-D400 */
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
},
{ USB_DEVICE(0x22b8, 0x6425), /* Motorola MOTOMAGX phones */
},
{ USB_DEVICE(0x0572, 0x1329), /* Hummingbird huc56s (Conexant) */
.driver_info = NO_UNION_NORMAL, /* union descriptor misplaced on
data interface instead of
communications interface.
Maybe we should define a new
quirk for this. */
},
/* control interfaces with various AT-command sets */
{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,

View file

@ -653,7 +653,7 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type,
if (result <= 0 && result != -ETIMEDOUT)
continue;
if (result > 1 && ((u8 *)buf)[1] != type) {
result = -EPROTO;
result = -ENODATA;
continue;
}
break;
@ -696,8 +696,13 @@ static int usb_get_string(struct usb_device *dev, unsigned short langid,
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
(USB_DT_STRING << 8) + index, langid, buf, size,
USB_CTRL_GET_TIMEOUT);
if (!(result == 0 || result == -EPIPE))
break;
if (result == 0 || result == -EPIPE)
continue;
if (result > 1 && ((u8 *) buf)[1] != USB_DT_STRING) {
result = -ENODATA;
continue;
}
break;
}
return result;
}

View file

@ -191,6 +191,7 @@ config USB_GADGET_OMAP
boolean "OMAP USB Device Controller"
depends on ARCH_OMAP
select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG
select USB_OTG_UTILS if ARCH_OMAP
help
Many Texas Instruments OMAP processors have flexible full
speed USB device controllers, with support for up to 30

View file

@ -366,9 +366,9 @@ obex_bind(struct usb_configuration *c, struct usb_function *f)
f->hs_descriptors = usb_copy_descriptors(hs_function);
obex->hs.obex_in = usb_find_endpoint(hs_function,
f->descriptors, &obex_hs_ep_in_desc);
f->hs_descriptors, &obex_hs_ep_in_desc);
obex->hs.obex_out = usb_find_endpoint(hs_function,
f->descriptors, &obex_hs_ep_out_desc);
f->hs_descriptors, &obex_hs_ep_out_desc);
}
/* Avoid letting this gadget enumerate until the userspace

View file

@ -3879,7 +3879,11 @@ static int __init check_parameters(struct fsg_dev *fsg)
mod_data.protocol_type = USB_SC_SCSI;
mod_data.protocol_name = "Transparent SCSI";
if (gadget_is_sh(fsg->gadget))
/* Some peripheral controllers are known not to be able to
* halt bulk endpoints correctly. If one of them is present,
* disable stalls.
*/
if (gadget_is_sh(fsg->gadget) || gadget_is_at91(fsg->gadget))
mod_data.can_stall = 0;
if (mod_data.release == 0xffff) { // Parameter wasn't set

View file

@ -404,7 +404,10 @@ static void struct_ep_qh_setup(struct fsl_udc *udc, unsigned char ep_num,
}
if (zlt)
tmp |= EP_QUEUE_HEAD_ZLT_SEL;
p_QH->max_pkt_length = cpu_to_le32(tmp);
p_QH->next_dtd_ptr = 1;
p_QH->size_ioc_int_sts = 0;
return;
}

View file

@ -485,6 +485,7 @@ static int ehci_init(struct usb_hcd *hcd)
* periodic_size can shrink by USBCMD update if hcc_params allows.
*/
ehci->periodic_size = DEFAULT_I_TDPS;
INIT_LIST_HEAD(&ehci->cached_itd_list);
if ((retval = ehci_mem_init(ehci, GFP_KERNEL)) < 0)
return retval;
@ -497,6 +498,7 @@ static int ehci_init(struct usb_hcd *hcd)
ehci->reclaim = NULL;
ehci->next_uframe = -1;
ehci->clock_frame = -1;
/*
* dedicate a qh for the async ring head, since we couldn't unlink

View file

@ -128,6 +128,7 @@ static inline void qh_put (struct ehci_qh *qh)
static void ehci_mem_cleanup (struct ehci_hcd *ehci)
{
free_cached_itd_list(ehci);
if (ehci->async)
qh_put (ehci->async);
ehci->async = NULL;

View file

@ -1004,7 +1004,8 @@ iso_stream_put(struct ehci_hcd *ehci, struct ehci_iso_stream *stream)
is_in = (stream->bEndpointAddress & USB_DIR_IN) ? 0x10 : 0;
stream->bEndpointAddress &= 0x0f;
stream->ep->hcpriv = NULL;
if (stream->ep)
stream->ep->hcpriv = NULL;
if (stream->rescheduled) {
ehci_info (ehci, "ep%d%s-iso rescheduled "
@ -1653,14 +1654,28 @@ itd_complete (
(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
}
iso_stream_put (ehci, stream);
/* OK to recycle this ITD now that its completion callback ran. */
done:
usb_put_urb(urb);
itd->urb = NULL;
itd->stream = NULL;
list_move(&itd->itd_list, &stream->free_list);
iso_stream_put(ehci, stream);
if (ehci->clock_frame != itd->frame || itd->index[7] != -1) {
/* OK to recycle this ITD now. */
itd->stream = NULL;
list_move(&itd->itd_list, &stream->free_list);
iso_stream_put(ehci, stream);
} else {
/* HW might remember this ITD, so we can't recycle it yet.
* Move it to a safe place until a new frame starts.
*/
list_move(&itd->itd_list, &ehci->cached_itd_list);
if (stream->refcount == 2) {
/* If iso_stream_put() were called here, stream
* would be freed. Instead, just prevent reuse.
*/
stream->ep->hcpriv = NULL;
stream->ep = NULL;
}
}
return retval;
}
@ -2101,6 +2116,20 @@ done:
/*-------------------------------------------------------------------------*/
static void free_cached_itd_list(struct ehci_hcd *ehci)
{
struct ehci_itd *itd, *n;
list_for_each_entry_safe(itd, n, &ehci->cached_itd_list, itd_list) {
struct ehci_iso_stream *stream = itd->stream;
itd->stream = NULL;
list_move(&itd->itd_list, &stream->free_list);
iso_stream_put(ehci, stream);
}
}
/*-------------------------------------------------------------------------*/
static void
scan_periodic (struct ehci_hcd *ehci)
{
@ -2115,10 +2144,17 @@ scan_periodic (struct ehci_hcd *ehci)
* Touches as few pages as possible: cache-friendly.
*/
now_uframe = ehci->next_uframe;
if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
if (HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
clock = ehci_readl(ehci, &ehci->regs->frame_index);
else
clock_frame = (clock >> 3) % ehci->periodic_size;
} else {
clock = now_uframe + mod - 1;
clock_frame = -1;
}
if (ehci->clock_frame != clock_frame) {
free_cached_itd_list(ehci);
ehci->clock_frame = clock_frame;
}
clock %= mod;
clock_frame = clock >> 3;
@ -2277,6 +2313,10 @@ restart:
/* rescan the rest of this frame, then ... */
clock = now;
clock_frame = clock >> 3;
if (ehci->clock_frame != clock_frame) {
free_cached_itd_list(ehci);
ehci->clock_frame = clock_frame;
}
} else {
now_uframe++;
now_uframe %= mod;

View file

@ -87,6 +87,10 @@ struct ehci_hcd { /* one per controller */
int next_uframe; /* scan periodic, start here */
unsigned periodic_sched; /* periodic activity count */
/* list of itds completed while clock_frame was still active */
struct list_head cached_itd_list;
unsigned clock_frame;
/* per root hub port */
unsigned long reset_done [EHCI_MAX_ROOT_PORTS];
@ -220,6 +224,8 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
}
}
static void free_cached_itd_list(struct ehci_hcd *ehci);
/*-------------------------------------------------------------------------*/
#include <linux/usb/ehci_def.h>

View file

@ -377,18 +377,8 @@ int __init musb_platform_init(struct musb *musb)
u32 revision;
musb->mregs += DAVINCI_BASE_OFFSET;
#if 0
/* REVISIT there's something odd about clocking, this
* didn't appear do the job ...
*/
musb->clock = clk_get(pDevice, "usb");
if (IS_ERR(musb->clock))
return PTR_ERR(musb->clock);
status = clk_enable(musb->clock);
if (status < 0)
return -ENODEV;
#endif
clk_enable(musb->clock);
/* returns zero if e.g. not clocked */
revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG);
@ -453,5 +443,8 @@ int musb_platform_exit(struct musb *musb)
}
phy_off();
clk_disable(musb->clock);
return 0;
}

View file

@ -115,7 +115,7 @@
unsigned musb_debug;
module_param(musb_debug, uint, S_IRUGO | S_IWUSR);
module_param_named(debug, musb_debug, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug message level. Default = 0");
#define DRIVER_AUTHOR "Mentor Graphics, Texas Instruments, Nokia"
@ -767,6 +767,7 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
#ifdef CONFIG_USB_MUSB_HDRC_HCD
case OTG_STATE_A_HOST:
case OTG_STATE_A_SUSPEND:
usb_hcd_resume_root_hub(musb_to_hcd(musb));
musb_root_disconnect(musb);
if (musb->a_wait_bcon != 0)
musb_platform_try_idle(musb, jiffies
@ -1815,7 +1816,7 @@ static void musb_free(struct musb *musb)
#ifdef CONFIG_SYSFS
device_remove_file(musb->controller, &dev_attr_mode);
device_remove_file(musb->controller, &dev_attr_vbus);
#ifdef CONFIG_USB_MUSB_OTG
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
device_remove_file(musb->controller, &dev_attr_srp);
#endif
#endif
@ -2063,7 +2064,7 @@ fail2:
#ifdef CONFIG_SYSFS
device_remove_file(musb->controller, &dev_attr_mode);
device_remove_file(musb->controller, &dev_attr_vbus);
#ifdef CONFIG_USB_MUSB_OTG
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
device_remove_file(musb->controller, &dev_attr_srp);
#endif
#endif
@ -2243,10 +2244,10 @@ static int __init musb_init(void)
return platform_driver_probe(&musb_driver, musb_probe);
}
/* make us init after usbcore and before usb
* gadget and host-side drivers start to register
/* make us init after usbcore and i2c (transceivers, regulators, etc)
* and before usb gadget and host-side drivers start to register
*/
subsys_initcall(musb_init);
fs_initcall(musb_init);
static void __exit musb_cleanup(void)
{

View file

@ -575,7 +575,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
struct usb_request *request = &req->request;
struct musb_ep *musb_ep = &musb->endpoints[epnum].ep_out;
void __iomem *epio = musb->endpoints[epnum].regs;
u16 fifo_count = 0;
unsigned fifo_count = 0;
u16 len = musb_ep->packet_sz;
csr = musb_readw(epio, MUSB_RXCSR);
@ -687,7 +687,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
len, fifo_count,
musb_ep->packet_sz);
fifo_count = min(len, fifo_count);
fifo_count = min_t(unsigned, len, fifo_count);
#ifdef CONFIG_USB_TUSB_OMAP_DMA
if (tusb_dma_omap() && musb_ep->dma) {

View file

@ -335,16 +335,11 @@ musb_save_toggle(struct musb_hw_ep *ep, int is_in, struct urb *urb)
static struct musb_qh *
musb_giveback(struct musb_qh *qh, struct urb *urb, int status)
{
int is_in;
struct musb_hw_ep *ep = qh->hw_ep;
struct musb *musb = ep->musb;
int is_in = usb_pipein(urb->pipe);
int ready = qh->is_ready;
if (ep->is_shared_fifo)
is_in = 1;
else
is_in = usb_pipein(urb->pipe);
/* save toggle eagerly, for paranoia */
switch (qh->type) {
case USB_ENDPOINT_XFER_BULK:
@ -432,7 +427,7 @@ musb_advance_schedule(struct musb *musb, struct urb *urb,
else
qh = musb_giveback(qh, urb, urb->status);
if (qh && qh->is_ready && !list_empty(&qh->hep->urb_list)) {
if (qh != NULL && qh->is_ready) {
DBG(4, "... next ep%d %cX urb %p\n",
hw_ep->epnum, is_in ? 'R' : 'T',
next_urb(qh));
@ -942,8 +937,8 @@ static bool musb_h_ep0_continue(struct musb *musb, u16 len, struct urb *urb)
switch (musb->ep0_stage) {
case MUSB_EP0_IN:
fifo_dest = urb->transfer_buffer + urb->actual_length;
fifo_count = min(len, ((u16) (urb->transfer_buffer_length
- urb->actual_length)));
fifo_count = min_t(size_t, len, urb->transfer_buffer_length -
urb->actual_length);
if (fifo_count < len)
urb->status = -EOVERFLOW;
@ -976,10 +971,9 @@ static bool musb_h_ep0_continue(struct musb *musb, u16 len, struct urb *urb)
}
/* FALLTHROUGH */
case MUSB_EP0_OUT:
fifo_count = min(qh->maxpacket, ((u16)
(urb->transfer_buffer_length
- urb->actual_length)));
fifo_count = min_t(size_t, qh->maxpacket,
urb->transfer_buffer_length -
urb->actual_length);
if (fifo_count) {
fifo_dest = (u8 *) (urb->transfer_buffer
+ urb->actual_length);
@ -1161,7 +1155,8 @@ void musb_host_tx(struct musb *musb, u8 epnum)
struct urb *urb;
struct musb_hw_ep *hw_ep = musb->endpoints + epnum;
void __iomem *epio = hw_ep->regs;
struct musb_qh *qh = hw_ep->out_qh;
struct musb_qh *qh = hw_ep->is_shared_fifo ? hw_ep->in_qh
: hw_ep->out_qh;
u32 status = 0;
void __iomem *mbase = musb->mregs;
struct dma_channel *dma;
@ -1308,7 +1303,8 @@ void musb_host_tx(struct musb *musb, u8 epnum)
* packets before updating TXCSR ... other docs disagree ...
*/
/* PIO: start next packet in this URB */
wLength = min(qh->maxpacket, (u16) wLength);
if (wLength > qh->maxpacket)
wLength = qh->maxpacket;
musb_write_fifo(hw_ep, wLength, buf);
qh->segsize = wLength;
@ -1867,19 +1863,21 @@ static int musb_urb_enqueue(
}
qh->type_reg = type_reg;
/* precompute rxinterval/txinterval register */
interval = min((u8)16, epd->bInterval); /* log encoding */
/* Precompute RXINTERVAL/TXINTERVAL register */
switch (qh->type) {
case USB_ENDPOINT_XFER_INT:
/* fullspeed uses linear encoding */
if (USB_SPEED_FULL == urb->dev->speed) {
interval = epd->bInterval;
if (!interval)
interval = 1;
/*
* Full/low speeds use the linear encoding,
* high speed uses the logarithmic encoding.
*/
if (urb->dev->speed <= USB_SPEED_FULL) {
interval = max_t(u8, epd->bInterval, 1);
break;
}
/* FALLTHROUGH */
case USB_ENDPOINT_XFER_ISOC:
/* iso always uses log encoding */
/* ISO always uses logarithmic encoding */
interval = min_t(u8, epd->bInterval, 16);
break;
default:
/* REVISIT we actually want to use NAK limits, hinting to the
@ -2037,9 +2035,9 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
goto done;
/* Any URB not actively programmed into endpoint hardware can be
* immediately given back. Such an URB must be at the head of its
* immediately given back; that's any URB not at the head of an
* endpoint queue, unless someday we get real DMA queues. And even
* then, it might not be known to the hardware...
* if it's at the head, it might not be known to the hardware...
*
* Otherwise abort current transfer, pending dma, etc.; urb->status
* has already been updated. This is a synchronous abort; it'd be
@ -2078,6 +2076,15 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
qh->is_ready = 0;
__musb_giveback(musb, urb, 0);
qh->is_ready = ready;
/* If nothing else (usually musb_giveback) is using it
* and its URB list has emptied, recycle this qh.
*/
if (ready && list_empty(&qh->hep->urb_list)) {
qh->hep->hcpriv = NULL;
list_del(&qh->ring);
kfree(qh);
}
} else
ret = musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN);
done:
@ -2093,15 +2100,16 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
unsigned long flags;
struct musb *musb = hcd_to_musb(hcd);
u8 is_in = epnum & USB_DIR_IN;
struct musb_qh *qh = hep->hcpriv;
struct urb *urb, *tmp;
struct musb_qh *qh;
struct urb *urb;
struct list_head *sched;
if (!qh)
return;
spin_lock_irqsave(&musb->lock, flags);
qh = hep->hcpriv;
if (qh == NULL)
goto exit;
switch (qh->type) {
case USB_ENDPOINT_XFER_CONTROL:
sched = &musb->control;
@ -2135,13 +2143,28 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
/* cleanup */
musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN);
} else
urb = NULL;
/* then just nuke all the others */
list_for_each_entry_safe_from(urb, tmp, &hep->urb_list, urb_list)
musb_giveback(qh, urb, -ESHUTDOWN);
/* Then nuke all the others ... and advance the
* queue on hw_ep (e.g. bulk ring) when we're done.
*/
while (!list_empty(&hep->urb_list)) {
urb = next_urb(qh);
urb->status = -ESHUTDOWN;
musb_advance_schedule(musb, urb, qh->hw_ep, is_in);
}
} else {
/* Just empty the queue; the hardware is busy with
* other transfers, and since !qh->is_ready nothing
* will activate any of these as it advances.
*/
while (!list_empty(&hep->urb_list))
__musb_giveback(musb, next_urb(qh), -ESHUTDOWN);
hep->hcpriv = NULL;
list_del(&qh->ring);
kfree(qh);
}
exit:
spin_unlock_irqrestore(&musb->lock, flags);
}

View file

@ -294,7 +294,11 @@ static int option_send_setup(struct tty_struct *tty, struct usb_serial_port *po
/* Ericsson products */
#define ERICSSON_VENDOR_ID 0x0bdb
#define ERICSSON_PRODUCT_F3507G 0x1900
#define ERICSSON_PRODUCT_F3507G_1 0x1900
#define ERICSSON_PRODUCT_F3507G_2 0x1902
#define BENQ_VENDOR_ID 0x04a5
#define BENQ_PRODUCT_H10 0x4068
static struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
@ -509,7 +513,10 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF626) },
{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF628) },
{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH) },
{ USB_DEVICE(ERICSSON_VENDOR_ID, ERICSSON_PRODUCT_F3507G) },
{ USB_DEVICE(ERICSSON_VENDOR_ID, ERICSSON_PRODUCT_F3507G_1) },
{ USB_DEVICE(ERICSSON_VENDOR_ID, ERICSSON_PRODUCT_F3507G_2) },
{ USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) },
{ USB_DEVICE(0x1da5, 0x4515) }, /* BenQ H20 */
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, option_ids);

View file

@ -907,13 +907,13 @@ UNUSUAL_DEV( 0x05e3, 0x0701, 0x0000, 0xffff,
"Genesys Logic",
"USB to IDE Optical",
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 ),
US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 | US_FL_IGNORE_RESIDUE ),
UNUSUAL_DEV( 0x05e3, 0x0702, 0x0000, 0xffff,
"Genesys Logic",
"USB to IDE Disk",
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 ),
US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 | US_FL_IGNORE_RESIDUE ),
/* Reported by Ben Efros <ben@pc-doctor.com> */
UNUSUAL_DEV( 0x05e3, 0x0723, 0x9451, 0x9451,