Commit 69d42f24 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge kroah.com:/home/greg/linux/BK/bleed-2.5

into kroah.com:/home/greg/linux/BK/gregkh-2.5
parents 1a1b6495 db186469
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#define USBMIDI_ROLAND_UA100G 0x0000 #define USBMIDI_ROLAND_UA100G 0x0000
#define USBMIDI_ROLAND_MPU64 0x0002 #define USBMIDI_ROLAND_MPU64 0x0002
#define USBMIDI_ROLAND_SC8850 0x0003 #define USBMIDI_ROLAND_SC8850 0x0003
#define USBMIDI_ROLAND_SC8820 0x0007
#define USBMIDI_ROLAND_UM2 0x0005 #define USBMIDI_ROLAND_UM2 0x0005
#define USBMIDI_ROLAND_UM1 0x0009 #define USBMIDI_ROLAND_UM1 0x0009
#define USBMIDI_ROLAND_PC300 0x0008 #define USBMIDI_ROLAND_PC300 0x0008
...@@ -104,6 +105,13 @@ static struct usb_midi_device usb_midi_devices[] = { ...@@ -104,6 +105,13 @@ static struct usb_midi_device usb_midi_devices[] = {
{ { 0x01, 15 }, {-1, -1} }, { { 0x01, 15 }, {-1, -1} },
}, },
{ /* Roland SC8820 */
"Roland SC8820",
USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8820, 2, -1,
{ { 0x81, 17 }, {-1, -1} },
{ { 0x01, 17 }, {-1, -1} },
},
{ /* YAMAHA MU1000 */ { /* YAMAHA MU1000 */
"YAMAHA MU1000", "YAMAHA MU1000",
USB_VENDOR_ID_YAMAHA, USBMIDI_YAMAHA_MU1000, 0, -1, USB_VENDOR_ID_YAMAHA, USBMIDI_YAMAHA_MU1000, 0, -1,
......
...@@ -183,15 +183,21 @@ show_##field (struct device *dev, char *buf) \ ...@@ -183,15 +183,21 @@ show_##field (struct device *dev, char *buf) \
} \ } \
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
usb_intf_attr (bInterfaceNumber, "%02x\n")
usb_intf_attr (bAlternateSetting, "%2d\n") usb_intf_attr (bAlternateSetting, "%2d\n")
usb_intf_attr (bNumEndpoints, "%02x\n")
usb_intf_attr (bInterfaceClass, "%02x\n") usb_intf_attr (bInterfaceClass, "%02x\n")
usb_intf_attr (bInterfaceSubClass, "%02x\n") usb_intf_attr (bInterfaceSubClass, "%02x\n")
usb_intf_attr (bInterfaceProtocol, "%02x\n") usb_intf_attr (bInterfaceProtocol, "%02x\n")
usb_intf_attr (iInterface, "%02x\n")
void usb_create_driverfs_intf_files (struct usb_interface *intf) void usb_create_driverfs_intf_files (struct usb_interface *intf)
{ {
device_create_file (&intf->dev, &dev_attr_bInterfaceNumber);
device_create_file (&intf->dev, &dev_attr_bAlternateSetting); device_create_file (&intf->dev, &dev_attr_bAlternateSetting);
device_create_file (&intf->dev, &dev_attr_bNumEndpoints);
device_create_file (&intf->dev, &dev_attr_bInterfaceClass); device_create_file (&intf->dev, &dev_attr_bInterfaceClass);
device_create_file (&intf->dev, &dev_attr_bInterfaceSubClass); device_create_file (&intf->dev, &dev_attr_bInterfaceSubClass);
device_create_file (&intf->dev, &dev_attr_bInterfaceProtocol); device_create_file (&intf->dev, &dev_attr_bInterfaceProtocol);
device_create_file (&intf->dev, &dev_attr_iInterface);
} }
...@@ -1148,7 +1148,7 @@ void usb_hub_cleanup(void) ...@@ -1148,7 +1148,7 @@ void usb_hub_cleanup(void)
int ret; int ret;
/* Kill the thread */ /* Kill the thread */
ret = kill_proc(khubd_pid, SIGTERM, 1); ret = kill_proc(khubd_pid, SIGKILL, 1);
wait_for_completion(&khubd_exited); wait_for_completion(&khubd_exited);
......
...@@ -605,8 +605,10 @@ show_registers (struct device *dev, char *buf) ...@@ -605,8 +605,10 @@ show_registers (struct device *dev, char *buf)
} }
#ifdef EHCI_STATS #ifdef EHCI_STATS
temp = snprintf (next, size, "irq normal %ld err %ld reclaim %ld\n", temp = snprintf (next, size,
ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim); "irq normal %ld err %ld reclaim %ld (lost %ld)\n",
ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim,
ehci->stats.lost_iaa);
size -= temp; size -= temp;
next += temp; next += temp;
......
...@@ -260,6 +260,7 @@ static void ehci_watchdog (unsigned long param) ...@@ -260,6 +260,7 @@ static void ehci_watchdog (unsigned long param)
if (status & STS_IAA) { if (status & STS_IAA) {
ehci_vdbg (ehci, "lost IAA\n"); ehci_vdbg (ehci, "lost IAA\n");
COUNT (ehci->stats.lost_iaa);
writel (STS_IAA, &ehci->regs->status); writel (STS_IAA, &ehci->regs->status);
ehci->reclaim_ready = 1; ehci->reclaim_ready = 1;
} }
...@@ -547,8 +548,9 @@ static void ehci_stop (struct usb_hcd *hcd) ...@@ -547,8 +548,9 @@ static void ehci_stop (struct usb_hcd *hcd)
ehci_mem_cleanup (ehci); ehci_mem_cleanup (ehci);
#ifdef EHCI_STATS #ifdef EHCI_STATS
ehci_dbg (ehci, "irq normal %ld err %ld reclaim %ld\n", ehci_dbg (ehci, "irq normal %ld err %ld reclaim %ld (lost %ld)\n",
ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim); ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim,
ehci->stats.lost_iaa);
ehci_dbg (ehci, "complete %ld unlink %ld\n", ehci_dbg (ehci, "complete %ld unlink %ld\n",
ehci->stats.complete, ehci->stats.unlink); ehci->stats.complete, ehci->stats.unlink);
#endif #endif
......
...@@ -800,6 +800,7 @@ static struct ehci_qh *qh_append_tds ( ...@@ -800,6 +800,7 @@ static struct ehci_qh *qh_append_tds (
&& !usb_pipecontrol (urb->pipe)) { && !usb_pipecontrol (urb->pipe)) {
/* "never happens": drivers do stall cleanup right */ /* "never happens": drivers do stall cleanup right */
if (qh->qh_state != QH_STATE_IDLE if (qh->qh_state != QH_STATE_IDLE
&& !list_empty (&qh->qtd_list)
&& qh->qh_state != QH_STATE_COMPLETING) && qh->qh_state != QH_STATE_COMPLETING)
ehci_warn (ehci, "clear toggle dev%d " ehci_warn (ehci, "clear toggle dev%d "
"ep%d%s: not idle\n", "ep%d%s: not idle\n",
...@@ -1014,6 +1015,7 @@ static void ...@@ -1014,6 +1015,7 @@ static void
scan_async (struct ehci_hcd *ehci, struct pt_regs *regs) scan_async (struct ehci_hcd *ehci, struct pt_regs *regs)
{ {
struct ehci_qh *qh; struct ehci_qh *qh;
int unlink_delay = 0;
if (!++(ehci->stamp)) if (!++(ehci->stamp))
ehci->stamp++; ehci->stamp++;
...@@ -1040,17 +1042,25 @@ scan_async (struct ehci_hcd *ehci, struct pt_regs *regs) ...@@ -1040,17 +1042,25 @@ scan_async (struct ehci_hcd *ehci, struct pt_regs *regs)
} }
} }
/* unlink idle entries, reducing HC PCI usage as /* unlink idle entries, reducing HC PCI usage as well
* well as HCD schedule-scanning costs. * as HCD schedule-scanning costs. delay for any qh
* * we just scanned, there's a not-unusual case that it
* FIXME don't unlink idle entries so quickly; it * doesn't stay idle for long.
* can penalize (common) half duplex protocols. * (plus, avoids some kind of re-activation race.)
*/ */
if (list_empty (&qh->qtd_list) && !ehci->reclaim) { if (list_empty (&qh->qtd_list)) {
start_unlink_async (ehci, qh); if (qh->stamp == ehci->stamp)
unlink_delay = 1;
else if (!ehci->reclaim) {
start_unlink_async (ehci, qh);
unlink_delay = 0;
}
} }
qh = qh->qh_next.qh; qh = qh->qh_next.qh;
} while (qh); } while (qh);
} }
if (unlink_delay && !timer_pending (&ehci->watchdog))
mod_timer (&ehci->watchdog, jiffies + EHCI_WATCHDOG_JIFFIES/2);
} }
...@@ -27,6 +27,7 @@ struct ehci_stats { ...@@ -27,6 +27,7 @@ struct ehci_stats {
unsigned long normal; unsigned long normal;
unsigned long error; unsigned long error;
unsigned long reclaim; unsigned long reclaim;
unsigned long lost_iaa;
/* termination of urbs from core */ /* termination of urbs from core */
unsigned long complete; unsigned long complete;
......
This diff is collapsed.
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
* *
* History: * History:
* *
* 2003/02/24 show registers in sysfs (Kevin Brosius)
*
* 2002/09/03 get rid of ed hashtables, rework periodic scheduling and * 2002/09/03 get rid of ed hashtables, rework periodic scheduling and
* bandwidth accounting; if debugging, show schedules in driverfs * bandwidth accounting; if debugging, show schedules in driverfs
* 2002/07/19 fixes to management of ED and schedule state. * 2002/07/19 fixes to management of ED and schedule state.
...@@ -105,11 +107,10 @@ ...@@ -105,11 +107,10 @@
* TO DO: * TO DO:
* *
* - "disabled" and "sleeping" should be in hcd->state * - "disabled" and "sleeping" should be in hcd->state
* - bandwidth alloc to generic code
* - lots more testing!! * - lots more testing!!
*/ */
#define DRIVER_VERSION "2002-Sep-17" #define DRIVER_VERSION "2003 Feb 24"
#define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell" #define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
#define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver" #define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
...@@ -125,6 +126,8 @@ ...@@ -125,6 +126,8 @@
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static const char hcd_name [] = "ohci-hcd";
#include "ohci.h" #include "ohci.h"
static inline void disable (struct ohci_hcd *ohci) static inline void disable (struct ohci_hcd *ohci)
...@@ -275,6 +278,7 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) ...@@ -275,6 +278,7 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
urb_print (urb, "UNLINK", 1); urb_print (urb, "UNLINK", 1);
#endif #endif
spin_lock_irqsave (&ohci->lock, flags);
if (!ohci->disabled) { if (!ohci->disabled) {
urb_priv_t *urb_priv; urb_priv_t *urb_priv;
...@@ -282,21 +286,24 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) ...@@ -282,21 +286,24 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
* handed to us, flag it for unlink and giveback, and force * handed to us, flag it for unlink and giveback, and force
* some upcoming INTR_SF to call finish_unlinks() * some upcoming INTR_SF to call finish_unlinks()
*/ */
spin_lock_irqsave (&ohci->lock, flags);
urb_priv = urb->hcpriv; urb_priv = urb->hcpriv;
if (urb_priv) { if (urb_priv) {
urb_priv->state = URB_DEL; urb_priv->state = URB_DEL;
if (urb_priv->ed->state == ED_OPER) if (urb_priv->ed->state == ED_OPER)
start_urb_unlink (ohci, urb_priv->ed); start_urb_unlink (ohci, urb_priv->ed);
} }
spin_unlock_irqrestore (&ohci->lock, flags);
} else { } else {
/* /*
* with HC dead, we won't respect hc queue pointers * with HC dead, we won't respect hc queue pointers
* any more ... just clean up every urb's memory. * any more ... just clean up every urb's memory.
*/ */
finish_urb (ohci, urb, NULL); if (urb->hcpriv) {
spin_unlock (&ohci->lock);
finish_urb (ohci, urb, NULL);
spin_lock (&ohci->lock);
}
} }
spin_unlock_irqrestore (&ohci->lock, flags);
return 0; return 0;
} }
...@@ -332,9 +339,11 @@ ohci_free_config (struct usb_hcd *hcd, struct usb_device *udev) ...@@ -332,9 +339,11 @@ ohci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
td_free (ohci, ed->dummy); td_free (ohci, ed->dummy);
break; break;
default: default:
err ("%s-%s ed %p (#%d) not unlinked; disconnect() bug? %d", ohci_err (ohci,
ohci->hcd.self.bus_name, udev->devpath, ed, "dev %s ep%d-%s linked; disconnect() bug?\n",
i, ed->state); udev->devpath,
(i >> 1) & 0x0f, (i & 1) ? "out" : "in");
/* ED_OPER: some driver disconnect() is broken, /* ED_OPER: some driver disconnect() is broken,
* it didn't even start its unlinks much less wait * it didn't even start its unlinks much less wait
* for their completions. * for their completions.
...@@ -354,8 +363,10 @@ ohci_free_config (struct usb_hcd *hcd, struct usb_device *udev) ...@@ -354,8 +363,10 @@ ohci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
#ifdef DEBUG #ifdef DEBUG
/* a driver->disconnect() returned before its unlinks completed? */ /* a driver->disconnect() returned before its unlinks completed? */
if (in_interrupt ()) { if (in_interrupt ()) {
warn ("disconnect() bug for dev usb-%s-%s ep 0x%x", ohci_warn (ohci,
ohci->hcd.self.bus_name, udev->devpath, i); "driver disconnect() bug %s ep%d-%s\n",
udev->devpath,
(i >> 1) & 0x0f, (i & 1) ? "out" : "in");
} }
#endif #endif
...@@ -381,9 +392,12 @@ static int hc_reset (struct ohci_hcd *ohci) ...@@ -381,9 +392,12 @@ static int hc_reset (struct ohci_hcd *ohci)
{ {
u32 temp; u32 temp;
/* SMM owns the HC? not for long! */ /* SMM owns the HC? not for long!
* On PA-RISC, PDC can leave IR set incorrectly; ignore it there.
*/
#ifndef __hppa__
if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { if (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
dev_dbg (ohci->hcd.controller, "USB HC TakeOver from BIOS/SMM\n"); ohci_dbg (ohci, "USB HC TakeOver from BIOS/SMM\n");
/* this timeout is arbitrary. we make it long, so systems /* this timeout is arbitrary. we make it long, so systems
* depending on usb keyboards may be usable even if the * depending on usb keyboards may be usable even if the
...@@ -396,17 +410,18 @@ static int hc_reset (struct ohci_hcd *ohci) ...@@ -396,17 +410,18 @@ static int hc_reset (struct ohci_hcd *ohci)
while (readl (&ohci->regs->control) & OHCI_CTRL_IR) { while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
wait_ms (10); wait_ms (10);
if (--temp == 0) { if (--temp == 0) {
dev_err (ohci->hcd.controller, "USB HC TakeOver failed!\n"); ohci_err (ohci, "USB HC TakeOver failed!\n");
return -1; return -1;
} }
} }
} }
#endif
/* Disable HC interrupts */ /* Disable HC interrupts */
writel (OHCI_INTR_MIE, &ohci->regs->intrdisable); writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
dev_dbg (ohci->hcd.controller, "USB HC reset_hc %s: ctrl = 0x%x ;\n", ohci_dbg (ohci, "USB HC reset_hc %s: ctrl = 0x%x ;\n",
ohci->hcd.self.bus_name, hcd_to_bus (&ohci->hcd)->bus_name,
readl (&ohci->regs->control)); readl (&ohci->regs->control));
/* Reset USB (needed by some controllers); RemoteWakeupConnected /* Reset USB (needed by some controllers); RemoteWakeupConnected
...@@ -422,7 +437,7 @@ static int hc_reset (struct ohci_hcd *ohci) ...@@ -422,7 +437,7 @@ static int hc_reset (struct ohci_hcd *ohci)
temp = 30; /* ... allow extra time */ temp = 30; /* ... allow extra time */
while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) { while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
if (--temp == 0) { if (--temp == 0) {
dev_err (ohci->hcd.controller, "USB HC reset timed out!"); ohci_err (ohci, "USB HC reset timed out!\n");
return -1; return -1;
} }
udelay (1); udelay (1);
...@@ -451,8 +466,9 @@ static int hc_reset (struct ohci_hcd *ohci) ...@@ -451,8 +466,9 @@ static int hc_reset (struct ohci_hcd *ohci)
*/ */
static int hc_start (struct ohci_hcd *ohci) static int hc_start (struct ohci_hcd *ohci)
{ {
u32 mask; u32 mask, tmp;
struct usb_device *udev; struct usb_device *udev;
struct usb_bus *bus;
spin_lock_init (&ohci->lock); spin_lock_init (&ohci->lock);
ohci->disabled = 1; ohci->disabled = 1;
...@@ -478,7 +494,7 @@ static int hc_start (struct ohci_hcd *ohci) ...@@ -478,7 +494,7 @@ static int hc_start (struct ohci_hcd *ohci)
*/ */
if ((readl (&ohci->regs->fminterval) & 0x3fff0000) == 0 if ((readl (&ohci->regs->fminterval) & 0x3fff0000) == 0
|| !readl (&ohci->regs->periodicstart)) { || !readl (&ohci->regs->periodicstart)) {
err ("%s init err", ohci->hcd.self.bus_name); ohci_err (ohci, "init err\n");
return -EOVERFLOW; return -EOVERFLOW;
} }
...@@ -493,9 +509,20 @@ static int hc_start (struct ohci_hcd *ohci) ...@@ -493,9 +509,20 @@ static int hc_start (struct ohci_hcd *ohci)
writel (mask, &ohci->regs->intrstatus); writel (mask, &ohci->regs->intrstatus);
writel (mask, &ohci->regs->intrenable); writel (mask, &ohci->regs->intrenable);
/* hub power always on: required for AMD-756 and some Mac platforms */ /* handle root hub init quirks ... */
writel ((roothub_a (ohci) | RH_A_NPS) & ~(RH_A_PSM | RH_A_OCPM), tmp = roothub_a (ohci);
&ohci->regs->roothub.a); tmp &= ~(RH_A_PSM | RH_A_OCPM);
if (ohci->flags & OHCI_QUIRK_SUPERIO) {
/* NSC 87560 and maybe others */
tmp |= RH_A_NOCP;
tmp &= ~(RH_A_POTPGT | RH_A_NPS);
} else {
/* hub power always on; required for AMD-756 and some
* Mac platforms, use this mode everywhere by default
*/
tmp |= RH_A_NPS;
}
writel (tmp, &ohci->regs->roothub.a);
writel (RH_HS_LPSC, &ohci->regs->roothub.status); writel (RH_HS_LPSC, &ohci->regs->roothub.status);
writel (0, &ohci->regs->roothub.b); writel (0, &ohci->regs->roothub.b);
...@@ -503,7 +530,8 @@ static int hc_start (struct ohci_hcd *ohci) ...@@ -503,7 +530,8 @@ static int hc_start (struct ohci_hcd *ohci)
mdelay ((roothub_a (ohci) >> 23) & 0x1fe); mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
/* connect the virtual root hub */ /* connect the virtual root hub */
ohci->hcd.self.root_hub = udev = usb_alloc_dev (NULL, &ohci->hcd.self); bus = hcd_to_bus (&ohci->hcd);
bus->root_hub = udev = usb_alloc_dev (NULL, bus);
ohci->hcd.state = USB_STATE_READY; ohci->hcd.state = USB_STATE_READY;
if (!udev) { if (!udev) {
disable (ohci); disable (ohci);
...@@ -514,9 +542,9 @@ static int hc_start (struct ohci_hcd *ohci) ...@@ -514,9 +542,9 @@ static int hc_start (struct ohci_hcd *ohci)
usb_connect (udev); usb_connect (udev);
udev->speed = USB_SPEED_FULL; udev->speed = USB_SPEED_FULL;
if (usb_register_root_hub (udev, ohci->hcd.controller) != 0) { if (hcd_register_root (&ohci->hcd) != 0) {
usb_put_dev (udev); usb_put_dev (udev);
ohci->hcd.self.root_hub = NULL; bus->root_hub = NULL;
disable (ohci); disable (ohci);
ohci->hc_control &= ~OHCI_CTRL_HCFS; ohci->hc_control &= ~OHCI_CTRL_HCFS;
writel (ohci->hc_control, &ohci->regs->control); writel (ohci->hc_control, &ohci->regs->control);
...@@ -545,7 +573,7 @@ static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) ...@@ -545,7 +573,7 @@ static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
/* cardbus/... hardware gone before remove() */ /* cardbus/... hardware gone before remove() */
} else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) { } else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
disable (ohci); disable (ohci);
dbg ("%s device removed!", hcd->self.bus_name); ohci_dbg (ohci, "device removed!\n");
return; return;
/* interrupt for some other device? */ /* interrupt for some other device? */
...@@ -553,13 +581,9 @@ static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) ...@@ -553,13 +581,9 @@ static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
return; return;
} }
// dbg ("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no));
if (ints & OHCI_INTR_UE) { if (ints & OHCI_INTR_UE) {
disable (ohci); disable (ohci);
err ("OHCI Unrecoverable Error, %s disabled", ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n");
hcd->self.bus_name);
// e.g. due to PCI Master/Target Abort // e.g. due to PCI Master/Target Abort
ohci_dump (ohci, 1); ohci_dump (ohci, 1);
...@@ -579,7 +603,8 @@ static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) ...@@ -579,7 +603,8 @@ static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
*/ */
spin_lock (&ohci->lock); spin_lock (&ohci->lock);
if (ohci->ed_rm_list) if (ohci->ed_rm_list)
finish_unlinks (ohci, le16_to_cpu (ohci->hcca->frame_no), ptregs); finish_unlinks (ohci, le16_to_cpu (ohci->hcca->frame_no),
ptregs);
if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list) if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list)
writel (OHCI_INTR_SF, &regs->intrdisable); writel (OHCI_INTR_SF, &regs->intrdisable);
spin_unlock (&ohci->lock); spin_unlock (&ohci->lock);
...@@ -594,7 +619,7 @@ static void ohci_stop (struct usb_hcd *hcd) ...@@ -594,7 +619,7 @@ static void ohci_stop (struct usb_hcd *hcd)
{ {
struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ohci_hcd *ohci = hcd_to_ohci (hcd);
dev_dbg (hcd->controller, "stop %s controller%s\n", ohci_dbg (ohci, "stop %s controller%s\n",
hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS), hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
ohci->disabled ? " (disabled)" : "" ohci->disabled ? " (disabled)" : ""
); );
...@@ -629,8 +654,8 @@ static int hc_restart (struct ohci_hcd *ohci) ...@@ -629,8 +654,8 @@ static int hc_restart (struct ohci_hcd *ohci)
ohci->disabled = 1; ohci->disabled = 1;
ohci->sleeping = 0; ohci->sleeping = 0;
if (ohci->hcd.self.root_hub) if (hcd_to_bus (&ohci->hcd)->root_hub)
usb_disconnect (&ohci->hcd.self.root_hub); usb_disconnect (&hcd_to_bus (&ohci->hcd)->root_hub);
/* empty the interrupt branches */ /* empty the interrupt branches */
for (i = 0; i < NUM_INTS; i++) ohci->load [i] = 0; for (i = 0; i < NUM_INTS; i++) ohci->load [i] = 0;
...@@ -644,18 +669,16 @@ static int hc_restart (struct ohci_hcd *ohci) ...@@ -644,18 +669,16 @@ static int hc_restart (struct ohci_hcd *ohci)
ohci->ed_bulktail = NULL; ohci->ed_bulktail = NULL;
if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0) { if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0) {
err ("can't restart %s, %d", ohci->hcd.self.bus_name, temp); ohci_err (ohci, "can't restart, %d\n", temp);
return temp; return temp;
} else } else
dbg ("restart %s completed", ohci->hcd.self.bus_name); ohci_dbg (ohci, "restart complete\n");
return 0; return 0;
} }
#endif #endif
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static const char hcd_name [] = "ohci-hcd";
#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
MODULE_AUTHOR (DRIVER_AUTHOR); MODULE_AUTHOR (DRIVER_AUTHOR);
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
* (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
* *
* This file is licenced under GPL * This file is licenced under GPL
* $Id: ohci-hub.c,v 1.3 2002/03/22 16:04:54 dbrownell Exp $
*/ */
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -41,7 +40,7 @@ static u32 roothub_portstatus (struct ohci_hcd *hc, int i) ...@@ -41,7 +40,7 @@ static u32 roothub_portstatus (struct ohci_hcd *hc, int i)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
#define dbg_port(hc,label,num,value) \ #define dbg_port(hc,label,num,value) \
dev_dbg (hc->hcd.controller, \ ohci_dbg (hc, \
"%s roothub.portstatus [%d] " \ "%s roothub.portstatus [%d] " \
"= 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s\n", \ "= 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s\n", \
label, num, temp, \ label, num, temp, \
...@@ -76,9 +75,8 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) ...@@ -76,9 +75,8 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
if (ports > MAX_ROOT_PORTS) { if (ports > MAX_ROOT_PORTS) {
if (ohci->disabled) if (ohci->disabled)
return -ESHUTDOWN; return -ESHUTDOWN;
err ("%s bogus NDP=%d, rereads as NDP=%d", ohci_err (ohci, "bogus NDP=%d, rereads as NDP=%d\n",
hcd->self.bus_name, ports, ports, readl (&ohci->regs->roothub.a) & RH_A_NDP);
readl (&ohci->regs->roothub.a) & RH_A_NDP);
/* retry later; "should not happen" */ /* retry later; "should not happen" */
return 0; return 0;
} }
...@@ -159,7 +157,7 @@ static int ohci_hub_control ( ...@@ -159,7 +157,7 @@ static int ohci_hub_control (
u16 wLength u16 wLength
) { ) {
struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int ports = hcd->self.root_hub->maxchild; int ports = hcd_to_bus (hcd)->root_hub->maxchild;
u32 temp; u32 temp;
int retval = 0; int retval = 0;
......
...@@ -115,8 +115,8 @@ td_free (struct ohci_hcd *hc, struct td *td) ...@@ -115,8 +115,8 @@ td_free (struct ohci_hcd *hc, struct td *td)
prev = &(*prev)->td_hash; prev = &(*prev)->td_hash;
if (*prev) if (*prev)
*prev = td->td_hash; *prev = td->td_hash;
else else if ((td->hwINFO & TD_DONE) != 0)
dev_dbg (hc->hcd.controller, "bad hash for td %p\n", td); ohci_dbg (hc, "no hash for td %p\n", td);
pci_pool_free (hc->td_cache, td, td->td_dma); pci_pool_free (hc->td_cache, td, td->td_dma);
} }
......
...@@ -29,17 +29,6 @@ ...@@ -29,17 +29,6 @@
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
struct ohci_hcd *dev_to_ohci(struct device *dev) {
struct pci_dev *pdev =
container_of (dev, struct pci_dev, dev);
struct ohci_hcd *ohci =
container_of (pci_get_drvdata (pdev), struct ohci_hcd, hcd);
return ohci;
}
/*-------------------------------------------------------------------------*/
static int __devinit static int __devinit
ohci_pci_start (struct usb_hcd *hcd) ohci_pci_start (struct usb_hcd *hcd)
{ {
...@@ -55,22 +44,43 @@ ohci_pci_start (struct usb_hcd *hcd) ...@@ -55,22 +44,43 @@ ohci_pci_start (struct usb_hcd *hcd)
/* AMD 756, for most chips (early revs), corrupts register /* AMD 756, for most chips (early revs), corrupts register
* values on read ... so enable the vendor workaround. * values on read ... so enable the vendor workaround.
*/ */
if (hcd->pdev->vendor == 0x1022 if (hcd->pdev->vendor == PCI_VENDOR_ID_AMD
&& hcd->pdev->device == 0x740c) { && hcd->pdev->device == 0x740c) {
ohci->flags = OHCI_QUIRK_AMD756; ohci->flags = OHCI_QUIRK_AMD756;
info ("%s: AMD756 erratum 4 workaround", ohci_info (ohci, "AMD756 erratum 4 workaround\n");
hcd->self.bus_name);
} }
/* FIXME for some of the early AMD 760 southbridges, OHCI
* won't work at all. blacklist them.
*/
/* Apple's OHCI driver has a lot of bizarre workarounds /* Apple's OHCI driver has a lot of bizarre workarounds
* for this chip. Evidently control and bulk lists * for this chip. Evidently control and bulk lists
* can get confused. (B&W G3 models, and ...) * can get confused. (B&W G3 models, and ...)
*/ */
else if (hcd->pdev->vendor == 0x1045 else if (hcd->pdev->vendor == PCI_VENDOR_ID_OPTI
&& hcd->pdev->device == 0xc861) { && hcd->pdev->device == 0xc861) {
info ("%s: WARNING: OPTi workarounds unavailable", ohci_info (ohci,
hcd->self.bus_name); "WARNING: OPTi workarounds unavailable\n");
} }
/* Check for NSC87560. We have to look at the bridge (fn1) to
* identify the USB (fn2). This quirk might apply to more or
* even all NSC stuff.
*/
else if (hcd->pdev->vendor == PCI_VENDOR_ID_NS) {
struct pci_dev *b, *hc;
hc = hcd->pdev;
b = pci_find_slot (hc->bus->number,
PCI_DEVFN (PCI_SLOT (hc->devfn), 1));
if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
&& b->vendor == PCI_VENDOR_ID_NS) {
ohci->flags |= OHCI_QUIRK_SUPERIO;
ohci_info (ohci, "Using NSC SuperIO setup\n");
}
}
} }
memset (ohci->hcca, 0, sizeof (struct ohci_hcca)); memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
...@@ -86,7 +96,7 @@ ohci_pci_start (struct usb_hcd *hcd) ...@@ -86,7 +96,7 @@ ohci_pci_start (struct usb_hcd *hcd)
} }
if (hc_start (ohci) < 0) { if (hc_start (ohci) < 0) {
err ("can't start %s", ohci->hcd.self.bus_name); ohci_err (ohci, "can't start\n");
ohci_stop (hcd); ohci_stop (hcd);
return -EBUSY; return -EBUSY;
} }
...@@ -106,13 +116,13 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state) ...@@ -106,13 +116,13 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state)
u16 cmd; u16 cmd;
if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) { if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) {
dbg ("can't suspend %s (state is %s)", hcd->self.bus_name, ohci_dbg (ohci, "can't suspend (state is %s)\n",
hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS)); hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS));
return -EIO; return -EIO;
} }
/* act as if usb suspend can always be used */ /* act as if usb suspend can always be used */
dbg ("%s: suspend to %d", hcd->self.bus_name, state); ohci_dbg (ohci, "suspend to %d\n", state);
ohci->sleeping = 1; ohci->sleeping = 1;
/* First stop processing */ /* First stop processing */
...@@ -147,16 +157,16 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state) ...@@ -147,16 +157,16 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state)
switch (readl (&ohci->regs->control) & OHCI_CTRL_HCFS) { switch (readl (&ohci->regs->control) & OHCI_CTRL_HCFS) {
case OHCI_USB_RESET: case OHCI_USB_RESET:
dbg ("%s suspend->reset ?", hcd->self.bus_name); ohci_dbg (ohci, "suspend->reset ?\n");
break; break;
case OHCI_USB_RESUME: case OHCI_USB_RESUME:
dbg ("%s suspend->resume ?", hcd->self.bus_name); ohci_dbg (ohci, "suspend->resume ?\n");
break; break;
case OHCI_USB_OPER: case OHCI_USB_OPER:
dbg ("%s suspend->operational ?", hcd->self.bus_name); ohci_dbg (ohci, "suspend->operational ?\n");
break; break;
case OHCI_USB_SUSPEND: case OHCI_USB_SUSPEND:
dbg ("%s suspended", hcd->self.bus_name); ohci_dbg (ohci, "suspended\n");
break; break;
} }
...@@ -204,7 +214,7 @@ static int ohci_pci_resume (struct usb_hcd *hcd) ...@@ -204,7 +214,7 @@ static int ohci_pci_resume (struct usb_hcd *hcd)
#ifdef DEBUG #ifdef DEBUG
/* the registers may look crazy here */ /* the registers may look crazy here */
ohci_dump_status (ohci); ohci_dump_status (ohci, 0, 0);
#endif #endif
/* Re-enable bus mastering */ /* Re-enable bus mastering */
...@@ -213,13 +223,13 @@ static int ohci_pci_resume (struct usb_hcd *hcd) ...@@ -213,13 +223,13 @@ static int ohci_pci_resume (struct usb_hcd *hcd)
switch (temp) { switch (temp) {
case OHCI_USB_RESET: // lost power case OHCI_USB_RESET: // lost power
info ("USB restart: %s", hcd->self.bus_name); ohci_info (ohci, "USB restart\n");
retval = hc_restart (ohci); retval = hc_restart (ohci);
break; break;
case OHCI_USB_SUSPEND: // host wakeup case OHCI_USB_SUSPEND: // host wakeup
case OHCI_USB_RESUME: // remote wakeup case OHCI_USB_RESUME: // remote wakeup
info ("USB continue: %s from %s wakeup", hcd->self.bus_name, ohci_info (ohci, "USB continue from %s wakeup\n",
(temp == OHCI_USB_SUSPEND) (temp == OHCI_USB_SUSPEND)
? "host" : "remote"); ? "host" : "remote");
ohci->hc_control = OHCI_USB_RESUME; ohci->hc_control = OHCI_USB_RESUME;
...@@ -232,7 +242,7 @@ static int ohci_pci_resume (struct usb_hcd *hcd) ...@@ -232,7 +242,7 @@ static int ohci_pci_resume (struct usb_hcd *hcd)
temp = readl (&ohci->regs->control); temp = readl (&ohci->regs->control);
temp = ohci->hc_control & OHCI_CTRL_HCFS; temp = ohci->hc_control & OHCI_CTRL_HCFS;
if (temp != OHCI_USB_RESUME) { if (temp != OHCI_USB_RESUME) {
err ("controller %s won't resume", hcd->self.bus_name); ohci_err (ohci, "controller won't resume\n");
ohci->disabled = 1; ohci->disabled = 1;
retval = -EIO; retval = -EIO;
break; break;
...@@ -278,11 +288,12 @@ static int ohci_pci_resume (struct usb_hcd *hcd) ...@@ -278,11 +288,12 @@ static int ohci_pci_resume (struct usb_hcd *hcd)
writel (OHCI_BLF | OHCI_CLF, &ohci->regs->cmdstatus); writel (OHCI_BLF | OHCI_CLF, &ohci->regs->cmdstatus);
// ohci_dump_status (ohci); // ohci_dump_status (ohci);
dbg ("sleeping = %d, disabled = %d", ohci->sleeping, ohci->disabled); ohci_dbg (ohci, "sleeping = %d, disabled = %d\n",
ohci->sleeping, ohci->disabled);
break; break;
default: default:
warn ("odd PCI resume for %s", hcd->self.bus_name); ohci_warn (ohci, "odd PCI resume\n");
} }
return retval; return retval;
} }
...@@ -373,11 +384,11 @@ static struct pci_driver ohci_pci_driver = { ...@@ -373,11 +384,11 @@ static struct pci_driver ohci_pci_driver = {
static int __init ohci_hcd_pci_init (void) static int __init ohci_hcd_pci_init (void)
{ {
dbg (DRIVER_INFO " (PCI)"); printk (KERN_DEBUG "%s: " DRIVER_INFO " (PCI)\n", hcd_name);
if (usb_disabled()) if (usb_disabled())
return -ENODEV; return -ENODEV;
dbg ("block sizes: ed %d td %d", printk (KERN_DEBUG "%s: block sizes: ed %d td %d\n", hcd_name,
sizeof (struct ed), sizeof (struct td)); sizeof (struct ed), sizeof (struct td));
return pci_module_init (&ohci_pci_driver); return pci_module_init (&ohci_pci_driver);
} }
......
...@@ -30,29 +30,28 @@ static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv) ...@@ -30,29 +30,28 @@ static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv)
/* /*
* URB goes back to driver, and isn't reissued. * URB goes back to driver, and isn't reissued.
* It's completely gone from HC data structures. * It's completely gone from HC data structures.
* PRECONDITION: no locks held (Giveback can call into HCD.) * PRECONDITION: no locks held, irqs blocked (Giveback can call into HCD.)
*/ */
static void finish_urb (struct ohci_hcd *ohci, struct urb *urb, struct pt_regs *regs) static void
finish_urb (struct ohci_hcd *ohci, struct urb *urb, struct pt_regs *regs)
{ {
unsigned long flags;
// ASSERT (urb->hcpriv != 0); // ASSERT (urb->hcpriv != 0);
urb_free_priv (ohci, urb->hcpriv); urb_free_priv (ohci, urb->hcpriv);
urb->hcpriv = NULL; urb->hcpriv = NULL;
spin_lock_irqsave (&urb->lock, flags); spin_lock (&urb->lock);
if (likely (urb->status == -EINPROGRESS)) if (likely (urb->status == -EINPROGRESS))
urb->status = 0; urb->status = 0;
spin_unlock_irqrestore (&urb->lock, flags); spin_unlock (&urb->lock);
// what lock protects these? // what lock protects these?
switch (usb_pipetype (urb->pipe)) { switch (usb_pipetype (urb->pipe)) {
case PIPE_ISOCHRONOUS: case PIPE_ISOCHRONOUS:
ohci->hcd.self.bandwidth_isoc_reqs--; hcd_to_bus (&ohci->hcd)->bandwidth_isoc_reqs--;
break; break;
case PIPE_INTERRUPT: case PIPE_INTERRUPT:
ohci->hcd.self.bandwidth_int_reqs--; hcd_to_bus (&ohci->hcd)->bandwidth_int_reqs--;
break; break;
} }
...@@ -110,12 +109,9 @@ static void periodic_link (struct ohci_hcd *ohci, struct ed *ed) ...@@ -110,12 +109,9 @@ static void periodic_link (struct ohci_hcd *ohci, struct ed *ed)
{ {
unsigned i; unsigned i;
#ifdef OHCI_VERBOSE_DEBUG ohci_vdbg (ohci, "link %sed %p branch %d [%dus.], interval %d\n",
dbg ("%s: link %sed %p branch %d [%dus.], interval %d",
ohci->hcd.self.bus_name,
(ed->hwINFO & ED_ISO) ? "iso " : "", (ed->hwINFO & ED_ISO) ? "iso " : "",
ed, ed->branch, ed->load, ed->interval); ed, ed->branch, ed->load, ed->interval);
#endif
for (i = ed->branch; i < NUM_INTS; i += ed->interval) { for (i = ed->branch; i < NUM_INTS; i += ed->interval) {
struct ed **prev = &ohci->periodic [i]; struct ed **prev = &ohci->periodic [i];
...@@ -143,7 +139,7 @@ static void periodic_link (struct ohci_hcd *ohci, struct ed *ed) ...@@ -143,7 +139,7 @@ static void periodic_link (struct ohci_hcd *ohci, struct ed *ed)
} }
ohci->load [i] += ed->load; ohci->load [i] += ed->load;
} }
ohci->hcd.self.bandwidth_allocated += ed->load / ed->interval; hcd_to_bus (&ohci->hcd)->bandwidth_allocated += ed->load / ed->interval;
} }
/* link an ed into one of the HC chains */ /* link an ed into one of the HC chains */
...@@ -206,7 +202,7 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed) ...@@ -206,7 +202,7 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
default: default:
branch = balance (ohci, ed->interval, ed->load); branch = balance (ohci, ed->interval, ed->load);
if (branch < 0) { if (branch < 0) {
dev_dbg (ohci->hcd.controller, ohci_dbg (ohci,
"ERR %d, interval %d msecs, load %d\n", "ERR %d, interval %d msecs, load %d\n",
branch, ed->interval, ed->load); branch, ed->interval, ed->load);
// FIXME if there are TDs queued, fail them! // FIXME if there are TDs queued, fail them!
...@@ -244,14 +240,11 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed) ...@@ -244,14 +240,11 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed)
} }
ohci->load [i] -= ed->load; ohci->load [i] -= ed->load;
} }
ohci->hcd.self.bandwidth_allocated -= ed->load / ed->interval; hcd_to_bus (&ohci->hcd)->bandwidth_allocated -= ed->load / ed->interval;
#ifdef OHCI_VERBOSE_DEBUG ohci_vdbg (ohci, "unlink %sed %p branch %d [%dus.], interval %d\n",
dbg ("%s: unlink %sed %p branch %d [%dus.], interval %d",
ohci->hcd.self.bus_name,
(ed->hwINFO & ED_ISO) ? "iso " : "", (ed->hwINFO & ED_ISO) ? "iso " : "",
ed, ed->branch, ed->load, ed->interval); ed, ed->branch, ed->load, ed->interval);
#endif
} }
/* unlink an ed from one of the HC chains. /* unlink an ed from one of the HC chains.
...@@ -576,7 +569,7 @@ static void td_submit_urb ( ...@@ -576,7 +569,7 @@ static void td_submit_urb (
*/ */
case PIPE_INTERRUPT: case PIPE_INTERRUPT:
/* ... and periodic urbs have extra accounting */ /* ... and periodic urbs have extra accounting */
ohci->hcd.self.bandwidth_int_reqs++; hcd_to_bus (&ohci->hcd)->bandwidth_int_reqs++;
/* FALLTHROUGH */ /* FALLTHROUGH */
case PIPE_BULK: case PIPE_BULK:
info = is_out info = is_out
...@@ -644,7 +637,7 @@ static void td_submit_urb ( ...@@ -644,7 +637,7 @@ static void td_submit_urb (
data + urb->iso_frame_desc [cnt].offset, data + urb->iso_frame_desc [cnt].offset,
urb->iso_frame_desc [cnt].length, urb, cnt); urb->iso_frame_desc [cnt].length, urb, cnt);
} }
ohci->hcd.self.bandwidth_isoc_reqs++; hcd_to_bus (&ohci->hcd)->bandwidth_isoc_reqs++;
break; break;
} }
// ASSERT (urb_priv->length == cnt); // ASSERT (urb_priv->length == cnt);
...@@ -687,11 +680,10 @@ static void td_done (struct urb *urb, struct td *td) ...@@ -687,11 +680,10 @@ static void td_done (struct urb *urb, struct td *td)
urb->iso_frame_desc [td->index].actual_length = dlen; urb->iso_frame_desc [td->index].actual_length = dlen;
urb->iso_frame_desc [td->index].status = cc_to_error [cc]; urb->iso_frame_desc [td->index].status = cc_to_error [cc];
#ifdef VERBOSE_DEBUG
if (cc != TD_CC_NOERROR) if (cc != TD_CC_NOERROR)
dbg (" urb %p iso TD %p (%d) len %d CC %d", ohci_vdbg (ohci,
"urb %p iso td %p (%d) len %d cc %d\n",
urb, td, 1 + td->index, dlen, cc); urb, td, 1 + td->index, dlen, cc);
#endif
/* BULK, INT, CONTROL ... drivers see aggregate length/status, /* BULK, INT, CONTROL ... drivers see aggregate length/status,
* except that "setup" bytes aren't counted and "short" transfers * except that "setup" bytes aren't counted and "short" transfers
...@@ -730,13 +722,12 @@ static void td_done (struct urb *urb, struct td *td) ...@@ -730,13 +722,12 @@ static void td_done (struct urb *urb, struct td *td)
- td->data_dma; - td->data_dma;
} }
#ifdef VERBOSE_DEBUG
if (cc != TD_CC_NOERROR && cc < 0x0E) if (cc != TD_CC_NOERROR && cc < 0x0E)
dbg (" urb %p TD %p (%d) CC %d, len=%d/%d", ohci_vdbg (ohci,
"urb %p td %p (%d) cc %d, len=%d/%d\n",
urb, td, 1 + td->index, cc, urb, td, 1 + td->index, cc,
urb->actual_length, urb->actual_length,
urb->transfer_buffer_length); urb->transfer_buffer_length);
#endif
} }
} }
...@@ -791,14 +782,18 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) ...@@ -791,14 +782,18 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
ed->hwHeadP = next->hwNextTD | toggle; ed->hwHeadP = next->hwNextTD | toggle;
} }
/* help for troubleshooting: */ /* help for troubleshooting: report anything that
dev_dbg (&urb->dev->dev, * looks odd ... that doesn't include protocol stalls
"urb %p usb-%s-%s ep-%d-%s cc %d --> status %d\n", * (or maybe some other things)
urb, */
urb->dev->bus->bus_name, urb->dev->devpath, if (cc != TD_CC_STALL || !usb_pipecontrol (urb->pipe))
usb_pipeendpoint (urb->pipe), ohci_dbg (ohci,
usb_pipein (urb->pipe) ? "IN" : "OUT", "urb %p path %s ep%d%s %08x cc %d --> status %d\n",
cc, cc_to_error [cc]); urb, urb->dev->devpath,
usb_pipeendpoint (urb->pipe),
usb_pipein (urb->pipe) ? "in" : "out",
le32_to_cpu (td->hwINFO),
cc, cc_to_error [cc]);
return rev; return rev;
} }
...@@ -826,8 +821,7 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci) ...@@ -826,8 +821,7 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
td = dma_to_td (ohci, td_dma); td = dma_to_td (ohci, td_dma);
if (!td) { if (!td) {
err ("%s bad entry %8x", ohci_err (ohci, "bad entry %8x\n", td_dma);
ohci->hcd.self.bus_name, td_dma);
break; break;
} }
...@@ -855,7 +849,8 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci) ...@@ -855,7 +849,8 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
#define tick_before(t1,t2) ((((s16)(t1))-((s16)(t2))) < 0) #define tick_before(t1,t2) ((((s16)(t1))-((s16)(t2))) < 0)
/* there are some urbs/eds to unlink; called in_irq(), with HCD locked */ /* there are some urbs/eds to unlink; called in_irq(), with HCD locked */
static void finish_unlinks (struct ohci_hcd *ohci, u16 tick, struct pt_regs *regs) static void
finish_unlinks (struct ohci_hcd *ohci, u16 tick, struct pt_regs *regs)
{ {
struct ed *ed, **last; struct ed *ed, **last;
...@@ -983,7 +978,8 @@ static void finish_unlinks (struct ohci_hcd *ohci, u16 tick, struct pt_regs *reg ...@@ -983,7 +978,8 @@ static void finish_unlinks (struct ohci_hcd *ohci, u16 tick, struct pt_regs *reg
* path is finish_unlinks(), which unlinks URBs using ed_rm_list, instead of * path is finish_unlinks(), which unlinks URBs using ed_rm_list, instead of
* scanning the (re-reversed) donelist as this does. * scanning the (re-reversed) donelist as this does.
*/ */
static void dl_done_list (struct ohci_hcd *ohci, struct td *td, struct pt_regs *regs) static void
dl_done_list (struct ohci_hcd *ohci, struct td *td, struct pt_regs *regs)
{ {
unsigned long flags; unsigned long flags;
...@@ -1000,9 +996,9 @@ static void dl_done_list (struct ohci_hcd *ohci, struct td *td, struct pt_regs * ...@@ -1000,9 +996,9 @@ static void dl_done_list (struct ohci_hcd *ohci, struct td *td, struct pt_regs *
/* If all this urb's TDs are done, call complete() */ /* If all this urb's TDs are done, call complete() */
if (urb_priv->td_cnt == urb_priv->length) { if (urb_priv->td_cnt == urb_priv->length) {
spin_unlock_irqrestore (&ohci->lock, flags); spin_unlock (&ohci->lock);
finish_urb (ohci, urb, regs); finish_urb (ohci, urb, regs);
spin_lock_irqsave (&ohci->lock, flags); spin_lock (&ohci->lock);
} }
/* clean schedule: unlink EDs that are no longer busy */ /* clean schedule: unlink EDs that are no longer busy */
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
* (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
* (C) Hewlett-Packard Company * (C) Copyright 2002 Hewlett-Packard Company
* *
* SA1111 Bus Glue * SA1111 Bus Glue
* *
...@@ -27,14 +27,6 @@ extern int usb_disabled(void); ...@@ -27,14 +27,6 @@ extern int usb_disabled(void);
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
struct ohci_hcd *dev_to_ohci(struct device *dev) {
struct usb_hcd *hcd = dev->driver_data;
return hcd_to_ohci(hcd);
}
/*-------------------------------------------------------------------------*/
static void sa1111_start_hc(struct sa1111_dev *dev) static void sa1111_start_hc(struct sa1111_dev *dev)
{ {
unsigned int usb_rst = 0; unsigned int usb_rst = 0;
......
...@@ -372,6 +372,7 @@ struct ohci_hcd { ...@@ -372,6 +372,7 @@ struct ohci_hcd {
unsigned long flags; /* for HC bugs */ unsigned long flags; /* for HC bugs */
#define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */ #define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */
#define OHCI_QUIRK_SUPERIO 0x02 /* natsemi */
// there are also chip quirks/bugs in init logic // there are also chip quirks/bugs in init logic
/* /*
...@@ -382,4 +383,24 @@ struct ohci_hcd { ...@@ -382,4 +383,24 @@ struct ohci_hcd {
#define hcd_to_ohci(hcd_ptr) container_of(hcd_ptr, struct ohci_hcd, hcd) #define hcd_to_ohci(hcd_ptr) container_of(hcd_ptr, struct ohci_hcd, hcd)
struct ohci_hcd *dev_to_ohci(struct device *); /*-------------------------------------------------------------------------*/
#ifndef DEBUG
#define STUB_DEBUG_FILES
#endif /* DEBUG */
#define ohci_dbg(ohci, fmt, args...) \
dev_dbg ((ohci)->hcd.controller , fmt , ## args )
#define ohci_err(ohci, fmt, args...) \
dev_err ((ohci)->hcd.controller , fmt , ## args )
#define ohci_info(ohci, fmt, args...) \
dev_info ((ohci)->hcd.controller , fmt , ## args )
#define ohci_warn(ohci, fmt, args...) \
dev_warn ((ohci)->hcd.controller , fmt , ## args )
#ifdef OHCI_VERBOSE_DEBUG
# define ohci_vdbg ohci_dbg
#else
# define ohci_vdbg(ohci, fmt, args...) do { } while (0)
#endif
/* -*- linux-c -*- */ /* -*- linux-c -*- */
/* /*
* Driver for USB Scanners (linux-2.5.60) * Driver for USB Scanners (linux-2.5.64)
* *
* Copyright (C) 1999, 2000, 2001, 2002 David E. Nelson * Copyright (C) 1999, 2000, 2001, 2002 David E. Nelson
* Copyright (C) 2002, 2003 Henning Meier-Geinitz * Copyright (C) 2002, 2003 Henning Meier-Geinitz
...@@ -346,6 +346,11 @@ ...@@ -346,6 +346,11 @@
* - Print ids and device number when a device was detected. * - Print ids and device number when a device was detected.
* - Don't print errors when the device is busy. * - Don't print errors when the device is busy.
* *
* 0.4.11 2003-02-25
* - Added vendor/product ids for Artec, Avision, Brother, Medion, Primax,
* Prolink, Fujitsu, Plustek, and SYSCAN scanners.
* - Fixed generation of devfs names if dynamic minors are disabled.
*
* TODO * TODO
* - Performance * - Performance
* - Select/poll methods * - Select/poll methods
...@@ -1052,7 +1057,7 @@ probe_scanner(struct usb_interface *intf, ...@@ -1052,7 +1057,7 @@ probe_scanner(struct usb_interface *intf,
scn->scn_minor = scn_minor; scn->scn_minor = scn_minor;
scn->isopen = 0; scn->isopen = 0;
sprintf(name, "scanner%d", scn->scn_minor); sprintf(name, "scanner%d", scn->scn_minor - SCN_BASE_MNR);
scn->devfs = devfs_register(usb_devfs_handle, name, scn->devfs = devfs_register(usb_devfs_handle, name,
DEVFS_FL_DEFAULT, USB_MAJOR, DEVFS_FL_DEFAULT, USB_MAJOR,
......
/* /*
* Driver for USB Scanners (linux-2.5.60) * Driver for USB Scanners (linux-2.5.64)
* *
* Copyright (C) 1999, 2000, 2001, 2002 David E. Nelson * Copyright (C) 1999, 2000, 2001, 2002 David E. Nelson
* Previously maintained by Brian Beattie * Previously maintained by Brian Beattie
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
// #define DEBUG // #define DEBUG
#define DRIVER_VERSION "0.4.10" #define DRIVER_VERSION "0.4.11"
#define DRIVER_DESC "USB Scanner Driver" #define DRIVER_DESC "USB Scanner Driver"
#include <linux/usb.h> #include <linux/usb.h>
...@@ -99,7 +99,13 @@ static struct usb_device_id scanner_device_ids [] = { ...@@ -99,7 +99,13 @@ static struct usb_device_id scanner_device_ids [] = {
/* Artec */ /* Artec */
{ USB_DEVICE(0x05d8, 0x4001) }, /* Ultima 2000 */ { USB_DEVICE(0x05d8, 0x4001) }, /* Ultima 2000 */
{ USB_DEVICE(0x05d8, 0x4002) }, /* Ultima 2000 (GT6801 based) */ { USB_DEVICE(0x05d8, 0x4002) }, /* Ultima 2000 (GT6801 based) */
{ USB_DEVICE(0x05d8, 0x4003) }, /* E+ 48U */
{ USB_DEVICE(0x05d8, 0x4004) }, /* E+ Pro */
/* Avision */
{ USB_DEVICE(0x0638, 0x0a10) }, /* iVina FB1600 (=Umax Astra 4500) */
/* Benq: see Acer */ /* Benq: see Acer */
/* Brother */
{ USB_DEVICE(0x04f9, 0x0111) }, /* MFC 6800 */
/* Canon */ /* Canon */
{ USB_DEVICE(0x04a9, 0x2201) }, /* CanoScan FB320U */ { USB_DEVICE(0x04a9, 0x2201) }, /* CanoScan FB320U */
{ USB_DEVICE(0x04a9, 0x2202) }, /* CanoScan FB620U */ { USB_DEVICE(0x04a9, 0x2202) }, /* CanoScan FB620U */
...@@ -117,6 +123,10 @@ static struct usb_device_id scanner_device_ids [] = { ...@@ -117,6 +123,10 @@ static struct usb_device_id scanner_device_ids [] = {
/* Compaq */ /* Compaq */
{ USB_DEVICE(0x049f, 0x0021) }, /* S200 */ { USB_DEVICE(0x049f, 0x0021) }, /* S200 */
/* Epson -- See Seiko/Epson below */ /* Epson -- See Seiko/Epson below */
/* Fujitsu */
{ USB_DEVICE(0x04c5, 0x1041) }, /* fi-4220c USB/SCSI info:mza@mu-tec.de */
{ USB_DEVICE(0x04c5, 0x1042) }, /* fi-4120c USB/SCSI info:mza@mu-tec.de */
{ USB_DEVICE(0x04c5, 0x1029) }, /* fi-4010c USB AVision info:mza@mu-tec.de */
/* Genius */ /* Genius */
{ USB_DEVICE(0x0458, 0x2001) }, /* ColorPage Vivid Pro */ { USB_DEVICE(0x0458, 0x2001) }, /* ColorPage Vivid Pro */
{ USB_DEVICE(0x0458, 0x2007) }, /* ColorPage HR6 V2 */ { USB_DEVICE(0x0458, 0x2007) }, /* ColorPage HR6 V2 */
...@@ -149,6 +159,8 @@ static struct usb_device_id scanner_device_ids [] = { ...@@ -149,6 +159,8 @@ static struct usb_device_id scanner_device_ids [] = {
{ USB_DEVICE(0x0638, 0x0268) }, /* 1200U */ { USB_DEVICE(0x0638, 0x0268) }, /* 1200U */
/* Lexmark */ /* Lexmark */
{ USB_DEVICE(0x043d, 0x002d) }, /* X70/X73 */ { USB_DEVICE(0x043d, 0x002d) }, /* X70/X73 */
/* Medion */
{ USB_DEVICE(0x0461, 0x0377) }, /* MD 5345 - repackaged Primax? */
/* Memorex */ /* Memorex */
{ USB_DEVICE(0x0461, 0x0346) }, /* 6136u - repackaged Primax ? */ { USB_DEVICE(0x0461, 0x0346) }, /* 6136u - repackaged Primax ? */
/* Microtek */ /* Microtek */
...@@ -202,7 +214,8 @@ static struct usb_device_id scanner_device_ids [] = { ...@@ -202,7 +214,8 @@ static struct usb_device_id scanner_device_ids [] = {
{ USB_DEVICE(0x07b3, 0x0015) }, /* OpticPro U24 */ { USB_DEVICE(0x07b3, 0x0015) }, /* OpticPro U24 */
{ USB_DEVICE(0x07b3, 0x0016) }, /* Unknown */ { USB_DEVICE(0x07b3, 0x0016) }, /* Unknown */
{ USB_DEVICE(0x07b3, 0x0017) }, /* OpticPro UT12/UT16/UT24 */ { USB_DEVICE(0x07b3, 0x0017) }, /* OpticPro UT12/UT16/UT24 */
{ USB_DEVICE(0x07b3, 0x0401) }, /* OpticPro 1248U */ { USB_DEVICE(0x07b3, 0x0400) }, /* OpticPro 1248U */
{ USB_DEVICE(0x07b3, 0x0401) }, /* OpticPro 1248U (another one) */
/* Primax/Colorado */ /* Primax/Colorado */
{ USB_DEVICE(0x0461, 0x0300) }, /* G2-300 #1 */ { USB_DEVICE(0x0461, 0x0300) }, /* G2-300 #1 */
{ USB_DEVICE(0x0461, 0x0301) }, /* G2E-300 #1 */ { USB_DEVICE(0x0461, 0x0301) }, /* G2E-300 #1 */
...@@ -210,12 +223,15 @@ static struct usb_device_id scanner_device_ids [] = { ...@@ -210,12 +223,15 @@ static struct usb_device_id scanner_device_ids [] = {
{ USB_DEVICE(0x0461, 0x0303) }, /* G2E-300 #2 */ { USB_DEVICE(0x0461, 0x0303) }, /* G2E-300 #2 */
{ USB_DEVICE(0x0461, 0x0340) }, /* Colorado USB 9600 */ { USB_DEVICE(0x0461, 0x0340) }, /* Colorado USB 9600 */
{ USB_DEVICE(0x0461, 0x0341) }, /* Colorado 600u */ { USB_DEVICE(0x0461, 0x0341) }, /* Colorado 600u */
{ USB_DEVICE(0x0461, 0x0347) }, /* Primascan Colorado 2600u */
{ USB_DEVICE(0x0461, 0x0360) }, /* Colorado USB 19200 */ { USB_DEVICE(0x0461, 0x0360) }, /* Colorado USB 19200 */
{ USB_DEVICE(0x0461, 0x0361) }, /* Colorado 1200u */ { USB_DEVICE(0x0461, 0x0361) }, /* Colorado 1200u */
{ USB_DEVICE(0x0461, 0x0380) }, /* G2-600 #1 */ { USB_DEVICE(0x0461, 0x0380) }, /* G2-600 #1 */
{ USB_DEVICE(0x0461, 0x0381) }, /* ReadyScan 636i */ { USB_DEVICE(0x0461, 0x0381) }, /* ReadyScan 636i */
{ USB_DEVICE(0x0461, 0x0382) }, /* G2-600 #2 */ { USB_DEVICE(0x0461, 0x0382) }, /* G2-600 #2 */
{ USB_DEVICE(0x0461, 0x0383) }, /* G2E-600 */ { USB_DEVICE(0x0461, 0x0383) }, /* G2E-600 */
/* Prolink */
{ USB_DEVICE(0x06dc, 0x0014) }, /* Winscan Pro 2448U */
/* Relisis */ /* Relisis */
// { USB_DEVICE(0x0475, 0x0103) }, /* Episode - undetected endpoint */ // { USB_DEVICE(0x0475, 0x0103) }, /* Episode - undetected endpoint */
/* Seiko/Epson Corp. */ /* Seiko/Epson Corp. */
...@@ -241,6 +257,8 @@ static struct usb_device_id scanner_device_ids [] = { ...@@ -241,6 +257,8 @@ static struct usb_device_id scanner_device_ids [] = {
{ USB_DEVICE(0x04b8, 0x011e) }, /* Perfection 1660 Photo */ { USB_DEVICE(0x04b8, 0x011e) }, /* Perfection 1660 Photo */
{ USB_DEVICE(0x04b8, 0x0801) }, /* Stylus CX5200 */ { USB_DEVICE(0x04b8, 0x0801) }, /* Stylus CX5200 */
{ USB_DEVICE(0x04b8, 0x0802) }, /* Stylus CX3200 */ { USB_DEVICE(0x04b8, 0x0802) }, /* Stylus CX3200 */
/* SYSCAN */
{ USB_DEVICE(0x0a82, 0x4600) }, /* TravelScan 460/464 */
/* Umax */ /* Umax */
{ USB_DEVICE(0x1606, 0x0010) }, /* Astra 1220U */ { USB_DEVICE(0x1606, 0x0010) }, /* Astra 1220U */
{ USB_DEVICE(0x1606, 0x0030) }, /* Astra 2000U */ { USB_DEVICE(0x1606, 0x0030) }, /* Astra 2000U */
......
...@@ -159,6 +159,20 @@ config USB_WACOM ...@@ -159,6 +159,20 @@ config USB_WACOM
The module will be called wacom. If you want to compile it as a The module will be called wacom. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>. module, say M here and read <file:Documentation/modules.txt>.
config USB_KBTAB
tristate "KB Gear JamStudio tablet support"
depends on USB && INPUT
help
Say Y here if you want to use the USB version of the KB Gear
JamStudio tablet. Make sure to say Y to "Mouse support"
(CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
(CONFIG_INPUT_EVDEV) as well.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called kbtab.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
config USB_POWERMATE config USB_POWERMATE
tristate "Griffin PowerMate and Contour Jog support" tristate "Griffin PowerMate and Contour Jog support"
depends on USB && INPUT depends on USB && INPUT
......
...@@ -31,5 +31,6 @@ obj-$(CONFIG_USB_HID) += hid.o ...@@ -31,5 +31,6 @@ obj-$(CONFIG_USB_HID) += hid.o
obj-$(CONFIG_USB_KBD) += usbkbd.o obj-$(CONFIG_USB_KBD) += usbkbd.o
obj-$(CONFIG_USB_MOUSE) += usbmouse.o obj-$(CONFIG_USB_MOUSE) += usbmouse.o
obj-$(CONFIG_USB_WACOM) += wacom.o obj-$(CONFIG_USB_WACOM) += wacom.o
obj-$(CONFIG_USB_KBTAB) += kbtab.o
obj-$(CONFIG_USB_POWERMATE) += powermate.o obj-$(CONFIG_USB_POWERMATE) += powermate.o
obj-$(CONFIG_USB_XPAD) += xpad.o obj-$(CONFIG_USB_XPAD) += xpad.o
...@@ -1304,6 +1304,10 @@ void hid_init_reports(struct hid_device *hid) ...@@ -1304,6 +1304,10 @@ void hid_init_reports(struct hid_device *hid)
#define USB_DEVICE_ID_WACOM_PL 0x0030 #define USB_DEVICE_ID_WACOM_PL 0x0030
#define USB_DEVICE_ID_WACOM_INTUOS2 0x0040 #define USB_DEVICE_ID_WACOM_INTUOS2 0x0040
#define USB_VENDOR_ID_KBGEAR 0x084e
#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001
#define USB_VENDOR_ID_AIPTEK 0x08ca #define USB_VENDOR_ID_AIPTEK 0x08ca
#define USB_DEVICE_ID_AIPTEK_6000 0x0020 #define USB_DEVICE_ID_AIPTEK_6000 0x0020
...@@ -1355,6 +1359,7 @@ struct hid_blacklist { ...@@ -1355,6 +1359,7 @@ struct hid_blacklist {
{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 3, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 3, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 4, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 4, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 5, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 5, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_6000, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_6000, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE },
......
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb.h>
/*
* Version Information
* v0.0.1 - Original, extremely basic version, 2.4.xx only
* v0.0.2 - Updated, works with 2.5.62 and 2.4.20;
* - added pressure-threshold modules param code from
* Alex Perry <alex.perry@ieee.org>
*/
#define DRIVER_VERSION "v0.0.2"
#define DRIVER_AUTHOR "Josh Myer <josh@joshisanerd.com>"
#define DRIVER_DESC "USB KB Gear JamStudio Tablet driver"
#define DRIVER_LICENSE "GPL"
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);
#define USB_VENDOR_ID_KBGEAR 0x084e
static int kb_pressure_click = 0x10;
MODULE_PARM (kb_pressure_click,"i");
MODULE_PARM_DESC(kb_pressure_click,
"pressure threshold for clicks");
struct kbtab {
signed char *data;
dma_addr_t data_dma;
struct input_dev dev;
struct usb_device *usbdev;
struct urb *irq;
int open;
int x, y;
int button;
int pressure;
__u32 serial[2];
char phys[32];
};
static void kbtab_irq(struct urb *urb, struct pt_regs *regs)
{
struct kbtab *kbtab = urb->context;
unsigned char *data = kbtab->data;
struct input_dev *dev = &kbtab->dev;
int retval;
switch (urb->status) {
case 0:
/* success */
break;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
return;
default:
dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
goto exit;
}
kbtab->x = (data[2] << 8) + data[1];
kbtab->y = (data[4] << 8) + data[3];
kbtab->pressure = (data[5]);
input_report_key(dev, BTN_TOOL_PEN, 1);
input_report_abs(dev, ABS_X, kbtab->x);
input_report_abs(dev, ABS_Y, kbtab->y);
/*input_report_abs(dev, ABS_PRESSURE, kbtab->pressure);*/
/*input_report_key(dev, BTN_TOUCH , data[0] & 0x01);*/
input_report_key(dev, BTN_RIGHT, data[0] & 0x02);
input_report_key(dev, BTN_LEFT, (kbtab->pressure > kb_pressure_click) ? 1 : 0);
input_sync(dev);
exit:
retval = usb_submit_urb (urb, GFP_ATOMIC);
if (retval)
err ("%s - usb_submit_urb failed with result %d",
__FUNCTION__, retval);
}
struct usb_device_id kbtab_ids[] = {
{ USB_DEVICE(USB_VENDOR_ID_KBGEAR, 0x1001), driver_info : 0 },
{ }
};
MODULE_DEVICE_TABLE(usb, kbtab_ids);
static int kbtab_open(struct input_dev *dev)
{
struct kbtab *kbtab = dev->private;
if (kbtab->open++)
return 0;
kbtab->irq->dev = kbtab->usbdev;
if (usb_submit_urb(kbtab->irq, GFP_KERNEL))
return -EIO;
return 0;
}
static void kbtab_close(struct input_dev *dev)
{
struct kbtab *kbtab = dev->private;
if (!--kbtab->open)
usb_unlink_urb(kbtab->irq);
}
static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);
struct usb_endpoint_descriptor *endpoint;
struct kbtab *kbtab;
char path[64];
if (!(kbtab = kmalloc(sizeof(struct kbtab), GFP_KERNEL)))
return -ENOMEM;
memset(kbtab, 0, sizeof(struct kbtab));
kbtab->data = usb_buffer_alloc(dev, 8, SLAB_ATOMIC, &kbtab->data_dma);
if (!kbtab->data) {
kfree(kbtab);
return -ENOMEM;
}
kbtab->irq = usb_alloc_urb(0, GFP_KERNEL);
if (!kbtab->irq) {
usb_buffer_free(dev, 10, kbtab->data, kbtab->data_dma);
kfree(kbtab);
return -ENOMEM;
}
kbtab->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC);
kbtab->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
kbtab->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
kbtab->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH);
kbtab->dev.mscbit[0] |= BIT(MSC_SERIAL);
kbtab->dev.absmax[ABS_X] = 0x2000;
kbtab->dev.absmax[ABS_Y] = 0x1750;
kbtab->dev.absmax[ABS_PRESSURE] = 0xff;
kbtab->dev.absfuzz[ABS_X] = 4;
kbtab->dev.absfuzz[ABS_Y] = 4;
kbtab->dev.private = kbtab;
kbtab->dev.open = kbtab_open;
kbtab->dev.close = kbtab_close;
usb_make_path(dev, path, 64);
sprintf(kbtab->phys, "%s/input0", path);
kbtab->dev.name = "KB Gear Tablet";
kbtab->dev.phys = kbtab->phys;
kbtab->dev.id.bustype = BUS_USB;
kbtab->dev.id.vendor = dev->descriptor.idVendor;
kbtab->dev.id.product = dev->descriptor.idProduct;
kbtab->dev.id.version = dev->descriptor.bcdDevice;
kbtab->usbdev = dev;
endpoint = &intf->altsetting[0].endpoint[0].desc;
usb_fill_int_urb(kbtab->irq, dev,
usb_rcvintpipe(dev, endpoint->bEndpointAddress),
kbtab->data, 8,
kbtab_irq, kbtab, endpoint->bInterval);
kbtab->irq->transfer_dma = kbtab->data_dma;
kbtab->irq->transfer_flags |= URB_NO_DMA_MAP;
input_register_device(&kbtab->dev);
printk(KERN_INFO "input: KB Gear Tablet on %s\n", path);
usb_set_intfdata(intf, kbtab);
return 0;
}
static void kbtab_disconnect(struct usb_interface *intf)
{
struct kbtab *kbtab = usb_get_intfdata (intf);
usb_set_intfdata(intf, NULL);
if (kbtab) {
usb_unlink_urb(kbtab->irq);
input_unregister_device(&kbtab->dev);
usb_free_urb(kbtab->irq);
usb_buffer_free(interface_to_usbdev(intf), 10, kbtab->data, kbtab->data_dma);
kfree(kbtab);
}
}
static struct usb_driver kbtab_driver = {
.name = "kbtab",
.probe = kbtab_probe,
.disconnect = kbtab_disconnect,
.id_table = kbtab_ids,
};
static int __init kbtab_init(void)
{
usb_register(&kbtab_driver);
info(DRIVER_VERSION ":" DRIVER_DESC);
return 0;
}
static void __exit kbtab_exit(void)
{
usb_deregister(&kbtab_driver);
}
module_init(kbtab_init);
module_exit(kbtab_exit);
This diff is collapsed.
...@@ -552,6 +552,7 @@ static int ch9_postconfig (struct usbtest_dev *dev) ...@@ -552,6 +552,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
* (b) protocol stalls (control-only) will autorecover. * (b) protocol stalls (control-only) will autorecover.
* it's quite not like bulk/intr; no halt clearing. * it's quite not like bulk/intr; no halt clearing.
* (c) short control reads are reported and handled. * (c) short control reads are reported and handled.
* (d) queues are always processed in-order
*/ */
struct ctrl_ctx { struct ctrl_ctx {
...@@ -563,66 +564,68 @@ struct ctrl_ctx { ...@@ -563,66 +564,68 @@ struct ctrl_ctx {
int status; int status;
struct urb **urb; struct urb **urb;
struct usbtest_param *param; struct usbtest_param *param;
int last;
};
#define NUM_SUBCASES 13 /* how many test subcases here? */
struct subcase {
struct usb_ctrlrequest setup;
int number;
int expected;
}; };
static void ctrl_complete (struct urb *urb, struct pt_regs *regs) static void ctrl_complete (struct urb *urb, struct pt_regs *regs)
{ {
struct ctrl_ctx *ctx = urb->context; struct ctrl_ctx *ctx = urb->context;
struct usb_ctrlrequest *reqp; struct usb_ctrlrequest *reqp;
struct subcase *subcase;
int status = urb->status; int status = urb->status;
reqp = (struct usb_ctrlrequest *)urb->setup_packet; reqp = (struct usb_ctrlrequest *)urb->setup_packet;
subcase = container_of (reqp, struct subcase, setup);
spin_lock (&ctx->lock); spin_lock (&ctx->lock);
ctx->count--; ctx->count--;
ctx->pending--; ctx->pending--;
/* FIXME verify that the completions are in the right sequence. /* queue must transfer and complete in fifo order, unless
* we could store the test number with the setup packet, that * usb_unlink_urb() is used to unlink something not at the
* buffer has extra space. * physical queue head (not tested).
*/ */
if (subcase->number > 0) {
switch (status) { if ((subcase->number - ctx->last) != 1) {
case 0: /* success */ dbg ("subcase %d completed out of order, last %d",
case -EREMOTEIO: /* short read */ subcase->number, ctx->last);
if (reqp->bRequestType == (USB_DIR_IN|USB_RECIP_DEVICE) status = -EDOM;
&& reqp->bRequest == USB_REQ_GET_DESCRIPTOR goto error;
&& ((le16_to_cpu (reqp->wValue) >> 8)
== USB_DT_DEVICE)) {
if (reqp->wLength > USB_DT_DEVICE_SIZE
&& status == -EREMOTEIO)
status = 0;
else if (reqp->wLength == USB_DT_DEVICE_SIZE
&& status != 0)
status = -EIO;
if (status)
goto error;
} }
break; }
case -ECONNRESET: /* async unlink */ ctx->last = subcase->number;
break;
case -EPIPE: /* (protocol) stall */ /* succeed or fault in only one way? */
if (reqp->bRequestType == (USB_DIR_IN|USB_RECIP_INTERFACE) if (status == subcase->expected)
&& reqp->bRequest == USB_REQ_GET_INTERFACE) status = 0;
/* async unlink for cleanup? */
else if (status != -ECONNRESET) {
/* some faults are allowed, not required */
if (subcase->expected > 0 && (
((urb->status == -subcase->expected /* happened */
|| urb->status == 0)))) /* didn't */
status = 0; status = 0;
else if (reqp->bRequestType == (USB_DIR_IN|USB_RECIP_DEVICE) /* sometimes more than one fault is allowed */
&& reqp->bRequest == USB_REQ_GET_DESCRIPTOR) { else if (subcase->number == 12 && status == -EPIPE)
switch (le16_to_cpu (reqp->wValue) >> 8) {
case USB_DT_DEVICE_QUALIFIER:
case USB_DT_OTHER_SPEED_CONFIG:
case USB_DT_INTERFACE:
case USB_DT_ENDPOINT:
status = 0;
}
} else if (reqp->bRequestType == USB_RECIP_ENDPOINT
&& reqp->bRequest == USB_REQ_CLEAR_FEATURE)
status = 0; status = 0;
/* some stalls we plan on; others would be errors */ else
if (status == 0) dbg ("subtest %d error, status %d",
break; subcase->number, status);
/* else FALLTHROUGH */ }
/* unexpected status codes mean errors; ideally, in hardware */
if (status) {
error: error:
default: /* this fault's an error */
if (ctx->status == 0) { if (ctx->status == 0) {
int i; int i;
...@@ -631,10 +634,8 @@ static void ctrl_complete (struct urb *urb, struct pt_regs *regs) ...@@ -631,10 +634,8 @@ static void ctrl_complete (struct urb *urb, struct pt_regs *regs)
reqp->bRequestType, reqp->bRequest, reqp->bRequestType, reqp->bRequest,
status, ctx->count); status, ctx->count);
/* FIXME use this "unlink everything" exit route /* FIXME this "unlink everything" exit route should
* in all cases, not just for fault cleanup. * be a separate test case.
* it'll be another test mode, but one that makes
* testing be more consistent.
*/ */
/* unlink whatever's still pending */ /* unlink whatever's still pending */
...@@ -688,6 +689,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) ...@@ -688,6 +689,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
context.pending = 0; context.pending = 0;
context.status = -ENOMEM; context.status = -ENOMEM;
context.param = param; context.param = param;
context.last = -1;
/* allocate and init the urbs we'll queue. /* allocate and init the urbs we'll queue.
* as with bulk/intr sglists, sglen is the queue depth; it also * as with bulk/intr sglists, sglen is the queue depth; it also
...@@ -701,7 +703,9 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) ...@@ -701,7 +703,9 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
int pipe = usb_rcvctrlpipe (udev, 0); int pipe = usb_rcvctrlpipe (udev, 0);
unsigned len; unsigned len;
struct urb *u; struct urb *u;
struct usb_ctrlrequest req, *reqp; struct usb_ctrlrequest req;
struct subcase *reqp;
int expected = 0;
/* requests here are mostly expected to succeed on any /* requests here are mostly expected to succeed on any
* device, but some are chosen to trigger protocol stalls * device, but some are chosen to trigger protocol stalls
...@@ -711,7 +715,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) ...@@ -711,7 +715,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
req.bRequest = USB_REQ_GET_DESCRIPTOR; req.bRequest = USB_REQ_GET_DESCRIPTOR;
req.bRequestType = USB_DIR_IN|USB_RECIP_DEVICE; req.bRequestType = USB_DIR_IN|USB_RECIP_DEVICE;
switch (i % 12 /* number of subtest cases here */) { switch (i % NUM_SUBCASES) {
case 0: // get device descriptor case 0: // get device descriptor
req.wValue = cpu_to_le16 (USB_DT_DEVICE << 8); req.wValue = cpu_to_le16 (USB_DT_DEVICE << 8);
len = sizeof (struct usb_device_descriptor); len = sizeof (struct usb_device_descriptor);
...@@ -725,6 +729,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) ...@@ -725,6 +729,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
req.bRequestType = USB_DIR_IN|USB_RECIP_INTERFACE; req.bRequestType = USB_DIR_IN|USB_RECIP_INTERFACE;
// index = 0 means first interface // index = 0 means first interface
len = 1; len = 1;
expected = EPIPE;
break; break;
case 3: // get interface status case 3: // get interface status
req.bRequest = USB_REQ_GET_STATUS; req.bRequest = USB_REQ_GET_STATUS;
...@@ -740,6 +745,8 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) ...@@ -740,6 +745,8 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
case 5: // get device qualifier (MAY STALL) case 5: // get device qualifier (MAY STALL)
req.wValue = cpu_to_le16 (USB_DT_DEVICE_QUALIFIER << 8); req.wValue = cpu_to_le16 (USB_DT_DEVICE_QUALIFIER << 8);
len = sizeof (struct usb_qualifier_descriptor); len = sizeof (struct usb_qualifier_descriptor);
if (udev->speed != USB_SPEED_HIGH)
expected = EPIPE;
break; break;
case 6: // get first config descriptor, plus interface case 6: // get first config descriptor, plus interface
req.wValue = cpu_to_le16 ((USB_DT_CONFIG << 8) | 0); req.wValue = cpu_to_le16 ((USB_DT_CONFIG << 8) | 0);
...@@ -750,6 +757,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) ...@@ -750,6 +757,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
req.wValue = cpu_to_le16 (USB_DT_INTERFACE << 8); req.wValue = cpu_to_le16 (USB_DT_INTERFACE << 8);
// interface == 0 // interface == 0
len = sizeof (struct usb_interface_descriptor); len = sizeof (struct usb_interface_descriptor);
expected = -EPIPE;
break; break;
// NOTE: two consecutive stalls in the queue here. // NOTE: two consecutive stalls in the queue here.
// that tests fault recovery a bit more aggressively. // that tests fault recovery a bit more aggressively.
...@@ -760,6 +768,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) ...@@ -760,6 +768,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
// wIndex 0 == ep0 (shouldn't halt!) // wIndex 0 == ep0 (shouldn't halt!)
len = 0; len = 0;
pipe = usb_sndctrlpipe (udev, 0); pipe = usb_sndctrlpipe (udev, 0);
expected = EPIPE;
break; break;
case 9: // get endpoint status case 9: // get endpoint status
req.bRequest = USB_REQ_GET_STATUS; req.bRequest = USB_REQ_GET_STATUS;
...@@ -770,18 +779,21 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) ...@@ -770,18 +779,21 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
case 10: // trigger short read (EREMOTEIO) case 10: // trigger short read (EREMOTEIO)
req.wValue = cpu_to_le16 ((USB_DT_CONFIG << 8) | 0); req.wValue = cpu_to_le16 ((USB_DT_CONFIG << 8) | 0);
len = 1024; len = 1024;
expected = -EREMOTEIO;
break; break;
// NOTE: two consecutive _different_ faults in the queue. // NOTE: two consecutive _different_ faults in the queue.
case 11: // get endpoint descriptor (ALWAYS STALLS) case 11: // get endpoint descriptor (ALWAYS STALLS)
req.wValue = cpu_to_le16 (USB_DT_ENDPOINT << 8); req.wValue = cpu_to_le16 (USB_DT_ENDPOINT << 8);
// endpoint == 0 // endpoint == 0
len = sizeof (struct usb_interface_descriptor); len = sizeof (struct usb_interface_descriptor);
expected = -EPIPE;
break; break;
// NOTE: sometimes even a third fault in the queue! // NOTE: sometimes even a third fault in the queue!
case 12: // get string 0 descriptor (MAY STALL) case 12: // get string 0 descriptor (MAY STALL)
req.wValue = cpu_to_le16 (USB_DT_STRING << 8); req.wValue = cpu_to_le16 (USB_DT_STRING << 8);
// string == 0, for language IDs // string == 0, for language IDs
len = sizeof (struct usb_interface_descriptor); len = sizeof (struct usb_interface_descriptor);
expected = EREMOTEIO; // or EPIPE, if no strings
break; break;
default: default:
err ("bogus number of ctrl queue testcases!"); err ("bogus number of ctrl queue testcases!");
...@@ -793,12 +805,14 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) ...@@ -793,12 +805,14 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
if (!u) if (!u)
goto cleanup; goto cleanup;
reqp = usb_buffer_alloc (udev, sizeof req, SLAB_KERNEL, reqp = usb_buffer_alloc (udev, sizeof *reqp, SLAB_KERNEL,
&u->setup_dma); &u->setup_dma);
if (!reqp) if (!reqp)
goto cleanup; goto cleanup;
*reqp = req; reqp->setup = req;
u->setup_packet = (char *) reqp; reqp->number = i % NUM_SUBCASES;
reqp->expected = expected;
u->setup_packet = (char *) &reqp->setup;
u->context = &context; u->context = &context;
u->complete = ctrl_complete; u->complete = ctrl_complete;
...@@ -839,6 +853,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) ...@@ -839,6 +853,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
kfree (urb); kfree (urb);
return context.status; return context.status;
} }
#undef NUM_SUBCASES
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -886,7 +901,16 @@ static int unlink1 (struct usbtest_dev *dev, int pipe, int size, int async) ...@@ -886,7 +901,16 @@ static int unlink1 (struct usbtest_dev *dev, int pipe, int size, int async)
* hcd states and code paths, even with little other system load. * hcd states and code paths, even with little other system load.
*/ */
wait_ms (jiffies % (2 * INTERRUPT_RATE)); wait_ms (jiffies % (2 * INTERRUPT_RATE));
retry:
retval = usb_unlink_urb (urb); retval = usb_unlink_urb (urb);
if (retval == -EBUSY) {
/* we can't unlink urbs while they're completing.
* "normal" drivers would prevent resubmission, but
* since we're testing unlink paths, we can't.
*/
dbg ("unlink retry");
goto retry;
}
if (!(retval == 0 || retval == -EINPROGRESS)) { if (!(retval == 0 || retval == -EINPROGRESS)) {
dbg ("submit/unlink fail %d", retval); dbg ("submit/unlink fail %d", retval);
return retval; return retval;
...@@ -1309,7 +1333,13 @@ static struct usbtest_info ez2_info = { ...@@ -1309,7 +1333,13 @@ static struct usbtest_info ez2_info = {
.alt = 1, .alt = 1,
}; };
/* ezusb family device with dedicated usb test firmware*/ /* ezusb family device with dedicated usb test firmware,
* or a peripheral running Linux and 'zero.c' test firmware.
*
* FIXME usbtest should read the descriptors, since compatible
* test firmware might run on hardware (pxa250 for one) that
* can't configure an ep2in-bulk.
*/
static struct usbtest_info fw_info = { static struct usbtest_info fw_info = {
.name = "usb test device", .name = "usb test device",
.ep_in = 2, .ep_in = 2,
......
...@@ -144,6 +144,7 @@ static struct usb_serial_device_type belkin_device = { ...@@ -144,6 +144,7 @@ static struct usb_serial_device_type belkin_device = {
struct belkin_sa_private { struct belkin_sa_private {
spinlock_t lock;
unsigned long control_state; unsigned long control_state;
unsigned char last_lsr; unsigned char last_lsr;
unsigned char last_msr; unsigned char last_msr;
...@@ -175,6 +176,7 @@ static int belkin_sa_startup (struct usb_serial *serial) ...@@ -175,6 +176,7 @@ static int belkin_sa_startup (struct usb_serial *serial)
if (!priv) if (!priv)
return (-1); /* error */ return (-1); /* error */
/* set initial values for control structures */ /* set initial values for control structures */
spin_lock_init(&priv->lock);
priv->control_state = 0; priv->control_state = 0;
priv->last_lsr = 0; priv->last_lsr = 0;
priv->last_msr = 0; priv->last_msr = 0;
...@@ -262,6 +264,7 @@ static void belkin_sa_read_int_callback (struct urb *urb, struct pt_regs *regs) ...@@ -262,6 +264,7 @@ static void belkin_sa_read_int_callback (struct urb *urb, struct pt_regs *regs)
struct usb_serial *serial; struct usb_serial *serial;
unsigned char *data = urb->transfer_buffer; unsigned char *data = urb->transfer_buffer;
int retval; int retval;
unsigned long flags;
switch (urb->status) { switch (urb->status) {
case 0: case 0:
...@@ -289,6 +292,7 @@ static void belkin_sa_read_int_callback (struct urb *urb, struct pt_regs *regs) ...@@ -289,6 +292,7 @@ static void belkin_sa_read_int_callback (struct urb *urb, struct pt_regs *regs)
/* ignore data[0] and data[1] */ /* ignore data[0] and data[1] */
priv = usb_get_serial_port_data(port); priv = usb_get_serial_port_data(port);
spin_lock_irqsave(&priv->lock, flags);
priv->last_msr = data[BELKIN_SA_MSR_INDEX]; priv->last_msr = data[BELKIN_SA_MSR_INDEX];
/* Record Control Line states */ /* Record Control Line states */
...@@ -336,6 +340,7 @@ static void belkin_sa_read_int_callback (struct urb *urb, struct pt_regs *regs) ...@@ -336,6 +340,7 @@ static void belkin_sa_read_int_callback (struct urb *urb, struct pt_regs *regs)
} }
} }
#endif #endif
spin_unlock_irqrestore(&priv->lock, flags);
exit: exit:
retval = usb_submit_urb (urb, GFP_ATOMIC); retval = usb_submit_urb (urb, GFP_ATOMIC);
if (retval) if (retval)
...@@ -352,6 +357,9 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios ...@@ -352,6 +357,9 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios
unsigned int old_iflag = 0; unsigned int old_iflag = 0;
unsigned int old_cflag = 0; unsigned int old_cflag = 0;
__u16 urb_value = 0; /* Will hold the new flags */ __u16 urb_value = 0; /* Will hold the new flags */
unsigned long flags;
unsigned long control_state;
int bad_flow_control;
if ((!port->tty) || (!port->tty->termios)) { if ((!port->tty) || (!port->tty->termios)) {
dbg ("%s - no tty or termios structure", __FUNCTION__); dbg ("%s - no tty or termios structure", __FUNCTION__);
...@@ -361,6 +369,12 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios ...@@ -361,6 +369,12 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios
iflag = port->tty->termios->c_iflag; iflag = port->tty->termios->c_iflag;
cflag = port->tty->termios->c_cflag; cflag = port->tty->termios->c_cflag;
/* get a local copy of the current port settings */
spin_lock_irqsave(&priv->lock, flags);
control_state = priv->control_state;
bad_flow_control = priv->bad_flow_control;
spin_unlock_irqrestore(&priv->lock, flags);
/* check that they really want us to change something */ /* check that they really want us to change something */
if (old_termios) { if (old_termios) {
if ((cflag == old_termios->c_cflag) && if ((cflag == old_termios->c_cflag) &&
...@@ -376,7 +390,7 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios ...@@ -376,7 +390,7 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios
if( (cflag&CBAUD) != (old_cflag&CBAUD) ) { if( (cflag&CBAUD) != (old_cflag&CBAUD) ) {
/* reassert DTR and (maybe) RTS on transition from B0 */ /* reassert DTR and (maybe) RTS on transition from B0 */
if( (old_cflag&CBAUD) == B0 ) { if( (old_cflag&CBAUD) == B0 ) {
priv->control_state |= (TIOCM_DTR|TIOCM_RTS); control_state |= (TIOCM_DTR|TIOCM_RTS);
if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 1) < 0) if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 1) < 0)
err("Set DTR error"); err("Set DTR error");
/* don't set RTS if using hardware flow control */ /* don't set RTS if using hardware flow control */
...@@ -410,7 +424,7 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios ...@@ -410,7 +424,7 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios
err("Disable flowcontrol error"); err("Disable flowcontrol error");
/* Drop RTS and DTR */ /* Drop RTS and DTR */
priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS); control_state &= ~(TIOCM_DTR | TIOCM_RTS);
if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 0) < 0) if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 0) < 0)
err("DTR LOW error"); err("DTR LOW error");
if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 0) < 0) if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 0) < 0)
...@@ -465,12 +479,17 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios ...@@ -465,12 +479,17 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios
else else
urb_value &= ~(BELKIN_SA_FLOW_OCTS | BELKIN_SA_FLOW_IRTS); urb_value &= ~(BELKIN_SA_FLOW_OCTS | BELKIN_SA_FLOW_IRTS);
if (priv->bad_flow_control) if (bad_flow_control)
urb_value &= ~(BELKIN_SA_FLOW_IRTS); urb_value &= ~(BELKIN_SA_FLOW_IRTS);
if (BSA_USB_CMD(BELKIN_SA_SET_FLOW_CTRL_REQUEST, urb_value) < 0) if (BSA_USB_CMD(BELKIN_SA_SET_FLOW_CTRL_REQUEST, urb_value) < 0)
err("Set flow control error"); err("Set flow control error");
} }
/* save off the modified port settings */
spin_lock_irqsave(&priv->lock, flags);
priv->control_state = control_state;
spin_unlock_irqrestore(&priv->lock, flags);
} /* belkin_sa_set_termios */ } /* belkin_sa_set_termios */
...@@ -488,12 +507,19 @@ static int belkin_sa_ioctl (struct usb_serial_port *port, struct file * file, un ...@@ -488,12 +507,19 @@ static int belkin_sa_ioctl (struct usb_serial_port *port, struct file * file, un
struct usb_serial *serial = port->serial; struct usb_serial *serial = port->serial;
__u16 urb_value; /* Will hold the new flags */ __u16 urb_value; /* Will hold the new flags */
struct belkin_sa_private *priv = usb_get_serial_port_data(port); struct belkin_sa_private *priv = usb_get_serial_port_data(port);
int ret, mask; int ret = 0;
int mask;
unsigned long control_state;
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
control_state = priv->control_state;
spin_unlock_irqrestore(&priv->lock, flags);
/* Based on code from acm.c and others */ /* Based on code from acm.c and others */
switch (cmd) { switch (cmd) {
case TIOCMGET: case TIOCMGET:
return put_user(priv->control_state, (unsigned long *) arg); return put_user(control_state, (unsigned long *) arg);
break; break;
case TIOCMSET: /* Turns on and off the lines as specified by the mask */ case TIOCMSET: /* Turns on and off the lines as specified by the mask */
...@@ -506,13 +532,13 @@ static int belkin_sa_ioctl (struct usb_serial_port *port, struct file * file, un ...@@ -506,13 +532,13 @@ static int belkin_sa_ioctl (struct usb_serial_port *port, struct file * file, un
/* RTS needs set */ /* RTS needs set */
urb_value = ((cmd == TIOCMSET) && (mask & TIOCM_RTS)) || (cmd == TIOCMBIS) ? 1 : 0; urb_value = ((cmd == TIOCMSET) && (mask & TIOCM_RTS)) || (cmd == TIOCMBIS) ? 1 : 0;
if (urb_value) if (urb_value)
priv->control_state |= TIOCM_RTS; control_state |= TIOCM_RTS;
else else
priv->control_state &= ~TIOCM_RTS; control_state &= ~TIOCM_RTS;
if ((ret = BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, urb_value)) < 0) { if ((ret = BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, urb_value)) < 0) {
err("Set RTS error %d", ret); err("Set RTS error %d", ret);
return(ret); goto cmerror;
} }
} }
...@@ -520,14 +546,19 @@ static int belkin_sa_ioctl (struct usb_serial_port *port, struct file * file, un ...@@ -520,14 +546,19 @@ static int belkin_sa_ioctl (struct usb_serial_port *port, struct file * file, un
/* DTR needs set */ /* DTR needs set */
urb_value = ((cmd == TIOCMSET) && (mask & TIOCM_DTR)) || (cmd == TIOCMBIS) ? 1 : 0; urb_value = ((cmd == TIOCMSET) && (mask & TIOCM_DTR)) || (cmd == TIOCMBIS) ? 1 : 0;
if (urb_value) if (urb_value)
priv->control_state |= TIOCM_DTR; control_state |= TIOCM_DTR;
else else
priv->control_state &= ~TIOCM_DTR; control_state &= ~TIOCM_DTR;
if ((ret = BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, urb_value)) < 0) { if ((ret = BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, urb_value)) < 0) {
err("Set DTR error %d", ret); err("Set DTR error %d", ret);
return(ret); goto cmerror;
} }
} }
cmerror:
spin_lock_irqsave(&priv->lock, flags);
priv->control_state = control_state;
spin_unlock_irqrestore(&priv->lock, flags);
return ret;
break; break;
case TIOCMIWAIT: case TIOCMIWAIT:
......
...@@ -107,6 +107,7 @@ static struct usb_device_id ipaq_id_table [] = { ...@@ -107,6 +107,7 @@ static struct usb_device_id ipaq_id_table [] = {
{ USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_IPAQ_ID) }, { USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_IPAQ_ID) },
{ USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_0032_ID) }, { USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_0032_ID) },
{ USB_DEVICE(DELL_VENDOR_ID, DELL_AXIM_ID) }, { USB_DEVICE(DELL_VENDOR_ID, DELL_AXIM_ID) },
{ USB_DEVICE(FSC_VENDOR_ID, FSC_LOOX_ID) },
{ USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_548_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_548_ID) },
{ USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_568_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_568_ID) },
{ USB_DEVICE(HP_VENDOR_ID, HP_2016_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_2016_ID) },
......
...@@ -33,6 +33,9 @@ ...@@ -33,6 +33,9 @@
#define DELL_VENDOR_ID 0x413c #define DELL_VENDOR_ID 0x413c
#define DELL_AXIM_ID 0x4001 #define DELL_AXIM_ID 0x4001
#define FSC_VENDOR_ID 0x0bf8
#define FSC_LOOX_ID 0x1001
#define HP_VENDOR_ID 0x03f0 #define HP_VENDOR_ID 0x03f0
#define HP_JORNADA_548_ID 0x1016 #define HP_JORNADA_548_ID 0x1016
#define HP_JORNADA_568_ID 0x1116 #define HP_JORNADA_568_ID 0x1116
......
...@@ -166,7 +166,7 @@ struct klsi_105_private { ...@@ -166,7 +166,7 @@ struct klsi_105_private {
unsigned long line_state; /* modem line settings */ unsigned long line_state; /* modem line settings */
/* write pool */ /* write pool */
struct urb * write_urb_pool[NUM_URBS]; struct urb * write_urb_pool[NUM_URBS];
spinlock_t write_urb_pool_lock; spinlock_t lock;
unsigned long bytes_in; unsigned long bytes_in;
unsigned long bytes_out; unsigned long bytes_out;
}; };
...@@ -284,7 +284,7 @@ static int klsi_105_startup (struct usb_serial *serial) ...@@ -284,7 +284,7 @@ static int klsi_105_startup (struct usb_serial *serial)
priv->bytes_out = 0; priv->bytes_out = 0;
usb_set_serial_port_data(&serial->port[i], priv); usb_set_serial_port_data(&serial->port[i], priv);
spin_lock_init (&priv->write_urb_pool_lock); spin_lock_init (&priv->lock);
for (i=0; i<NUM_URBS; i++) { for (i=0; i<NUM_URBS; i++) {
struct urb* urb = usb_alloc_urb(0, GFP_KERNEL); struct urb* urb = usb_alloc_urb(0, GFP_KERNEL);
...@@ -326,7 +326,7 @@ static void klsi_105_shutdown (struct usb_serial *serial) ...@@ -326,7 +326,7 @@ static void klsi_105_shutdown (struct usb_serial *serial)
/* kill our write urb pool */ /* kill our write urb pool */
int j; int j;
struct urb **write_urbs = priv->write_urb_pool; struct urb **write_urbs = priv->write_urb_pool;
spin_lock_irqsave(&priv->write_urb_pool_lock,flags); spin_lock_irqsave(&priv->lock,flags);
for (j = 0; j < NUM_URBS; j++) { for (j = 0; j < NUM_URBS; j++) {
if (write_urbs[j]) { if (write_urbs[j]) {
...@@ -343,8 +343,7 @@ static void klsi_105_shutdown (struct usb_serial *serial) ...@@ -343,8 +343,7 @@ static void klsi_105_shutdown (struct usb_serial *serial)
} }
} }
spin_unlock_irqrestore (&priv->write_urb_pool_lock, spin_unlock_irqrestore (&priv->lock, flags);
flags);
kfree(priv); kfree(priv);
usb_set_serial_port_data(&serial->port[i], NULL); usb_set_serial_port_data(&serial->port[i], NULL);
...@@ -360,6 +359,8 @@ static int klsi_105_open (struct usb_serial_port *port, struct file *filp) ...@@ -360,6 +359,8 @@ static int klsi_105_open (struct usb_serial_port *port, struct file *filp)
int rc; int rc;
int i; int i;
unsigned long line_state; unsigned long line_state;
struct klsi_105_port_settings cfg;
unsigned long flags;
dbg("%s port %d", __FUNCTION__, port->number); dbg("%s port %d", __FUNCTION__, port->number);
...@@ -374,21 +375,27 @@ static int klsi_105_open (struct usb_serial_port *port, struct file *filp) ...@@ -374,21 +375,27 @@ static int klsi_105_open (struct usb_serial_port *port, struct file *filp)
* Then read the modem line control and store values in * Then read the modem line control and store values in
* priv->line_state. * priv->line_state.
*/ */
priv->cfg.pktlen = 5; cfg.pktlen = 5;
priv->cfg.baudrate = kl5kusb105a_sio_b9600; cfg.baudrate = kl5kusb105a_sio_b9600;
priv->cfg.databits = kl5kusb105a_dtb_8; cfg.databits = kl5kusb105a_dtb_8;
priv->cfg.unknown1 = 0; cfg.unknown1 = 0;
priv->cfg.unknown2 = 1; cfg.unknown2 = 1;
klsi_105_chg_port_settings(serial, &(priv->cfg)); klsi_105_chg_port_settings(serial, &cfg);
/* set up termios structure */ /* set up termios structure */
spin_lock_irqsave (&priv->lock, flags);
priv->termios.c_iflag = port->tty->termios->c_iflag; priv->termios.c_iflag = port->tty->termios->c_iflag;
priv->termios.c_oflag = port->tty->termios->c_oflag; priv->termios.c_oflag = port->tty->termios->c_oflag;
priv->termios.c_cflag = port->tty->termios->c_cflag; priv->termios.c_cflag = port->tty->termios->c_cflag;
priv->termios.c_lflag = port->tty->termios->c_lflag; priv->termios.c_lflag = port->tty->termios->c_lflag;
for (i=0; i<NCCS; i++) for (i=0; i<NCCS; i++)
priv->termios.c_cc[i] = port->tty->termios->c_cc[i]; priv->termios.c_cc[i] = port->tty->termios->c_cc[i];
priv->cfg.pktlen = cfg.pktlen;
priv->cfg.baudrate = cfg.baudrate;
priv->cfg.databits = cfg.databits;
priv->cfg.unknown1 = cfg.unknown1;
priv->cfg.unknown2 = cfg.unknown2;
spin_unlock_irqrestore (&priv->lock, flags);
/* READ_ON and urb submission */ /* READ_ON and urb submission */
usb_fill_bulk_urb(port->read_urb, serial->dev, usb_fill_bulk_urb(port->read_urb, serial->dev,
...@@ -422,7 +429,9 @@ static int klsi_105_open (struct usb_serial_port *port, struct file *filp) ...@@ -422,7 +429,9 @@ static int klsi_105_open (struct usb_serial_port *port, struct file *filp)
rc = klsi_105_get_line_state(serial, &line_state); rc = klsi_105_get_line_state(serial, &line_state);
if (rc >= 0) { if (rc >= 0) {
spin_lock_irqsave (&priv->lock, flags);
priv->line_state = line_state; priv->line_state = line_state;
spin_unlock_irqrestore (&priv->lock, flags);
dbg("%s - read line state 0x%lx", __FUNCTION__, line_state); dbg("%s - read line state 0x%lx", __FUNCTION__, line_state);
retval = 0; retval = 0;
} else } else
...@@ -492,7 +501,7 @@ static int klsi_105_write (struct usb_serial_port *port, int from_user, ...@@ -492,7 +501,7 @@ static int klsi_105_write (struct usb_serial_port *port, int from_user,
unsigned long flags; unsigned long flags;
int i; int i;
/* since the pool is per-port we might not need the spin lock !? */ /* since the pool is per-port we might not need the spin lock !? */
spin_lock_irqsave (&priv->write_urb_pool_lock, flags); spin_lock_irqsave (&priv->lock, flags);
for (i=0; i<NUM_URBS; i++) { for (i=0; i<NUM_URBS; i++) {
if (priv->write_urb_pool[i]->status != -EINPROGRESS) { if (priv->write_urb_pool[i]->status != -EINPROGRESS) {
urb = priv->write_urb_pool[i]; urb = priv->write_urb_pool[i];
...@@ -500,7 +509,7 @@ static int klsi_105_write (struct usb_serial_port *port, int from_user, ...@@ -500,7 +509,7 @@ static int klsi_105_write (struct usb_serial_port *port, int from_user,
break; break;
} }
} }
spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags); spin_unlock_irqrestore (&priv->lock, flags);
if (urb==NULL) { if (urb==NULL) {
dbg("%s - no more free urbs", __FUNCTION__); dbg("%s - no more free urbs", __FUNCTION__);
...@@ -552,6 +561,7 @@ static int klsi_105_write (struct usb_serial_port *port, int from_user, ...@@ -552,6 +561,7 @@ static int klsi_105_write (struct usb_serial_port *port, int from_user,
count -= size; count -= size;
} }
exit: exit:
/* lockless, but it's for debug info only... */
priv->bytes_out+=bytes_sent; priv->bytes_out+=bytes_sent;
return bytes_sent; /* that's how much we wrote */ return bytes_sent; /* that's how much we wrote */
...@@ -588,7 +598,7 @@ static int klsi_105_chars_in_buffer (struct usb_serial_port *port) ...@@ -588,7 +598,7 @@ static int klsi_105_chars_in_buffer (struct usb_serial_port *port)
unsigned long flags; unsigned long flags;
struct klsi_105_private *priv = usb_get_serial_port_data(port); struct klsi_105_private *priv = usb_get_serial_port_data(port);
spin_lock_irqsave (&priv->write_urb_pool_lock, flags); spin_lock_irqsave (&priv->lock, flags);
for (i = 0; i < NUM_URBS; ++i) { for (i = 0; i < NUM_URBS; ++i) {
if (priv->write_urb_pool[i]->status == -EINPROGRESS) { if (priv->write_urb_pool[i]->status == -EINPROGRESS) {
...@@ -596,7 +606,7 @@ static int klsi_105_chars_in_buffer (struct usb_serial_port *port) ...@@ -596,7 +606,7 @@ static int klsi_105_chars_in_buffer (struct usb_serial_port *port)
} }
} }
spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags); spin_unlock_irqrestore (&priv->lock, flags);
dbg("%s - returns %d", __FUNCTION__, chars); dbg("%s - returns %d", __FUNCTION__, chars);
return (chars); return (chars);
...@@ -609,14 +619,14 @@ static int klsi_105_write_room (struct usb_serial_port *port) ...@@ -609,14 +619,14 @@ static int klsi_105_write_room (struct usb_serial_port *port)
int room = 0; int room = 0;
struct klsi_105_private *priv = usb_get_serial_port_data(port); struct klsi_105_private *priv = usb_get_serial_port_data(port);
spin_lock_irqsave (&priv->write_urb_pool_lock, flags); spin_lock_irqsave (&priv->lock, flags);
for (i = 0; i < NUM_URBS; ++i) { for (i = 0; i < NUM_URBS; ++i) {
if (priv->write_urb_pool[i]->status != -EINPROGRESS) { if (priv->write_urb_pool[i]->status != -EINPROGRESS) {
room += URB_TRANSFER_BUFFER_SIZE; room += URB_TRANSFER_BUFFER_SIZE;
} }
} }
spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags); spin_unlock_irqrestore (&priv->lock, flags);
dbg("%s - returns %d", __FUNCTION__, room); dbg("%s - returns %d", __FUNCTION__, room);
return (room); return (room);
...@@ -690,6 +700,8 @@ static void klsi_105_read_bulk_callback (struct urb *urb, struct pt_regs *regs) ...@@ -690,6 +700,8 @@ static void klsi_105_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
tty_insert_flip_char(tty, ((__u8*) data)[i], 0); tty_insert_flip_char(tty, ((__u8*) data)[i], 0);
} }
tty_flip_buffer_push(tty); tty_flip_buffer_push(tty);
/* again lockless, but debug info only */
priv->bytes_in += bytes_sent; priv->bytes_in += bytes_sent;
} }
/* Continue trying to always read */ /* Continue trying to always read */
...@@ -715,6 +727,11 @@ static void klsi_105_set_termios (struct usb_serial_port *port, ...@@ -715,6 +727,11 @@ static void klsi_105_set_termios (struct usb_serial_port *port,
unsigned int old_iflag = old_termios->c_iflag; unsigned int old_iflag = old_termios->c_iflag;
unsigned int cflag = port->tty->termios->c_cflag; unsigned int cflag = port->tty->termios->c_cflag;
unsigned int old_cflag = old_termios->c_cflag; unsigned int old_cflag = old_termios->c_cflag;
struct klsi_105_port_settings cfg;
unsigned long flags;
/* lock while we are modifying the settings */
spin_lock_irqsave (&priv->lock, flags);
/* /*
* Update baud rate * Update baud rate
...@@ -838,9 +855,11 @@ static void klsi_105_set_termios (struct usb_serial_port *port, ...@@ -838,9 +855,11 @@ static void klsi_105_set_termios (struct usb_serial_port *port,
#endif #endif
; ;
} }
memcpy (&cfg, &priv->cfg, sizeof(cfg));
spin_unlock_irqrestore (&priv->lock, flags);
/* now commit changes to device */ /* now commit changes to device */
klsi_105_chg_port_settings(serial, &(priv->cfg)); klsi_105_chg_port_settings(serial, &cfg);
} /* klsi_105_set_termios */ } /* klsi_105_set_termios */
...@@ -866,6 +885,7 @@ static int klsi_105_ioctl (struct usb_serial_port *port, struct file * file, ...@@ -866,6 +885,7 @@ static int klsi_105_ioctl (struct usb_serial_port *port, struct file * file,
struct usb_serial *serial = port->serial; struct usb_serial *serial = port->serial;
struct klsi_105_private *priv = usb_get_serial_port_data(port); struct klsi_105_private *priv = usb_get_serial_port_data(port);
int mask; int mask;
unsigned long flags;
dbg("%scmd=0x%x", __FUNCTION__, cmd); dbg("%scmd=0x%x", __FUNCTION__, cmd);
...@@ -881,11 +901,12 @@ static int klsi_105_ioctl (struct usb_serial_port *port, struct file * file, ...@@ -881,11 +901,12 @@ static int klsi_105_ioctl (struct usb_serial_port *port, struct file * file,
err("Reading line control failed (error = %d)", rc); err("Reading line control failed (error = %d)", rc);
/* better return value? EAGAIN? */ /* better return value? EAGAIN? */
return -ENOIOCTLCMD; return -ENOIOCTLCMD;
} else {
priv->line_state = line_state;
dbg("%s - read line state 0x%lx", __FUNCTION__, line_state);
} }
return put_user(priv->line_state, (unsigned long *) arg); spin_lock_irqsave (&priv->lock, flags);
priv->line_state = line_state;
spin_unlock_irqrestore (&priv->lock, flags);
dbg("%s - read line state 0x%lx", __FUNCTION__, line_state);
return put_user(line_state, (unsigned long *) arg);
}; };
case TIOCMSET: /* Turns on and off the lines as specified by the mask */ case TIOCMSET: /* Turns on and off the lines as specified by the mask */
......
...@@ -171,6 +171,7 @@ static struct usb_serial_device_type mct_u232_device = { ...@@ -171,6 +171,7 @@ static struct usb_serial_device_type mct_u232_device = {
struct mct_u232_private { struct mct_u232_private {
spinlock_t lock;
unsigned long control_state; /* Modem Line Setting (TIOCM) */ unsigned long control_state; /* Modem Line Setting (TIOCM) */
unsigned char last_lcr; /* Line Control Register */ unsigned char last_lcr; /* Line Control Register */
unsigned char last_lsr; /* Line Status Register */ unsigned char last_lsr; /* Line Status Register */
...@@ -306,8 +307,9 @@ static int mct_u232_startup (struct usb_serial *serial) ...@@ -306,8 +307,9 @@ static int mct_u232_startup (struct usb_serial *serial)
/* allocate the private data structure */ /* allocate the private data structure */
priv = kmalloc(sizeof(struct mct_u232_private), GFP_KERNEL); priv = kmalloc(sizeof(struct mct_u232_private), GFP_KERNEL);
if (!priv) if (!priv)
return (-1); /* error */ return -ENOMEM;
/* set initial values for control structures */ /* set initial values for control structures */
spin_lock_init(&priv->lock);
priv->control_state = 0; priv->control_state = 0;
priv->last_lsr = 0; priv->last_lsr = 0;
priv->last_msr = 0; priv->last_msr = 0;
...@@ -339,6 +341,10 @@ static int mct_u232_open (struct usb_serial_port *port, struct file *filp) ...@@ -339,6 +341,10 @@ static int mct_u232_open (struct usb_serial_port *port, struct file *filp)
struct usb_serial *serial = port->serial; struct usb_serial *serial = port->serial;
struct mct_u232_private *priv = usb_get_serial_port_data(port); struct mct_u232_private *priv = usb_get_serial_port_data(port);
int retval = 0; int retval = 0;
unsigned long control_state;
unsigned long flags;
unsigned char last_lcr;
unsigned char last_msr;
dbg("%s port %d", __FUNCTION__, port->number); dbg("%s port %d", __FUNCTION__, port->number);
...@@ -355,20 +361,27 @@ static int mct_u232_open (struct usb_serial_port *port, struct file *filp) ...@@ -355,20 +361,27 @@ static int mct_u232_open (struct usb_serial_port *port, struct file *filp)
* sure if this is really necessary. But it should not harm * sure if this is really necessary. But it should not harm
* either. * either.
*/ */
spin_lock_irqsave(&priv->lock, flags);
if (port->tty->termios->c_cflag & CBAUD) if (port->tty->termios->c_cflag & CBAUD)
priv->control_state = TIOCM_DTR | TIOCM_RTS; priv->control_state = TIOCM_DTR | TIOCM_RTS;
else else
priv->control_state = 0; priv->control_state = 0;
mct_u232_set_modem_ctrl(serial, priv->control_state);
priv->last_lcr = (MCT_U232_DATA_BITS_8 | priv->last_lcr = (MCT_U232_DATA_BITS_8 |
MCT_U232_PARITY_NONE | MCT_U232_PARITY_NONE |
MCT_U232_STOP_BITS_1); MCT_U232_STOP_BITS_1);
mct_u232_set_line_ctrl(serial, priv->last_lcr); control_state = priv->control_state;
last_lcr = priv->last_lcr;
spin_unlock_irqrestore(&priv->lock, flags);
mct_u232_set_modem_ctrl(serial, control_state);
mct_u232_set_line_ctrl(serial, last_lcr);
/* Read modem status and update control state */ /* Read modem status and update control state */
mct_u232_get_modem_stat(serial, &priv->last_msr); mct_u232_get_modem_stat(serial, &last_msr);
spin_lock_irqsave(&priv->lock, flags);
priv->last_msr = last_msr;
mct_u232_msr_to_state(&priv->control_state, priv->last_msr); mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
spin_unlock_irqrestore(&priv->lock, flags);
{ {
/* Puh, that's dirty */ /* Puh, that's dirty */
...@@ -523,6 +536,7 @@ static void mct_u232_read_int_callback (struct urb *urb, struct pt_regs *regs) ...@@ -523,6 +536,7 @@ static void mct_u232_read_int_callback (struct urb *urb, struct pt_regs *regs)
struct tty_struct *tty; struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer; unsigned char *data = urb->transfer_buffer;
int status; int status;
unsigned long flags;
dbg("%s - port %d", __FUNCTION__, port->number); dbg("%s - port %d", __FUNCTION__, port->number);
...@@ -567,6 +581,7 @@ static void mct_u232_read_int_callback (struct urb *urb, struct pt_regs *regs) ...@@ -567,6 +581,7 @@ static void mct_u232_read_int_callback (struct urb *urb, struct pt_regs *regs)
* The interrupt-in pipe signals exceptional conditions (modem line * The interrupt-in pipe signals exceptional conditions (modem line
* signal changes and errors). data[0] holds MSR, data[1] holds LSR. * signal changes and errors). data[0] holds MSR, data[1] holds LSR.
*/ */
spin_lock_irqsave(&priv->lock, flags);
priv->last_msr = data[MCT_U232_MSR_INDEX]; priv->last_msr = data[MCT_U232_MSR_INDEX];
/* Record Control Line states */ /* Record Control Line states */
...@@ -597,6 +612,7 @@ static void mct_u232_read_int_callback (struct urb *urb, struct pt_regs *regs) ...@@ -597,6 +612,7 @@ static void mct_u232_read_int_callback (struct urb *urb, struct pt_regs *regs)
} }
} }
#endif #endif
spin_unlock_irqrestore(&priv->lock, flags);
exit: exit:
status = usb_submit_urb (urb, GFP_ATOMIC); status = usb_submit_urb (urb, GFP_ATOMIC);
if (status) if (status)
...@@ -614,7 +630,16 @@ static void mct_u232_set_termios (struct usb_serial_port *port, ...@@ -614,7 +630,16 @@ static void mct_u232_set_termios (struct usb_serial_port *port,
unsigned int old_iflag = old_termios->c_iflag; unsigned int old_iflag = old_termios->c_iflag;
unsigned int cflag = port->tty->termios->c_cflag; unsigned int cflag = port->tty->termios->c_cflag;
unsigned int old_cflag = old_termios->c_cflag; unsigned int old_cflag = old_termios->c_cflag;
unsigned long flags;
unsigned long control_state;
unsigned char last_lcr;
/* get a local copy of the current port settings */
spin_lock_irqsave(&priv->lock, flags);
control_state = priv->control_state;
last_lcr = priv->last_lcr;
spin_unlock_irqrestore(&priv->lock, flags);
/* /*
* Update baud rate * Update baud rate
*/ */
...@@ -622,12 +647,12 @@ static void mct_u232_set_termios (struct usb_serial_port *port, ...@@ -622,12 +647,12 @@ static void mct_u232_set_termios (struct usb_serial_port *port,
/* reassert DTR and (maybe) RTS on transition from B0 */ /* reassert DTR and (maybe) RTS on transition from B0 */
if( (old_cflag & CBAUD) == B0 ) { if( (old_cflag & CBAUD) == B0 ) {
dbg("%s: baud was B0", __FUNCTION__); dbg("%s: baud was B0", __FUNCTION__);
priv->control_state |= TIOCM_DTR; control_state |= TIOCM_DTR;
/* don't set RTS if using hardware flow control */ /* don't set RTS if using hardware flow control */
if (!(old_cflag & CRTSCTS)) { if (!(old_cflag & CRTSCTS)) {
priv->control_state |= TIOCM_RTS; control_state |= TIOCM_RTS;
} }
mct_u232_set_modem_ctrl(serial, priv->control_state); mct_u232_set_modem_ctrl(serial, control_state);
} }
switch(cflag & CBAUD) { switch(cflag & CBAUD) {
...@@ -659,8 +684,8 @@ static void mct_u232_set_termios (struct usb_serial_port *port, ...@@ -659,8 +684,8 @@ static void mct_u232_set_termios (struct usb_serial_port *port,
if ((cflag & CBAUD) == B0 ) { if ((cflag & CBAUD) == B0 ) {
dbg("%s: baud is B0", __FUNCTION__); dbg("%s: baud is B0", __FUNCTION__);
/* Drop RTS and DTR */ /* Drop RTS and DTR */
priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS); control_state &= ~(TIOCM_DTR | TIOCM_RTS);
mct_u232_set_modem_ctrl(serial, priv->control_state); mct_u232_set_modem_ctrl(serial, control_state);
} }
} }
...@@ -672,36 +697,36 @@ static void mct_u232_set_termios (struct usb_serial_port *port, ...@@ -672,36 +697,36 @@ static void mct_u232_set_termios (struct usb_serial_port *port,
|| (cflag & CSTOPB) != (old_cflag & CSTOPB) ) { || (cflag & CSTOPB) != (old_cflag & CSTOPB) ) {
priv->last_lcr = 0; last_lcr = 0;
/* set the parity */ /* set the parity */
if (cflag & PARENB) if (cflag & PARENB)
priv->last_lcr |= (cflag & PARODD) ? last_lcr |= (cflag & PARODD) ?
MCT_U232_PARITY_ODD : MCT_U232_PARITY_EVEN; MCT_U232_PARITY_ODD : MCT_U232_PARITY_EVEN;
else else
priv->last_lcr |= MCT_U232_PARITY_NONE; last_lcr |= MCT_U232_PARITY_NONE;
/* set the number of data bits */ /* set the number of data bits */
switch (cflag & CSIZE) { switch (cflag & CSIZE) {
case CS5: case CS5:
priv->last_lcr |= MCT_U232_DATA_BITS_5; break; last_lcr |= MCT_U232_DATA_BITS_5; break;
case CS6: case CS6:
priv->last_lcr |= MCT_U232_DATA_BITS_6; break; last_lcr |= MCT_U232_DATA_BITS_6; break;
case CS7: case CS7:
priv->last_lcr |= MCT_U232_DATA_BITS_7; break; last_lcr |= MCT_U232_DATA_BITS_7; break;
case CS8: case CS8:
priv->last_lcr |= MCT_U232_DATA_BITS_8; break; last_lcr |= MCT_U232_DATA_BITS_8; break;
default: default:
err("CSIZE was not CS5-CS8, using default of 8"); err("CSIZE was not CS5-CS8, using default of 8");
priv->last_lcr |= MCT_U232_DATA_BITS_8; last_lcr |= MCT_U232_DATA_BITS_8;
break; break;
} }
/* set the number of stop bits */ /* set the number of stop bits */
priv->last_lcr |= (cflag & CSTOPB) ? last_lcr |= (cflag & CSTOPB) ?
MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1; MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1;
mct_u232_set_line_ctrl(serial, priv->last_lcr); mct_u232_set_line_ctrl(serial, last_lcr);
} }
/* /*
...@@ -714,11 +739,17 @@ static void mct_u232_set_termios (struct usb_serial_port *port, ...@@ -714,11 +739,17 @@ static void mct_u232_set_termios (struct usb_serial_port *port,
/* Drop DTR/RTS if no flow control otherwise assert */ /* Drop DTR/RTS if no flow control otherwise assert */
if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS) ) if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS) )
priv->control_state |= TIOCM_DTR | TIOCM_RTS; control_state |= TIOCM_DTR | TIOCM_RTS;
else else
priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS); control_state &= ~(TIOCM_DTR | TIOCM_RTS);
mct_u232_set_modem_ctrl(serial, priv->control_state); mct_u232_set_modem_ctrl(serial, control_state);
} }
/* save off the modified port settings */
spin_lock_irqsave(&priv->lock, flags);
priv->control_state = control_state;
priv->last_lcr = last_lcr;
spin_unlock_irqrestore(&priv->lock, flags);
} /* mct_u232_set_termios */ } /* mct_u232_set_termios */
...@@ -726,10 +757,15 @@ static void mct_u232_break_ctl( struct usb_serial_port *port, int break_state ) ...@@ -726,10 +757,15 @@ static void mct_u232_break_ctl( struct usb_serial_port *port, int break_state )
{ {
struct usb_serial *serial = port->serial; struct usb_serial *serial = port->serial;
struct mct_u232_private *priv = usb_get_serial_port_data(port); struct mct_u232_private *priv = usb_get_serial_port_data(port);
unsigned char lcr = priv->last_lcr; unsigned char lcr;
unsigned long flags;
dbg("%sstate=%d", __FUNCTION__, break_state); dbg("%sstate=%d", __FUNCTION__, break_state);
spin_lock_irqsave(&priv->lock, flags);
lcr = priv->last_lcr;
spin_unlock_irqrestore(&priv->lock, flags);
if (break_state) if (break_state)
lcr |= MCT_U232_SET_BREAK; lcr |= MCT_U232_SET_BREAK;
...@@ -743,13 +779,19 @@ static int mct_u232_ioctl (struct usb_serial_port *port, struct file * file, ...@@ -743,13 +779,19 @@ static int mct_u232_ioctl (struct usb_serial_port *port, struct file * file,
struct usb_serial *serial = port->serial; struct usb_serial *serial = port->serial;
struct mct_u232_private *priv = usb_get_serial_port_data(port); struct mct_u232_private *priv = usb_get_serial_port_data(port);
int mask; int mask;
unsigned long control_state;
unsigned long flags;
dbg("%scmd=0x%x", __FUNCTION__, cmd); dbg("%scmd=0x%x", __FUNCTION__, cmd);
spin_lock_irqsave(&priv->lock, flags);
control_state = priv->control_state;
spin_unlock_irqrestore(&priv->lock, flags);
/* Based on code from acm.c and others */ /* Based on code from acm.c and others */
switch (cmd) { switch (cmd) {
case TIOCMGET: case TIOCMGET:
return put_user(priv->control_state, (unsigned long *) arg); return put_user(control_state, (unsigned long *) arg);
break; break;
case TIOCMSET: /* Turns on and off the lines as specified by the mask */ case TIOCMSET: /* Turns on and off the lines as specified by the mask */
...@@ -762,20 +804,24 @@ static int mct_u232_ioctl (struct usb_serial_port *port, struct file * file, ...@@ -762,20 +804,24 @@ static int mct_u232_ioctl (struct usb_serial_port *port, struct file * file,
/* RTS needs set */ /* RTS needs set */
if( ((cmd == TIOCMSET) && (mask & TIOCM_RTS)) || if( ((cmd == TIOCMSET) && (mask & TIOCM_RTS)) ||
(cmd == TIOCMBIS) ) (cmd == TIOCMBIS) )
priv->control_state |= TIOCM_RTS; control_state |= TIOCM_RTS;
else else
priv->control_state &= ~TIOCM_RTS; control_state &= ~TIOCM_RTS;
} }
if ((cmd == TIOCMSET) || (mask & TIOCM_DTR)) { if ((cmd == TIOCMSET) || (mask & TIOCM_DTR)) {
/* DTR needs set */ /* DTR needs set */
if( ((cmd == TIOCMSET) && (mask & TIOCM_DTR)) || if( ((cmd == TIOCMSET) && (mask & TIOCM_DTR)) ||
(cmd == TIOCMBIS) ) (cmd == TIOCMBIS) )
priv->control_state |= TIOCM_DTR; control_state |= TIOCM_DTR;
else else
priv->control_state &= ~TIOCM_DTR; control_state &= ~TIOCM_DTR;
} }
mct_u232_set_modem_ctrl(serial, priv->control_state); mct_u232_set_modem_ctrl(serial, control_state);
spin_lock_irqsave(&priv->lock, flags);
priv->control_state = control_state;
spin_unlock_irqrestore(&priv->lock, flags);
break; break;
case TIOCMIWAIT: case TIOCMIWAIT:
......
...@@ -148,7 +148,8 @@ static struct usb_serial_device_type pl2303_device = { ...@@ -148,7 +148,8 @@ static struct usb_serial_device_type pl2303_device = {
.shutdown = pl2303_shutdown, .shutdown = pl2303_shutdown,
}; };
struct pl2303_private { struct pl2303_private {
spinlock_t lock;
u8 line_control; u8 line_control;
u8 termios_initialized; u8 termios_initialized;
}; };
...@@ -164,6 +165,7 @@ static int pl2303_startup (struct usb_serial *serial) ...@@ -164,6 +165,7 @@ static int pl2303_startup (struct usb_serial *serial)
if (!priv) if (!priv)
return -ENOMEM; return -ENOMEM;
memset (priv, 0x00, sizeof (struct pl2303_private)); memset (priv, 0x00, sizeof (struct pl2303_private));
spin_lock_init(&priv->lock);
usb_set_serial_port_data(&serial->port[i], priv); usb_set_serial_port_data(&serial->port[i], priv);
} }
return 0; return 0;
...@@ -223,18 +225,21 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol ...@@ -223,18 +225,21 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol
int baud; int baud;
int i; int i;
dbg("%s - port %d, initialized = %d", __FUNCTION__, port->number, priv->termios_initialized); dbg("%s - port %d", __FUNCTION__, port->number);
if ((!port->tty) || (!port->tty->termios)) { if ((!port->tty) || (!port->tty->termios)) {
dbg("%s - no tty structures", __FUNCTION__); dbg("%s - no tty structures", __FUNCTION__);
return; return;
} }
spin_lock(&priv->lock);
if (!priv->termios_initialized) { if (!priv->termios_initialized) {
*(port->tty->termios) = tty_std_termios; *(port->tty->termios) = tty_std_termios;
port->tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; port->tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
priv->termios_initialized = 1; priv->termios_initialized = 1;
} }
spin_unlock(&priv->lock);
cflag = port->tty->termios->c_cflag; cflag = port->tty->termios->c_cflag;
/* check that they really want us to change something */ /* check that they really want us to change something */
if (old_termios) { if (old_termios) {
...@@ -341,11 +346,16 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol ...@@ -341,11 +346,16 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol
dbg ("0x21:0x20:0:0 %d", i); dbg ("0x21:0x20:0:0 %d", i);
if (cflag && CBAUD) { if (cflag && CBAUD) {
u8 control;
spin_lock (&priv->lock);
if ((cflag && CBAUD) == B0) if ((cflag && CBAUD) == B0)
priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
else else
priv->line_control |= (CONTROL_DTR | CONTROL_RTS); priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
set_control_lines (serial->dev, priv->line_control); control = priv->line_control;
spin_unlock (&priv->lock);
set_control_lines (serial->dev, control);
} }
buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0; buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
...@@ -444,48 +454,50 @@ static void pl2303_close (struct usb_serial_port *port, struct file *filp) ...@@ -444,48 +454,50 @@ static void pl2303_close (struct usb_serial_port *port, struct file *filp)
dbg("%s - port %d", __FUNCTION__, port->number); dbg("%s - port %d", __FUNCTION__, port->number);
if (serial->dev) { /* shutdown our urbs */
if (port->tty) { dbg("%s - shutting down urbs", __FUNCTION__);
c_cflag = port->tty->termios->c_cflag; result = usb_unlink_urb (port->write_urb);
if (c_cflag & HUPCL) { if (result)
/* drop DTR and RTS */ dbg("%s - usb_unlink_urb (write_urb)"
priv = usb_get_serial_port_data(port); " failed with reason: %d", __FUNCTION__,
priv->line_control = 0; result);
set_control_lines (port->serial->dev,
priv->line_control);
}
}
/* shutdown our urbs */ result = usb_unlink_urb (port->read_urb);
dbg("%s - shutting down urbs", __FUNCTION__); if (result)
result = usb_unlink_urb (port->write_urb); dbg("%s - usb_unlink_urb (read_urb) "
if (result) "failed with reason: %d", __FUNCTION__,
dbg("%s - usb_unlink_urb (write_urb)" result);
" failed with reason: %d", __FUNCTION__,
result);
result = usb_unlink_urb (port->read_urb); result = usb_unlink_urb (port->interrupt_in_urb);
if (result) if (result)
dbg("%s - usb_unlink_urb (read_urb) " dbg("%s - usb_unlink_urb (interrupt_in_urb)"
"failed with reason: %d", __FUNCTION__, " failed with reason: %d", __FUNCTION__,
result); result);
result = usb_unlink_urb (port->interrupt_in_urb); if (port->tty) {
if (result) c_cflag = port->tty->termios->c_cflag;
dbg("%s - usb_unlink_urb (interrupt_in_urb)" if (c_cflag & HUPCL) {
" failed with reason: %d", __FUNCTION__, /* drop DTR and RTS */
result); priv = usb_get_serial_port_data(port);
spin_lock (&priv->lock);
priv->line_control = 0;
spin_unlock (&priv->lock);
set_control_lines (port->serial->dev, 0);
}
} }
} }
static int set_modem_info (struct usb_serial_port *port, unsigned int cmd, unsigned int *value) static int set_modem_info (struct usb_serial_port *port, unsigned int cmd, unsigned int *value)
{ {
struct pl2303_private *priv = usb_get_serial_port_data(port); struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned int arg; unsigned int arg;
u8 control;
if (copy_from_user(&arg, value, sizeof(int))) if (copy_from_user(&arg, value, sizeof(int)))
return -EFAULT; return -EFAULT;
spin_lock (&priv->lock);
switch (cmd) { switch (cmd) {
case TIOCMBIS: case TIOCMBIS:
if (arg & TIOCM_RTS) if (arg & TIOCM_RTS)
...@@ -509,16 +521,22 @@ static int set_modem_info (struct usb_serial_port *port, unsigned int cmd, unsig ...@@ -509,16 +521,22 @@ static int set_modem_info (struct usb_serial_port *port, unsigned int cmd, unsig
priv->line_control |= ((arg & TIOCM_DTR) ? CONTROL_DTR : 0); priv->line_control |= ((arg & TIOCM_DTR) ? CONTROL_DTR : 0);
break; break;
} }
control = priv->line_control;
spin_unlock (&priv->lock);
return set_control_lines (port->serial->dev, priv->line_control); return set_control_lines (port->serial->dev, control);
} }
static int get_modem_info (struct usb_serial_port *port, unsigned int *value) static int get_modem_info (struct usb_serial_port *port, unsigned int *value)
{ {
struct pl2303_private *priv = usb_get_serial_port_data(port); struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned int mcr = priv->line_control; unsigned int mcr;
unsigned int result; unsigned int result;
spin_lock (&priv->lock);
mcr = priv->line_control;
spin_unlock (&priv->lock);
result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0) result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0)
| ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0); | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0);
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* USB HandSpring Visor, Palm m50x, and Sony Clie driver * USB HandSpring Visor, Palm m50x, and Sony Clie driver
* (supports all of the Palm OS USB devices) * (supports all of the Palm OS USB devices)
* *
* Copyright (C) 1999 - 2002 * Copyright (C) 1999 - 2003
* Greg Kroah-Hartman (greg@kroah.com) * Greg Kroah-Hartman (greg@kroah.com)
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -183,34 +183,34 @@ static int palm_os_4_probe (struct usb_serial *serial, const struct usb_device_i ...@@ -183,34 +183,34 @@ static int palm_os_4_probe (struct usb_serial *serial, const struct usb_device_i
static struct usb_device_id id_table [] = { static struct usb_device_id id_table [] = {
{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID), { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID),
.driver_info = (unsigned int)&palm_os_3_probe }, .driver_info = (kernel_ulong_t)&palm_os_3_probe },
{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO_ID), { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO_ID),
.driver_info = (unsigned int)&palm_os_4_probe }, .driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID), { USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID),
.driver_info = (unsigned int)&palm_os_4_probe }, .driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID), { USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID),
.driver_info = (unsigned int)&palm_os_4_probe }, .driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID), { USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID),
.driver_info = (unsigned int)&palm_os_4_probe }, .driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID), { USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID),
.driver_info = (unsigned int)&palm_os_4_probe }, .driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID), { USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID),
.driver_info = (unsigned int)&palm_os_4_probe }, .driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID), { USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID),
.driver_info = (unsigned int)&palm_os_4_probe }, .driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID), { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID),
.driver_info = (unsigned int)&palm_os_4_probe }, .driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID), { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID),
.driver_info = (unsigned int)&palm_os_4_probe }, .driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID), { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID),
.driver_info = (unsigned int)&palm_os_4_probe }, .driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID), { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID),
.driver_info = (unsigned int)&palm_os_4_probe }, .driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID), { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID),
.driver_info = (unsigned int)&palm_os_4_probe }, .driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_1_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_1_ID) },
{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NX60_ID), { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NX60_ID),
.driver_info = (unsigned int)&palm_os_4_probe }, .driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
...@@ -374,27 +374,22 @@ static void visor_close (struct usb_serial_port *port, struct file * filp) ...@@ -374,27 +374,22 @@ static void visor_close (struct usb_serial_port *port, struct file * filp)
if (!serial) if (!serial)
return; return;
if (serial->dev) { /* shutdown our urbs */
/* only send a shutdown message if the usb_unlink_urb (port->read_urb);
* device is still here */ if (port->interrupt_in_urb)
transfer_buffer = kmalloc (0x12, GFP_KERNEL); usb_unlink_urb (port->interrupt_in_urb);
if (!transfer_buffer) {
dev_err(&port->dev, "%s - kmalloc(%d) failed.\n", __FUNCTION__, 0x12); /* Try to send shutdown message, if the device is gone, this will just fail. */
} else { transfer_buffer = kmalloc (0x12, GFP_KERNEL);
/* send a shutdown message to the device */ if (transfer_buffer) {
usb_control_msg (serial->dev, usb_control_msg (serial->dev,
usb_rcvctrlpipe(serial->dev, 0), usb_rcvctrlpipe(serial->dev, 0),
VISOR_CLOSE_NOTIFICATION, 0xc2, VISOR_CLOSE_NOTIFICATION, 0xc2,
0x0000, 0x0000, 0x0000, 0x0000,
transfer_buffer, 0x12, 300); transfer_buffer, 0x12, 300);
kfree (transfer_buffer); kfree (transfer_buffer);
}
/* shutdown our bulk read */
usb_unlink_urb (port->read_urb);
if (port->interrupt_in_urb)
usb_unlink_urb (port->interrupt_in_urb);
} }
/* Uncomment the following line if you want to see some statistics in your syslog */ /* Uncomment the following line if you want to see some statistics in your syslog */
/* dev_info (&port->dev, "Bytes In = %d Bytes Out = %d\n", bytes_in, bytes_out); */ /* dev_info (&port->dev, "Bytes In = %d Bytes Out = %d\n", bytes_in, bytes_out); */
} }
......
...@@ -137,12 +137,12 @@ UNUSUAL_DEV( 0x04da, 0x0901, 0x0100, 0x0200, ...@@ -137,12 +137,12 @@ UNUSUAL_DEV( 0x04da, 0x0901, 0x0100, 0x0200,
"LS-120 Camera", "LS-120 Camera",
US_SC_UFI, US_PR_CBI, NULL, 0), US_SC_UFI, US_PR_CBI, NULL, 0),
/* Reported by Peter Wchtler <pwaechtler@loewe-komp.de> */ /* From Yukihiro Nakai, via zaitcev@yahoo.com.
UNUSUAL_DEV( 0x04ce, 0x0002, 0x0074, 0x0074, * This is needed for CB instead of CBI */
"ScanLogic", UNUSUAL_DEV( 0x04da, 0x0d05, 0x0000, 0x0000,
"SL11R-IDE 0049SQFP-1.2 A002", "Sharp CE-CW05",
US_SC_SCSI, US_PR_BULK, NULL, "CD-R/RW Drive",
US_FL_FIX_INQUIRY ), US_SC_8070, US_PR_CB, NULL, 0),
/* Most of the following entries were developed with the help of /* Most of the following entries were developed with the help of
* Shuttle/SCM directly. * Shuttle/SCM directly.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment