From 011db815231f40d4d53531b5d41b82c8dc7c44bf Mon Sep 17 00:00:00 2001 From: Micah Gruber Date: Wed, 5 Sep 2007 13:49:58 +0800 Subject: USB: Remove unneeded pointer intf from speedtch_upload_firmware() This trivial patch removes the unneeded pointer intf returned from usb_ifnum_to_if(), which is never used. The check for NULL can be simply done by if (!usb_ifnum_to_if(usb_dev, 2)). Signed-off-by: Micah Gruber Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/speedtch.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index eb0615abff6..8b132c4a503 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -251,7 +251,6 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance, { unsigned char *buffer; struct usbatm_data *usbatm = instance->usbatm; - struct usb_interface *intf; struct usb_device *usb_dev = usbatm->usb_dev; int actual_length; int ret = 0; @@ -265,7 +264,7 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance, goto out; } - if (!(intf = usb_ifnum_to_if(usb_dev, 2))) { + if (!usb_ifnum_to_if(usb_dev, 2)) { ret = -ENODEV; usb_dbg(usbatm, "%s: interface not found!\n", __func__); goto out_free; -- cgit v1.2.3-70-g09d2 From ca337db6f92a32347172a20b96f6f51b7bb63b7c Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sat, 21 Jul 2007 17:02:59 +0200 Subject: USB: Clean up duplicate includes in drivers/usb/ This patch cleans up duplicate includes in drivers/usb/ Signed-off-by: Jesper Juhl Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/u132-hcd.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index b88eb3c62c0..598ad098aee 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -51,7 +51,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3-70-g09d2 From 7f477358e2384c54b190cc3b6ce28277050a041b Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Mon, 23 Jul 2007 01:58:15 -0700 Subject: usblp: Implement the ENOSPC convention This patch implements a mode when a printer returns ENOSPC when it runs out of paper. The default remains the same as before. An application which wishes to use this function has to enable it explicitly with an ioctl LPABORT. This is done on a request by our (Fedora) CUPS guy, Tim Waugh. The API is similar enough to the lp0's one that CUPS works with both (but see below), but it's has some differences. Most importantly, the abort mode is persistent in case of lp0: once tunelp was run your cat fill blow up until you reboot or run tunelp again. For usblp, I made it so the abort mode is only in effect as long as device is open. This way you can mix and match CUPS and cat(1) freely and nothing bad happens even if you run out of paper. It is also safer in the face of any unexpected crashes. It has to be noted that mixing LPABORT and O_NONBLOCK is not advised. It probably does not do what you want: instead of returning -ENOSPC it will always return -EAGAIN (because it would otherwise block while waiting for the paper). Applications which use O_NONBLOCK should continue to use LPGETSTATUS like before. Finally, CUPS actually requires patching to take full advantage of this. It has several components; those which invoke LPABORT work, but some of them need the ioctl added. This is completely compatible, you can mix old CUPS and new kernels or vice versa. Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usblp.c | 65 ++++++++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 5192cd9356d..30d5a1315cc 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -69,7 +69,6 @@ #define USBLP_DEVICE_ID_SIZE 1024 /* ioctls: */ -#define LPGETSTATUS 0x060b /* same as in drivers/char/lp.c */ #define IOCNR_GET_DEVICE_ID 1 #define IOCNR_GET_PROTOCOLS 2 #define IOCNR_SET_PROTOCOL 3 @@ -159,10 +158,12 @@ struct usblp { int wstatus; /* bytes written or error */ int rstatus; /* bytes ready or error */ unsigned int quirks; /* quirks flags */ + unsigned int flags; /* mode flags */ unsigned char used; /* True if open */ unsigned char present; /* True if not disconnected */ unsigned char bidir; /* interface is bidirectional */ unsigned char sleeping; /* interface is suspended */ + unsigned char no_paper; /* Paper Out happened */ unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */ /* first 2 bytes are (big-endian) length */ }; @@ -325,6 +326,7 @@ static void usblp_bulk_write(struct urb *urb) usblp->wstatus = status; else usblp->wstatus = urb->actual_length; + usblp->no_paper = 0; usblp->wcomplete = 1; wake_up(&usblp->wwait); spin_unlock(&usblp->lock); @@ -411,18 +413,10 @@ static int usblp_open(struct inode *inode, struct file *file) goto out; /* - * TODO: need to implement LP_ABORTOPEN + O_NONBLOCK as in drivers/char/lp.c ??? - * This is #if 0-ed because we *don't* want to fail an open - * just because the printer is off-line. + * We do not implement LP_ABORTOPEN/LPABORTOPEN for two reasons: + * - We do not want persistent state which close(2) does not clear + * - It is not used anyway, according to CUPS people */ -#if 0 - if ((retval = usblp_check_status(usblp, 0))) { - retval = retval > 1 ? -EIO : -ENOSPC; - goto out; - } -#else - retval = 0; -#endif retval = usb_autopm_get_interface(intf); if (retval < 0) @@ -463,6 +457,8 @@ static int usblp_release(struct inode *inode, struct file *file) { struct usblp *usblp = file->private_data; + usblp->flags &= ~LP_ABORT; + mutex_lock (&usblp_mutex); usblp->used = 0; if (usblp->present) { @@ -486,7 +482,7 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait poll_wait(file, &usblp->wwait, wait); spin_lock_irqsave(&usblp->lock, flags); ret = ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN | POLLRDNORM) - | (!usblp->wcomplete ? 0 : POLLOUT | POLLWRNORM); + | ((usblp->no_paper || usblp->wcomplete) ? POLLOUT | POLLWRNORM : 0); spin_unlock_irqrestore(&usblp->lock, flags); return ret; } @@ -675,6 +671,13 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; + case LPABORT: + if (arg) + usblp->flags |= LP_ABORT; + else + usblp->flags &= ~LP_ABORT; + break; + default: retval = -ENOTTY; } @@ -730,6 +733,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) { usblp->wstatus = 0; spin_lock_irq(&usblp->lock); + usblp->no_paper = 0; usblp->wcomplete = 1; wake_up(&usblp->wwait); spin_unlock_irq(&usblp->lock); @@ -747,12 +751,17 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t /* Presume that it's going to complete well. */ writecount += transfer_length; } + if (rv == -ENOSPC) { + spin_lock_irq(&usblp->lock); + usblp->no_paper = 1; /* Mark for poll(2) */ + spin_unlock_irq(&usblp->lock); + writecount += transfer_length; + } /* Leave URB dangling, to be cleaned on close. */ goto collect_error; } if (usblp->wstatus < 0) { - usblp_check_status(usblp, 0); rv = -EIO; goto collect_error; } @@ -838,32 +847,36 @@ done: * when O_NONBLOCK is set. So, applications setting O_NONBLOCK must use * select(2) or poll(2) to wait for the buffer to drain before closing. * Alternatively, set blocking mode with fcntl and issue a zero-size write. - * - * Old v0.13 code had a non-functional timeout for wait_event(). Someone forgot - * to check the return code for timeout expiration, so it had no effect. - * Apparently, it was intended to check for error conditons, such as out - * of paper. It is going to return when we settle things with CUPS. XXX */ static int usblp_wwait(struct usblp *usblp, int nonblock) { DECLARE_WAITQUEUE(waita, current); int rc; + int err = 0; add_wait_queue(&usblp->wwait, &waita); for (;;) { + set_current_state(TASK_INTERRUPTIBLE); if (mutex_lock_interruptible(&usblp->mut)) { rc = -EINTR; break; } - set_current_state(TASK_INTERRUPTIBLE); - if ((rc = usblp_wtest(usblp, nonblock)) < 0) { - mutex_unlock(&usblp->mut); - break; - } + rc = usblp_wtest(usblp, nonblock); mutex_unlock(&usblp->mut); - if (rc == 0) + if (rc <= 0) break; - schedule(); + + if (usblp->flags & LP_ABORT) { + if (schedule_timeout(msecs_to_jiffies(5000)) == 0) { + err = usblp_check_status(usblp, err); + if (err == 1) { /* Paper out */ + rc = -ENOSPC; + break; + } + } + } else { + schedule(); + } } set_current_state(TASK_RUNNING); remove_wait_queue(&usblp->wwait, &waita); -- cgit v1.2.3-70-g09d2 From e8fa0ce65c58dbb60be279c4e33534650dcacc31 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Mon, 23 Jul 2007 02:17:49 -0700 Subject: usblp: Make use of URB_FREE_BUFFER Employ the new API URB_FREE_BUFFER that we've got. There was talk of a combined constructor for this case, but apparently it's not happening, so just set the flag explicitly for now. Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usblp.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 30d5a1315cc..9696668e575 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -331,9 +331,6 @@ static void usblp_bulk_write(struct urb *urb) wake_up(&usblp->wwait); spin_unlock(&usblp->lock); - /* XXX Use usb_setup_bulk_urb when available. Talk to Marcel. */ - kfree(urb->transfer_buffer); - urb->transfer_buffer = NULL; /* Not refcounted, so to be safe... */ usb_free_urb(urb); } @@ -719,6 +716,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t usb_sndbulkpipe(usblp->dev, usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress), writebuf, transfer_length, usblp_bulk_write, usblp); + writeurb->transfer_flags |= URB_FREE_BUFFER; usb_anchor_urb(writeurb, &usblp->urbs); if (copy_from_user(writebuf, -- cgit v1.2.3-70-g09d2 From 89a0fd18a96eb1f8732714b575073f8a8d69c009 Mon Sep 17 00:00:00 2001 From: Mike Nuss Date: Wed, 1 Aug 2007 13:24:30 -0700 Subject: USB: OHCI handles more ZFMicro quirks The ZF Micro OHCI controller exhibits unexpected behavior that seems to be related to high load. Under certain conditions, the controller will complete a TD, remove it from the endpoint's queue, and fail to add it to the donelist. This causes the endpoint to appear to stop responding. Worse, if the device is removed while in that state, OHCI will hang while waiting for the orphaned TD to complete. The situation is not recoverable without rebooting. This fix enhances the scope of the existing OHCI_QUIRK_ZFMICRO flag: 1. A watchdog routine periodically scans the OHCI structures to check for orphaned TDs. In these cases the TD is taken back from the controller and completed normally. 2. If a device is removed while the endpoint is hung but before the watchdog catches the situation, any outstanding TDs are taken back from the controller in the 'sanitize' phase. The ohci-hcd driver used to print "INTR_SF lossage" in this situation; this changes it to the universally accurate "ED unlink timeout". Other instances of this message presumably have different root causes. Both this Compaq quirk and a NEC quirk are now properly compiled out for non-PCI builds of this driver. Signed-off-by: Mike Nuss Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 166 +++++++++++++++++++++++++++++++++++++------- drivers/usb/host/ohci-mem.c | 1 - drivers/usb/host/ohci-pci.c | 22 +++++- drivers/usb/host/ohci-q.c | 113 ++++++++++++++++++------------ drivers/usb/host/ohci.h | 26 +++++++ 5 files changed, 253 insertions(+), 75 deletions(-) diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 6edf4097d2d..d673cb9c36b 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -81,7 +81,6 @@ static void ohci_dump (struct ohci_hcd *ohci, int verbose); static int ohci_init (struct ohci_hcd *ohci); static void ohci_stop (struct usb_hcd *hcd); static int ohci_restart (struct ohci_hcd *ohci); -static void ohci_quirk_nec_worker (struct work_struct *work); #include "ohci-hub.c" #include "ohci-dbg.c" @@ -314,6 +313,8 @@ rescan: if (!HC_IS_RUNNING (hcd->state)) { sanitize: ed->state = ED_IDLE; + if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT) + ohci->eds_scheduled--; finish_unlinks (ohci, 0); } @@ -321,7 +322,12 @@ sanitize: case ED_UNLINK: /* wait for hw to finish? */ /* major IRQ delivery trouble loses INTR_SF too... */ if (limit-- == 0) { - ohci_warn (ohci, "IRQ INTR_SF lossage\n"); + ohci_warn(ohci, "ED unlink timeout\n"); + if (quirk_zfmicro(ohci)) { + ohci_warn(ohci, "Attempting ZF TD recovery\n"); + ohci->ed_to_check = ed; + ohci->zf_delay = 2; + } goto sanitize; } spin_unlock_irqrestore (&ohci->lock, flags); @@ -379,6 +385,93 @@ ohci_shutdown (struct usb_hcd *hcd) (void) ohci_readl (ohci, &ohci->regs->control); } +static int check_ed(struct ohci_hcd *ohci, struct ed *ed) +{ + return (hc32_to_cpu(ohci, ed->hwINFO) & ED_IN) != 0 + && (hc32_to_cpu(ohci, ed->hwHeadP) & TD_MASK) + == (hc32_to_cpu(ohci, ed->hwTailP) & TD_MASK) + && !list_empty(&ed->td_list); +} + +/* ZF Micro watchdog timer callback. The ZF Micro chipset sometimes completes + * an interrupt TD but neglects to add it to the donelist. On systems with + * this chipset, we need to periodically check the state of the queues to look + * for such "lost" TDs. + */ +static void unlink_watchdog_func(unsigned long _ohci) +{ + long flags; + unsigned max; + unsigned seen_count = 0; + unsigned i; + struct ed **seen = NULL; + struct ohci_hcd *ohci = (struct ohci_hcd *) _ohci; + + spin_lock_irqsave(&ohci->lock, flags); + max = ohci->eds_scheduled; + if (!max) + goto done; + + if (ohci->ed_to_check) + goto out; + + seen = kcalloc(max, sizeof *seen, GFP_ATOMIC); + if (!seen) + goto out; + + for (i = 0; i < NUM_INTS; i++) { + struct ed *ed = ohci->periodic[i]; + + while (ed) { + unsigned temp; + + /* scan this branch of the periodic schedule tree */ + for (temp = 0; temp < seen_count; temp++) { + if (seen[temp] == ed) { + /* we've checked it and what's after */ + ed = NULL; + break; + } + } + if (!ed) + break; + seen[seen_count++] = ed; + if (!check_ed(ohci, ed)) { + ed = ed->ed_next; + continue; + } + + /* HC's TD list is empty, but HCD sees at least one + * TD that's not been sent through the donelist. + */ + ohci->ed_to_check = ed; + ohci->zf_delay = 2; + + /* The HC may wait until the next frame to report the + * TD as done through the donelist and INTR_WDH. (We + * just *assume* it's not a multi-TD interrupt URB; + * those could defer the IRQ more than one frame, using + * DI...) Check again after the next INTR_SF. + */ + ohci_writel(ohci, OHCI_INTR_SF, + &ohci->regs->intrstatus); + ohci_writel(ohci, OHCI_INTR_SF, + &ohci->regs->intrenable); + + /* flush those writes */ + (void) ohci_readl(ohci, &ohci->regs->control); + + goto out; + } + } +out: + kfree(seen); + if (ohci->eds_scheduled) + mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ)); +done: + spin_unlock_irqrestore(&ohci->lock, flags); +} + /*-------------------------------------------------------------------------* * HC functions *-------------------------------------------------------------------------*/ @@ -616,6 +709,15 @@ retry: mdelay ((temp >> 23) & 0x1fe); hcd->state = HC_STATE_RUNNING; + if (quirk_zfmicro(ohci)) { + /* Create timer to watch for bad queue state on ZF Micro */ + setup_timer(&ohci->unlink_watchdog, unlink_watchdog_func, + (unsigned long) ohci); + + ohci->eds_scheduled = 0; + ohci->ed_to_check = NULL; + } + ohci_dump (ohci, 1); return 0; @@ -629,10 +731,11 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ohci_regs __iomem *regs = ohci->regs; - int ints; + int ints; /* we can eliminate a (slow) ohci_readl() - if _only_ WDH caused this irq */ + * if _only_ WDH caused this irq + */ if ((ohci->hcca->done_head != 0) && ! (hc32_to_cpup (ohci, &ohci->hcca->done_head) & 0x01)) { @@ -651,7 +754,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) if (ints & OHCI_INTR_UE) { // e.g. due to PCI Master/Target Abort - if (ohci->flags & OHCI_QUIRK_NEC) { + if (quirk_nec(ohci)) { /* Workaround for a silicon bug in some NEC chips used * in Apple's PowerBooks. Adapted from Darwin code. */ @@ -713,6 +816,31 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrenable); } + if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) { + spin_lock(&ohci->lock); + if (ohci->ed_to_check) { + struct ed *ed = ohci->ed_to_check; + + if (check_ed(ohci, ed)) { + /* HC thinks the TD list is empty; HCD knows + * at least one TD is outstanding + */ + if (--ohci->zf_delay == 0) { + struct td *td = list_entry( + ed->td_list.next, + struct td, td_list); + ohci_warn(ohci, + "Reclaiming orphan TD %p\n", + td); + takeback_td(ohci, td); + ohci->ed_to_check = NULL; + } + } else + ohci->ed_to_check = NULL; + } + spin_unlock(&ohci->lock); + } + /* could track INTR_SO to reduce available PCI/... bandwidth */ /* handle any pending URB/ED unlinks, leaving INTR_SF enabled @@ -721,7 +849,9 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) spin_lock (&ohci->lock); if (ohci->ed_rm_list) finish_unlinks (ohci, ohci_frame_no(ohci)); - if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list + if ((ints & OHCI_INTR_SF) != 0 + && !ohci->ed_rm_list + && !ohci->ed_to_check && HC_IS_RUNNING(hcd->state)) ohci_writel (ohci, OHCI_INTR_SF, ®s->intrdisable); spin_unlock (&ohci->lock); @@ -751,6 +881,9 @@ static void ohci_stop (struct usb_hcd *hcd) free_irq(hcd->irq, hcd); hcd->irq = -1; + if (quirk_zfmicro(ohci)) + del_timer(&ohci->unlink_watchdog); + remove_debug_files (ohci); ohci_mem_cleanup (ohci); if (ohci->hcca) { @@ -828,27 +961,6 @@ static int ohci_restart (struct ohci_hcd *ohci) /*-------------------------------------------------------------------------*/ -/* NEC workaround */ -static void ohci_quirk_nec_worker(struct work_struct *work) -{ - struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work); - int status; - - status = ohci_init(ohci); - if (status != 0) { - ohci_err(ohci, "Restarting NEC controller failed " - "in ohci_init, %d\n", status); - return; - } - - status = ohci_restart(ohci); - if (status != 0) - ohci_err(ohci, "Restarting NEC controller failed " - "in ohci_restart, %d\n", status); -} - -/*-------------------------------------------------------------------------*/ - #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC MODULE_AUTHOR (DRIVER_AUTHOR); diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c index 450c7b460c5..2f20d3dc895 100644 --- a/drivers/usb/host/ohci-mem.c +++ b/drivers/usb/host/ohci-mem.c @@ -28,7 +28,6 @@ static void ohci_hcd_init (struct ohci_hcd *ohci) ohci->next_statechange = jiffies; spin_lock_init (&ohci->lock); INIT_LIST_HEAD (&ohci->pending); - INIT_WORK (&ohci->nec_work, ohci_quirk_nec_worker); } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index a5e2eb85d07..d0360f65ebd 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -84,7 +84,7 @@ static int ohci_quirk_zfmicro(struct usb_hcd *hcd) struct ohci_hcd *ohci = hcd_to_ohci (hcd); ohci->flags |= OHCI_QUIRK_ZFMICRO; - ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n"); + ohci_dbg(ohci, "enabled Compaq ZFMicro chipset quirks\n"); return 0; } @@ -113,11 +113,31 @@ static int ohci_quirk_toshiba_scc(struct usb_hcd *hcd) /* Check for NEC chip and apply quirk for allegedly lost interrupts. */ + +static void ohci_quirk_nec_worker(struct work_struct *work) +{ + struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work); + int status; + + status = ohci_init(ohci); + if (status != 0) { + ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n", + "ohci_init", status); + return; + } + + status = ohci_restart(ohci); + if (status != 0) + ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n", + "ohci_restart", status); +} + static int ohci_quirk_nec(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); ohci->flags |= OHCI_QUIRK_NEC; + INIT_WORK(&ohci->nec_work, ohci_quirk_nec_worker); ohci_dbg (ohci, "enabled NEC chipset lost interrupt quirk\n"); return 0; diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 830a3fe8615..547d39be3eb 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -179,6 +179,10 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed) ed->ed_prev = NULL; ed->ed_next = NULL; ed->hwNextED = 0; + if (quirk_zfmicro(ohci) + && (ed->type == PIPE_INTERRUPT) + && !(ohci->eds_scheduled++)) + mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ)); wmb (); /* we care about rm_list when setting CLE/BLE in case the HC was at @@ -940,8 +944,12 @@ skip_ed: TD_MASK; /* INTR_WDH may need to clean up first */ - if (td->td_dma != head) - goto skip_ed; + if (td->td_dma != head) { + if (ed == ohci->ed_to_check) + ohci->ed_to_check = NULL; + else + goto skip_ed; + } } } @@ -998,6 +1006,8 @@ rescan_this: /* ED's now officially unlinked, hc doesn't see */ ed->state = ED_IDLE; + if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT) + ohci->eds_scheduled--; ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H); ed->hwNextED = 0; wmb (); @@ -1021,7 +1031,7 @@ rescan_this: if (ohci->ed_controltail) { command |= OHCI_CLF; - if (ohci->flags & OHCI_QUIRK_ZFMICRO) + if (quirk_zfmicro(ohci)) mdelay(1); if (!(ohci->hc_control & OHCI_CTRL_CLE)) { control |= OHCI_CTRL_CLE; @@ -1031,7 +1041,7 @@ rescan_this: } if (ohci->ed_bulktail) { command |= OHCI_BLF; - if (ohci->flags & OHCI_QUIRK_ZFMICRO) + if (quirk_zfmicro(ohci)) mdelay(1); if (!(ohci->hc_control & OHCI_CTRL_BLE)) { control |= OHCI_CTRL_BLE; @@ -1043,13 +1053,13 @@ rescan_this: /* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */ if (control) { ohci->hc_control |= control; - if (ohci->flags & OHCI_QUIRK_ZFMICRO) + if (quirk_zfmicro(ohci)) mdelay(1); ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); } if (command) { - if (ohci->flags & OHCI_QUIRK_ZFMICRO) + if (quirk_zfmicro(ohci)) mdelay(1); ohci_writel (ohci, command, &ohci->regs->cmdstatus); } @@ -1060,12 +1070,60 @@ rescan_this: /*-------------------------------------------------------------------------*/ +/* + * Used to take back a TD from the host controller. This would normally be + * called from within dl_done_list, however it may be called directly if the + * HC no longer sees the TD and it has not appeared on the donelist (after + * two frames). This bug has been observed on ZF Micro systems. + */ +static void takeback_td(struct ohci_hcd *ohci, struct td *td) +{ + struct urb *urb = td->urb; + urb_priv_t *urb_priv = urb->hcpriv; + struct ed *ed = td->ed; + + /* update URB's length and status from TD */ + td_done(ohci, urb, td); + urb_priv->td_cnt++; + + /* If all this urb's TDs are done, call complete() */ + if (urb_priv->td_cnt == urb_priv->length) + finish_urb(ohci, urb); + + /* clean schedule: unlink EDs that are no longer busy */ + if (list_empty(&ed->td_list)) { + if (ed->state == ED_OPER) + start_ed_unlink(ohci, ed); + + /* ... reenabling halted EDs only after fault cleanup */ + } else if ((ed->hwINFO & cpu_to_hc32(ohci, ED_SKIP | ED_DEQUEUE)) + == cpu_to_hc32(ohci, ED_SKIP)) { + td = list_entry(ed->td_list.next, struct td, td_list); + if (!(td->hwINFO & cpu_to_hc32(ohci, TD_DONE))) { + ed->hwINFO &= ~cpu_to_hc32(ohci, ED_SKIP); + /* ... hc may need waking-up */ + switch (ed->type) { + case PIPE_CONTROL: + ohci_writel(ohci, OHCI_CLF, + &ohci->regs->cmdstatus); + break; + case PIPE_BULK: + ohci_writel(ohci, OHCI_BLF, + &ohci->regs->cmdstatus); + break; + } + } + } +} + /* * Process normal completions (error or success) and clean the schedules. * * This is the main path for handing urbs back to drivers. The only other - * path is finish_unlinks(), which unlinks URBs using ed_rm_list, instead of - * scanning the (re-reversed) donelist as this does. + * normal path is finish_unlinks(), which unlinks URBs using ed_rm_list, + * instead of scanning the (re-reversed) donelist as this does. There's + * an abnormal path too, handling a quirk in some Compaq silicon: URBs + * with TDs that appear to be orphaned are directly reclaimed. */ static void dl_done_list (struct ohci_hcd *ohci) @@ -1074,44 +1132,7 @@ dl_done_list (struct ohci_hcd *ohci) while (td) { struct td *td_next = td->next_dl_td; - struct urb *urb = td->urb; - urb_priv_t *urb_priv = urb->hcpriv; - struct ed *ed = td->ed; - - /* update URB's length and status from TD */ - td_done (ohci, urb, td); - urb_priv->td_cnt++; - - /* If all this urb's TDs are done, call complete() */ - if (urb_priv->td_cnt == urb_priv->length) - finish_urb (ohci, urb); - - /* clean schedule: unlink EDs that are no longer busy */ - if (list_empty (&ed->td_list)) { - if (ed->state == ED_OPER) - start_ed_unlink (ohci, ed); - - /* ... reenabling halted EDs only after fault cleanup */ - } else if ((ed->hwINFO & cpu_to_hc32 (ohci, - ED_SKIP | ED_DEQUEUE)) - == cpu_to_hc32 (ohci, ED_SKIP)) { - td = list_entry (ed->td_list.next, struct td, td_list); - if (!(td->hwINFO & cpu_to_hc32 (ohci, TD_DONE))) { - ed->hwINFO &= ~cpu_to_hc32 (ohci, ED_SKIP); - /* ... hc may need waking-up */ - switch (ed->type) { - case PIPE_CONTROL: - ohci_writel (ohci, OHCI_CLF, - &ohci->regs->cmdstatus); - break; - case PIPE_BULK: - ohci_writel (ohci, OHCI_BLF, - &ohci->regs->cmdstatus); - break; - } - } - } - + takeback_td(ohci, td); td = td_next; } } diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 4ada43cf138..dd4d5b4dcb6 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -401,8 +401,34 @@ struct ohci_hcd { // there are also chip quirks/bugs in init logic struct work_struct nec_work; /* Worker for NEC quirk */ + + /* Needed for ZF Micro quirk */ + struct timer_list unlink_watchdog; + unsigned eds_scheduled; + struct ed *ed_to_check; + unsigned zf_delay; }; +#ifdef CONFIG_PCI +static inline int quirk_nec(struct ohci_hcd *ohci) +{ + return ohci->flags & OHCI_QUIRK_NEC; +} +static inline int quirk_zfmicro(struct ohci_hcd *ohci) +{ + return ohci->flags & OHCI_QUIRK_ZFMICRO; +} +#else +static inline int quirk_nec(struct ohci_hcd *ohci) +{ + return 0; +} +static inline int quirk_zfmicro(struct ohci_hcd *ohci) +{ + return 0; +} +#endif + /* convert between an hcd pointer and the corresponding ohci_hcd */ static inline struct ohci_hcd *hcd_to_ohci (struct usb_hcd *hcd) { -- cgit v1.2.3-70-g09d2 From 9f705bde6e77c24a3ba737ac45abc0f8e619e92e Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Wed, 1 Aug 2007 18:16:55 -0400 Subject: USB: Remove dead references to "SAFE_SERIAL" CONFIG variables. Remove the references to CONFIG_USBD_SAFE_SERIAL_{VENDOR,PRODUCT}, which aren't defined in any Kconfig file. Signed-off-by: Robert P. J. Day Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/safe_serial.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index 51669b7622b..4e6dcc199be 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c @@ -90,18 +90,12 @@ MODULE_AUTHOR (DRIVER_AUTHOR); MODULE_DESCRIPTION (DRIVER_DESC); MODULE_LICENSE("GPL"); -#if defined(CONFIG_USBD_SAFE_SERIAL_VENDOR) && !defined(CONFIG_USBD_SAFE_SERIAL_PRODUCT) -#error "SAFE_SERIAL_VENDOR defined without SAFE_SERIAL_PRODUCT" -#endif - -#if ! defined(CONFIG_USBD_SAFE_SERIAL_VENDOR) static __u16 vendor; // no default static __u16 product; // no default module_param(vendor, ushort, 0); MODULE_PARM_DESC(vendor, "User specified USB idVendor (required)"); module_param(product, ushort, 0); MODULE_PARM_DESC(product, "User specified USB idProduct (required)"); -#endif module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); @@ -145,11 +139,6 @@ static struct usb_device_id id_table[] = { {MY_USB_DEVICE (0x4dd, 0x8003, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Collie {MY_USB_DEVICE (0x4dd, 0x8004, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Collie {MY_USB_DEVICE (0x5f9, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Sharp tmp -#if defined(CONFIG_USB_SAFE_SERIAL_VENDOR) - {MY_USB_DEVICE - (CONFIG_USB_SAFE_SERIAL_VENDOR, CONFIG_USB_SAFE_SERIAL_PRODUCT, CDC_DEVICE_CLASS, - LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, -#endif // extra null entry for module // vendor/produc parameters {MY_USB_DEVICE (0, 0, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, -- cgit v1.2.3-70-g09d2 From efc9052e01fd316b7bd6b108feff7689c927ebe9 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 1 Aug 2007 16:04:53 -0700 Subject: USB: usb_gadget.h whitespace fixes This just fixes some whitespace bugs in , mostly extraneous spaces where a single tab suffices. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- include/linux/usb_gadget.h | 62 +++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h index 4f59b2aa8a9..ec9732e7fea 100644 --- a/include/linux/usb_gadget.h +++ b/include/linux/usb_gadget.h @@ -22,10 +22,10 @@ struct usb_ep; /** * struct usb_request - describes one i/o request * @buf: Buffer used for data. Always provide this; some controllers - * only use PIO, or don't use DMA for some endpoints. + * only use PIO, or don't use DMA for some endpoints. * @dma: DMA address corresponding to 'buf'. If you don't set this - * field, and the usb controller needs one, it is responsible - * for mapping and unmapping the buffer. + * field, and the usb controller needs one, it is responsible + * for mapping and unmapping the buffer. * @length: Length of that data * @no_interrupt: If true, hints that no completion irq is needed. * Helpful sometimes with deep request queues that are handled @@ -45,16 +45,16 @@ struct usb_ep; * @context: For use by the completion callback * @list: For use by the gadget driver. * @status: Reports completion code, zero or a negative errno. - * Normally, faults block the transfer queue from advancing until - * the completion callback returns. - * Code "-ESHUTDOWN" indicates completion caused by device disconnect, - * or when the driver disabled the endpoint. + * Normally, faults block the transfer queue from advancing until + * the completion callback returns. + * Code "-ESHUTDOWN" indicates completion caused by device disconnect, + * or when the driver disabled the endpoint. * @actual: Reports bytes transferred to/from the buffer. For reads (OUT - * transfers) this may be less than the requested length. If the - * short_not_ok flag is set, short reads are treated as errors - * even when status otherwise indicates successful completion. - * Note that for writes (IN transfers) some data bytes may still - * reside in a device-side FIFO when the request is reported as + * transfers) this may be less than the requested length. If the + * short_not_ok flag is set, short reads are treated as errors + * even when status otherwise indicates successful completion. + * Note that for writes (IN transfers) some data bytes may still + * reside in a device-side FIFO when the request is reported as * complete. * * These are allocated/freed through the endpoint they're used with. The @@ -128,7 +128,7 @@ struct usb_ep_ops { * value can sometimes be reduced (hardware allowing), according to * the endpoint descriptor used to configure the endpoint. * @driver_data:for use by the gadget driver. all other fields are - * read-only to gadget drivers. + * read-only to gadget drivers. * * the bus controller driver lists all the general purpose endpoints in * gadget->ep_list. the control endpoint (gadget->ep0) is not in that list, @@ -148,10 +148,10 @@ struct usb_ep { /** * usb_ep_enable - configure endpoint, making it usable * @ep:the endpoint being configured. may not be the endpoint named "ep0". - * drivers discover endpoints through the ep_list of a usb_gadget. + * drivers discover endpoints through the ep_list of a usb_gadget. * @desc:descriptor for desired behavior. caller guarantees this pointer - * remains valid until the endpoint is disabled; the data byte order - * is little-endian (usb-standard). + * remains valid until the endpoint is disabled; the data byte order + * is little-endian (usb-standard). * * when configurations are set, or when interface settings change, the driver * will enable or disable the relevant endpoints. while it is enabled, an @@ -232,7 +232,7 @@ usb_ep_free_request (struct usb_ep *ep, struct usb_request *req) * @ep:the endpoint associated with the request * @req:the request being submitted * @gfp_flags: GFP_* flags to use in case the lower level driver couldn't - * pre-allocate all necessary memory with the request. + * pre-allocate all necessary memory with the request. * * This tells the device controller to perform the specified request through * that endpoint (reading or writing a buffer). When the request completes, @@ -415,7 +415,7 @@ struct usb_gadget_ops { * struct usb_gadget - represents a usb slave device * @ops: Function pointers used to access hardware-specific operations. * @ep0: Endpoint zero, used when reading or writing responses to - * driver setup() requests + * driver setup() requests * @ep_list: List of other endpoints supported by the device. * @speed: Speed of current connection to USB host. * @is_dualspeed: True if the controller supports both high and full speed @@ -432,7 +432,7 @@ struct usb_gadget_ops { * @b_hnp_enable: OTG device feature flag, indicating that the A-Host * enabled HNP support. * @name: Identifies the controller hardware type. Used in diagnostics - * and sometimes configuration. + * and sometimes configuration. * @dev: Driver model state for this abstract device. * * Gadgets have a mostly-portable "gadget driver" implementing device @@ -655,23 +655,23 @@ usb_gadget_disconnect (struct usb_gadget *gadget) * @function: String describing the gadget's function * @speed: Highest speed the driver handles. * @bind: Invoked when the driver is bound to a gadget, usually - * after registering the driver. - * At that point, ep0 is fully initialized, and ep_list holds - * the currently-available endpoints. - * Called in a context that permits sleeping. + * after registering the driver. + * At that point, ep0 is fully initialized, and ep_list holds + * the currently-available endpoints. + * Called in a context that permits sleeping. * @setup: Invoked for ep0 control requests that aren't handled by - * the hardware level driver. Most calls must be handled by - * the gadget driver, including descriptor and configuration - * management. The 16 bit members of the setup data are in - * USB byte order. Called in_interrupt; this may not sleep. Driver + * the hardware level driver. Most calls must be handled by + * the gadget driver, including descriptor and configuration + * management. The 16 bit members of the setup data are in + * USB byte order. Called in_interrupt; this may not sleep. Driver * queues a response to ep0, or returns negative to stall. * @disconnect: Invoked after all transfers have been stopped, - * when the host is disconnected. May be called in_interrupt; this - * may not sleep. Some devices can't detect disconnect, so this might + * when the host is disconnected. May be called in_interrupt; this + * may not sleep. Some devices can't detect disconnect, so this might * not be called except as part of controller shutdown. * @unbind: Invoked when the driver is unbound from a gadget, - * usually from rmmod (after a disconnect is reported). - * Called in a context that permits sleeping. + * usually from rmmod (after a disconnect is reported). + * Called in a context that permits sleeping. * @suspend: Invoked on USB suspend. May be called in_interrupt. * @resume: Invoked on USB resume. May be called in_interrupt. * @driver: Driver model state for this driver. -- cgit v1.2.3-70-g09d2 From a96173af521a173f45d3a27fa24265081f12e978 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 31 Jul 2007 00:28:22 +0200 Subject: USB: Storage: usbat_check_status(): fix check-after-use The Coverity checker spotted that we have already oops'ed if "us" was NULL. Since "us" can't be NULL in the only caller this patch removes the NULL check. Signed-off-by: Adrian Bunk Signed-off-by: Matthew Dharm Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/shuttle_usbat.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c index 5e27297c017..17ca4d73577 100644 --- a/drivers/usb/storage/shuttle_usbat.c +++ b/drivers/usb/storage/shuttle_usbat.c @@ -190,9 +190,6 @@ static int usbat_check_status(struct us_data *us) unsigned char *reply = us->iobuf; int rc; - if (!us) - return USB_STOR_TRANSPORT_ERROR; - rc = usbat_get_status(us, reply); if (rc != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_FAILED; -- cgit v1.2.3-70-g09d2 From 5b653c79c04c6b152b8dc7d18f8c8a7f77f4b235 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 30 Jul 2007 17:04:37 -0400 Subject: USB: add urb->ep This patch (as943) prepares the way for eliminating urb->pipe by introducing an endpoint pointer into struct urb. For now urb->ep is set by usb_submit_urb() from the pipe value; eventually drivers will set it themselves and we will remove urb->pipe completely. The patch also adds new inline routines to retrieve an endpoint descriptor's number and transfer type, essentially as replacements for usb_pipeendpoint and usb_pipetype. usb_submit_urb(), usb_hcd_submit_urb(), and usb_hcd_unlink_urb() are converted to use the new field and new routines. Other parts of usbcore will be converted in later patches. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 13 ++++------ drivers/usb/core/urb.c | 65 +++++++++++++++++++++++++++----------------------- include/linux/usb.h | 26 ++++++++++++++++++++ 3 files changed, 65 insertions(+), 39 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 42ef1d5f6c8..fb82c500caf 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -962,14 +962,14 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) spin_lock_irqsave(&hcd_urb_list_lock, flags); ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out) [usb_pipeendpoint(urb->pipe)]; - if (unlikely (!ep)) + if (unlikely(ep != urb->ep)) status = -ENOENT; else if (unlikely (urb->reject)) status = -EPERM; else switch (hcd->state) { case HC_STATE_RUNNING: case HC_STATE_RESUMING: - list_add_tail (&urb->urb_list, &ep->urb_list); + list_add_tail (&urb->urb_list, &urb->ep->urb_list); status = 0; break; default: @@ -1022,7 +1022,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) : DMA_TO_DEVICE); } - status = hcd->driver->urb_enqueue (hcd, ep, urb, mem_flags); + status = hcd->driver->urb_enqueue (hcd, urb->ep, urb, mem_flags); done: if (unlikely (status)) { urb_unlink(hcd, urb); @@ -1071,7 +1071,6 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb) */ int usb_hcd_unlink_urb (struct urb *urb, int status) { - struct usb_host_endpoint *ep; struct usb_hcd *hcd = NULL; struct device *sys = NULL; unsigned long flags; @@ -1082,10 +1081,6 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) return -EINVAL; if (!urb->dev || !urb->dev->bus) return -ENODEV; - ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out) - [usb_pipeendpoint(urb->pipe)]; - if (!ep) - return -ENODEV; /* * we contend for urb->status with the hcd core, @@ -1109,7 +1104,7 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) } /* insist the urb is still queued */ - list_for_each(tmp, &ep->urb_list) { + list_for_each(tmp, &urb->ep->urb_list) { if (tmp == &urb->urb_list) break; } diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index be630228461..ff53acb4fab 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -277,9 +277,10 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb); */ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) { - int pipe, temp, max; - struct usb_device *dev; - int is_out; + int xfertype, max; + struct usb_device *dev; + struct usb_host_endpoint *ep; + int is_out; if (!urb || urb->hcpriv || !urb->complete) return -EINVAL; @@ -291,30 +292,34 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) || dev->state == USB_STATE_SUSPENDED) return -EHOSTUNREACH; + /* For now, get the endpoint from the pipe. Eventually drivers + * will be required to set urb->ep directly and we will eliminate + * urb->pipe. + */ + ep = (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out) + [usb_pipeendpoint(urb->pipe)]; + if (!ep) + return -ENOENT; + + urb->ep = ep; urb->status = -EINPROGRESS; urb->actual_length = 0; /* Lots of sanity checks, so HCDs can rely on clean data * and don't need to duplicate tests */ - pipe = urb->pipe; - temp = usb_pipetype(pipe); - is_out = usb_pipeout(pipe); + xfertype = usb_endpoint_type(&ep->desc); + is_out = usb_pipeout(urb->pipe); - if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED) + if (xfertype != USB_ENDPOINT_XFER_CONTROL && + dev->state < USB_STATE_CONFIGURED) return -ENODEV; - /* FIXME there should be a sharable lock protecting us against - * config/altsetting changes and disconnects, kicking in here. - * (here == before maxpacket, and eventually endpoint type, - * checks get made.) - */ - - max = usb_maxpacket(dev, pipe, is_out); + max = le16_to_cpu(ep->desc.wMaxPacketSize); if (max <= 0) { dev_dbg(&dev->dev, "bogus endpoint ep%d%s in %s (bad maxpacket %d)\n", - usb_pipeendpoint(pipe), is_out ? "out" : "in", + usb_endpoint_num(&ep->desc), is_out ? "out" : "in", __FUNCTION__, max); return -EMSGSIZE; } @@ -323,7 +328,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) * but drivers only control those sizes for ISO. * while we're checking, initialize return status. */ - if (temp == PIPE_ISOCHRONOUS) { + if (xfertype == USB_ENDPOINT_XFER_ISOC) { int n, len; /* "high bandwidth" mode, 1-3 packets/uframe? */ @@ -359,19 +364,19 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) /* enforce simple/standard policy */ allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP | URB_NO_INTERRUPT); - switch (temp) { - case PIPE_BULK: + switch (xfertype) { + case USB_ENDPOINT_XFER_BULK: if (is_out) allowed |= URB_ZERO_PACKET; /* FALLTHROUGH */ - case PIPE_CONTROL: + case USB_ENDPOINT_XFER_CONTROL: allowed |= URB_NO_FSBR; /* only affects UHCI */ /* FALLTHROUGH */ default: /* all non-iso endpoints */ if (!is_out) allowed |= URB_SHORT_NOT_OK; break; - case PIPE_ISOCHRONOUS: + case USB_ENDPOINT_XFER_ISOC: allowed |= URB_ISO_ASAP; break; } @@ -393,9 +398,9 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) * supports different values... this uses EHCI/UHCI defaults (and * EHCI can use smaller non-default values). */ - switch (temp) { - case PIPE_ISOCHRONOUS: - case PIPE_INTERRUPT: + switch (xfertype) { + case USB_ENDPOINT_XFER_ISOC: + case USB_ENDPOINT_XFER_INT: /* too small? */ if (urb->interval <= 0) return -EINVAL; @@ -405,29 +410,29 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) // NOTE usb handles 2^15 if (urb->interval > (1024 * 8)) urb->interval = 1024 * 8; - temp = 1024 * 8; + max = 1024 * 8; break; case USB_SPEED_FULL: /* units are frames/msec */ case USB_SPEED_LOW: - if (temp == PIPE_INTERRUPT) { + if (xfertype == USB_ENDPOINT_XFER_INT) { if (urb->interval > 255) return -EINVAL; // NOTE ohci only handles up to 32 - temp = 128; + max = 128; } else { if (urb->interval > 1024) urb->interval = 1024; // NOTE usb and ohci handle up to 2^15 - temp = 1024; + max = 1024; } break; default: return -EINVAL; } /* power of two? */ - while (temp > urb->interval) - temp >>= 1; - urb->interval = temp; + while (max > urb->interval) + max >>= 1; + urb->interval = max; } return usb_hcd_submit_urb(urb, mem_flags); diff --git a/include/linux/usb.h b/include/linux/usb.h index 4f33a58fa9d..105e3e9362d 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -554,6 +554,29 @@ static inline int usb_make_path (struct usb_device *dev, char *buf, /*-------------------------------------------------------------------------*/ +/** + * usb_endpoint_num - get the endpoint's number + * @epd: endpoint to be checked + * + * Returns @epd's number: 0 to 15. + */ +static inline int usb_endpoint_num(const struct usb_endpoint_descriptor *epd) +{ + return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; +} + +/** + * usb_endpoint_type - get the endpoint's transfer type + * @epd: endpoint to be checked + * + * Returns one of USB_ENDPOINT_XFER_{CONTROL, ISOC, BULK, INT} according + * to @epd's transfer type. + */ +static inline int usb_endpoint_type(const struct usb_endpoint_descriptor *epd) +{ + return epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; +} + /** * usb_endpoint_dir_in - check if the endpoint has IN direction * @epd: endpoint to be checked @@ -1037,6 +1060,8 @@ typedef void (*usb_complete_t)(struct urb *); * @urb_list: For use by current owner of the URB. * @anchor_list: membership in the list of an anchor * @anchor: to anchor URBs to a common mooring + * @ep: Points to the endpoint's data structure. Will eventually + * replace @pipe. * @pipe: Holds endpoint number, direction, type, and more. * Create these values with the eight macros available; * usb_{snd,rcv}TYPEpipe(dev,endpoint), where the TYPE is "ctrl" @@ -1212,6 +1237,7 @@ struct urb struct list_head anchor_list; /* the URB may be anchored by the driver */ struct usb_anchor *anchor; struct usb_device *dev; /* (in) pointer to associated device */ + struct usb_host_endpoint *ep; /* (internal) pointer to endpoint struct */ unsigned int pipe; /* (in) pipe information */ int status; /* (return) non-ISO status */ unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | ...*/ -- cgit v1.2.3-70-g09d2 From bdd016ba64d909329cb4bacacc8443901c00e112 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 30 Jul 2007 17:05:22 -0400 Subject: USB: add ep->enable This patch (as944) adds an explicit "enabled" field to the usb_host_endpoint structure and uses it in place of the current mechanism. This is merely a time-space tradeoff; it makes checking whether URBs may be submitted to an endpoint simpler. The existing mechanism is efficient when converting urb->pipe to an endpoint pointer, but it's not so efficient when urb->ep is used instead. As a side effect, the procedure for enabling an endpoint is now a little more complicated. The ad-hoc inline code in usb.c and hub.c for enabling ep0 is now replaced with calls to usb_enable_endpoint, which is no longer static. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 5 +---- drivers/usb/core/hub.c | 2 +- drivers/usb/core/message.c | 20 ++++++++++---------- drivers/usb/core/usb.c | 2 +- drivers/usb/core/usb.h | 2 ++ include/linux/usb.h | 2 ++ 6 files changed, 17 insertions(+), 16 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index fb82c500caf..cc5b1d3c368 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -943,7 +943,6 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) { int status; struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus); - struct usb_host_endpoint *ep; unsigned long flags; if (!hcd) @@ -960,9 +959,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) // FIXME: verify that quiescing hc works right (RH cleans up) spin_lock_irqsave(&hcd_urb_list_lock, flags); - ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out) - [usb_pipeendpoint(urb->pipe)]; - if (unlikely(ep != urb->ep)) + if (unlikely(!urb->ep->enabled)) status = -ENOENT; else if (unlikely (urb->reject)) status = -EPERM; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index f7b337feb3e..c8a01f66df7 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1999,7 +1999,7 @@ static void ep0_reinit(struct usb_device *udev) { usb_disable_endpoint(udev, 0 + USB_DIR_IN); usb_disable_endpoint(udev, 0 + USB_DIR_OUT); - udev->ep_in[0] = udev->ep_out[0] = &udev->ep0; + usb_enable_endpoint(udev, &udev->ep0); } #define usb_sndaddr0pipe() (PIPE_CONTROL << 30) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index d8f7b089a8f..0d618647758 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1013,8 +1013,10 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr) ep = dev->ep_in[epnum]; dev->ep_in[epnum] = NULL; } - if (ep && dev->bus) + if (ep) { + ep->enabled = 0; usb_hcd_endpoint_disable(dev, ep); + } } /** @@ -1096,23 +1098,21 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) * Resets the endpoint toggle, and sets dev->ep_{in,out} pointers. * For control endpoints, both the input and output sides are handled. */ -static void -usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep) +void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep) { - unsigned int epaddr = ep->desc.bEndpointAddress; - unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK; - int is_control; + int epnum = usb_endpoint_num(&ep->desc); + int is_out = usb_endpoint_dir_out(&ep->desc); + int is_control = usb_endpoint_xfer_control(&ep->desc); - is_control = ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_CONTROL); - if (usb_endpoint_out(epaddr) || is_control) { + if (is_out || is_control) { usb_settoggle(dev, epnum, 1, 0); dev->ep_out[epnum] = ep; } - if (!usb_endpoint_out(epaddr) || is_control) { + if (!is_out || is_control) { usb_settoggle(dev, epnum, 0, 0); dev->ep_in[epnum] = ep; } + ep->enabled = 1; } /* diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 0fee5c66fd6..d3c68d8eafb 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -260,7 +260,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE; dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT; /* ep0 maxpacket comes later, from device descriptor */ - dev->ep_in[0] = dev->ep_out[0] = &dev->ep0; + usb_enable_endpoint(dev, &dev->ep0); /* Save readable and stable topology id, distinguishing devices * by location for diagnostics, tools, driver model, etc. The diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index ad5fa0338f4..cde6e52b84f 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -8,6 +8,8 @@ extern int usb_create_ep_files(struct device *parent, struct usb_host_endpoint * struct usb_device *udev); extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint); +extern void usb_enable_endpoint(struct usb_device *dev, + struct usb_host_endpoint *ep); extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr); extern void usb_disable_interface (struct usb_device *dev, struct usb_interface *intf); diff --git a/include/linux/usb.h b/include/linux/usb.h index 105e3e9362d..818a1b4f737 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -52,6 +52,7 @@ struct ep_device; * @ep_dev: ep_device for sysfs info * @extra: descriptors following this endpoint in the configuration * @extralen: how many bytes of "extra" are valid + * @enabled: URBs may be submitted to this endpoint * * USB requests are always queued to a given endpoint, identified by a * descriptor within an active interface in a given USB configuration. @@ -64,6 +65,7 @@ struct usb_host_endpoint { unsigned char *extra; /* Extra descriptors */ int extralen; + int enabled; }; /* host-side wrapper for one interface setting's parsed descriptors */ -- cgit v1.2.3-70-g09d2 From fea3409112a93581db18da4c4332c8bf8d68af6b Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 30 Jul 2007 17:06:16 -0400 Subject: USB: add direction bit to urb->transfer_flags This patch (as945) adds a bit to urb->transfer_flags for recording the direction of the URB. The bit is set/cleared automatically in usb_submit_urb() so drivers don't have to worry about it (although as a result, it isn't valid until the URB has been submitted). Inline routines are added for easily checking an URB's direction. They replace calls to usb_pipein in the DMA-mapping parts of hcd.c. For non-control endpoints, the direction is determined directly from the endpoint descriptor. However control endpoints are bi-directional; for them the direction is determined from the bRequestType byte and the wLength value in the setup packet. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 4 ++-- drivers/usb/core/urb.c | 18 ++++++++++++++++-- include/linux/usb.h | 30 ++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index cc5b1d3c368..bcbaedc897d 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -928,7 +928,7 @@ static void urb_unlink(struct usb_hcd *hcd, struct urb *urb) dma_unmap_single (hcd->self.controller, urb->transfer_dma, urb->transfer_buffer_length, - usb_pipein (urb->pipe) + usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } @@ -1014,7 +1014,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) hcd->self.controller, urb->transfer_buffer, urb->transfer_buffer_length, - usb_pipein (urb->pipe) + usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index ff53acb4fab..1a64a6a850f 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -309,7 +309,21 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) * and don't need to duplicate tests */ xfertype = usb_endpoint_type(&ep->desc); - is_out = usb_pipeout(urb->pipe); + if (xfertype == USB_ENDPOINT_XFER_CONTROL) { + struct usb_ctrlrequest *setup = + (struct usb_ctrlrequest *) urb->setup_packet; + + if (!setup) + return -ENOEXEC; + is_out = !(setup->bRequestType & USB_DIR_IN) || + !setup->wLength; + } else { + is_out = usb_endpoint_dir_out(&ep->desc); + } + + /* Cache the direction for later use */ + urb->transfer_flags = (urb->transfer_flags & ~URB_DIR_MASK) | + (is_out ? URB_DIR_OUT : URB_DIR_IN); if (xfertype != USB_ENDPOINT_XFER_CONTROL && dev->state < USB_STATE_CONFIGURED) @@ -363,7 +377,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) /* enforce simple/standard policy */ allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP | - URB_NO_INTERRUPT); + URB_NO_INTERRUPT | URB_DIR_MASK); switch (xfertype) { case USB_ENDPOINT_XFER_BULK: if (is_out) diff --git a/include/linux/usb.h b/include/linux/usb.h index 818a1b4f737..9d08f5a5ba7 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1021,6 +1021,8 @@ extern int usb_disabled(void); /* * urb->transfer_flags: + * + * Note: URB_DIR_IN/OUT is automatically set in usb_submit_urb(). */ #define URB_SHORT_NOT_OK 0x0001 /* report short reads as errors */ #define URB_ISO_ASAP 0x0002 /* iso-only, urb->start_frame @@ -1033,6 +1035,10 @@ extern int usb_disabled(void); * needed */ #define URB_FREE_BUFFER 0x0100 /* Free transfer buffer with the URB */ +#define URB_DIR_IN 0x0200 /* Transfer from device to host */ +#define URB_DIR_OUT 0 +#define URB_DIR_MASK URB_DIR_IN + struct usb_iso_packet_descriptor { unsigned int offset; unsigned int length; /* expected length */ @@ -1380,6 +1386,30 @@ extern void usb_unanchor_urb(struct urb *urb); extern int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor, unsigned int timeout); +/** + * usb_urb_dir_in - check if an URB describes an IN transfer + * @urb: URB to be checked + * + * Returns 1 if @urb describes an IN transfer (device-to-host), + * otherwise 0. + */ +static inline int usb_urb_dir_in(struct urb *urb) +{ + return (urb->transfer_flags & URB_DIR_MASK) != URB_DIR_OUT; +} + +/** + * usb_urb_dir_out - check if an URB describes an OUT transfer + * @urb: URB to be checked + * + * Returns 1 if @urb describes an OUT transfer (host-to-device), + * otherwise 0. + */ +static inline int usb_urb_dir_out(struct urb *urb) +{ + return (urb->transfer_flags & URB_DIR_MASK) == URB_DIR_OUT; +} + void *usb_buffer_alloc (struct usb_device *dev, size_t size, gfp_t mem_flags, dma_addr_t *dma); void usb_buffer_free (struct usb_device *dev, size_t size, -- cgit v1.2.3-70-g09d2 From 5e60a16139c2a48b9876b0ff910671eee5fb32ec Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 30 Jul 2007 17:07:21 -0400 Subject: USB: avoid using urb->pipe in usbcore This patch (as946) eliminates many of the uses of urb->pipe in usbcore. Unfortunately there will have to be a significant API change, affecting all USB drivers, before we can remove it entirely. This patch contents itself with changing only the interface to usb_buffer_map_sg() and friends: The pipe argument is replaced with a direction flag. That can be done easily because those routines get used in only one place. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 40 ++++++++++++++++++++++++---------------- drivers/usb/core/message.c | 14 ++++++++------ drivers/usb/core/usb.c | 19 +++++++++---------- include/linux/usb.h | 6 +++--- 4 files changed, 44 insertions(+), 35 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index bcbaedc897d..739c5e0aa3b 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -635,9 +635,9 @@ static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb) static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb) { - if (usb_pipeint (urb->pipe)) + if (usb_endpoint_xfer_int(&urb->ep->desc)) return rh_queue_status (hcd, urb); - if (usb_pipecontrol (urb->pipe)) + if (usb_endpoint_xfer_control(&urb->ep->desc)) return rh_call_control (hcd, urb); return -EINVAL; } @@ -651,7 +651,7 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) { unsigned long flags; - if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */ + if (usb_endpoint_num(&urb->ep->desc) == 0) { /* Control URB */ ; /* Do nothing */ } else { /* Status URB */ @@ -918,7 +918,7 @@ static void urb_unlink(struct usb_hcd *hcd, struct urb *urb) spin_unlock_irqrestore(&hcd_urb_list_lock, flags); if (hcd->self.uses_dma && !is_root_hub(urb->dev)) { - if (usb_pipecontrol (urb->pipe) + if (usb_endpoint_xfer_control(&urb->ep->desc) && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) dma_unmap_single (hcd->self.controller, urb->setup_dma, sizeof (struct usb_ctrlrequest), @@ -1001,7 +1001,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) * unless it uses pio or talks to another transport. */ if (hcd->self.uses_dma) { - if (usb_pipecontrol (urb->pipe) + if (usb_endpoint_xfer_control(&urb->ep->desc) && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) urb->setup_dma = dma_map_single ( hcd->self.controller, @@ -1201,11 +1201,13 @@ rescan: spin_lock(&hcd_urb_list_lock); list_for_each_entry (urb, &ep->urb_list, urb_list) { int tmp; + int is_in; /* the urb may already have been unlinked */ if (urb->status != -EINPROGRESS) continue; usb_get_urb (urb); + is_in = usb_urb_dir_in(urb); spin_unlock(&hcd_urb_list_lock); spin_lock (&urb->lock); @@ -1216,19 +1218,25 @@ rescan: /* kick hcd unless it's already returning this */ if (tmp == -EINPROGRESS) { - tmp = urb->pipe; unlink1 (hcd, urb); dev_dbg (hcd->self.controller, - "shutdown urb %p pipe %08x ep%d%s%s\n", - urb, tmp, usb_pipeendpoint (tmp), - (tmp & USB_DIR_IN) ? "in" : "out", - ({ char *s; \ - switch (usb_pipetype (tmp)) { \ - case PIPE_CONTROL: s = ""; break; \ - case PIPE_BULK: s = "-bulk"; break; \ - case PIPE_INTERRUPT: s = "-intr"; break; \ - default: s = "-iso"; break; \ - }; s;})); + "shutdown urb %p ep%d%s%s\n", + urb, usb_endpoint_num(&ep->desc), + is_in ? "in" : "out", + ({ char *s; + + switch (usb_endpoint_type(&ep->desc)) { + case USB_ENDPOINT_XFER_CONTROL: + s = ""; break; + case USB_ENDPOINT_XFER_BULK: + s = "-bulk"; break; + case USB_ENDPOINT_XFER_INT: + s = "-intr"; break; + default: + s = "-iso"; break; + }; + s; + })); } usb_put_urb (urb); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 0d618647758..a26a7292b61 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -59,8 +59,8 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length) dev_dbg(&urb->dev->dev, "%s timed out on ep%d%s len=%d/%d\n", current->comm, - usb_pipeendpoint(urb->pipe), - usb_pipein(urb->pipe) ? "in" : "out", + usb_endpoint_num(&urb->ep->desc), + usb_urb_dir_in(urb) ? "in" : "out", urb->actual_length, urb->transfer_buffer_length); } else @@ -250,7 +250,8 @@ static void sg_clean (struct usb_sg_request *io) io->urbs = NULL; } if (io->dev->dev.dma_mask != NULL) - usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents); + usb_buffer_unmap_sg (io->dev, usb_pipein(io->pipe), + io->sg, io->nents); io->dev = NULL; } @@ -278,8 +279,8 @@ static void sg_complete (struct urb *urb) dev_err (io->dev->bus->controller, "dev %s ep%d%s scatterlist error %d/%d\n", io->dev->devpath, - usb_pipeendpoint (urb->pipe), - usb_pipein (urb->pipe) ? "in" : "out", + usb_endpoint_num(&urb->ep->desc), + usb_urb_dir_in(urb) ? "in" : "out", status, io->status); // BUG (); } @@ -379,7 +380,8 @@ int usb_sg_init ( */ dma = (dev->dev.dma_mask != NULL); if (dma) - io->entries = usb_buffer_map_sg (dev, pipe, sg, nents); + io->entries = usb_buffer_map_sg(dev, usb_pipein(pipe), + sg, nents); else io->entries = nents; diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index d3c68d8eafb..67e2e582e46 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -748,7 +748,7 @@ void usb_buffer_unmap(struct urb *urb) /** * usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint * @dev: device to which the scatterlist will be mapped - * @pipe: endpoint defining the mapping direction + * @is_in: mapping transfer direction * @sg: the scatterlist to map * @nents: the number of entries in the scatterlist * @@ -771,14 +771,13 @@ void usb_buffer_unmap(struct urb *urb) * * Reverse the effect of this call with usb_buffer_unmap_sg(). */ -int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe, +int usb_buffer_map_sg(const struct usb_device *dev, int is_in, struct scatterlist *sg, int nents) { struct usb_bus *bus; struct device *controller; if (!dev - || usb_pipecontrol(pipe) || !(bus = dev->bus) || !(controller = bus->controller) || !controller->dma_mask) @@ -786,7 +785,7 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe, // FIXME generic api broken like pci, can't report errors return dma_map_sg(controller, sg, nents, - usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } /* XXX DISABLED, no users currently. If you wish to re-enable this @@ -799,14 +798,14 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe, /** * usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s) * @dev: device to which the scatterlist will be mapped - * @pipe: endpoint defining the mapping direction + * @is_in: mapping transfer direction * @sg: the scatterlist to synchronize * @n_hw_ents: the positive return value from usb_buffer_map_sg * * Use this when you are re-using a scatterlist's data buffers for * another USB request. */ -void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe, +void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in, struct scatterlist *sg, int n_hw_ents) { struct usb_bus *bus; @@ -819,20 +818,20 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe, return; dma_sync_sg(controller, sg, n_hw_ents, - usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } #endif /** * usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist * @dev: device to which the scatterlist will be mapped - * @pipe: endpoint defining the mapping direction + * @is_in: mapping transfer direction * @sg: the scatterlist to unmap * @n_hw_ents: the positive return value from usb_buffer_map_sg * * Reverses the effect of usb_buffer_map_sg(). */ -void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe, +void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in, struct scatterlist *sg, int n_hw_ents) { struct usb_bus *bus; @@ -845,7 +844,7 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe, return; dma_unmap_sg(controller, sg, n_hw_ents, - usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } /* format to disable USB on kernel command line is: nousb */ diff --git a/include/linux/usb.h b/include/linux/usb.h index 9d08f5a5ba7..019ae963a9f 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1422,13 +1422,13 @@ void usb_buffer_unmap (struct urb *urb); #endif struct scatterlist; -int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe, +int usb_buffer_map_sg(const struct usb_device *dev, int is_in, struct scatterlist *sg, int nents); #if 0 -void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe, +void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in, struct scatterlist *sg, int n_hw_ents); #endif -void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe, +void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in, struct scatterlist *sg, int n_hw_ents); /*-------------------------------------------------------------------* -- cgit v1.2.3-70-g09d2 From 4326ed0be93574dac5b5e475713015159108bd88 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 30 Jul 2007 17:08:43 -0400 Subject: USB: address-0 handling during device initialization This patch (as947) changes the device initialization and enumeration code in hub.c; now udev->devnum will be set to 0 while the device is being accessed at address 0. Until now this wasn't needed because the address value was passed as part of urb->pipe; without that field the device address must be stored elsewhere. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 21 +++++++++++++-------- drivers/usb/core/urb.c | 4 +--- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index c8a01f66df7..34be27a6cbb 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1481,6 +1481,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1, case 0: /* TRSTRCY = 10 ms; plus some extra */ msleep(10 + 40); + udev->devnum = 0; /* Device now at address 0 */ /* FALL THROUGH */ case -ENOTCONN: case -ENODEV: @@ -2005,20 +2006,21 @@ static void ep0_reinit(struct usb_device *udev) #define usb_sndaddr0pipe() (PIPE_CONTROL << 30) #define usb_rcvaddr0pipe() ((PIPE_CONTROL << 30) | USB_DIR_IN) -static int hub_set_address(struct usb_device *udev) +static int hub_set_address(struct usb_device *udev, int devnum) { int retval; - if (udev->devnum == 0) + if (devnum <= 1) return -EINVAL; if (udev->state == USB_STATE_ADDRESS) return 0; if (udev->state != USB_STATE_DEFAULT) return -EINVAL; retval = usb_control_msg(udev, usb_sndaddr0pipe(), - USB_REQ_SET_ADDRESS, 0, udev->devnum, 0, + USB_REQ_SET_ADDRESS, 0, devnum, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); if (retval == 0) { + udev->devnum = devnum; /* Device now using proper address */ usb_set_device_state(udev, USB_STATE_ADDRESS); ep0_reinit(udev); } @@ -2045,6 +2047,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, unsigned delay = HUB_SHORT_RESET_TIME; enum usb_device_speed oldspeed = udev->speed; char *speed, *type; + int devnum = udev->devnum; /* root hub ports have a slightly longer reset period * (from USB 2.0 spec, section 7.1.7.5) @@ -2074,7 +2077,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, goto fail; } oldspeed = udev->speed; - + /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ... * it's fixed size except for full speed devices. * For Wireless USB devices, ep0 max packet is always 512 (tho @@ -2115,7 +2118,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, dev_info (&udev->dev, "%s %s speed %sUSB device using %s and address %d\n", (udev->config) ? "reset" : "new", speed, type, - udev->bus->controller->driver->name, udev->devnum); + udev->bus->controller->driver->name, devnum); /* Set up TT records, if needed */ if (hdev->tt) { @@ -2202,7 +2205,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, } for (j = 0; j < SET_ADDRESS_TRIES; ++j) { - retval = hub_set_address(udev); + retval = hub_set_address(udev, devnum); if (retval >= 0) break; msleep(200); @@ -2210,7 +2213,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, if (retval < 0) { dev_err(&udev->dev, "device not accepting address %d, error %d\n", - udev->devnum, retval); + devnum, retval); goto fail; } @@ -2263,8 +2266,10 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, retval = 0; fail: - if (retval) + if (retval) { hub_port_disable(hub, port1, 0); + udev->devnum = devnum; /* for disconnect processing */ + } mutex_unlock(&usb_address0_mutex); return retval; } diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 1a64a6a850f..1acca8696bc 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -284,9 +284,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) if (!urb || urb->hcpriv || !urb->complete) return -EINVAL; - if (!(dev = urb->dev) || - (dev->state < USB_STATE_DEFAULT) || - (!dev->bus) || (dev->devnum <= 0)) + if (!(dev = urb->dev) || dev->state < USB_STATE_DEFAULT) return -ENODEV; if (dev->bus->controller->power.power_state.event != PM_EVENT_ON || dev->state == USB_STATE_SUSPENDED) -- cgit v1.2.3-70-g09d2 From 93cf9b909efb773f74b5d87659d41f957ccbce7e Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 30 Jul 2007 17:09:28 -0400 Subject: USB: avoid urb->pipe in usbfs This patch (as948) removes most of the references to urb->pipe from the usbfs routines in devio.c. The one tricky aspect is in snoop_urb(), which can be called before the URB is submitted and which uses usb_urb_dir_in(). For this to work properly, the URB's direction flag must be set manually in proc_do_submiturb(). The patch also fixes a minor bug; the wValue, wIndex, and wLength fields were snooped in proc_do_submiturb() without conversion from le16 to CPU-byte-ordering. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 69 ++++++++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 927a181120a..b9f1edd6af5 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -289,10 +289,8 @@ static void snoop_urb(struct urb *urb, void __user *userurb) if (!usbfs_snoop) return; - if (urb->pipe & USB_DIR_IN) - dev_info(&urb->dev->dev, "direction=IN\n"); - else - dev_info(&urb->dev->dev, "direction=OUT\n"); + dev_info(&urb->dev->dev, "direction=%s\n", + usb_urb_dir_in(urb) ? "IN" : "OUT"); dev_info(&urb->dev->dev, "userurb=%p\n", userurb); dev_info(&urb->dev->dev, "transfer_buffer_length=%d\n", urb->transfer_buffer_length); @@ -910,6 +908,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, struct usb_ctrlrequest *dr = NULL; unsigned int u, totlen, isofrmlen; int ret, ifnum = -1; + int is_in; if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK| URB_NO_FSBR|URB_ZERO_PACKET)) @@ -924,16 +923,18 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, if ((ret = checkintf(ps, ifnum))) return ret; } - if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) - ep = ps->dev->ep_in [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; - else - ep = ps->dev->ep_out [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; + if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) { + is_in = 1; + ep = ps->dev->ep_in[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; + } else { + is_in = 0; + ep = ps->dev->ep_out[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; + } if (!ep) return -ENOENT; switch(uurb->type) { case USBDEVFS_URB_TYPE_CONTROL: - if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - != USB_ENDPOINT_XFER_CONTROL) + if (!usb_endpoint_xfer_control(&ep->desc)) return -EINVAL; /* min 8 byte setup packet, max 8 byte setup plus an arbitrary data stage */ if (uurb->buffer_length < 8 || uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE)) @@ -952,23 +953,32 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, kfree(dr); return ret; } - uurb->endpoint = (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->bRequestType & USB_ENDPOINT_DIR_MASK); uurb->number_of_packets = 0; uurb->buffer_length = le16_to_cpup(&dr->wLength); uurb->buffer += 8; - if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) { + if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) { + is_in = 1; + uurb->endpoint |= USB_DIR_IN; + } else { + is_in = 0; + uurb->endpoint &= ~USB_DIR_IN; + } + if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, + uurb->buffer, uurb->buffer_length)) { kfree(dr); return -EFAULT; } snoop(&ps->dev->dev, "control urb: bRequest=%02x " "bRrequestType=%02x wValue=%04x " "wIndex=%04x wLength=%04x\n", - dr->bRequest, dr->bRequestType, dr->wValue, - dr->wIndex, dr->wLength); + dr->bRequest, dr->bRequestType, + __le16_to_cpup(&dr->wValue), + __le16_to_cpup(&dr->wIndex), + __le16_to_cpup(&dr->wLength)); break; case USBDEVFS_URB_TYPE_BULK: - switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + switch (usb_endpoint_type(&ep->desc)) { case USB_ENDPOINT_XFER_CONTROL: case USB_ENDPOINT_XFER_ISOC: return -EINVAL; @@ -977,7 +987,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, uurb->number_of_packets = 0; if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) return -EINVAL; - if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) + if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, + uurb->buffer, uurb->buffer_length)) return -EFAULT; snoop(&ps->dev->dev, "bulk urb\n"); break; @@ -986,8 +997,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, /* arbitrary limit */ if (uurb->number_of_packets < 1 || uurb->number_of_packets > 128) return -EINVAL; - if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - != USB_ENDPOINT_XFER_ISOC) + if (!usb_endpoint_xfer_isoc(&ep->desc)) return -EINVAL; isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets; if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL))) @@ -1014,12 +1024,12 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, case USBDEVFS_URB_TYPE_INTERRUPT: uurb->number_of_packets = 0; - if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - != USB_ENDPOINT_XFER_INT) + if (!usb_endpoint_xfer_int(&ep->desc)) return -EINVAL; if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) return -EINVAL; - if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) + if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, + uurb->buffer, uurb->buffer_length)) return -EFAULT; snoop(&ps->dev->dev, "interrupt urb\n"); break; @@ -1039,8 +1049,11 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, return -ENOMEM; } as->urb->dev = ps->dev; - as->urb->pipe = (uurb->type << 30) | __create_pipe(ps->dev, uurb->endpoint & 0xf) | (uurb->endpoint & USB_DIR_IN); - as->urb->transfer_flags = uurb->flags; + as->urb->pipe = (uurb->type << 30) | + __create_pipe(ps->dev, uurb->endpoint & 0xf) | + (uurb->endpoint & USB_DIR_IN); + as->urb->transfer_flags = uurb->flags | + (is_in ? URB_DIR_IN : URB_DIR_OUT); as->urb->transfer_buffer_length = uurb->buffer_length; as->urb->setup_packet = (unsigned char*)dr; as->urb->start_frame = uurb->start_frame; @@ -1070,13 +1083,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, as->uid = current->uid; as->euid = current->euid; security_task_getsecid(current, &as->secid); - if (!(uurb->endpoint & USB_DIR_IN)) { - if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, as->urb->transfer_buffer_length)) { + if (!is_in) { + if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, + as->urb->transfer_buffer_length)) { free_async(as); return -EFAULT; } } - snoop(&as->urb->dev->dev, "submit urb\n"); snoop_urb(as->urb, as->userurb); async_newpending(as); if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) { @@ -1126,7 +1139,7 @@ static int processcompl(struct async *as, void __user * __user *arg) if (put_user(urb->error_count, &userurb->error_count)) return -EFAULT; - if (usb_pipeisoc(urb->pipe)) { + if (usb_endpoint_xfer_isoc(&urb->ep->desc)) { for (i = 0; i < urb->number_of_packets; i++) { if (put_user(urb->iso_frame_desc[i].actual_length, &userurb->iso_frame_desc[i].actual_length)) @@ -1240,7 +1253,7 @@ static int processcompl_compat(struct async *as, void __user * __user *arg) if (put_user(urb->error_count, &userurb->error_count)) return -EFAULT; - if (usb_pipeisoc(urb->pipe)) { + if (usb_endpoint_xfer_isoc(&urb->ep->desc)) { for (i = 0; i < urb->number_of_packets; i++) { if (put_user(urb->iso_frame_desc[i].actual_length, &userurb->iso_frame_desc[i].actual_length)) -- cgit v1.2.3-70-g09d2 From 18ea5d00d05fa6300606f0711748016c95fb26dc Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 30 Jul 2007 17:10:36 -0400 Subject: USB: avoid urb->pipe in usbmon This patch (as949) changes the usbmon driver to use the new urb->ep field rather than urb->pipe. Signed-off-by: Alan Stern Cc: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mon/mon_bin.c | 44 +++++++++++++++++++++++++++-------- drivers/usb/mon/mon_main.c | 4 ++-- drivers/usb/mon/mon_text.c | 58 +++++++++++++++++++++++++--------------------- 3 files changed, 68 insertions(+), 38 deletions(-) diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index c03dfd7a9d3..0b0d77c669d 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -354,7 +354,7 @@ static inline char mon_bin_get_setup(unsigned char *setupb, const struct urb *urb, char ev_type) { - if (!usb_pipecontrol(urb->pipe) || ev_type != 'S') + if (!usb_endpoint_xfer_control(&urb->ep->desc) || ev_type != 'S') return '-'; if (urb->dev->bus->uses_dma && @@ -410,7 +410,7 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, if (length >= rp->b_size/5) length = rp->b_size/5; - if (usb_pipein(urb->pipe)) { + if (usb_urb_dir_in(urb)) { if (ev_type == 'S') { length = 0; data_tag = '<'; @@ -440,10 +440,22 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, */ memset(ep, 0, PKT_SIZE); ep->type = ev_type; - ep->xfer_type = usb_pipetype(urb->pipe); - /* We use the fact that usb_pipein() returns 0x80 */ - ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe); - ep->devnum = usb_pipedevice(urb->pipe); + switch (usb_endpoint_type(&urb->ep->desc)) { + case USB_ENDPOINT_XFER_CONTROL: + ep->xfer_type = PIPE_CONTROL; + break; + case USB_ENDPOINT_XFER_BULK: + ep->xfer_type = PIPE_BULK; + break; + case USB_ENDPOINT_XFER_INT: + ep->xfer_type = PIPE_INTERRUPT; + break; + default: + ep->xfer_type = PIPE_ISOCHRONOUS; + break; + } + ep->epnum = urb->ep->desc.bEndpointAddress; + ep->devnum = urb->dev->devnum; ep->busnum = urb->dev->bus->busnum; ep->id = (unsigned long) urb; ep->ts_sec = ts.tv_sec; @@ -500,10 +512,22 @@ static void mon_bin_error(void *data, struct urb *urb, int error) memset(ep, 0, PKT_SIZE); ep->type = 'E'; - ep->xfer_type = usb_pipetype(urb->pipe); - /* We use the fact that usb_pipein() returns 0x80 */ - ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe); - ep->devnum = usb_pipedevice(urb->pipe); + switch (usb_endpoint_type(&urb->ep->desc)) { + case USB_ENDPOINT_XFER_CONTROL: + ep->xfer_type = PIPE_CONTROL; + break; + case USB_ENDPOINT_XFER_BULK: + ep->xfer_type = PIPE_BULK; + break; + case USB_ENDPOINT_XFER_INT: + ep->xfer_type = PIPE_INTERRUPT; + break; + default: + ep->xfer_type = PIPE_ISOCHRONOUS; + break; + } + ep->epnum = urb->ep->desc.bEndpointAddress; + ep->devnum = urb->dev->devnum; ep->busnum = urb->dev->bus->busnum; ep->id = (unsigned long) urb; ep->status = error; diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c index ce61d8b0fd8..e58f761d060 100644 --- a/drivers/usb/mon/mon_main.c +++ b/drivers/usb/mon/mon_main.c @@ -154,8 +154,8 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb) * This should not happen. * At this point we do not even know the bus number... */ - printk(KERN_ERR TAG ": Null mon bus in URB, pipe 0x%x\n", - urb->pipe); + printk(KERN_ERR TAG ": Null mon bus in URB, address %p\n", + urb); return; } diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 8f27a9e1c36..9d0070ceef5 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -50,10 +50,12 @@ struct mon_iso_desc { struct mon_event_text { struct list_head e_link; int type; /* submit, complete, etc. */ - unsigned int pipe; /* Pipe */ unsigned long id; /* From pointer, most of the time */ unsigned int tstamp; + int xfertype; int busnum; + int devnum; + int epnum; int length; /* Depends on type: xfer length or act length */ int status; int interval; @@ -61,6 +63,7 @@ struct mon_event_text { int error_count; char setup_flag; char data_flag; + char is_in; int numdesc; /* Full number */ struct mon_iso_desc isodesc[ISODESC_MAX]; unsigned char setup[SETUP_MAX]; @@ -121,7 +124,7 @@ static inline char mon_text_get_setup(struct mon_event_text *ep, struct urb *urb, char ev_type, struct mon_bus *mbus) { - if (!usb_pipecontrol(urb->pipe) || ev_type != 'S') + if (ep->xfertype != USB_ENDPOINT_XFER_CONTROL || ev_type != 'S') return '-'; if (urb->dev->bus->uses_dma && @@ -138,14 +141,12 @@ static inline char mon_text_get_setup(struct mon_event_text *ep, static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb, int len, char ev_type, struct mon_bus *mbus) { - int pipe = urb->pipe; - if (len <= 0) return 'L'; if (len >= DATA_MAX) len = DATA_MAX; - if (usb_pipein(pipe)) { + if (ep->is_in) { if (ev_type != 'C') return '<'; } else { @@ -203,24 +204,28 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, } ep->type = ev_type; - ep->pipe = urb->pipe; ep->id = (unsigned long) urb; ep->busnum = urb->dev->bus->busnum; + ep->devnum = urb->dev->devnum; + ep->epnum = usb_endpoint_num(&urb->ep->desc); + ep->xfertype = usb_endpoint_type(&urb->ep->desc); + ep->is_in = usb_urb_dir_in(urb); ep->tstamp = stamp; ep->length = (ev_type == 'S') ? urb->transfer_buffer_length : urb->actual_length; /* Collecting status makes debugging sense for submits, too */ ep->status = urb->status; - if (usb_pipeint(urb->pipe)) { + if (ep->xfertype == USB_ENDPOINT_XFER_INT) { ep->interval = urb->interval; - } else if (usb_pipeisoc(urb->pipe)) { + } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) { ep->interval = urb->interval; ep->start_frame = urb->start_frame; ep->error_count = urb->error_count; } ep->numdesc = urb->number_of_packets; - if (usb_pipeisoc(urb->pipe) && urb->number_of_packets > 0) { + if (ep->xfertype == USB_ENDPOINT_XFER_ISOC && + urb->number_of_packets > 0) { if ((ndesc = urb->number_of_packets) > ISODESC_MAX) ndesc = ISODESC_MAX; fp = urb->iso_frame_desc; @@ -268,9 +273,12 @@ static void mon_text_error(void *data, struct urb *urb, int error) } ep->type = 'E'; - ep->pipe = urb->pipe; ep->id = (unsigned long) urb; ep->busnum = 0; + ep->devnum = urb->dev->devnum; + ep->epnum = usb_endpoint_num(&urb->ep->desc); + ep->xfertype = usb_endpoint_type(&urb->ep->desc); + ep->is_in = usb_urb_dir_in(urb); ep->tstamp = 0; ep->length = 0; ep->status = error; @@ -413,10 +421,10 @@ static ssize_t mon_text_read_u(struct file *file, char __user *buf, mon_text_read_head_u(rp, &ptr, ep); if (ep->type == 'E') { mon_text_read_statset(rp, &ptr, ep); - } else if (usb_pipeisoc(ep->pipe)) { + } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) { mon_text_read_isostat(rp, &ptr, ep); mon_text_read_isodesc(rp, &ptr, ep); - } else if (usb_pipeint(ep->pipe)) { + } else if (ep->xfertype == USB_ENDPOINT_XFER_INT) { mon_text_read_intstat(rp, &ptr, ep); } else { mon_text_read_statset(rp, &ptr, ep); @@ -468,18 +476,17 @@ static void mon_text_read_head_t(struct mon_reader_text *rp, { char udir, utype; - udir = usb_pipein(ep->pipe) ? 'i' : 'o'; - switch (usb_pipetype(ep->pipe)) { - case PIPE_ISOCHRONOUS: utype = 'Z'; break; - case PIPE_INTERRUPT: utype = 'I'; break; - case PIPE_CONTROL: utype = 'C'; break; + udir = (ep->is_in ? 'i' : 'o'); + switch (ep->xfertype) { + case USB_ENDPOINT_XFER_ISOC: utype = 'Z'; break; + case USB_ENDPOINT_XFER_INT: utype = 'I'; break; + case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break; default: /* PIPE_BULK */ utype = 'B'; } p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, "%lx %u %c %c%c:%03u:%02u", ep->id, ep->tstamp, ep->type, - utype, udir, - usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe)); + utype, udir, ep->devnum, ep->epnum); } static void mon_text_read_head_u(struct mon_reader_text *rp, @@ -487,18 +494,17 @@ static void mon_text_read_head_u(struct mon_reader_text *rp, { char udir, utype; - udir = usb_pipein(ep->pipe) ? 'i' : 'o'; - switch (usb_pipetype(ep->pipe)) { - case PIPE_ISOCHRONOUS: utype = 'Z'; break; - case PIPE_INTERRUPT: utype = 'I'; break; - case PIPE_CONTROL: utype = 'C'; break; + udir = (ep->is_in ? 'i' : 'o'); + switch (ep->xfertype) { + case USB_ENDPOINT_XFER_ISOC: utype = 'Z'; break; + case USB_ENDPOINT_XFER_INT: utype = 'I'; break; + case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break; default: /* PIPE_BULK */ utype = 'B'; } p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, "%lx %u %c %c%c:%d:%03u:%u", ep->id, ep->tstamp, ep->type, - utype, udir, - ep->busnum, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe)); + utype, udir, ep->busnum, ep->devnum, ep->epnum); } static void mon_text_read_statset(struct mon_reader_text *rp, -- cgit v1.2.3-70-g09d2 From d617bc83ff48ebf0df253605529d8b3bef15773a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 2 Aug 2007 15:04:52 -0400 Subject: USB: cleanup for previous patches This patch (as951) cleans up a few loose ends from earlier patches. Redundant checks for non-NULL urb->dev are removed, as are checks of urb->dev->bus (which can never be NULL). Conversely, a check for non-NULL urb->ep is added to the unlink paths. A homegrown round-down-to-power-of-2 loop is simplified by using the ilog2 routine. The comparison in usb_urb_dir_in() is made more transparent. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 5 ----- drivers/usb/core/urb.c | 13 +++++++------ include/linux/usb.h | 2 +- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 739c5e0aa3b..47a055a2acf 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1074,11 +1074,6 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) struct list_head *tmp; int retval; - if (!urb) - return -EINVAL; - if (!urb->dev || !urb->dev->bus) - return -ENODEV; - /* * we contend for urb->status with the hcd core, * which changes it while returning the urb. diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 1acca8696bc..19f5f66c273 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include "hcd.h" @@ -441,10 +442,8 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) default: return -EINVAL; } - /* power of two? */ - while (max > urb->interval) - max >>= 1; - urb->interval = max; + /* Round down to a power of 2, no more than max */ + urb->interval = min(max, 1 << ilog2(urb->interval)); } return usb_hcd_submit_urb(urb, mem_flags); @@ -513,8 +512,10 @@ int usb_unlink_urb(struct urb *urb) { if (!urb) return -EINVAL; - if (!(urb->dev && urb->dev->bus)) + if (!urb->dev) return -ENODEV; + if (!urb->ep) + return -EIDRM; return usb_hcd_unlink_urb(urb, -ECONNRESET); } @@ -541,7 +542,7 @@ int usb_unlink_urb(struct urb *urb) void usb_kill_urb(struct urb *urb) { might_sleep(); - if (!(urb && urb->dev && urb->dev->bus)) + if (!(urb && urb->dev && urb->ep)) return; spin_lock_irq(&urb->lock); ++urb->reject; diff --git a/include/linux/usb.h b/include/linux/usb.h index 019ae963a9f..a51f34e8057 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1395,7 +1395,7 @@ extern int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor, */ static inline int usb_urb_dir_in(struct urb *urb) { - return (urb->transfer_flags & URB_DIR_MASK) != URB_DIR_OUT; + return (urb->transfer_flags & URB_DIR_MASK) == URB_DIR_IN; } /** -- cgit v1.2.3-70-g09d2 From 9439eb94b5c374d5b02699f8897fc43aa3603701 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 2 Aug 2007 15:05:45 -0400 Subject: USB: update spinlock usage for root-hub URBs This patch (as952) adjusts the spinlock usage in the root-hub emulation part of usbcore, to make it match more closely the pattern used by regular host controller drivers. To wit: The private lock (usb_hcd_root_hub_lock) is held throughout the important parts, and it is dropped temporarily without re-enabling interrupts around the call to usb_hcd_giveback_urb(). A nice side effect is that the code now avoids calling local_irq_save(), thereby becoming more RT-friendly. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 52 ++++++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 47a055a2acf..f8e7deb03ee 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -356,10 +356,11 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) const u8 *bufp = tbuf; int len = 0; int patch_wakeup = 0; - unsigned long flags; int status = 0; int n; + might_sleep(); + cmd = (struct usb_ctrlrequest *) urb->setup_packet; typeReq = (cmd->bRequestType << 8) | cmd->bRequest; wValue = le16_to_cpu (cmd->wValue); @@ -523,13 +524,21 @@ error: } /* any errors get returned through the urb completion */ - local_irq_save (flags); - spin_lock (&urb->lock); + spin_lock_irq(&hcd_root_hub_lock); + spin_lock(&urb->lock); if (urb->status == -EINPROGRESS) urb->status = status; - spin_unlock (&urb->lock); - usb_hcd_giveback_urb (hcd, urb); - local_irq_restore (flags); + spin_unlock(&urb->lock); + + /* This peculiar use of spinlocks echoes what real HC drivers do. + * Avoiding calls to local_irq_disable/enable makes the code + * RT-friendly. + */ + spin_unlock(&hcd_root_hub_lock); + usb_hcd_giveback_urb(hcd, urb); + spin_lock(&hcd_root_hub_lock); + + spin_unlock_irq(&hcd_root_hub_lock); return 0; } @@ -559,8 +568,7 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd) if (length > 0) { /* try to complete the status urb */ - local_irq_save (flags); - spin_lock(&hcd_root_hub_lock); + spin_lock_irqsave(&hcd_root_hub_lock, flags); urb = hcd->status_urb; if (urb) { spin_lock(&urb->lock); @@ -574,16 +582,16 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd) } else /* urb has been unlinked */ length = 0; spin_unlock(&urb->lock); + + spin_unlock(&hcd_root_hub_lock); + usb_hcd_giveback_urb(hcd, urb); + spin_lock(&hcd_root_hub_lock); } else length = 0; - spin_unlock(&hcd_root_hub_lock); - /* local irqs are always blocked in completions */ - if (length > 0) - usb_hcd_giveback_urb (hcd, urb); - else + if (length <= 0) hcd->poll_pending = 1; - local_irq_restore (flags); + spin_unlock_irqrestore(&hcd_root_hub_lock, flags); } /* The USB 2.0 spec says 256 ms. This is close enough and won't @@ -651,25 +659,23 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) { unsigned long flags; + spin_lock_irqsave(&hcd_root_hub_lock, flags); if (usb_endpoint_num(&urb->ep->desc) == 0) { /* Control URB */ ; /* Do nothing */ } else { /* Status URB */ if (!hcd->uses_new_polling) del_timer (&hcd->rh_timer); - local_irq_save (flags); - spin_lock (&hcd_root_hub_lock); if (urb == hcd->status_urb) { hcd->status_urb = NULL; urb->hcpriv = NULL; - } else - urb = NULL; /* wasn't fully queued */ - spin_unlock (&hcd_root_hub_lock); - if (urb) - usb_hcd_giveback_urb (hcd, urb); - local_irq_restore (flags); - } + spin_unlock(&hcd_root_hub_lock); + usb_hcd_giveback_urb(hcd, urb); + spin_lock(&hcd_root_hub_lock); + } + } + spin_unlock_irqrestore(&hcd_root_hub_lock, flags); return 0; } -- cgit v1.2.3-70-g09d2 From 9a9bf406df3ce238089d14f4cb41157ca56d8ad3 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 2 Aug 2007 15:06:54 -0400 Subject: USB: separate out endpoint queue management and DMA mapping routines This patch (as953) separates out three key portions from usb_hcd_submit_urb(), usb_hcd_unlink_urb(), and usb_hcd_giveback_urb() and puts them in separate functions of their own. In the next patch, these functions will be called directly by host controller drivers while holding their private spinlocks, which will remove the possibility of some unpleasant races. The code responsible for mapping and unmapping DMA buffers is also placed into a couple of separate subroutines, for the sake of cleanliness and consistency. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 316 ++++++++++++++++++++++++++----------------------- 1 file changed, 166 insertions(+), 150 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index f8e7deb03ee..eb212178826 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -914,99 +914,117 @@ EXPORT_SYMBOL (usb_calc_bus_time); /*-------------------------------------------------------------------------*/ -static void urb_unlink(struct usb_hcd *hcd, struct urb *urb) +static int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb) { - unsigned long flags; + unsigned long flags; + int rc = 0; - /* clear all state linking urb to this dev (and hcd) */ spin_lock_irqsave(&hcd_urb_list_lock, flags); - list_del_init (&urb->urb_list); - spin_unlock_irqrestore(&hcd_urb_list_lock, flags); - if (hcd->self.uses_dma && !is_root_hub(urb->dev)) { - if (usb_endpoint_xfer_control(&urb->ep->desc) - && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) - dma_unmap_single (hcd->self.controller, urb->setup_dma, - sizeof (struct usb_ctrlrequest), - DMA_TO_DEVICE); - if (urb->transfer_buffer_length != 0 - && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) - dma_unmap_single (hcd->self.controller, - urb->transfer_dma, - urb->transfer_buffer_length, - usb_urb_dir_in(urb) - ? DMA_FROM_DEVICE - : DMA_TO_DEVICE); + /* Check that the URB isn't being killed */ + if (unlikely(urb->reject)) { + rc = -EPERM; + goto done; } -} - -/* may be called in any context with a valid urb->dev usecount - * caller surrenders "ownership" of urb - * expects usb_submit_urb() to have sanity checked and conditioned all - * inputs in the urb - */ -int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) -{ - int status; - struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus); - unsigned long flags; - - if (!hcd) - return -ENODEV; - usbmon_urb_submit(&hcd->self, urb); + if (unlikely(!urb->ep->enabled)) { + rc = -ENOENT; + goto done; + } /* - * Atomically queue the urb, first to our records, then to the HCD. - * Access to urb->status is controlled by urb->lock ... changes on - * i/o completion (normal or fault) or unlinking. + * Check the host controller's state and add the URB to the + * endpoint's queue. */ - - // FIXME: verify that quiescing hc works right (RH cleans up) - - spin_lock_irqsave(&hcd_urb_list_lock, flags); - if (unlikely(!urb->ep->enabled)) - status = -ENOENT; - else if (unlikely (urb->reject)) - status = -EPERM; - else switch (hcd->state) { + switch (hcd->state) { case HC_STATE_RUNNING: case HC_STATE_RESUMING: - list_add_tail (&urb->urb_list, &urb->ep->urb_list); - status = 0; + list_add_tail(&urb->urb_list, &urb->ep->urb_list); break; default: - status = -ESHUTDOWN; - break; + rc = -ESHUTDOWN; + goto done; } + done: spin_unlock_irqrestore(&hcd_urb_list_lock, flags); - if (status) { - INIT_LIST_HEAD (&urb->urb_list); - usbmon_urb_submit_error(&hcd->self, urb, status); - return status; + return rc; +} + +static int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb, + int status) +{ + unsigned long flags; + struct list_head *tmp; + int rc = 0; + + /* + * we contend for urb->status with the hcd core, + * which changes it while returning the urb. + * + * Caller guaranteed that the urb pointer hasn't been freed, and + * that it was submitted. But as a rule it can't know whether or + * not it's already been unlinked ... so we respect the reversed + * lock sequence needed for the usb_hcd_giveback_urb() code paths + * (urb lock, then hcd_urb_list_lock) in case some other CPU is now + * unlinking it. + */ + spin_lock_irqsave(&urb->lock, flags); + spin_lock(&hcd_urb_list_lock); + + /* insist the urb is still queued */ + list_for_each(tmp, &urb->ep->urb_list) { + if (tmp == &urb->urb_list) + break; + } + if (tmp != &urb->urb_list) { + rc = -EIDRM; + goto done; } - /* increment urb's reference count as part of giving it to the HCD - * (which now controls it). HCD guarantees that it either returns - * an error or calls giveback(), but not both. + /* Any status except -EINPROGRESS means something already started to + * unlink this URB from the hardware. So there's no more work to do. */ - urb = usb_get_urb (urb); - atomic_inc (&urb->use_count); - - if (is_root_hub(urb->dev)) { - /* NOTE: requirement on hub callers (usbfs and the hub - * driver, for now) that URBs' urb->transfer_buffer be - * valid and usb_buffer_{sync,unmap}() not be needed, since - * they could clobber root hub response data. - */ - status = rh_urb_enqueue (hcd, urb); + if (urb->status != -EINPROGRESS) { + rc = -EBUSY; goto done; } + urb->status = status; + + /* IRQ setup can easily be broken so that USB controllers + * never get completion IRQs ... maybe even the ones we need to + * finish unlinking the initial failed usb_set_address() + * or device descriptor fetch. + */ + if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) && + !is_root_hub(urb->dev)) { + dev_warn(hcd->self.controller, "Unlink after no-IRQ? " + "Controller is probably using the wrong IRQ.\n"); + set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); + } + + done: + spin_unlock(&hcd_urb_list_lock); + spin_unlock_irqrestore (&urb->lock, flags); + return rc; +} + +static void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb) +{ + unsigned long flags; - /* lower level hcd code should use *_dma exclusively, + /* clear all state linking urb to this dev (and hcd) */ + spin_lock_irqsave(&hcd_urb_list_lock, flags); + list_del_init(&urb->urb_list); + spin_unlock_irqrestore(&hcd_urb_list_lock, flags); +} + +static void map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) +{ + /* Map the URB's buffers for DMA access. + * Lower level HCD code should use *_dma exclusively, * unless it uses pio or talks to another transport. */ - if (hcd->self.uses_dma) { + if (hcd->self.uses_dma && !is_root_hub(urb->dev)) { if (usb_endpoint_xfer_control(&urb->ep->desc) && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) urb->setup_dma = dma_map_single ( @@ -1024,16 +1042,73 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } +} - status = hcd->driver->urb_enqueue (hcd, urb->ep, urb, mem_flags); -done: - if (unlikely (status)) { - urb_unlink(hcd, urb); - atomic_dec (&urb->use_count); - if (urb->reject) - wake_up (&usb_kill_urb_queue); +static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) +{ + if (hcd->self.uses_dma && !is_root_hub(urb->dev)) { + if (usb_endpoint_xfer_control(&urb->ep->desc) + && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) + dma_unmap_single(hcd->self.controller, urb->setup_dma, + sizeof(struct usb_ctrlrequest), + DMA_TO_DEVICE); + if (urb->transfer_buffer_length != 0 + && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) + dma_unmap_single(hcd->self.controller, + urb->transfer_dma, + urb->transfer_buffer_length, + usb_urb_dir_in(urb) + ? DMA_FROM_DEVICE + : DMA_TO_DEVICE); + } +} + +/*-------------------------------------------------------------------------*/ + +/* may be called in any context with a valid urb->dev usecount + * caller surrenders "ownership" of urb + * expects usb_submit_urb() to have sanity checked and conditioned all + * inputs in the urb + */ +int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) +{ + int status; + struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus); + + /* increment urb's reference count as part of giving it to the HCD + * (which will control it). HCD guarantees that it either returns + * an error or calls giveback(), but not both. + */ + usb_get_urb(urb); + atomic_inc(&urb->use_count); + usbmon_urb_submit(&hcd->self, urb); + + /* NOTE requirements on root-hub callers (usbfs and the hub + * driver, for now): URBs' urb->transfer_buffer must be + * valid and usb_buffer_{sync,unmap}() not be needed, since + * they could clobber root hub response data. Also, control + * URBs must be submitted in process context with interrupts + * enabled. + */ + status = usb_hcd_link_urb_to_ep(hcd, urb); + if (!status) { + map_urb_for_dma(hcd, urb); + if (is_root_hub(urb->dev)) + status = rh_urb_enqueue(hcd, urb); + else + status = hcd->driver->urb_enqueue(hcd, urb->ep, urb, + mem_flags); + } + + if (unlikely(status)) { usbmon_urb_submit_error(&hcd->self, urb, status); - usb_put_urb (urb); + unmap_urb_for_dma(hcd, urb); + usb_hcd_unlink_urb_from_ep(hcd, urb); + INIT_LIST_HEAD(&urb->urb_list); + atomic_dec(&urb->use_count); + if (urb->reject) + wake_up(&usb_kill_urb_queue); + usb_put_urb(urb); } return status; } @@ -1074,78 +1149,20 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb) */ int usb_hcd_unlink_urb (struct urb *urb, int status) { - struct usb_hcd *hcd = NULL; - struct device *sys = NULL; - unsigned long flags; - struct list_head *tmp; - int retval; - - /* - * we contend for urb->status with the hcd core, - * which changes it while returning the urb. - * - * Caller guaranteed that the urb pointer hasn't been freed, and - * that it was submitted. But as a rule it can't know whether or - * not it's already been unlinked ... so we respect the reversed - * lock sequence needed for the usb_hcd_giveback_urb() code paths - * (urb lock, then hcd_urb_list_lock) in case some other CPU is now - * unlinking it. - */ - spin_lock_irqsave (&urb->lock, flags); - spin_lock(&hcd_urb_list_lock); + struct usb_hcd *hcd; + int retval; - sys = &urb->dev->dev; hcd = bus_to_hcd(urb->dev->bus); - if (hcd == NULL) { - retval = -ENODEV; - goto done; - } - - /* insist the urb is still queued */ - list_for_each(tmp, &urb->ep->urb_list) { - if (tmp == &urb->urb_list) - break; - } - if (tmp != &urb->urb_list) { - retval = -EIDRM; - goto done; - } - /* Any status except -EINPROGRESS means something already started to - * unlink this URB from the hardware. So there's no more work to do. - */ - if (urb->status != -EINPROGRESS) { - retval = -EBUSY; - goto done; - } + retval = usb_hcd_check_unlink_urb(hcd, urb, status); + if (!retval) + retval = unlink1(hcd, urb); - /* IRQ setup can easily be broken so that USB controllers - * never get completion IRQs ... maybe even the ones we need to - * finish unlinking the initial failed usb_set_address() - * or device descriptor fetch. - */ - if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) && - !is_root_hub(urb->dev)) { - dev_warn (hcd->self.controller, "Unlink after no-IRQ? " - "Controller is probably using the wrong IRQ.\n"); - set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); - } - - urb->status = status; - - spin_unlock(&hcd_urb_list_lock); - spin_unlock_irqrestore (&urb->lock, flags); - - retval = unlink1 (hcd, urb); if (retval == 0) retval = -EINPROGRESS; - return retval; - -done: - spin_unlock(&hcd_urb_list_lock); - spin_unlock_irqrestore (&urb->lock, flags); - if (retval != -EIDRM && sys && sys->driver) - dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval); + else if (retval != -EIDRM) + dev_dbg(&urb->dev->dev, "hcd_unlink_urb %p fail %d\n", + urb, retval); return retval; } @@ -1165,7 +1182,8 @@ done: */ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) { - urb_unlink(hcd, urb); + usb_hcd_unlink_urb_from_ep(hcd, urb); + unmap_urb_for_dma(hcd, urb); usbmon_urb_complete (&hcd->self, urb); usb_unanchor_urb(urb); @@ -1194,12 +1212,12 @@ void usb_hcd_endpoint_disable (struct usb_device *udev, struct usb_hcd *hcd; struct urb *urb; + might_sleep(); hcd = bus_to_hcd(udev->bus); - local_irq_disable (); /* ep is already gone from udev->ep_{in,out}[]; no more submits */ rescan: - spin_lock(&hcd_urb_list_lock); + spin_lock_irq(&hcd_urb_list_lock); list_for_each_entry (urb, &ep->urb_list, urb_list) { int tmp; int is_in; @@ -1244,13 +1262,11 @@ rescan: /* list contents may have changed */ goto rescan; } - spin_unlock(&hcd_urb_list_lock); - local_irq_enable (); + spin_unlock_irq(&hcd_urb_list_lock); /* synchronize with the hardware, so old configuration state * clears out immediately (and will be freed). */ - might_sleep (); if (hcd->driver->endpoint_disable) hcd->driver->endpoint_disable (hcd, ep); -- cgit v1.2.3-70-g09d2 From a1d534bb23e5c5c28fb6f6fb48588362df0907e8 Mon Sep 17 00:00:00 2001 From: Nico Erfurth Date: Thu, 2 Aug 2007 22:25:20 +0200 Subject: USB: Add drivers/usb/misc/iowarrior.c to the Makefile This patch adds the new iowarrior module to the Makefile in drivers/usb. Currently the module isn't build unless another driver from usb/misc is selected. Signed-off-by: Nico Erfurth Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index ac49b15fa76..cce216517ca 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_USB_EMI26) += misc/ obj-$(CONFIG_USB_EMI62) += misc/ obj-$(CONFIG_USB_FTDI_ELAN) += misc/ obj-$(CONFIG_USB_IDMOUSE) += misc/ +obj-$(CONFIG_USB_IOWARRIOR) += misc/ obj-$(CONFIG_USB_LCD) += misc/ obj-$(CONFIG_USB_LD) += misc/ obj-$(CONFIG_USB_LED) += misc/ -- cgit v1.2.3-70-g09d2 From a4e3ef5597e26dad006544d38b9ab6ff42382b76 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 1 Aug 2007 23:58:22 -0700 Subject: USB: gadget: gadget_is_{dualspeed,otg} predicates and cleanup This adds two small inlines to the gadget stack, which will often evaluate to compile-time constants. That can help shrink object code and remove #ifdeffery. - gadget_is_dualspeed(), currently always a compile-time constant (depending on which controller is selected). - gadget_is_otg(), usually a compile time "false", but this is a runtime test if the platform enables OTG (since it's reasonable to populate boards with different USB sockets). It also updates two peripheral controller drivers to use these: - fsl_usb2_udc, mostly OTG-related bugfixes: non-OTG devices must follow the rules about drawing VBUS power, and OTG ones need to reject invalid SET_FEATURE requests. - omap_udc, just scrubbing a bit of #ifdeffery. And also gadgetfs, which lost some #ifdefs and moved to a more standard handling of DEBUG and VERBOSE_DEBUG. The main benefits come from patches which will follow. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/fsl_usb2_udc.c | 9 +++----- drivers/usb/gadget/inode.c | 44 ++++++++++++++++++--------------------- drivers/usb/gadget/omap_udc.c | 10 +++------ include/linux/usb_gadget.h | 33 +++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 37 deletions(-) diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c index d57bcfbc08a..89c768e2aed 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.c +++ b/drivers/usb/gadget/fsl_usb2_udc.c @@ -1090,14 +1090,11 @@ static int fsl_vbus_session(struct usb_gadget *gadget, int is_active) */ static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA) { -#ifdef CONFIG_USB_OTG struct fsl_udc *udc; udc = container_of(gadget, struct fsl_udc, gadget); - if (udc->transceiver) return otg_set_power(udc->transceiver, mA); -#endif return -ENOTSUPP; } @@ -1321,7 +1318,7 @@ static void setup_received_irq(struct fsl_udc *udc, | USB_TYPE_STANDARD)) { /* Note: The driver has not include OTG support yet. * This will be set when OTG support is added */ - if (!udc->gadget.is_otg) + if (!gadget_is_otg(udc->gadget)) break; else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE) udc->gadget.b_hnp_enable = 1; @@ -1330,6 +1327,8 @@ static void setup_received_irq(struct fsl_udc *udc, else if (setup->bRequest == USB_DEVICE_A_ALT_HNP_SUPPORT) udc->gadget.a_alt_hnp_support = 1; + else + break; rc = 0; } else break; @@ -1840,10 +1839,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) if (!driver || driver != udc_controller->driver || !driver->unbind) return -EINVAL; -#ifdef CONFIG_USB_OTG if (udc_controller->transceiver) (void)otg_set_peripheral(udc_controller->transceiver, 0); -#endif /* stop DR, disable intr */ dr_controller_stop(udc_controller); diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 173004f60fe..129eda5358f 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -20,8 +20,7 @@ */ -// #define DEBUG /* data to help fault diagnosis */ -// #define VERBOSE /* extra debug messages (success too) */ +/* #define VERBOSE_DEBUG */ #include #include @@ -253,7 +252,7 @@ static const char *CHIP; do { } while (0) #endif /* DEBUG */ -#ifdef VERBOSE +#ifdef VERBOSE_DEBUG #define VDEBUG DBG #else #define VDEBUG(dev,fmt,args...) \ @@ -1010,11 +1009,12 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) /* assume that was SET_CONFIGURATION */ if (dev->current_config) { unsigned power; -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (dev->gadget->speed == USB_SPEED_HIGH) + + if (gadget_is_dualspeed(dev->gadget) + && (dev->gadget->speed + == USB_SPEED_HIGH)) power = dev->hs_config->bMaxPower; else -#endif power = dev->config->bMaxPower; usb_gadget_vbus_draw(dev->gadget, 2 * power); } @@ -1355,24 +1355,21 @@ static int config_buf (struct dev_data *dev, u8 type, unsigned index) { int len; -#ifdef CONFIG_USB_GADGET_DUALSPEED - int hs; -#endif + int hs = 0; /* only one configuration */ if (index > 0) return -EINVAL; -#ifdef CONFIG_USB_GADGET_DUALSPEED - hs = (dev->gadget->speed == USB_SPEED_HIGH); - if (type == USB_DT_OTHER_SPEED_CONFIG) - hs = !hs; + if (gadget_is_dualspeed(dev->gadget)) { + hs = (dev->gadget->speed == USB_SPEED_HIGH); + if (type == USB_DT_OTHER_SPEED_CONFIG) + hs = !hs; + } if (hs) { dev->req->buf = dev->hs_config; len = le16_to_cpu(dev->hs_config->wTotalLength); - } else -#endif - { + } else { dev->req->buf = dev->config; len = le16_to_cpu(dev->config->wTotalLength); } @@ -1393,13 +1390,13 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) spin_lock (&dev->lock); dev->setup_abort = 0; if (dev->state == STATE_DEV_UNCONNECTED) { -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == NULL) { + if (gadget_is_dualspeed(gadget) + && gadget->speed == USB_SPEED_HIGH + && dev->hs_config == NULL) { spin_unlock(&dev->lock); ERROR (dev, "no high speed config??\n"); return -EINVAL; } -#endif /* CONFIG_USB_GADGET_DUALSPEED */ dev->state = STATE_DEV_CONNECTED; dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket; @@ -1469,13 +1466,12 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) // user mode expected to disable endpoints } else { u8 config, power; -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (gadget->speed == USB_SPEED_HIGH) { + + if (gadget_is_dualspeed(gadget) + && gadget->speed == USB_SPEED_HIGH) { config = dev->hs_config->bConfigurationValue; power = dev->hs_config->bMaxPower; - } else -#endif - { + } else { config = dev->config->bConfigurationValue; power = dev->config->bMaxPower; } diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 9b0f0925ddd..bf2788dfb32 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -1241,19 +1241,15 @@ static void pullup_enable(struct omap_udc *udc) udc->gadget.dev.parent->power.power_state = PMSG_ON; udc->gadget.dev.power.power_state = PMSG_ON; UDC_SYSCON1_REG |= UDC_PULLUP_EN; -#ifndef CONFIG_USB_OTG - if (!cpu_is_omap15xx()) + if (!gadget_is_otg(udc->gadget) && !cpu_is_omap15xx()) OTG_CTRL_REG |= OTG_BSESSVLD; -#endif UDC_IRQ_EN_REG = UDC_DS_CHG_IE; } static void pullup_disable(struct omap_udc *udc) { -#ifndef CONFIG_USB_OTG - if (!cpu_is_omap15xx()) + if (!gadget_is_otg(udc->gadget) && !cpu_is_omap15xx()) OTG_CTRL_REG &= ~OTG_BSESSVLD; -#endif UDC_IRQ_EN_REG = UDC_DS_CHG_IE; UDC_SYSCON1_REG &= ~UDC_PULLUP_EN; } @@ -1390,7 +1386,7 @@ static void update_otg(struct omap_udc *udc) { u16 devstat; - if (!udc->gadget.is_otg) + if (!gadget_is_otg(udc->gadget)) return; if (OTG_CTRL_REG & OTG_ID) diff --git a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h index ec9732e7fea..5ea611e48ec 100644 --- a/include/linux/usb_gadget.h +++ b/include/linux/usb_gadget.h @@ -479,6 +479,39 @@ static inline void *get_gadget_data (struct usb_gadget *gadget) list_for_each_entry(tmp, &(gadget)->ep_list, ep_list) +/** + * gadget_is_dualspeed - return true iff the hardware handles high speed + * @gadget: controller that might support both high and full speeds + */ +static inline int gadget_is_dualspeed(struct usb_gadget *g) +{ +#ifdef CONFIG_USB_GADGET_DUALSPEED + /* runtime test would check "g->is_dualspeed" ... that might be + * useful to work around hardware bugs, but is mostly pointless + */ + return 1; +#else + return 0; +#endif +} + +/** + * gadget_is_otg - return true iff the hardware is OTG-ready + * @gadget: controller that might have a Mini-AB connector + * + * This is a runtime test, since kernels with a USB-OTG stack sometimes + * run on boards which only have a Mini-B (or Mini-A) connector. + */ +static inline int gadget_is_otg(struct usb_gadget *g) +{ +#ifdef CONFIG_USB_OTG + return g->is_otg; +#else + return 0; +#endif +} + + /** * usb_gadget_frame_number - returns the current frame number * @gadget: controller that reports the frame number -- cgit v1.2.3-70-g09d2 From 0cf4f2de0a0f4100795f38ef894d4910678c74f8 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 2 Aug 2007 00:00:38 -0700 Subject: USB: gadget: ethernet gadget cleanups, shrinkage Clean up the ethernet gadget, using newer APIs and conventions: - gadget_is_dualspeed() and gadget_is_otg() ... #ifdef removal - Remove many now-needless #includes - Use the VERBOSE_DEBUG convention - Minor whitespace fixes. - Fix a warning from "sparse". Surprisingly, this saved about 2K of code (16%) on a fullspeed-only ARMv4 platform. I'm bit puzzled by that (it's so much!), but approve of the result. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ether.c | 141 +++++++++++++++++---------------------------- 1 file changed, 54 insertions(+), 87 deletions(-) diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index f70055473a0..ff244f42723 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -19,41 +19,19 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* #define VERBOSE_DEBUG */ -// #define DEBUG 1 -// #define VERBOSE - -#include #include -#include -#include -#include -#include -#include -#include -#include -#include #include #include -#include #include - -#include -#include -#include -#include -#include -#include +#include +#include #include #include #include -#include -#include -#include -#include - #include "gadget_chips.h" /*-------------------------------------------------------------------------*/ @@ -356,15 +334,15 @@ module_param (qmult, uint, S_IRUGO|S_IWUSR); #define qlen(gadget) \ (DEFAULT_QLEN*((gadget->speed == USB_SPEED_HIGH) ? qmult : 1)) -/* also defer IRQs on highspeed TX */ -#define TX_DELAY qmult - static inline int BITRATE(struct usb_gadget *g) { return (g->speed == USB_SPEED_HIGH) ? HS_BPS : FS_BPS; } #else /* full speed (low speed doesn't do bulk) */ + +#define qmult 1 + #define DEVSPEED USB_SPEED_FULL #define qlen(gadget) DEFAULT_QLEN @@ -390,7 +368,7 @@ static inline int BITRATE(struct usb_gadget *g) do { } while (0) #endif /* DEBUG */ -#ifdef VERBOSE +#ifdef VERBOSE_DEBUG #define VDEBUG DEBUG #else #define VDEBUG(dev,fmt,args...) \ @@ -830,8 +808,6 @@ static const struct usb_descriptor_header *fs_rndis_function [] = { }; #endif -#ifdef CONFIG_USB_GADGET_DUALSPEED - /* * usb 2.0 devices need to expose both high speed and full speed * descriptors, unless they only run at full speed. @@ -934,18 +910,15 @@ static const struct usb_descriptor_header *hs_rndis_function [] = { /* maxpacket and other transfer characteristics vary by speed. */ -#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs)) - -#else - -/* if there's no high speed support, maxpacket doesn't change. */ -#define ep_desc(g,hs,fs) (((void)(g)), (fs)) - -static inline void __init hs_subset_descriptors(void) +static inline struct usb_endpoint_descriptor * +ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs, + struct usb_endpoint_descriptor *fs) { + if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + return hs; + return fs; } -#endif /* !CONFIG_USB_GADGET_DUALSPEED */ /*-------------------------------------------------------------------------*/ @@ -989,22 +962,19 @@ static struct usb_gadget_strings stringtab = { * complications: class descriptors, and an altsetting. */ static int -config_buf (enum usb_device_speed speed, - u8 *buf, u8 type, - unsigned index, int is_otg) +config_buf(struct usb_gadget *g, u8 *buf, u8 type, unsigned index, int is_otg) { int len; const struct usb_config_descriptor *config; const struct usb_descriptor_header **function; -#ifdef CONFIG_USB_GADGET_DUALSPEED - int hs = (speed == USB_SPEED_HIGH); + int hs = 0; - if (type == USB_DT_OTHER_SPEED_CONFIG) - hs = !hs; + if (gadget_is_dualspeed(g)) { + hs = (g->speed == USB_SPEED_HIGH); + if (type == USB_DT_OTHER_SPEED_CONFIG) + hs = !hs; + } #define which_fn(t) (hs ? hs_ ## t ## _function : fs_ ## t ## _function) -#else -#define which_fn(t) (fs_ ## t ## _function) -#endif if (index >= device_desc.bNumConfigurations) return -EINVAL; @@ -1217,7 +1187,7 @@ eth_set_config (struct eth_dev *dev, unsigned number, gfp_t gfp_flags) if (number) eth_reset_config (dev); usb_gadget_vbus_draw(dev->gadget, - dev->gadget->is_otg ? 8 : 100); + gadget_is_otg(dev->gadget) ? 8 : 100); } else { char *speed; unsigned power; @@ -1399,24 +1369,22 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) value = min (wLength, (u16) sizeof device_desc); memcpy (req->buf, &device_desc, value); break; -#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; value = min (wLength, (u16) sizeof dev_qualifier); memcpy (req->buf, &dev_qualifier, value); break; case USB_DT_OTHER_SPEED_CONFIG: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; // FALLTHROUGH -#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: - value = config_buf (gadget->speed, req->buf, + value = config_buf(gadget, req->buf, wValue >> 8, wValue & 0xff, - gadget->is_otg); + gadget_is_otg(gadget)); if (value >= 0) value = min (wLength, (u16) value); break; @@ -1585,12 +1553,12 @@ done_set_intf: && rndis_control_intf.bInterfaceNumber == wIndex) { u8 *buf; + u32 n; /* return the result */ - buf = rndis_get_next_response (dev->rndis_config, - &value); + buf = rndis_get_next_response(dev->rndis_config, &n); if (buf) { - memcpy (req->buf, buf, value); + memcpy(req->buf, buf, n); req->complete = rndis_response_complete; rndis_free_response(dev->rndis_config, buf); } @@ -2026,12 +1994,11 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) req->length = length; -#ifdef CONFIG_USB_GADGET_DUALSPEED /* throttle highspeed IRQ rate back slightly */ - req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH) - ? ((atomic_read (&dev->tx_qlen) % TX_DELAY) != 0) - : 0; -#endif + if (gadget_is_dualspeed(dev->gadget)) + req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH) + ? ((atomic_read(&dev->tx_qlen) % qmult) != 0) + : 0; retval = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC); switch (retval) { @@ -2188,8 +2155,7 @@ static int eth_stop (struct net_device *net) } if (rndis_active(dev)) { - rndis_set_param_medium (dev->rndis_config, - NDIS_MEDIUM_802_3, 0); + rndis_set_param_medium(dev->rndis_config, NDIS_MEDIUM_802_3, 0); (void) rndis_signal_disconnect (dev->rndis_config); } @@ -2443,26 +2409,28 @@ autoconf_fail: if (rndis) device_desc.bNumConfigurations = 2; -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (rndis) - dev_qualifier.bNumConfigurations = 2; - else if (!cdc) - dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC; + if (gadget_is_dualspeed(gadget)) { + if (rndis) + dev_qualifier.bNumConfigurations = 2; + else if (!cdc) + dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC; - /* assumes ep0 uses the same value for both speeds ... */ - dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; + /* assumes ep0 uses the same value for both speeds ... */ + dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; - /* and that all endpoints are dual-speed */ - hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; - hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; + /* and that all endpoints are dual-speed */ + hs_source_desc.bEndpointAddress = + fs_source_desc.bEndpointAddress; + hs_sink_desc.bEndpointAddress = + fs_sink_desc.bEndpointAddress; #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) - if (status_ep) - hs_status_desc.bEndpointAddress = - fs_status_desc.bEndpointAddress; + if (status_ep) + hs_status_desc.bEndpointAddress = + fs_status_desc.bEndpointAddress; #endif -#endif /* DUALSPEED */ + } - if (gadget->is_otg) { + if (gadget_is_otg(gadget)) { otg_descriptor.bmAttributes |= USB_OTG_HNP, eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; eth_config.bMaxPower = 4; @@ -2598,12 +2566,11 @@ fail0: if (rndis_set_param_dev (dev->rndis_config, dev->net, &dev->stats, &dev->cdc_filter)) goto fail0; - if (rndis_set_param_vendor (dev->rndis_config, vendorID, - manufacturer)) + if (rndis_set_param_vendor(dev->rndis_config, vendorID, + manufacturer)) goto fail0; - if (rndis_set_param_medium (dev->rndis_config, - NDIS_MEDIUM_802_3, - 0)) + if (rndis_set_param_medium(dev->rndis_config, + NDIS_MEDIUM_802_3, 0)) goto fail0; INFO (dev, "RNDIS ready\n"); } -- cgit v1.2.3-70-g09d2 From 8c07021635a10c9a4969cbff0f2325a94c860f77 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 2 Aug 2007 00:01:27 -0700 Subject: USB: gadget: gmidi cleanups Clean up the midi gadget, using newer APIs and conventions: - Remove many now-needless #includes - Use the DEBUG (from Kconfig+Makefile) and VERBOSE_DEBUG conventions. - Whitespace fixes There should be no effect on object code size. Signed-off-by: David Brownell Cc: Ben Williamson Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/gmidi.c | 80 +++++++++++++++++++--------------------------- 1 file changed, 32 insertions(+), 48 deletions(-) diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index 1c5aa49d743..d2475755a20 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -18,17 +18,11 @@ * http://www.usb.org/developers/devclass_docs/midi10.pdf */ -#define DEBUG 1 -// #define VERBOSE +/* #define VERBOSE_DEBUG */ -#include #include -#include -#include -#include #include #include -#include #include #include @@ -139,30 +133,16 @@ struct gmidi_device { static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req); -#define xprintk(d,level,fmt,args...) \ - dev_printk(level , &(d)->gadget->dev , fmt , ## args) - -#ifdef DEBUG -#define DBG(dev,fmt,args...) \ - xprintk(dev , KERN_DEBUG , fmt , ## args) -#else -#define DBG(dev,fmt,args...) \ - do { } while (0) -#endif /* DEBUG */ - -#ifdef VERBOSE -#define VDBG DBG -#else -#define VDBG(dev,fmt,args...) \ - do { } while (0) -#endif /* VERBOSE */ - -#define ERROR(dev,fmt,args...) \ - xprintk(dev , KERN_ERR , fmt , ## args) -#define WARN(dev,fmt,args...) \ - xprintk(dev , KERN_WARNING , fmt , ## args) -#define INFO(dev,fmt,args...) \ - xprintk(dev , KERN_INFO , fmt , ## args) +#define DBG(d, fmt, args...) \ + dev_dbg(&(d)->gadget->dev , fmt , ## args) +#define VDBG(d, fmt, args...) \ + dev_vdbg(&(d)->gadget->dev , fmt , ## args) +#define ERROR(d, fmt, args...) \ + dev_err(&(d)->gadget->dev , fmt , ## args) +#define WARN(d, fmt, args...) \ + dev_warn(&(d)->gadget->dev , fmt , ## args) +#define INFO(d, fmt, args...) \ + dev_info(&(d)->gadget->dev , fmt , ## args) static unsigned buflen = 256; @@ -425,7 +405,7 @@ static int config_buf(struct usb_gadget *gadget, return len; } -static struct usb_request* alloc_ep_req(struct usb_ep *ep, unsigned length) +static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length) { struct usb_request *req; @@ -455,7 +435,7 @@ static const uint8_t gmidi_cin_length[] = { * Receives a chunk of MIDI data. */ static void gmidi_read_data(struct usb_ep *ep, int cable, - uint8_t* data, int length) + uint8_t *data, int length) { struct gmidi_device *dev = ep->driver_data; /* cable is ignored, because for now we only have one. */ @@ -541,7 +521,7 @@ static int set_gmidi_config(struct gmidi_device *dev, gfp_t gfp_flags) { int err = 0; struct usb_request *req; - struct usb_ep* ep; + struct usb_ep *ep; unsigned i; err = usb_ep_enable(dev->in_ep, &bulk_in_desc); @@ -628,7 +608,7 @@ gmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags) if (gadget_is_sa1100(gadget) && dev->config) { /* tx fifo is full, but we can't clear it...*/ - INFO(dev, "can't change configurations\n"); + ERROR(dev, "can't change configurations\n"); return -ESPIPE; } gmidi_reset_config(dev); @@ -843,7 +823,7 @@ static void gmidi_disconnect(struct usb_gadget *gadget) static void /* __init_or_exit */ gmidi_unbind(struct usb_gadget *gadget) { struct gmidi_device *dev = get_gadget_data(gadget); - struct snd_card* card; + struct snd_card *card; DBG(dev, "unbind\n"); @@ -867,12 +847,12 @@ static int gmidi_snd_free(struct snd_device *device) return 0; } -static void gmidi_transmit_packet(struct usb_request* req, uint8_t p0, +static void gmidi_transmit_packet(struct usb_request *req, uint8_t p0, uint8_t p1, uint8_t p2, uint8_t p3) { unsigned length = req->length; + u8 *buf = (u8 *)req->buf + length; - uint8_t* buf = (uint8_t*)req->buf + length; buf[0] = p0; buf[1] = p1; buf[2] = p2; @@ -883,8 +863,8 @@ static void gmidi_transmit_packet(struct usb_request* req, uint8_t p0, /* * Converts MIDI commands to USB MIDI packets. */ -static void gmidi_transmit_byte(struct usb_request* req, - struct gmidi_in_port* port, uint8_t b) +static void gmidi_transmit_byte(struct usb_request *req, + struct gmidi_in_port *port, uint8_t b) { uint8_t p0 = port->cable; @@ -981,10 +961,10 @@ static void gmidi_transmit_byte(struct usb_request* req, } } -static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req) +static void gmidi_transmit(struct gmidi_device *dev, struct usb_request *req) { - struct usb_ep* ep = dev->in_ep; - struct gmidi_in_port* port = &dev->in_port; + struct usb_ep *ep = dev->in_ep; + struct gmidi_in_port *port = &dev->in_port; if (!ep) { return; @@ -1020,14 +1000,14 @@ static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req) static void gmidi_in_tasklet(unsigned long data) { - struct gmidi_device* dev = (struct gmidi_device*)data; + struct gmidi_device *dev = (struct gmidi_device *)data; gmidi_transmit(dev, NULL); } static int gmidi_in_open(struct snd_rawmidi_substream *substream) { - struct gmidi_device* dev = substream->rmidi->private_data; + struct gmidi_device *dev = substream->rmidi->private_data; VDBG(dev, "gmidi_in_open\n"); dev->in_substream = substream; @@ -1037,13 +1017,15 @@ static int gmidi_in_open(struct snd_rawmidi_substream *substream) static int gmidi_in_close(struct snd_rawmidi_substream *substream) { + struct gmidi_device *dev = substream->rmidi->private_data; + VDBG(dev, "gmidi_in_close\n"); return 0; } static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up) { - struct gmidi_device* dev = substream->rmidi->private_data; + struct gmidi_device *dev = substream->rmidi->private_data; VDBG(dev, "gmidi_in_trigger %d\n", up); dev->in_port.active = up; @@ -1054,7 +1036,7 @@ static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up) static int gmidi_out_open(struct snd_rawmidi_substream *substream) { - struct gmidi_device* dev = substream->rmidi->private_data; + struct gmidi_device *dev = substream->rmidi->private_data; VDBG(dev, "gmidi_out_open\n"); dev->out_substream = substream; @@ -1063,13 +1045,15 @@ static int gmidi_out_open(struct snd_rawmidi_substream *substream) static int gmidi_out_close(struct snd_rawmidi_substream *substream) { + struct gmidi_device *dev = substream->rmidi->private_data; + VDBG(dev, "gmidi_out_close\n"); return 0; } static void gmidi_out_trigger(struct snd_rawmidi_substream *substream, int up) { - struct gmidi_device* dev = substream->rmidi->private_data; + struct gmidi_device *dev = substream->rmidi->private_data; VDBG(dev, "gmidi_out_trigger %d\n", up); if (up) { -- cgit v1.2.3-70-g09d2 From 51a0e85cd9b47e2e6332b40ea486cc1659d8a3ec Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 2 Aug 2007 00:02:47 -0700 Subject: USB: gadget: serial gadget cleanups Clean up the serial gadget, using newer APIs and conventions: - gadget_is_dualspeed() and gadget_is_otg() ... #ifdef removal - Remove many now-needless #includes - Use the DEBUG and VERBOSE_DEBUG conventions; turned up a bug in the original debug messaging - Various whitespace fixes. This gave only a minor object code shrinkage, but the source looks much cleaner in various places. Signed-off-by: David Brownell Cc: Al Borchers Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/serial.c | 166 +++++++++++++++++++------------------------- 1 file changed, 73 insertions(+), 93 deletions(-) diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index ce4d2e09633..afdf71f76f7 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -17,30 +17,11 @@ * */ -#include #include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include #include #include #include -#include - -#include -#include -#include -#include -#include -#include #include #include @@ -89,30 +70,29 @@ #define GS_DEFAULT_PARITY USB_CDC_NO_PARITY #define GS_DEFAULT_CHAR_FORMAT USB_CDC_1_STOP_BITS -/* select highspeed/fullspeed, hiding highspeed if not configured */ -#ifdef CONFIG_USB_GADGET_DUALSPEED -#define GS_SPEED_SELECT(is_hs,hs,fs) ((is_hs) ? (hs) : (fs)) -#else -#define GS_SPEED_SELECT(is_hs,hs,fs) (fs) -#endif /* CONFIG_USB_GADGET_DUALSPEED */ +/* maxpacket and other transfer characteristics vary by speed. */ +static inline struct usb_endpoint_descriptor * +choose_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs, + struct usb_endpoint_descriptor *fs) +{ + if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + return hs; + return fs; +} + /* debug settings */ -#ifdef GS_DEBUG +#ifdef DEBUG static int debug = 1; +#else +#define debug 0 +#endif #define gs_debug(format, arg...) \ do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0) #define gs_debug_level(level, format, arg...) \ do { if (debug>=level) printk(KERN_DEBUG format, ## arg); } while(0) -#else - -#define gs_debug(format, arg...) \ - do { } while(0) -#define gs_debug_level(level, format, arg...) \ - do { } while(0) - -#endif /* GS_DEBUG */ /* Thanks to NetChip Technologies for donating this product ID. * @@ -147,10 +127,10 @@ struct gs_req_entry { /* the port structure holds info for each port, one for each minor number */ struct gs_port { - struct gs_dev *port_dev; /* pointer to device struct */ + struct gs_dev *port_dev; /* pointer to device struct */ struct tty_struct *port_tty; /* pointer to tty struct */ spinlock_t port_lock; - int port_num; + int port_num; int port_open_count; int port_in_use; /* open/close in progress */ wait_queue_head_t port_write_wait;/* waiting to write */ @@ -188,7 +168,7 @@ static void __exit gs_module_exit(void); /* tty driver */ static int gs_open(struct tty_struct *tty, struct file *file); static void gs_close(struct tty_struct *tty, struct file *file); -static int gs_write(struct tty_struct *tty, +static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count); static void gs_put_char(struct tty_struct *tty, unsigned char ch); static void gs_flush_chars(struct tty_struct *tty); @@ -222,7 +202,7 @@ static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req); static void gs_disconnect(struct usb_gadget *gadget); static int gs_set_config(struct gs_dev *dev, unsigned config); static void gs_reset_config(struct gs_dev *dev); -static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, +static int gs_build_config_buf(u8 *buf, struct usb_gadget *g, u8 type, unsigned int index, int is_otg); static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len, @@ -415,18 +395,18 @@ static const struct usb_cdc_header_desc gs_header_desc = { }; static const struct usb_cdc_call_mgmt_descriptor gs_call_mgmt_descriptor = { - .bLength = sizeof(gs_call_mgmt_descriptor), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE, - .bmCapabilities = 0, - .bDataInterface = 1, /* index of data interface */ + .bLength = sizeof(gs_call_mgmt_descriptor), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE, + .bmCapabilities = 0, + .bDataInterface = 1, /* index of data interface */ }; static struct usb_cdc_acm_descriptor gs_acm_descriptor = { - .bLength = sizeof(gs_acm_descriptor), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_ACM_TYPE, - .bmCapabilities = 0, + .bLength = sizeof(gs_acm_descriptor), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_ACM_TYPE, + .bmCapabilities = 0, }; static const struct usb_cdc_union_desc gs_union_desc = { @@ -436,7 +416,7 @@ static const struct usb_cdc_union_desc gs_union_desc = { .bMasterInterface0 = 0, /* index of control interface */ .bSlaveInterface0 = 1, /* index of data interface */ }; - + static struct usb_endpoint_descriptor gs_fullspeed_notify_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -482,7 +462,6 @@ static const struct usb_descriptor_header *gs_acm_fullspeed_function[] = { NULL, }; -#ifdef CONFIG_USB_GADGET_DUALSPEED static struct usb_endpoint_descriptor gs_highspeed_notify_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -536,15 +515,13 @@ static const struct usb_descriptor_header *gs_acm_highspeed_function[] = { NULL, }; -#endif /* CONFIG_USB_GADGET_DUALSPEED */ - /* Module */ MODULE_DESCRIPTION(GS_LONG_NAME); MODULE_AUTHOR("Al Borchers"); MODULE_LICENSE("GPL"); -#ifdef GS_DEBUG +#ifdef DEBUG module_param(debug, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on"); #endif @@ -915,7 +892,8 @@ static void gs_put_char(struct tty_struct *tty, unsigned char ch) return; } - gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p, %p, %p\n", port->port_num, tty, ch, __builtin_return_address(0), __builtin_return_address(1), __builtin_return_address(2)); + gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p\n", + port->port_num, tty, ch, __builtin_return_address(0)); spin_lock_irqsave(&port->port_lock, flags); @@ -1116,7 +1094,11 @@ static int gs_send(struct gs_dev *dev) len = gs_send_packet(dev, req->buf, ep->maxpacket); if (len > 0) { -gs_debug_level(3, "gs_send: len=%d, 0x%2.2x 0x%2.2x 0x%2.2x ...\n", len, *((unsigned char *)req->buf), *((unsigned char *)req->buf+1), *((unsigned char *)req->buf+2)); + gs_debug_level(3, "gs_send: len=%d, 0x%2.2x " + "0x%2.2x 0x%2.2x ...\n", len, + *((unsigned char *)req->buf), + *((unsigned char *)req->buf+1), + *((unsigned char *)req->buf+2)); list_del(&req_entry->re_entry); req->length = len; spin_unlock_irqrestore(&dev->dev_lock, flags); @@ -1269,7 +1251,7 @@ static void gs_read_complete(struct usb_ep *ep, struct usb_request *req) switch(req->status) { case 0: - /* normal completion */ + /* normal completion */ gs_recv_packet(dev, req->buf, req->actual); requeue: req->length = ep->maxpacket; @@ -1406,23 +1388,24 @@ static int __init gs_bind(struct usb_gadget *gadget) ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC; gs_device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; -#ifdef CONFIG_USB_GADGET_DUALSPEED - gs_qualifier_desc.bDeviceClass = use_acm - ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC; - /* assume ep0 uses the same packet size for both speeds */ - gs_qualifier_desc.bMaxPacketSize0 = gs_device_desc.bMaxPacketSize0; - /* assume endpoints are dual-speed */ - gs_highspeed_notify_desc.bEndpointAddress = - gs_fullspeed_notify_desc.bEndpointAddress; - gs_highspeed_in_desc.bEndpointAddress = - gs_fullspeed_in_desc.bEndpointAddress; - gs_highspeed_out_desc.bEndpointAddress = - gs_fullspeed_out_desc.bEndpointAddress; -#endif /* CONFIG_USB_GADGET_DUALSPEED */ + if (gadget_is_dualspeed(gadget)) { + gs_qualifier_desc.bDeviceClass = use_acm + ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC; + /* assume ep0 uses the same packet size for both speeds */ + gs_qualifier_desc.bMaxPacketSize0 = + gs_device_desc.bMaxPacketSize0; + /* assume endpoints are dual-speed */ + gs_highspeed_notify_desc.bEndpointAddress = + gs_fullspeed_notify_desc.bEndpointAddress; + gs_highspeed_in_desc.bEndpointAddress = + gs_fullspeed_in_desc.bEndpointAddress; + gs_highspeed_out_desc.bEndpointAddress = + gs_fullspeed_out_desc.bEndpointAddress; + } usb_gadget_set_selfpowered(gadget); - if (gadget->is_otg) { + if (gadget_is_otg(gadget)) { gs_otg_descriptor.bmAttributes |= USB_OTG_HNP, gs_bulk_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP; gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP; @@ -1570,9 +1553,8 @@ static int gs_setup_standard(struct usb_gadget *gadget, memcpy(req->buf, &gs_device_desc, ret); break; -#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; ret = min(wLength, (u16)sizeof(struct usb_qualifier_descriptor)); @@ -1580,14 +1562,13 @@ static int gs_setup_standard(struct usb_gadget *gadget, break; case USB_DT_OTHER_SPEED_CONFIG: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; /* fall through */ -#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: - ret = gs_build_config_buf(req->buf, gadget->speed, + ret = gs_build_config_buf(req->buf, gadget, wValue >> 8, wValue & 0xff, - gadget->is_otg); + gadget_is_otg(gadget)); if (ret >= 0) ret = min(wLength, (u16)ret); break; @@ -1827,8 +1808,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) if (EP_NOTIFY_NAME && strcmp(ep->name, EP_NOTIFY_NAME) == 0) { - ep_desc = GS_SPEED_SELECT( - gadget->speed == USB_SPEED_HIGH, + ep_desc = choose_ep_desc(gadget, &gs_highspeed_notify_desc, &gs_fullspeed_notify_desc); ret = usb_ep_enable(ep,ep_desc); @@ -1844,9 +1824,8 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) } else if (strcmp(ep->name, EP_IN_NAME) == 0) { - ep_desc = GS_SPEED_SELECT( - gadget->speed == USB_SPEED_HIGH, - &gs_highspeed_in_desc, + ep_desc = choose_ep_desc(gadget, + &gs_highspeed_in_desc, &gs_fullspeed_in_desc); ret = usb_ep_enable(ep,ep_desc); if (ret == 0) { @@ -1861,8 +1840,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) } else if (strcmp(ep->name, EP_OUT_NAME) == 0) { - ep_desc = GS_SPEED_SELECT( - gadget->speed == USB_SPEED_HIGH, + ep_desc = choose_ep_desc(gadget, &gs_highspeed_out_desc, &gs_fullspeed_out_desc); ret = usb_ep_enable(ep,ep_desc); @@ -1981,11 +1959,11 @@ static void gs_reset_config(struct gs_dev *dev) * Builds the config descriptors in the given buffer and returns the * length, or a negative error number. */ -static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, +static int gs_build_config_buf(u8 *buf, struct usb_gadget *g, u8 type, unsigned int index, int is_otg) { int len; - int high_speed; + int high_speed = 0; const struct usb_config_descriptor *config_desc; const struct usb_descriptor_header **function; @@ -1993,20 +1971,22 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, return -EINVAL; /* other speed switches high and full speed */ - high_speed = (speed == USB_SPEED_HIGH); - if (type == USB_DT_OTHER_SPEED_CONFIG) - high_speed = !high_speed; + if (gadget_is_dualspeed(g)) { + high_speed = (g->speed == USB_SPEED_HIGH); + if (type == USB_DT_OTHER_SPEED_CONFIG) + high_speed = !high_speed; + } if (use_acm) { config_desc = &gs_acm_config_desc; - function = GS_SPEED_SELECT(high_speed, - gs_acm_highspeed_function, - gs_acm_fullspeed_function); + function = high_speed + ? gs_acm_highspeed_function + : gs_acm_fullspeed_function; } else { config_desc = &gs_bulk_config_desc; - function = GS_SPEED_SELECT(high_speed, - gs_bulk_highspeed_function, - gs_bulk_fullspeed_function); + function = high_speed + ? gs_bulk_highspeed_function + : gs_bulk_fullspeed_function; } /* for now, don't advertise srp-only devices */ -- cgit v1.2.3-70-g09d2 From 2e806f67cc570d25395469a0ded0df8ffbd4d82f Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 2 Aug 2007 00:03:39 -0700 Subject: USB: gadget: file storage gadget cleanups Clean up the file storage gadget, using newer APIs and conventions: - gadget_is_dualspeed() and gadget_is_otg() ... #ifdef removal - Remove many now-needless #includes - Use the DEBUG (from Kconfig+Makefile) and VERBOSE_DEBUG conventions. - Remove some "sparse" warnings (it still dislikes the __user annotations) This gave only a minor object code shrinkage. Signed-off-by: David Brownell Cc: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/file_storage.c | 118 +++++++++++++++----------------------- 1 file changed, 45 insertions(+), 73 deletions(-) diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 965ad7bec7b..0019116ee41 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -217,17 +217,11 @@ */ -#undef DEBUG -#undef VERBOSE +/* #define VERBOSE_DEBUG */ #undef DUMP_MSGS -#include -#include - -#include #include -#include #include #include #include @@ -235,18 +229,10 @@ #include #include #include -#include -#include #include #include #include -#include -#include -#include -#include #include -#include -#include #include #include #include @@ -289,57 +275,51 @@ MODULE_LICENSE("Dual BSD/GPL"); /*-------------------------------------------------------------------------*/ -#define xprintk(f,level,fmt,args...) \ - dev_printk(level , &(f)->gadget->dev , fmt , ## args) #define yprintk(l,level,fmt,args...) \ dev_printk(level , &(l)->dev , fmt , ## args) #ifdef DEBUG -#define DBG(fsg,fmt,args...) \ - xprintk(fsg , KERN_DEBUG , fmt , ## args) #define LDBG(lun,fmt,args...) \ yprintk(lun , KERN_DEBUG , fmt , ## args) #define MDBG(fmt,args...) \ printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args) #else -#define DBG(fsg,fmt,args...) \ - do { } while (0) #define LDBG(lun,fmt,args...) \ do { } while (0) #define MDBG(fmt,args...) \ do { } while (0) -#undef VERBOSE +#undef VERBOSE_DEBUG #undef DUMP_MSGS #endif /* DEBUG */ -#ifdef VERBOSE -#define VDBG DBG +#ifdef VERBOSE_DEBUG #define VLDBG LDBG #else -#define VDBG(fsg,fmt,args...) \ - do { } while (0) #define VLDBG(lun,fmt,args...) \ do { } while (0) -#endif /* VERBOSE */ +#endif /* VERBOSE_DEBUG */ -#define ERROR(fsg,fmt,args...) \ - xprintk(fsg , KERN_ERR , fmt , ## args) #define LERROR(lun,fmt,args...) \ yprintk(lun , KERN_ERR , fmt , ## args) - -#define WARN(fsg,fmt,args...) \ - xprintk(fsg , KERN_WARNING , fmt , ## args) #define LWARN(lun,fmt,args...) \ yprintk(lun , KERN_WARNING , fmt , ## args) - -#define INFO(fsg,fmt,args...) \ - xprintk(fsg , KERN_INFO , fmt , ## args) #define LINFO(lun,fmt,args...) \ yprintk(lun , KERN_INFO , fmt , ## args) #define MINFO(fmt,args...) \ printk(KERN_INFO DRIVER_NAME ": " fmt , ## args) +#define DBG(d, fmt, args...) \ + dev_dbg(&(d)->gadget->dev , fmt , ## args) +#define VDBG(d, fmt, args...) \ + dev_vdbg(&(d)->gadget->dev , fmt , ## args) +#define ERROR(d, fmt, args...) \ + dev_err(&(d)->gadget->dev , fmt , ## args) +#define WARN(d, fmt, args...) \ + dev_warn(&(d)->gadget->dev , fmt , ## args) +#define INFO(d, fmt, args...) \ + dev_info(&(d)->gadget->dev , fmt , ## args) + /*-------------------------------------------------------------------------*/ @@ -350,8 +330,8 @@ MODULE_LICENSE("Dual BSD/GPL"); static struct { char *file[MAX_LUNS]; int ro[MAX_LUNS]; - int num_filenames; - int num_ros; + unsigned int num_filenames; + unsigned int num_ros; unsigned int nluns; int removable; @@ -950,8 +930,6 @@ static const struct usb_descriptor_header *fs_function[] = { #define FS_FUNCTION_PRE_EP_ENTRIES 2 -#ifdef CONFIG_USB_GADGET_DUALSPEED - /* * USB 2.0 devices need to expose both high speed and full speed * descriptors, unless they only run at full speed. @@ -1014,14 +992,14 @@ static const struct usb_descriptor_header *hs_function[] = { #define HS_FUNCTION_PRE_EP_ENTRIES 2 /* Maxpacket and other transfer characteristics vary by speed. */ -#define ep_desc(g,fs,hs) (((g)->speed==USB_SPEED_HIGH) ? (hs) : (fs)) - -#else - -/* If there's no high speed support, always use the full-speed descriptor. */ -#define ep_desc(g,fs,hs) fs - -#endif /* !CONFIG_USB_GADGET_DUALSPEED */ +static inline struct usb_endpoint_descriptor * +ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs, + struct usb_endpoint_descriptor *hs) +{ + if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + return hs; + return fs; +} /* The CBI specification limits the serial string to 12 uppercase hexadecimal @@ -1053,26 +1031,22 @@ static struct usb_gadget_strings stringtab = { static int populate_config_buf(struct usb_gadget *gadget, u8 *buf, u8 type, unsigned index) { -#ifdef CONFIG_USB_GADGET_DUALSPEED enum usb_device_speed speed = gadget->speed; -#endif int len; const struct usb_descriptor_header **function; if (index > 0) return -EINVAL; -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (type == USB_DT_OTHER_SPEED_CONFIG) + if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG) speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed; - if (speed == USB_SPEED_HIGH) + if (gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH) function = hs_function; else -#endif function = fs_function; /* for now, don't advertise srp-only devices */ - if (!gadget->is_otg) + if (!gadget_is_otg(gadget)) function++; len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function); @@ -1394,10 +1368,9 @@ static int standard_setup_req(struct fsg_dev *fsg, value = sizeof device_desc; memcpy(req->buf, &device_desc, value); break; -#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: VDBG(fsg, "get device qualifier\n"); - if (!fsg->gadget->is_dualspeed) + if (!gadget_is_dualspeed(fsg->gadget)) break; value = sizeof dev_qualifier; memcpy(req->buf, &dev_qualifier, value); @@ -1405,15 +1378,12 @@ static int standard_setup_req(struct fsg_dev *fsg, case USB_DT_OTHER_SPEED_CONFIG: VDBG(fsg, "get other-speed config descriptor\n"); - if (!fsg->gadget->is_dualspeed) + if (!gadget_is_dualspeed(fsg->gadget)) break; goto get_config; -#endif case USB_DT_CONFIG: VDBG(fsg, "get configuration descriptor\n"); -#ifdef CONFIG_USB_GADGET_DUALSPEED - get_config: -#endif +get_config: value = populate_config_buf(fsg->gadget, req->buf, w_value >> 8, @@ -3859,7 +3829,7 @@ static int __init fsg_bind(struct usb_gadget *gadget) /* Find out how many LUNs there should be */ i = mod_data.nluns; if (i == 0) - i = max(mod_data.num_filenames, 1); + i = max(mod_data.num_filenames, 1u); if (i > MAX_LUNS) { ERROR(fsg, "invalid number of LUNs: %d\n", i); rc = -EINVAL; @@ -3944,21 +3914,23 @@ static int __init fsg_bind(struct usb_gadget *gadget) intf_desc.bInterfaceProtocol = mod_data.transport_type; fs_function[i + FS_FUNCTION_PRE_EP_ENTRIES] = NULL; -#ifdef CONFIG_USB_GADGET_DUALSPEED - hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL; + if (gadget_is_dualspeed(gadget)) { + hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL; - /* Assume ep0 uses the same maxpacket value for both speeds */ - dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; + /* Assume ep0 uses the same maxpacket value for both speeds */ + dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; - /* Assume that all endpoint addresses are the same for both speeds */ - hs_bulk_in_desc.bEndpointAddress = fs_bulk_in_desc.bEndpointAddress; - hs_bulk_out_desc.bEndpointAddress = fs_bulk_out_desc.bEndpointAddress; - hs_intr_in_desc.bEndpointAddress = fs_intr_in_desc.bEndpointAddress; -#endif + /* Assume endpoint addresses are the same for both speeds */ + hs_bulk_in_desc.bEndpointAddress = + fs_bulk_in_desc.bEndpointAddress; + hs_bulk_out_desc.bEndpointAddress = + fs_bulk_out_desc.bEndpointAddress; + hs_intr_in_desc.bEndpointAddress = + fs_intr_in_desc.bEndpointAddress; + } - if (gadget->is_otg) { + if (gadget_is_otg(gadget)) otg_desc.bmAttributes |= USB_OTG_HNP; - } rc = -ENOMEM; -- cgit v1.2.3-70-g09d2 From ca2bdf4bcc91818f03e009b87c348609c2578d1d Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 2 Aug 2007 12:20:05 -0700 Subject: USB: gadget: gadget zero cleanups Clean up gadget zero, using newer APIs and conventions: - gadget_is_dualspeed() and gadget_is_otg() ... #ifdef removal - Remove many now-needless #includes - Use the VERBOSE_DEBUG convention - Some whitespace fixes. - A few comment updates - Plus a few other small cleanups: don't pass gfp_t around when it's always going to be GFP_ATOMIC, and do static init of serial number. Also go to straight GPL; there's no real point in dual licensing this stuff any more. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/zero.c | 237 +++++++++++++++++++--------------------------- 1 file changed, 96 insertions(+), 141 deletions(-) diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index fcfe869acb9..ff540879ce3 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -1,38 +1,22 @@ /* * zero.c -- Gadget Zero, for USB development * - * Copyright (C) 2003-2004 David Brownell + * Copyright (C) 2003-2007 David Brownell * All rights reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation, either version 2 of that License or (at your option) any - * later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -57,30 +41,18 @@ * Many drivers will only have one configuration, letting them be much * simpler if they also don't support high speed operation (like this * driver does). + * + * Why is *this* driver using two configurations, rather than setting up + * two interfaces with different functions? To help verify that multiple + * configuration infrastucture is working correctly; also, so that it can + * work with low capability USB controllers without four bulk endpoints. */ -#define DEBUG 1 -// #define VERBOSE +/* #define VERBOSE_DEBUG */ -#include #include -#include -#include -#include -#include -#include -#include -#include -#include #include #include -#include - -#include -#include -#include -#include -#include #include #include @@ -90,7 +62,7 @@ /*-------------------------------------------------------------------------*/ -#define DRIVER_VERSION "St Patrick's Day 2004" +#define DRIVER_VERSION "Lughnasadh, 2007" static const char shortname [] = "zero"; static const char longname [] = "Gadget Zero"; @@ -131,30 +103,16 @@ struct zero_dev { struct timer_list resume; }; -#define xprintk(d,level,fmt,args...) \ - dev_printk(level , &(d)->gadget->dev , fmt , ## args) - -#ifdef DEBUG -#define DBG(dev,fmt,args...) \ - xprintk(dev , KERN_DEBUG , fmt , ## args) -#else -#define DBG(dev,fmt,args...) \ - do { } while (0) -#endif /* DEBUG */ - -#ifdef VERBOSE -#define VDBG DBG -#else -#define VDBG(dev,fmt,args...) \ - do { } while (0) -#endif /* VERBOSE */ - -#define ERROR(dev,fmt,args...) \ - xprintk(dev , KERN_ERR , fmt , ## args) -#define WARN(dev,fmt,args...) \ - xprintk(dev , KERN_WARNING , fmt , ## args) -#define INFO(dev,fmt,args...) \ - xprintk(dev , KERN_INFO , fmt , ## args) +#define DBG(d, fmt, args...) \ + dev_dbg(&(d)->gadget->dev , fmt , ## args) +#define VDBG(d, fmt, args...) \ + dev_vdbg(&(d)->gadget->dev , fmt , ## args) +#define ERROR(d, fmt, args...) \ + dev_err(&(d)->gadget->dev , fmt , ## args) +#define WARN(d, fmt, args...) \ + dev_warn(&(d)->gadget->dev , fmt , ## args) +#define INFO(d, fmt, args...) \ + dev_info(&(d)->gadget->dev , fmt , ## args) /*-------------------------------------------------------------------------*/ @@ -326,8 +284,6 @@ static const struct usb_descriptor_header *fs_loopback_function [] = { NULL, }; -#ifdef CONFIG_USB_GADGET_DUALSPEED - /* * usb 2.0 devices need to expose both high speed and full speed * descriptors, unless they only run at full speed. @@ -383,17 +339,20 @@ static const struct usb_descriptor_header *hs_loopback_function [] = { }; /* maxpacket and other transfer characteristics vary by speed. */ -#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs)) - -#else +static inline struct usb_endpoint_descriptor * +ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs, + struct usb_endpoint_descriptor *fs) +{ + if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + return hs; + return fs; +} -/* if there's no high speed support, maxpacket doesn't change. */ -#define ep_desc(g,hs,fs) fs +static char manufacturer[50]; -#endif /* !CONFIG_USB_GADGET_DUALSPEED */ +/* default serial number takes at least two packets */ +static char serial[] = "0123456789.0123456789.0123456789"; -static char manufacturer [50]; -static char serial [40]; /* static strings, in UTF-8 */ static struct usb_string strings [] = { @@ -435,30 +394,29 @@ config_buf (struct usb_gadget *gadget, int is_source_sink; int len; const struct usb_descriptor_header **function; -#ifdef CONFIG_USB_GADGET_DUALSPEED - int hs = (gadget->speed == USB_SPEED_HIGH); -#endif + int hs = 0; /* two configurations will always be index 0 and index 1 */ if (index > 1) return -EINVAL; is_source_sink = loopdefault ? (index == 1) : (index == 0); -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (type == USB_DT_OTHER_SPEED_CONFIG) - hs = !hs; + if (gadget_is_dualspeed(gadget)) { + hs = (gadget->speed == USB_SPEED_HIGH); + if (type == USB_DT_OTHER_SPEED_CONFIG) + hs = !hs; + } if (hs) function = is_source_sink ? hs_source_sink_function : hs_loopback_function; else -#endif function = is_source_sink ? fs_source_sink_function : fs_loopback_function; /* for now, don't advertise srp-only devices */ - if (!gadget->is_otg) + if (!gadget_is_otg(gadget)) function++; len = usb_gadget_config_buf (is_source_sink @@ -498,6 +456,19 @@ static void free_ep_req (struct usb_ep *ep, struct usb_request *req) /*-------------------------------------------------------------------------*/ +/* + * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripherals, + * this just sinks bulk packets OUT to the peripheral and sources them IN + * to the host, optionally with specific data patterns. + * + * In terms of control messaging, this supports all the standard requests + * plus two that support control-OUT tests. + * + * Note that because this doesn't queue more than one request at a time, + * some other function must be used to test queueing logic. The network + * link (g_ether) is probably the best option for that. + */ + /* optionally require specific source/sink data patterns */ static int @@ -534,12 +505,7 @@ check_read_data ( return 0; } -static void -reinit_write_data ( - struct zero_dev *dev, - struct usb_ep *ep, - struct usb_request *req -) +static void reinit_write_data(struct usb_ep *ep, struct usb_request *req) { unsigned i; u8 *buf = req->buf; @@ -566,16 +532,16 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req) switch (status) { - case 0: /* normal completion? */ + case 0: /* normal completion? */ if (ep == dev->out_ep) { check_read_data (dev, ep, req); memset (req->buf, 0x55, req->length); } else - reinit_write_data (dev, ep, req); + reinit_write_data(ep, req); break; /* this endpoint is normally active while we're configured */ - case -ECONNABORTED: /* hardware forced ep reset */ + case -ECONNABORTED: /* hardware forced ep reset */ case -ECONNRESET: /* request dequeued */ case -ESHUTDOWN: /* disconnect from host */ VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status, @@ -607,8 +573,7 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req) } } -static struct usb_request * -source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags) +static struct usb_request *source_sink_start_ep(struct usb_ep *ep) { struct usb_request *req; int status; @@ -621,11 +586,11 @@ source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags) req->complete = source_sink_complete; if (strcmp (ep->name, EP_IN_NAME) == 0) - reinit_write_data (ep->driver_data, ep, req); + reinit_write_data(ep, req); else memset (req->buf, 0x55, req->length); - status = usb_ep_queue (ep, req, gfp_flags); + status = usb_ep_queue(ep, req, GFP_ATOMIC); if (status) { struct zero_dev *dev = ep->driver_data; @@ -637,8 +602,7 @@ source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags) return req; } -static int -set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags) +static int set_source_sink_config(struct zero_dev *dev) { int result = 0; struct usb_ep *ep; @@ -653,8 +617,7 @@ set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags) result = usb_ep_enable (ep, d); if (result == 0) { ep->driver_data = dev; - if (source_sink_start_ep(ep, gfp_flags) - != NULL) { + if (source_sink_start_ep(ep) != NULL) { dev->in_ep = ep; continue; } @@ -668,8 +631,7 @@ set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags) result = usb_ep_enable (ep, d); if (result == 0) { ep->driver_data = dev; - if (source_sink_start_ep(ep, gfp_flags) - != NULL) { + if (source_sink_start_ep(ep) != NULL) { dev->out_ep = ep; continue; } @@ -701,7 +663,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req) switch (status) { - case 0: /* normal completion? */ + case 0: /* normal completion? */ if (ep == dev->out_ep) { /* loop this OUT packet back IN to the host */ req->zero = (req->actual < req->length); @@ -735,7 +697,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req) * rely on the hardware driver to clean up on disconnect or * endpoint disable. */ - case -ECONNABORTED: /* hardware forced ep reset */ + case -ECONNABORTED: /* hardware forced ep reset */ case -ECONNRESET: /* request dequeued */ case -ESHUTDOWN: /* disconnect from host */ free_ep_req (ep, req); @@ -743,8 +705,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req) } } -static int -set_loopback_config (struct zero_dev *dev, gfp_t gfp_flags) +static int set_loopback_config(struct zero_dev *dev) { int result = 0; struct usb_ep *ep; @@ -844,8 +805,7 @@ static void zero_reset_config (struct zero_dev *dev) * code can do, perhaps by disallowing more than one configuration or * by limiting configuration choices (like the pxa2xx). */ -static int -zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags) +static int zero_set_config(struct zero_dev *dev, unsigned number) { int result = 0; struct usb_gadget *gadget = dev->gadget; @@ -855,17 +815,17 @@ zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags) if (gadget_is_sa1100 (gadget) && dev->config) { /* tx fifo is full, but we can't clear it...*/ - INFO (dev, "can't change configurations\n"); + ERROR(dev, "can't change configurations\n"); return -ESPIPE; } zero_reset_config (dev); switch (number) { case CONFIG_SOURCE_SINK: - result = set_source_sink_config (dev, gfp_flags); + result = set_source_sink_config(dev); break; case CONFIG_LOOPBACK: - result = set_loopback_config (dev, gfp_flags); + result = set_loopback_config(dev); break; default: result = -EINVAL; @@ -885,7 +845,7 @@ zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags) case USB_SPEED_LOW: speed = "low"; break; case USB_SPEED_FULL: speed = "full"; break; case USB_SPEED_HIGH: speed = "high"; break; - default: speed = "?"; break; + default: speed = "?"; break; } dev->config = number; @@ -938,19 +898,17 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) value = min (w_length, (u16) sizeof device_desc); memcpy (req->buf, &device_desc, value); break; -#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; value = min (w_length, (u16) sizeof dev_qualifier); memcpy (req->buf, &dev_qualifier, value); break; case USB_DT_OTHER_SPEED_CONFIG: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; // FALLTHROUGH -#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: value = config_buf (gadget, req->buf, w_value >> 8, @@ -984,7 +942,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) else VDBG (dev, "HNP inactive\n"); spin_lock (&dev->lock); - value = zero_set_config (dev, w_value, GFP_ATOMIC); + value = zero_set_config(dev, w_value); spin_unlock (&dev->lock); break; case USB_REQ_GET_CONFIGURATION: @@ -1013,7 +971,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) * use this "reset the config" shortcut. */ zero_reset_config (dev); - zero_set_config (dev, config, GFP_ATOMIC); + zero_set_config(dev, config); value = 0; } spin_unlock (&dev->lock); @@ -1163,7 +1121,7 @@ autoconf_fail: } EP_IN_NAME = ep->name; ep->driver_data = ep; /* claim */ - + ep = usb_ep_autoconfig (gadget, &fs_sink_desc); if (!ep) goto autoconf_fail; @@ -1207,16 +1165,18 @@ autoconf_fail: device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; -#ifdef CONFIG_USB_GADGET_DUALSPEED - /* assume ep0 uses the same value for both speeds ... */ - dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; + if (gadget_is_dualspeed(gadget)) { + /* assume ep0 uses the same value for both speeds ... */ + dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; - /* and that all endpoints are dual-speed */ - hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; - hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; -#endif + /* and that all endpoints are dual-speed */ + hs_source_desc.bEndpointAddress = + fs_source_desc.bEndpointAddress; + hs_sink_desc.bEndpointAddress = + fs_sink_desc.bEndpointAddress; + } - if (gadget->is_otg) { + if (gadget_is_otg(gadget)) { otg_descriptor.bmAttributes |= USB_OTG_HNP, source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; @@ -1294,23 +1254,18 @@ static struct usb_gadget_driver zero_driver = { .suspend = zero_suspend, .resume = zero_resume, - .driver = { + .driver = { .name = (char *) shortname, .owner = THIS_MODULE, }, }; -MODULE_AUTHOR ("David Brownell"); -MODULE_LICENSE ("Dual BSD/GPL"); +MODULE_AUTHOR("David Brownell"); +MODULE_LICENSE("GPL"); static int __init init (void) { - /* a real value would likely come through some id prom - * or module option. this one takes at least two packets. - */ - strlcpy (serial, "0123456789.0123456789.0123456789", sizeof serial); - return usb_gadget_register_driver (&zero_driver); } module_init (init); -- cgit v1.2.3-70-g09d2 From da04b7a42711c1d1d8d9fbc2565cdd83efcfee40 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:33:57 -0700 Subject: usb: introduce usb_device authorization bits This just modifies 'struct usb_device' to contain the 'authorized' bit. It also adds a 'wusb' bit. This is needed because nonauthorized (and thus non-authenticated) wusb devices will fail certain kind of simple requests (such as string descriptors). By knowing the device is WUSB, we just avoid them. Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- include/linux/usb.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/linux/usb.h b/include/linux/usb.h index a51f34e8057..92d63c6b6fc 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -346,6 +346,11 @@ struct usb_tt; * * Usbcore drivers should not set usbdev->state directly. Instead use * usb_set_device_state(). + * + * @authorized: (user space) policy determines if we authorize this + * device to be used or not. By default, wired USB + * devices are authorized. WUSB devices are not, until we + * authorize them from user space. FIXME -- complete doc */ struct usb_device { int devnum; /* Address on USB bus */ @@ -380,6 +385,8 @@ struct usb_device { unsigned discon_suspended:1; /* Disconnected while suspended */ unsigned have_langid:1; /* whether string_langid is valid */ + unsigned authorized:1; /* Policy has determined we can use it */ + unsigned wusb:1; /* Device is Wireless USB */ int string_langid; /* language ID for strings */ /* static strings from the device */ -- cgit v1.2.3-70-g09d2 From 5234ce1b02ae2574098ebe9839dcf241076a9367 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:33:58 -0700 Subject: usb: add the concept of default authorization to USB hosts This introduces /sys/bus/devices/usb*/authorized_default; it dictates what is going to be the default authorization state for devices connected to the host. User space can set that using the sysfs file. We hook to the root hub instead of to the device controller as it is quite easy to get to it in sysfs from the device structure (device 5-4.3 is usb5) vs. backtracking to the controller device. By default it is set to be 'authorized' (!0) for normal, wired USB devices and 'unauthorized' (0) for Wireless USB devices. As suggested by Adrian Bunk, make authorized_default static Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++- drivers/usb/core/hcd.h | 7 +++++ 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index eb212178826..875e2476c1f 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -679,6 +679,66 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) return 0; } + + +/* + * Show & store the current value of authorized_default + */ +static ssize_t usb_host_authorized_default_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct usb_device *rh_usb_dev = to_usb_device(dev); + struct usb_bus *usb_bus = rh_usb_dev->bus; + struct usb_hcd *usb_hcd; + + if (usb_bus == NULL) /* FIXME: not sure if this case is possible */ + return -ENODEV; + usb_hcd = bus_to_hcd(usb_bus); + return snprintf(buf, PAGE_SIZE, "%u\n", usb_hcd->authorized_default); +} + +static ssize_t usb_host_authorized_default_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t result; + unsigned val; + struct usb_device *rh_usb_dev = to_usb_device(dev); + struct usb_bus *usb_bus = rh_usb_dev->bus; + struct usb_hcd *usb_hcd; + + if (usb_bus == NULL) /* FIXME: not sure if this case is possible */ + return -ENODEV; + usb_hcd = bus_to_hcd(usb_bus); + result = sscanf(buf, "%u\n", &val); + if (result == 1) { + usb_hcd->authorized_default = val? 1 : 0; + result = size; + } + else + result = -EINVAL; + return result; +} + +static DEVICE_ATTR(authorized_default, 0644, + usb_host_authorized_default_show, + usb_host_authorized_default_store); + + +/* Group all the USB bus attributes */ +static struct attribute *usb_bus_attrs[] = { + &dev_attr_authorized_default.attr, + NULL, +}; + +static struct attribute_group usb_bus_attr_group = { + .name = NULL, /* we want them in the same directory */ + .attrs = usb_bus_attrs, +}; + + + /*-------------------------------------------------------------------------*/ static struct class *usb_host_class; @@ -1542,7 +1602,6 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, hcd->driver = driver; hcd->product_desc = (driver->product_desc) ? driver->product_desc : "USB Host Controller"; - return hcd; } EXPORT_SYMBOL (usb_create_hcd); @@ -1587,6 +1646,7 @@ int usb_add_hcd(struct usb_hcd *hcd, dev_info(hcd->self.controller, "%s\n", hcd->product_desc); + hcd->authorized_default = hcd->wireless? 0 : 1; set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); /* HC is in reset state, but accessible. Now do the one-time init, @@ -1663,10 +1723,20 @@ int usb_add_hcd(struct usb_hcd *hcd, if ((retval = register_root_hub(hcd)) != 0) goto err_register_root_hub; + retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group); + if (retval < 0) { + printk(KERN_ERR "Cannot register USB bus sysfs attributes: %d\n", + retval); + goto error_create_attr_group; + } if (hcd->uses_new_polling && hcd->poll_rh) usb_hcd_poll_rh_status(hcd); return retval; +error_create_attr_group: + mutex_lock(&usb_bus_list_lock); + usb_disconnect(&hcd->self.root_hub); + mutex_unlock(&usb_bus_list_lock); err_register_root_hub: hcd->driver->stop(hcd); err_hcd_driver_start: @@ -1708,6 +1778,7 @@ void usb_remove_hcd(struct usb_hcd *hcd) cancel_work_sync(&hcd->wakeup_work); #endif + sysfs_remove_group(&hcd->self.root_hub->dev.kobj, &usb_bus_attr_group); mutex_lock(&usb_bus_list_lock); usb_disconnect(&hcd->self.root_hub); mutex_unlock(&usb_bus_list_lock); diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index b5ebb73c233..8683142e70e 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -51,6 +51,12 @@ * * Since "struct usb_bus" is so thin, you can't share much code in it. * This framework is a layer over that, and should be more sharable. + * + * @authorized_default: Specifies if new devices are authorized to + * connect by default or they require explicit + * user space authorization; this bit is settable + * through /sys/class/usb_host/X/authorized_default. + * For the rest is RO, so we don't lock to r/w it. */ /*-------------------------------------------------------------------------*/ @@ -90,6 +96,7 @@ struct usb_hcd { unsigned poll_rh:1; /* poll for rh status? */ unsigned poll_pending:1; /* status has changed? */ unsigned wireless:1; /* Wireless USB HCD */ + unsigned authorized_default:1; int irq; /* irq allocated */ void __iomem *regs; /* device memory/io */ -- cgit v1.2.3-70-g09d2 From eb579f5811ddbc052c8d6b3bba38dd4e5148cf7b Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:33:59 -0700 Subject: usb: cleanup usb_register_bus() and hook up sysfs group This path cleans the exit paths of usb_register_bus() [to use a goto schema], maximum line length (keeping it under ~75). Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 875e2476c1f..a5a46a55376 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -792,27 +792,23 @@ static void usb_bus_init (struct usb_bus *bus) */ static int usb_register_bus(struct usb_bus *bus) { + int result = -E2BIG; int busnum; mutex_lock(&usb_bus_list_lock); busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1); - if (busnum < USB_MAXBUS) { - set_bit (busnum, busmap.busmap); - bus->busnum = busnum; - } else { + if (busnum >= USB_MAXBUS) { printk (KERN_ERR "%s: too many buses\n", usbcore_name); - mutex_unlock(&usb_bus_list_lock); - return -E2BIG; + goto error_find_busnum; } - + set_bit (busnum, busmap.busmap); + bus->busnum = busnum; bus->class_dev = class_device_create(usb_host_class, NULL, MKDEV(0,0), - bus->controller, "usb_host%d", busnum); - if (IS_ERR(bus->class_dev)) { - clear_bit(busnum, busmap.busmap); - mutex_unlock(&usb_bus_list_lock); - return PTR_ERR(bus->class_dev); - } - + bus->controller, "usb_host%d", + busnum); + result = PTR_ERR(bus->class_dev); + if (IS_ERR(bus->class_dev)) + goto error_create_class_dev; class_set_devdata(bus->class_dev, bus); /* Add it to the local list of buses */ @@ -821,8 +817,15 @@ static int usb_register_bus(struct usb_bus *bus) usb_notify_add_bus(bus); - dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum); + dev_info (bus->controller, "new USB bus registered, assigned bus " + "number %d\n", bus->busnum); return 0; + +error_create_class_dev: + clear_bit(busnum, busmap.busmap); +error_find_busnum: + mutex_unlock(&usb_bus_list_lock); + return result; } /** -- cgit v1.2.3-70-g09d2 From d7d07255d3f5607802b0af29e11448d18e9ed558 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:34:00 -0700 Subject: usb: initialize authorization and wusb bits in USB devices Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/usb.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 67e2e582e46..e5ff161776f 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -223,6 +223,15 @@ static void ksuspend_usb_cleanup(void) #endif /* CONFIG_PM */ + +/* Returns 1 if @usb_bus is WUSB, 0 otherwise */ +static unsigned usb_bus_is_wusb(struct usb_bus *bus) +{ + struct usb_hcd *hcd = container_of(bus, struct usb_hcd, self); + return hcd->wireless; +} + + /** * usb_alloc_dev - usb device constructor (usbcore-internal) * @parent: hub to which device is connected; null to allocate a root hub @@ -239,6 +248,8 @@ struct usb_device * usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) { struct usb_device *dev; + struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self); + unsigned root_hub = 0; dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) @@ -275,6 +286,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) dev->dev.parent = bus->controller; sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum); + root_hub = 1; } else { /* match any labeling on the hubs; it's one-based */ if (parent->devpath[0] == '0') @@ -301,6 +313,12 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work); dev->autosuspend_delay = usb_autosuspend_delay * HZ; #endif + if (root_hub) /* Root hub always ok [and always wired] */ + dev->authorized = 1; + else { + dev->authorized = usb_hcd->authorized_default; + dev->wusb = usb_bus_is_wusb(bus)? 1 : 0; + } return dev; } -- cgit v1.2.3-70-g09d2 From 16bbab2966309ae82cda3d378964c56096d4858c Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:34:01 -0700 Subject: usb: usb_set_configuration() obeys authorization Will refuse to configure a non-authorized device. Update: simplified if statement--thanks to Ragner Magalhaes for the heads up. Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index a26a7292b61..025ac0bd353 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1483,6 +1483,9 @@ static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev, * channels are available independently; and choosing between open * standard device protocols (like CDC) or proprietary ones. * + * Note that a non-authorized device (dev->authorized == 0) will only + * be put in unconfigured mode. + * * Note that USB has an additional level of device configurability, * associated with interfaces. That configurability is accessed using * usb_set_interface(). @@ -1504,7 +1507,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration) struct usb_interface **new_interfaces = NULL; int n, nintf; - if (configuration == -1) + if (dev->authorized == 0 || configuration == -1) configuration = 0; else { for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { -- cgit v1.2.3-70-g09d2 From 1145065cd0434b0fd5cd7c0efe0f1438fb154ed0 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:34:02 -0700 Subject: usb: usb_get_configuration() obeys authorization If called and the device is not authorized to be used, then we don't allow reading the configurations. Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/config.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index cb69aa1e02e..1a8edcee7f3 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -507,18 +507,30 @@ void usb_destroy_configuration(struct usb_device *dev) } -// hub-only!! ... and only in reset path, or usb_new_device() -// (used by real hubs and virtual root hubs) +/* + * Get the USB config descriptors, cache and parse'em + * + * hub-only!! ... and only in reset path, or usb_new_device() + * (used by real hubs and virtual root hubs) + * + * NOTE: if this is a WUSB device and is not authorized, we skip the + * whole thing. A non-authorized USB device has no + * configurations. + */ int usb_get_configuration(struct usb_device *dev) { struct device *ddev = &dev->dev; int ncfg = dev->descriptor.bNumConfigurations; - int result = -ENOMEM; + int result = 0; unsigned int cfgno, length; unsigned char *buffer; unsigned char *bigbuffer; struct usb_config_descriptor *desc; + cfgno = 0; + if (dev->authorized == 0) /* Not really an error */ + goto out_not_authorized; + result = -ENOMEM; if (ncfg > USB_MAXCONFIG) { dev_warn(ddev, "too many configurations: %d, " "using maximum allowed: %d\n", ncfg, USB_MAXCONFIG); @@ -545,14 +557,15 @@ int usb_get_configuration(struct usb_device *dev) goto err2; desc = (struct usb_config_descriptor *)buffer; - for (cfgno = 0; cfgno < ncfg; cfgno++) { + result = 0; + for (; cfgno < ncfg; cfgno++) { /* We grab just the first descriptor so we know how long * the whole configuration is */ result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, USB_DT_CONFIG_SIZE); if (result < 0) { dev_err(ddev, "unable to read config index %d " - "descriptor/%s\n", cfgno, "start"); + "descriptor/%s: %d\n", cfgno, "start", result); dev_err(ddev, "chopping to %d config(s)\n", cfgno); dev->descriptor.bNumConfigurations = cfgno; break; @@ -599,6 +612,7 @@ int usb_get_configuration(struct usb_device *dev) err: kfree(buffer); +out_not_authorized: dev->descriptor.bNumConfigurations = cfgno; err2: if (result == -ENOMEM) -- cgit v1.2.3-70-g09d2 From 72230abb21349cda54d6cce0d6fd325c023b958e Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:34:03 -0700 Subject: usb: usb_probe_interface() obeys authorization If called and the device is not authorized to be used, it won't configure the interface and print a message saying so. Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 63b1243a913..8da4801bb92 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -202,6 +202,11 @@ static int usb_probe_interface(struct device *dev) intf = to_usb_interface(dev); udev = interface_to_usbdev(intf); + if (udev->authorized == 0) { + dev_err(&intf->dev, "Device is not authorized for usage\n"); + return -ENODEV; + } + id = usb_match_id(intf, driver->id_table); if (!id) id = usb_match_dynamic_id(intf, driver); -- cgit v1.2.3-70-g09d2 From f8a374648b58e5cfa14447eca866aed14a4fbfa8 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:34:04 -0700 Subject: usb: usb_generic_probe() obeys authorization If called and the device is not authorized to be used, then we won't choose a configuration (as they are not a concept that exists for an unauthorized device). However, the device is added to the system. Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/generic.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index b2fc2b11525..20b095050a1 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -161,17 +161,20 @@ static int generic_probe(struct usb_device *udev) /* Choose and set the configuration. This registers the interfaces * with the driver core and lets interface drivers bind to them. */ - c = choose_configuration(udev); - if (c >= 0) { - err = usb_set_configuration(udev, c); - if (err) { - dev_err(&udev->dev, "can't set config #%d, error %d\n", + if (udev->authorized == 0) + dev_err(&udev->dev, "Device is not authorized for usage\n"); + else { + c = choose_configuration(udev); + if (c >= 0) { + err = usb_set_configuration(udev, c); + if (err) { + dev_err(&udev->dev, "can't set config #%d, error %d\n", c, err); - /* This need not be fatal. The user can try to - * set other configurations. */ + /* This need not be fatal. The user can try to + * set other configurations. */ + } } } - /* USB device state == configured ... usable */ usb_notify_add_device(udev); -- cgit v1.2.3-70-g09d2 From d9d16e8a92e385c9f57d2081b7aa737770a0a829 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:34:05 -0700 Subject: usb: split usb_new_device for clarity and refactoring This patch takes hub.c:usb_new_device() and splits it in three parts: - The actual actions of adding a new device (quirk detection, announcement and autoresume tracking) - Actual discovery and probing of the configuration and interfaces (split into __usb_configure_device()) - Configuration of the On-the-go parameters (split into __usb_configure_device_otg()). The fundamental reasons for doing this split are clarity (smaller functions are easier to maintain) and to allow part of the code to be reused when authorizing devices to connect. When a device is authorized connection, we need to run through the hoops we didn't run when it was connected but not authorized, which is basically parsing the configurations and probing them. usb_configure_device() will do that for us. Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 136 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 88 insertions(+), 48 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 34be27a6cbb..65d9ea1e6d7 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1220,54 +1220,14 @@ static inline void show_string(struct usb_device *udev, char *id, char *string) #endif /** - * usb_new_device - perform initial device setup (usbcore-internal) + * usb_configure_device_otg - FIXME (usbcore-internal) * @udev: newly addressed device (in ADDRESS state) * - * This is called with devices which have been enumerated, but not yet - * configured. The device descriptor is available, but not descriptors - * for any device configuration. The caller must have locked either - * the parent hub (if udev is a normal device) or else the - * usb_bus_list_lock (if udev is a root hub). The parent's pointer to - * udev has already been installed, but udev is not yet visible through - * sysfs or other filesystem code. - * - * It will return if the device is configured properly or not. Zero if - * the interface was registered with the driver core; else a negative - * errno value. - * - * This call is synchronous, and may not be used in an interrupt context. - * - * Only the hub driver or root-hub registrar should ever call this. + * Do configuration for On-The-Go devices */ -int usb_new_device(struct usb_device *udev) +static int usb_configure_device_otg(struct usb_device *udev) { - int err; - - /* Determine quirks */ - usb_detect_quirks(udev); - - err = usb_get_configuration(udev); - if (err < 0) { - dev_err(&udev->dev, "can't read configurations, error %d\n", - err); - goto fail; - } - - /* read the standard strings and cache them if present */ - udev->product = usb_cache_string(udev, udev->descriptor.iProduct); - udev->manufacturer = usb_cache_string(udev, - udev->descriptor.iManufacturer); - udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); - - /* Tell the world! */ - dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, " - "SerialNumber=%d\n", - udev->descriptor.iManufacturer, - udev->descriptor.iProduct, - udev->descriptor.iSerialNumber); - show_string(udev, "Product", udev->product); - show_string(udev, "Manufacturer", udev->manufacturer); - show_string(udev, "SerialNumber", udev->serial); + int err = 0; #ifdef CONFIG_USB_OTG /* @@ -1329,8 +1289,82 @@ int usb_new_device(struct usb_device *udev) err = -ENOTSUPP; goto fail; } +fail: #endif + return err; +} + +/** + * usb_configure_device - Detect and probe device intfs/otg (usbcore-internal) + * @udev: newly addressed device (in ADDRESS state) + * + * This is only called by usb_new_device() and usb_authorize_device() + * and FIXME -- all comments that apply to them apply here wrt to + * environment. + * + * If the device is WUSB and not authorized, we don't attempt to read + * the string descriptors, as they will be errored out by the device + * until it has been authorized. + */ +static int usb_configure_device(struct usb_device *udev) +{ + int err; + + if (udev->config == NULL) { + err = usb_get_configuration(udev); + if (err < 0) { + dev_err(&udev->dev, "can't read configurations, error %d\n", + err); + goto fail; + } + } + if (udev->wusb == 1 && udev->authorized == 0) { + udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL); + udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL); + udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL); + } + else { + /* read the standard strings and cache them if present */ + udev->product = usb_cache_string(udev, udev->descriptor.iProduct); + udev->manufacturer = usb_cache_string(udev, + udev->descriptor.iManufacturer); + udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); + } + err = usb_configure_device_otg(udev); +fail: + return err; +} + + +/** + * usb_new_device - perform initial device setup (usbcore-internal) + * @udev: newly addressed device (in ADDRESS state) + * + * This is called with devices which have been enumerated, but not yet + * configured. The device descriptor is available, but not descriptors + * for any device configuration. The caller must have locked either + * the parent hub (if udev is a normal device) or else the + * usb_bus_list_lock (if udev is a root hub). The parent's pointer to + * udev has already been installed, but udev is not yet visible through + * sysfs or other filesystem code. + * + * It will return if the device is configured properly or not. Zero if + * the interface was registered with the driver core; else a negative + * errno value. + * + * This call is synchronous, and may not be used in an interrupt context. + * + * Only the hub driver or root-hub registrar should ever call this. + */ +int usb_new_device(struct usb_device *udev) +{ + int err; + + usb_detect_quirks(udev); /* Determine quirks */ + err = usb_configure_device(udev); /* detect & probe dev/intfs */ + if (err < 0) + goto fail; /* export the usbdev device-node for libusb */ udev->dev.devt = MKDEV(USB_DEVICE_MAJOR, (((udev->bus->busnum-1) * 128) + (udev->devnum-1))); @@ -1346,17 +1380,23 @@ int usb_new_device(struct usb_device *udev) err = device_add(&udev->dev); if (err) { dev_err(&udev->dev, "can't device_add, error %d\n", err); - if (udev->parent) - usb_autosuspend_device(udev->parent); goto fail; } -exit: + /* Tell the world! */ + dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, " + "SerialNumber=%d\n", + udev->descriptor.iManufacturer, + udev->descriptor.iProduct, + udev->descriptor.iSerialNumber); + show_string(udev, "Product", udev->product); + show_string(udev, "Manufacturer", udev->manufacturer); + show_string(udev, "SerialNumber", udev->serial); return err; fail: usb_set_device_state(udev, USB_STATE_NOTATTACHED); - goto exit; + return err; } static int hub_port_status(struct usb_hub *hub, int port1, -- cgit v1.2.3-70-g09d2 From 93993a0a3e528357ae4b9b0eb82fd4b428ebbf64 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:34:06 -0700 Subject: usb: introduce usb_authorize/deauthorize() These USB API functions will do the full authorization/deauthorization to be used for a device. When authorized we effectively allow a configuration to be set. Reverse that when deauthorized. Effectively this means that we have to clean all the configuration descriptors on deauthorize and reload them when we authorized. We could do without throwing them out for wired devices, but for wireless, we can read them only after authenticating, and thus, when authorizing an authenticated device we would need to read them. So to simplify, always release them on deauthorize(), re-read them on authorize(). Also fix leak reported by Ragner Magalhaes; in usb_deauthorize_device(), bNumConfigurations was being set to zero before the for loop, and thus the different raw descriptors where never being freed. Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/generic.c | 2 +- drivers/usb/core/hub.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/core/usb.h | 3 ++ 3 files changed, 85 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 20b095050a1..7b9e1ec718d 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -40,7 +40,7 @@ static int is_activesync(struct usb_interface_descriptor *desc) && desc->bInterfaceProtocol == 1; } -static int choose_configuration(struct usb_device *udev) +int choose_configuration(struct usb_device *udev) { int i; int num_configs; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 65d9ea1e6d7..f725d9e62b5 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1399,6 +1399,87 @@ fail: return err; } + +/** + * Similar to usb_disconnect() + * + * We share a lock (that we have) with device_del(), so we need to + * defer its call. + */ +int usb_deauthorize_device(struct usb_device *usb_dev) +{ + unsigned cnt; + usb_lock_device(usb_dev); + if (usb_dev->authorized == 0) + goto out_unauthorized; + usb_dev->authorized = 0; + usb_set_configuration(usb_dev, -1); + usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL); + usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL); + usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL); + kfree(usb_dev->config); + usb_dev->config = NULL; + for (cnt = 0; cnt < usb_dev->descriptor.bNumConfigurations; cnt++) + kfree(usb_dev->rawdescriptors[cnt]); + usb_dev->descriptor.bNumConfigurations = 0; + kfree(usb_dev->rawdescriptors); +out_unauthorized: + usb_unlock_device(usb_dev); + return 0; +} + + +int usb_authorize_device(struct usb_device *usb_dev) +{ + int result = 0, c; + usb_lock_device(usb_dev); + if (usb_dev->authorized == 1) + goto out_authorized; + kfree(usb_dev->product); + usb_dev->product = NULL; + kfree(usb_dev->manufacturer); + usb_dev->manufacturer = NULL; + kfree(usb_dev->serial); + usb_dev->serial = NULL; + result = usb_autoresume_device(usb_dev); + if (result < 0) { + dev_err(&usb_dev->dev, + "can't autoresume for authorization: %d\n", result); + goto error_autoresume; + } + result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor)); + if (result < 0) { + dev_err(&usb_dev->dev, "can't re-read device descriptor for " + "authorization: %d\n", result); + goto error_device_descriptor; + } + usb_dev->authorized = 1; + result = usb_configure_device(usb_dev); + if (result < 0) + goto error_configure; + /* Choose and set the configuration. This registers the interfaces + * with the driver core and lets interface drivers bind to them. + */ + c = choose_configuration(usb_dev); + if (c >= 0) { + result = usb_set_configuration(usb_dev, c); + if (result) { + dev_err(&usb_dev->dev, + "can't set config #%d, error %d\n", c, result); + /* This need not be fatal. The user can try to + * set other configurations. */ + } + } + dev_info(&usb_dev->dev, "authorized to connect\n"); +error_configure: +error_device_descriptor: +error_autoresume: +out_authorized: + usb_unlock_device(usb_dev); // complements locktree + return result; +} + + static int hub_port_status(struct usb_hub *hub, int port1, u16 *status, u16 *change) { diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index cde6e52b84f..e22ec7f8eb1 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -15,12 +15,15 @@ extern void usb_disable_interface (struct usb_device *dev, struct usb_interface *intf); extern void usb_release_interface_cache(struct kref *ref); extern void usb_disable_device (struct usb_device *dev, int skip_ep0); +extern int usb_deauthorize_device (struct usb_device *); +extern int usb_authorize_device (struct usb_device *); extern void usb_detect_quirks(struct usb_device *udev); extern int usb_get_device_descriptor(struct usb_device *dev, unsigned int size); extern char *usb_cache_string(struct usb_device *udev, int index); extern int usb_set_configuration(struct usb_device *dev, int configuration); +extern int choose_configuration(struct usb_device *udev); extern void usb_kick_khubd(struct usb_device *dev); extern int usb_match_device(struct usb_device *dev, -- cgit v1.2.3-70-g09d2 From e03f2e8a530e0ed46af43093e23a70b7c7215263 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:34:07 -0700 Subject: usb: hook up device authorization to sysfs Makes it possible to control the authorization of USB devices through sysfs's /sys/usb/devices/*/authorize. Update: per Adrian Bunk's suggestion, make dev_attr_authorized_default static Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/sysfs.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 2ab222be8fd..e02590297d3 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -413,6 +413,44 @@ usb_descriptor_attr(bDeviceProtocol, "%02x\n") usb_descriptor_attr(bNumConfigurations, "%d\n") usb_descriptor_attr(bMaxPacketSize0, "%d\n") + + +/* show if the device is authorized (1) or not (0) */ +static ssize_t usb_dev_authorized_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct usb_device *usb_dev = to_usb_device(dev); + return snprintf(buf, PAGE_SIZE, "%u\n", usb_dev->authorized); +} + + +/* + * Authorize a device to be used in the system + * + * Writing a 0 deauthorizes the device, writing a 1 authorizes it. + */ +static ssize_t usb_dev_authorized_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t result; + struct usb_device *usb_dev = to_usb_device(dev); + unsigned val; + result = sscanf(buf, "%u\n", &val); + if (result != 1) + result = -EINVAL; + else if (val == 0) + result = usb_deauthorize_device(usb_dev); + else + result = usb_authorize_device(usb_dev); + return result < 0? result : size; +} + +static DEVICE_ATTR(authorized, 0644, + usb_dev_authorized_show, usb_dev_authorized_store); + + static struct attribute *dev_attrs[] = { /* current configuration's attributes */ &dev_attr_configuration.attr, @@ -435,6 +473,7 @@ static struct attribute *dev_attrs[] = { &dev_attr_version.attr, &dev_attr_maxchild.attr, &dev_attr_quirks.attr, + &dev_attr_authorized.attr, NULL, }; static struct attribute_group dev_attr_grp = { -- cgit v1.2.3-70-g09d2 From 732bb9ee8195053a7dc00b9eec7be48891ad8668 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:34:08 -0700 Subject: usb: document device authorization Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- Documentation/usb/authorization.txt | 92 +++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 Documentation/usb/authorization.txt diff --git a/Documentation/usb/authorization.txt b/Documentation/usb/authorization.txt new file mode 100644 index 00000000000..2af40060949 --- /dev/null +++ b/Documentation/usb/authorization.txt @@ -0,0 +1,92 @@ + +Authorizing (or not) your USB devices to connect to the system + +(C) 2007 Inaky Perez-Gonzalez Intel Corporation + +This feature allows you to control if a USB device can be used (or +not) in a system. This feature will allow you to implement a lock-down +of USB devices, fully controlled by user space. + +As of now, when a USB device is connected it is configured and +it's interfaces inmediately made available to the users. With this +modification, only if root authorizes the device to be configured will +then it be possible to use it. + +Usage: + +Authorize a device to connect: + +$ echo 1 > /sys/usb/devices/DEVICE/authorized + +Deauthorize a device: + +$ echo 0 > /sys/usb/devices/DEVICE/authorized + +Set new devices connected to hostX to be deauthorized by default (ie: +lock down): + +$ echo 0 > /sys/bus/devices/usbX/authorized_default + +Remove the lock down: + +$ echo 1 > /sys/bus/devices/usbX/authorized_default + +By default, Wired USB devices are authorized by default to +connect. Wireless USB hosts deauthorize by default all new connected +devices (this is so because we need to do an authentication phase +before authorizing). + + +Example system lockdown (lame) +----------------------- + +Imagine you want to implement a lockdown so only devices of type XYZ +can be connected (for example, it is a kiosk machine with a visible +USB port): + +boot up +rc.local -> + + for host in /sys/bus/devices/usb* + do + echo 0 > $host/authorized_default + done + +Hookup an script to udev, for new USB devices + + if device_is_my_type $DEV + then + echo 1 > $device_path/authorized + done + + +Now, device_is_my_type() is where the juice for a lockdown is. Just +checking if the class, type and protocol match something is the worse +security verification you can make (or the best, for someone willing +to break it). If you need something secure, use crypto and Certificate +Authentication or stuff like that. Something simple for an storage key +could be: + +function device_is_my_type() +{ + echo 1 > authorized # temporarily authorize it + # FIXME: make sure none can mount it + mount DEVICENODE /mntpoint + sum=$(md5sum /mntpoint/.signature) + if [ $sum = $(cat /etc/lockdown/keysum) ] + then + echo "We are good, connected" + umount /mntpoint + # Other stuff so others can use it + else + echo 0 > authorized + fi +} + + +Of course, this is lame, you'd want to do a real certificate +verification stuff with PKI, so you don't depend on a shared secret, +etc, but you get the idea. Anybody with access to a device gadget kit +can fake descriptors and device info. Don't trust that. You are +welcome. + -- cgit v1.2.3-70-g09d2 From b5ea060f1e19c6a3f409d3472c723da4517547b8 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Aug 2007 22:44:27 -0600 Subject: USB: rename choose_configuration As it is global, give it a usb specific name in the global namespace. Cc: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/generic.c | 4 ++-- drivers/usb/core/hub.c | 2 +- drivers/usb/core/usb.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 7b9e1ec718d..9148b69785c 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -40,7 +40,7 @@ static int is_activesync(struct usb_interface_descriptor *desc) && desc->bInterfaceProtocol == 1; } -int choose_configuration(struct usb_device *udev) +int usb_choose_configuration(struct usb_device *udev) { int i; int num_configs; @@ -164,7 +164,7 @@ static int generic_probe(struct usb_device *udev) if (udev->authorized == 0) dev_err(&udev->dev, "Device is not authorized for usage\n"); else { - c = choose_configuration(udev); + c = usb_choose_configuration(udev); if (c >= 0) { err = usb_set_configuration(udev, c); if (err) { diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index f725d9e62b5..4c495c4d505 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1460,7 +1460,7 @@ int usb_authorize_device(struct usb_device *usb_dev) /* Choose and set the configuration. This registers the interfaces * with the driver core and lets interface drivers bind to them. */ - c = choose_configuration(usb_dev); + c = usb_choose_configuration(usb_dev); if (c >= 0) { result = usb_set_configuration(usb_dev, c); if (result) { diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index e22ec7f8eb1..c52626c51f7 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -23,7 +23,7 @@ extern int usb_get_device_descriptor(struct usb_device *dev, unsigned int size); extern char *usb_cache_string(struct usb_device *udev, int index); extern int usb_set_configuration(struct usb_device *dev, int configuration); -extern int choose_configuration(struct usb_device *udev); +extern int usb_choose_configuration(struct usb_device *udev); extern void usb_kick_khubd(struct usb_device *dev); extern int usb_match_device(struct usb_device *dev, -- cgit v1.2.3-70-g09d2 From b0e396e3097ce4914c643bc3f0c2fe0098f551eb Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Aug 2007 22:44:27 -0600 Subject: USB: make usb_release_interface static No one else calls it, this makes sparse happy. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 025ac0bd353..c905b35d4f8 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1330,7 +1330,7 @@ int usb_reset_configuration(struct usb_device *dev) return 0; } -void usb_release_interface(struct device *dev) +static void usb_release_interface(struct device *dev) { struct usb_interface *intf = to_usb_interface(dev); struct usb_interface_cache *intfc = -- cgit v1.2.3-70-g09d2 From e9df41c5c5899259541dc928872cad4d07b82076 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 8 Aug 2007 11:48:02 -0400 Subject: USB: make HCDs responsible for managing endpoint queues This patch (as954) implements a suggestion of David Brownell's. Now the host controller drivers are responsible for linking and unlinking URBs to/from their endpoint queues. This eliminates the possiblity of strange situations where usbcore thinks an URB is linked but the HCD thinks it isn't. It also means HCDs no longer have to check for URBs being dequeued before they were fully enqueued. In addition to the core changes, this requires changing every host controller driver and the root-hub URB handler. For the most part the required changes are fairly small; drivers have to call usb_hcd_link_urb_to_ep() in their urb_enqueue method, usb_hcd_check_unlink_urb() in their urb_dequeue method, and usb_hcd_unlink_urb_from_ep() before giving URBs back. A few HCDs make matters more complicated by the way they split up the flow of control. In addition some method interfaces get changed. The endpoint argument for urb_enqueue is now redundant so it is removed. The unlink status is required by usb_hcd_check_unlink_urb(), so it has been added to urb_dequeue. Signed-off-by: Alan Stern CC: David Brownell CC: Olav Kongas CC: Tony Olech CC: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 255 +++++++++++++++++++++------------------- drivers/usb/core/hcd.h | 14 ++- drivers/usb/gadget/dummy_hcd.c | 22 +++- drivers/usb/host/ehci-hcd.c | 14 ++- drivers/usb/host/ehci-q.c | 14 ++- drivers/usb/host/ehci-sched.c | 43 +++++-- drivers/usb/host/isp116x-hcd.c | 31 +++-- drivers/usb/host/ohci-hcd.c | 32 +++-- drivers/usb/host/ohci-q.c | 1 + drivers/usb/host/r8a66597-hcd.c | 37 ++++-- drivers/usb/host/sl811-hcd.c | 26 ++-- drivers/usb/host/u132-hcd.c | 170 +++++++++++++++++++-------- drivers/usb/host/uhci-q.c | 32 ++--- 13 files changed, 420 insertions(+), 271 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index a5a46a55376..a853f63b925 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -356,11 +356,17 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) const u8 *bufp = tbuf; int len = 0; int patch_wakeup = 0; - int status = 0; + int status; int n; might_sleep(); + spin_lock_irq(&hcd_root_hub_lock); + status = usb_hcd_link_urb_to_ep(hcd, urb); + spin_unlock_irq(&hcd_root_hub_lock); + if (status) + return status; + cmd = (struct usb_ctrlrequest *) urb->setup_packet; typeReq = (cmd->bRequestType << 8) | cmd->bRequest; wValue = le16_to_cpu (cmd->wValue); @@ -525,10 +531,9 @@ error: /* any errors get returned through the urb completion */ spin_lock_irq(&hcd_root_hub_lock); - spin_lock(&urb->lock); if (urb->status == -EINPROGRESS) urb->status = status; - spin_unlock(&urb->lock); + usb_hcd_unlink_urb_from_ep(hcd, urb); /* This peculiar use of spinlocks echoes what real HC drivers do. * Avoiding calls to local_irq_disable/enable makes the code @@ -571,26 +576,21 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd) spin_lock_irqsave(&hcd_root_hub_lock, flags); urb = hcd->status_urb; if (urb) { - spin_lock(&urb->lock); - if (urb->status == -EINPROGRESS) { - hcd->poll_pending = 0; - hcd->status_urb = NULL; - urb->status = 0; - urb->hcpriv = NULL; - urb->actual_length = length; - memcpy(urb->transfer_buffer, buffer, length); - } else /* urb has been unlinked */ - length = 0; - spin_unlock(&urb->lock); + hcd->poll_pending = 0; + hcd->status_urb = NULL; + urb->status = 0; + urb->hcpriv = NULL; + urb->actual_length = length; + memcpy(urb->transfer_buffer, buffer, length); + usb_hcd_unlink_urb_from_ep(hcd, urb); spin_unlock(&hcd_root_hub_lock); usb_hcd_giveback_urb(hcd, urb); spin_lock(&hcd_root_hub_lock); - } else + } else { length = 0; - - if (length <= 0) hcd->poll_pending = 1; + } spin_unlock_irqrestore(&hcd_root_hub_lock, flags); } @@ -619,24 +619,26 @@ static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb) int len = 1 + (urb->dev->maxchild / 8); spin_lock_irqsave (&hcd_root_hub_lock, flags); - if (urb->status != -EINPROGRESS) /* already unlinked */ - retval = urb->status; - else if (hcd->status_urb || urb->transfer_buffer_length < len) { + if (hcd->status_urb || urb->transfer_buffer_length < len) { dev_dbg (hcd->self.controller, "not queuing rh status urb\n"); retval = -EINVAL; - } else { - hcd->status_urb = urb; - urb->hcpriv = hcd; /* indicate it's queued */ + goto done; + } - if (!hcd->uses_new_polling) - mod_timer (&hcd->rh_timer, - (jiffies/(HZ/4) + 1) * (HZ/4)); + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval) + goto done; - /* If a status change has already occurred, report it ASAP */ - else if (hcd->poll_pending) - mod_timer (&hcd->rh_timer, jiffies); - retval = 0; - } + hcd->status_urb = urb; + urb->hcpriv = hcd; /* indicate it's queued */ + if (!hcd->uses_new_polling) + mod_timer(&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4)); + + /* If a status change has already occurred, report it ASAP */ + else if (hcd->poll_pending) + mod_timer(&hcd->rh_timer, jiffies); + retval = 0; + done: spin_unlock_irqrestore (&hcd_root_hub_lock, flags); return retval; } @@ -655,11 +657,16 @@ static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb) /* Unlinks of root-hub control URBs are legal, but they don't do anything * since these URBs always execute synchronously. */ -static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) +static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { unsigned long flags; + int rc; spin_lock_irqsave(&hcd_root_hub_lock, flags); + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) + goto done; + if (usb_endpoint_num(&urb->ep->desc) == 0) { /* Control URB */ ; /* Do nothing */ @@ -669,14 +676,16 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) if (urb == hcd->status_urb) { hcd->status_urb = NULL; urb->hcpriv = NULL; + usb_hcd_unlink_urb_from_ep(hcd, urb); spin_unlock(&hcd_root_hub_lock); usb_hcd_giveback_urb(hcd, urb); spin_lock(&hcd_root_hub_lock); } } + done: spin_unlock_irqrestore(&hcd_root_hub_lock, flags); - return 0; + return rc; } @@ -977,12 +986,26 @@ EXPORT_SYMBOL (usb_calc_bus_time); /*-------------------------------------------------------------------------*/ -static int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb) +/** + * usb_hcd_link_urb_to_ep - add an URB to its endpoint queue + * @hcd: host controller to which @urb was submitted + * @urb: URB being submitted + * + * Host controller drivers should call this routine in their enqueue() + * method. The HCD's private spinlock must be held and interrupts must + * be disabled. The actions carried out here are required for URB + * submission, as well as for endpoint shutdown and for usb_kill_urb. + * + * Returns 0 for no error, otherwise a negative error code (in which case + * the enqueue() method must fail). If no error occurs but enqueue() fails + * anyway, it must call usb_hcd_unlink_urb_from_ep() before releasing + * the private spinlock and returning. + */ +int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb) { - unsigned long flags; int rc = 0; - spin_lock_irqsave(&hcd_urb_list_lock, flags); + spin_lock(&hcd_urb_list_lock); /* Check that the URB isn't being killed */ if (unlikely(urb->reject)) { @@ -1009,48 +1032,48 @@ static int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb) goto done; } done: - spin_unlock_irqrestore(&hcd_urb_list_lock, flags); + spin_unlock(&hcd_urb_list_lock); return rc; } +EXPORT_SYMBOL_GPL(usb_hcd_link_urb_to_ep); -static int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb, +/** + * usb_hcd_check_unlink_urb - check whether an URB may be unlinked + * @hcd: host controller to which @urb was submitted + * @urb: URB being checked for unlinkability + * @status: error code to store in @urb if the unlink succeeds + * + * Host controller drivers should call this routine in their dequeue() + * method. The HCD's private spinlock must be held and interrupts must + * be disabled. The actions carried out here are required for making + * sure than an unlink is valid. + * + * Returns 0 for no error, otherwise a negative error code (in which case + * the dequeue() method must fail). The possible error codes are: + * + * -EIDRM: @urb was not submitted or has already completed. + * The completion function may not have been called yet. + * + * -EBUSY: @urb has already been unlinked. + */ +int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb, int status) { - unsigned long flags; struct list_head *tmp; - int rc = 0; - - /* - * we contend for urb->status with the hcd core, - * which changes it while returning the urb. - * - * Caller guaranteed that the urb pointer hasn't been freed, and - * that it was submitted. But as a rule it can't know whether or - * not it's already been unlinked ... so we respect the reversed - * lock sequence needed for the usb_hcd_giveback_urb() code paths - * (urb lock, then hcd_urb_list_lock) in case some other CPU is now - * unlinking it. - */ - spin_lock_irqsave(&urb->lock, flags); - spin_lock(&hcd_urb_list_lock); /* insist the urb is still queued */ list_for_each(tmp, &urb->ep->urb_list) { if (tmp == &urb->urb_list) break; } - if (tmp != &urb->urb_list) { - rc = -EIDRM; - goto done; - } + if (tmp != &urb->urb_list) + return -EIDRM; /* Any status except -EINPROGRESS means something already started to * unlink this URB from the hardware. So there's no more work to do. */ - if (urb->status != -EINPROGRESS) { - rc = -EBUSY; - goto done; - } + if (urb->status != -EINPROGRESS) + return -EBUSY; urb->status = status; /* IRQ setup can easily be broken so that USB controllers @@ -1065,21 +1088,28 @@ static int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb, set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); } - done: - spin_unlock(&hcd_urb_list_lock); - spin_unlock_irqrestore (&urb->lock, flags); - return rc; + return 0; } +EXPORT_SYMBOL_GPL(usb_hcd_check_unlink_urb); -static void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb) +/** + * usb_hcd_unlink_urb_from_ep - remove an URB from its endpoint queue + * @hcd: host controller to which @urb was submitted + * @urb: URB being unlinked + * + * Host controller drivers should call this routine before calling + * usb_hcd_giveback_urb(). The HCD's private spinlock must be held and + * interrupts must be disabled. The actions carried out here are required + * for URB completion. + */ +void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb) { - unsigned long flags; - /* clear all state linking urb to this dev (and hcd) */ - spin_lock_irqsave(&hcd_urb_list_lock, flags); + spin_lock(&hcd_urb_list_lock); list_del_init(&urb->urb_list); - spin_unlock_irqrestore(&hcd_urb_list_lock, flags); + spin_unlock(&hcd_urb_list_lock); } +EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep); static void map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) { @@ -1153,20 +1183,15 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) * URBs must be submitted in process context with interrupts * enabled. */ - status = usb_hcd_link_urb_to_ep(hcd, urb); - if (!status) { - map_urb_for_dma(hcd, urb); - if (is_root_hub(urb->dev)) - status = rh_urb_enqueue(hcd, urb); - else - status = hcd->driver->urb_enqueue(hcd, urb->ep, urb, - mem_flags); - } + map_urb_for_dma(hcd, urb); + if (is_root_hub(urb->dev)) + status = rh_urb_enqueue(hcd, urb); + else + status = hcd->driver->urb_enqueue(hcd, urb, mem_flags); if (unlikely(status)) { usbmon_urb_submit_error(&hcd->self, urb, status); unmap_urb_for_dma(hcd, urb); - usb_hcd_unlink_urb_from_ep(hcd, urb); INIT_LIST_HEAD(&urb->urb_list); atomic_dec(&urb->use_count); if (urb->reject) @@ -1183,24 +1208,19 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) * soon as practical. we've already set up the urb's return status, * but we can't know if the callback completed already. */ -static int -unlink1 (struct usb_hcd *hcd, struct urb *urb) +static int unlink1(struct usb_hcd *hcd, struct urb *urb, int status) { int value; if (is_root_hub(urb->dev)) - value = usb_rh_urb_dequeue (hcd, urb); + value = usb_rh_urb_dequeue(hcd, urb, status); else { /* The only reason an HCD might fail this call is if * it has not yet fully queued the urb to begin with. * Such failures should be harmless. */ - value = hcd->driver->urb_dequeue (hcd, urb); + value = hcd->driver->urb_dequeue(hcd, urb, status); } - - if (value != 0) - dev_dbg (hcd->self.controller, "dequeue %p --> %d\n", - urb, value); return value; } @@ -1216,14 +1236,11 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) int retval; hcd = bus_to_hcd(urb->dev->bus); - - retval = usb_hcd_check_unlink_urb(hcd, urb, status); - if (!retval) - retval = unlink1(hcd, urb); + retval = unlink1(hcd, urb, status); if (retval == 0) retval = -EINPROGRESS; - else if (retval != -EIDRM) + else if (retval != -EIDRM && retval != -EBUSY) dev_dbg(&urb->dev->dev, "hcd_unlink_urb %p fail %d\n", urb, retval); return retval; @@ -1245,7 +1262,6 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) */ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) { - usb_hcd_unlink_urb_from_ep(hcd, urb); unmap_urb_for_dma(hcd, urb); usbmon_urb_complete (&hcd->self, urb); usb_unanchor_urb(urb); @@ -1282,7 +1298,6 @@ void usb_hcd_endpoint_disable (struct usb_device *udev, rescan: spin_lock_irq(&hcd_urb_list_lock); list_for_each_entry (urb, &ep->urb_list, urb_list) { - int tmp; int is_in; /* the urb may already have been unlinked */ @@ -1292,34 +1307,26 @@ rescan: is_in = usb_urb_dir_in(urb); spin_unlock(&hcd_urb_list_lock); - spin_lock (&urb->lock); - tmp = urb->status; - if (tmp == -EINPROGRESS) - urb->status = -ESHUTDOWN; - spin_unlock (&urb->lock); - - /* kick hcd unless it's already returning this */ - if (tmp == -EINPROGRESS) { - unlink1 (hcd, urb); - dev_dbg (hcd->self.controller, - "shutdown urb %p ep%d%s%s\n", - urb, usb_endpoint_num(&ep->desc), - is_in ? "in" : "out", - ({ char *s; - - switch (usb_endpoint_type(&ep->desc)) { - case USB_ENDPOINT_XFER_CONTROL: - s = ""; break; - case USB_ENDPOINT_XFER_BULK: - s = "-bulk"; break; - case USB_ENDPOINT_XFER_INT: - s = "-intr"; break; - default: - s = "-iso"; break; - }; - s; - })); - } + /* kick hcd */ + unlink1(hcd, urb, -ESHUTDOWN); + dev_dbg (hcd->self.controller, + "shutdown urb %p ep%d%s%s\n", + urb, usb_endpoint_num(&ep->desc), + is_in ? "in" : "out", + ({ char *s; + + switch (usb_endpoint_type(&ep->desc)) { + case USB_ENDPOINT_XFER_CONTROL: + s = ""; break; + case USB_ENDPOINT_XFER_BULK: + s = "-bulk"; break; + case USB_ENDPOINT_XFER_INT: + s = "-intr"; break; + default: + s = "-iso"; break; + }; + s; + })); usb_put_urb (urb); /* list contents may have changed */ diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 8683142e70e..745be2566f6 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -189,11 +189,10 @@ struct hc_driver { int (*get_frame_number) (struct usb_hcd *hcd); /* manage i/o requests, device state */ - int (*urb_enqueue) (struct usb_hcd *hcd, - struct usb_host_endpoint *ep, - struct urb *urb, - gfp_t mem_flags); - int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb); + int (*urb_enqueue)(struct usb_hcd *hcd, + struct urb *urb, gfp_t mem_flags); + int (*urb_dequeue)(struct usb_hcd *hcd, + struct urb *urb, int status); /* hw synch, freeing endpoint resources that urb_dequeue can't */ void (*endpoint_disable)(struct usb_hcd *hcd, @@ -211,6 +210,11 @@ struct hc_driver { /* Needed only if port-change IRQs are level-triggered */ }; +extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb); +extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb, + int status); +extern void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb); + extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags); extern int usb_hcd_unlink_urb (struct urb *urb, int status); extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb); diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index d008d1360a7..c441d10c087 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -962,13 +962,13 @@ static struct platform_driver dummy_udc_driver = { static int dummy_urb_enqueue ( struct usb_hcd *hcd, - struct usb_host_endpoint *ep, struct urb *urb, gfp_t mem_flags ) { struct dummy *dum; struct urbp *urbp; unsigned long flags; + int rc; if (!urb->transfer_buffer && urb->transfer_buffer_length) return -EINVAL; @@ -980,6 +980,11 @@ static int dummy_urb_enqueue ( dum = hcd_to_dummy (hcd); spin_lock_irqsave (&dum->lock, flags); + rc = usb_hcd_link_urb_to_ep(hcd, urb); + if (rc) { + kfree(urbp); + goto done; + } if (!dum->udev) { dum->udev = urb->dev; @@ -997,22 +1002,28 @@ static int dummy_urb_enqueue ( mod_timer (&dum->timer, jiffies + 1); spin_unlock_irqrestore (&dum->lock, flags); - return 0; + done: + return rc; } -static int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) +static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct dummy *dum; unsigned long flags; + int rc; /* giveback happens automatically in timer callback, * so make sure the callback happens */ dum = hcd_to_dummy (hcd); spin_lock_irqsave (&dum->lock, flags); - if (dum->rh_state != DUMMY_RH_RUNNING && !list_empty(&dum->urbp_list)) + + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (!rc && dum->rh_state != DUMMY_RH_RUNNING && + !list_empty(&dum->urbp_list)) mod_timer (&dum->timer, jiffies); + spin_unlock_irqrestore (&dum->lock, flags); - return 0; + return rc; } static void maybe_set_status (struct urb *urb, int status) @@ -1511,6 +1522,7 @@ return_urb: if (ep) ep->already_seen = ep->setup_stage = 0; + usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb); spin_unlock (&dum->lock); usb_hcd_giveback_urb (dummy_to_hcd(dum), urb); spin_lock (&dum->lock); diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 35cdba10411..db00492588b 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -719,7 +719,6 @@ dead: */ static int ehci_urb_enqueue ( struct usb_hcd *hcd, - struct usb_host_endpoint *ep, struct urb *urb, gfp_t mem_flags ) { @@ -734,12 +733,12 @@ static int ehci_urb_enqueue ( default: if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags)) return -ENOMEM; - return submit_async (ehci, ep, urb, &qtd_list, mem_flags); + return submit_async(ehci, urb, &qtd_list, mem_flags); case PIPE_INTERRUPT: if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags)) return -ENOMEM; - return intr_submit (ehci, ep, urb, &qtd_list, mem_flags); + return intr_submit(ehci, urb, &qtd_list, mem_flags); case PIPE_ISOCHRONOUS: if (urb->dev->speed == USB_SPEED_HIGH) @@ -777,13 +776,18 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) * completions normally happen asynchronously */ -static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) +static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct ehci_qh *qh; unsigned long flags; + int rc; spin_lock_irqsave (&ehci->lock, flags); + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) + goto done; + switch (usb_pipetype (urb->pipe)) { // case PIPE_CONTROL: // case PIPE_BULK: @@ -838,7 +842,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) } done: spin_unlock_irqrestore (&ehci->lock, flags); - return 0; + return rc; } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 140bfa423e0..1da2de4d34e 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -262,6 +262,7 @@ __acquires(ehci->lock) #endif /* complete() can reenter this HCD */ + usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); spin_unlock (&ehci->lock); usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb); spin_lock (&ehci->lock); @@ -913,7 +914,6 @@ static struct ehci_qh *qh_append_tds ( static int submit_async ( struct ehci_hcd *ehci, - struct usb_host_endpoint *ep, struct urb *urb, struct list_head *qtd_list, gfp_t mem_flags @@ -922,10 +922,10 @@ submit_async ( int epnum; unsigned long flags; struct ehci_qh *qh = NULL; - int rc = 0; + int rc; qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list); - epnum = ep->desc.bEndpointAddress; + epnum = urb->ep->desc.bEndpointAddress; #ifdef EHCI_URB_TRACE ehci_dbg (ehci, @@ -933,7 +933,7 @@ submit_async ( __FUNCTION__, urb->dev->devpath, urb, epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out", urb->transfer_buffer_length, - qtd, ep->hcpriv); + qtd, urb->ep->hcpriv); #endif spin_lock_irqsave (&ehci->lock, flags); @@ -942,9 +942,13 @@ submit_async ( rc = -ESHUTDOWN; goto done; } + rc = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb); + if (unlikely(rc)) + goto done; - qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv); + qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv); if (unlikely(qh == NULL)) { + usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); rc = -ENOMEM; goto done; } diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index e682f2342ef..8b267b3fd2b 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -797,7 +797,6 @@ done: static int intr_submit ( struct ehci_hcd *ehci, - struct usb_host_endpoint *ep, struct urb *urb, struct list_head *qtd_list, gfp_t mem_flags @@ -805,23 +804,26 @@ static int intr_submit ( unsigned epnum; unsigned long flags; struct ehci_qh *qh; - int status = 0; + int status; struct list_head empty; /* get endpoint and transfer/schedule data */ - epnum = ep->desc.bEndpointAddress; + epnum = urb->ep->desc.bEndpointAddress; spin_lock_irqsave (&ehci->lock, flags); if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &ehci_to_hcd(ehci)->flags))) { status = -ESHUTDOWN; - goto done; + goto done_not_linked; } + status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb); + if (unlikely(status)) + goto done_not_linked; /* get qh and force any scheduling errors */ INIT_LIST_HEAD (&empty); - qh = qh_append_tds (ehci, urb, &empty, epnum, &ep->hcpriv); + qh = qh_append_tds(ehci, urb, &empty, epnum, &urb->ep->hcpriv); if (qh == NULL) { status = -ENOMEM; goto done; @@ -832,13 +834,16 @@ static int intr_submit ( } /* then queue the urb's tds to the qh */ - qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv); + qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv); BUG_ON (qh == NULL); /* ... update usbfs periodic stats */ ehci_to_hcd(ehci)->self.bandwidth_int_reqs++; done: + if (unlikely(status)) + usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); +done_not_linked: spin_unlock_irqrestore (&ehci->lock, flags); if (status) qtd_list_free (ehci, urb, qtd_list); @@ -1686,12 +1691,19 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, /* schedule ... need to lock */ spin_lock_irqsave (&ehci->lock, flags); if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, - &ehci_to_hcd(ehci)->flags))) + &ehci_to_hcd(ehci)->flags))) { status = -ESHUTDOWN; - else - status = iso_stream_schedule (ehci, urb, stream); + goto done_not_linked; + } + status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb); + if (unlikely(status)) + goto done_not_linked; + status = iso_stream_schedule(ehci, urb, stream); if (likely (status == 0)) itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); + else + usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); +done_not_linked: spin_unlock_irqrestore (&ehci->lock, flags); done: @@ -2049,12 +2061,19 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, /* schedule ... need to lock */ spin_lock_irqsave (&ehci->lock, flags); if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, - &ehci_to_hcd(ehci)->flags))) + &ehci_to_hcd(ehci)->flags))) { status = -ESHUTDOWN; - else - status = iso_stream_schedule (ehci, urb, stream); + goto done_not_linked; + } + status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb); + if (unlikely(status)) + goto done_not_linked; + status = iso_stream_schedule(ehci, urb, stream); if (status == 0) sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); + else + usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); +done_not_linked: spin_unlock_irqrestore (&ehci->lock, flags); done: diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 5c851a36de7..d5027dc75a5 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -290,6 +290,7 @@ __releases(isp116x->lock) __acquires(isp116x->lock) urb_dbg(urb, "Finish"); + usb_hcd_unlink_urb_from_ep(isp116x_to_hcd(isp116x), urb); spin_unlock(&isp116x->lock); usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb); spin_lock(&isp116x->lock); @@ -673,7 +674,7 @@ static int balance(struct isp116x *isp116x, u16 period, u16 load) /*-----------------------------------------------------------------*/ static int isp116x_urb_enqueue(struct usb_hcd *hcd, - struct usb_host_endpoint *hep, struct urb *urb, + struct urb *urb, gfp_t mem_flags) { struct isp116x *isp116x = hcd_to_isp116x(hcd); @@ -682,6 +683,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, int is_out = !usb_pipein(pipe); int type = usb_pipetype(pipe); int epnum = usb_pipeendpoint(pipe); + struct usb_host_endpoint *hep = urb->ep; struct isp116x_ep *ep = NULL; unsigned long flags; int i; @@ -705,7 +707,12 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, if (!HC_IS_RUNNING(hcd->state)) { kfree(ep); ret = -ENODEV; - goto fail; + goto fail_not_linked; + } + ret = usb_hcd_link_urb_to_ep(hcd, urb); + if (ret) { + kfree(ep); + goto fail_not_linked; } if (hep->hcpriv) @@ -818,6 +825,9 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, start_atl_transfers(isp116x); fail: + if (ret) + usb_hcd_unlink_urb_from_ep(hcd, urb); + fail_not_linked: spin_unlock_irqrestore(&isp116x->lock, flags); return ret; } @@ -825,20 +835,21 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, /* Dequeue URBs. */ -static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, + int status) { struct isp116x *isp116x = hcd_to_isp116x(hcd); struct usb_host_endpoint *hep; struct isp116x_ep *ep, *ep_act; unsigned long flags; + int rc; spin_lock_irqsave(&isp116x->lock, flags); + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) + goto done; + hep = urb->hcpriv; - /* URB already unlinked (or never linked)? */ - if (!hep) { - spin_unlock_irqrestore(&isp116x->lock, flags); - return 0; - } ep = hep->hcpriv; WARN_ON(hep != ep->hep); @@ -856,9 +867,9 @@ static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) if (urb) finish_request(isp116x, ep, urb); - + done: spin_unlock_irqrestore(&isp116x->lock, flags); - return 0; + return rc; } static void isp116x_endpoint_disable(struct usb_hcd *hcd, diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index d673cb9c36b..6b06ab69938 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -117,7 +117,6 @@ MODULE_PARM_DESC (no_handshake, "true (not default) disables BIOS handshake"); */ static int ohci_urb_enqueue ( struct usb_hcd *hcd, - struct usb_host_endpoint *ep, struct urb *urb, gfp_t mem_flags ) { @@ -134,7 +133,7 @@ static int ohci_urb_enqueue ( #endif /* every endpoint has a ed, locate and maybe (re)initialize it */ - if (! (ed = ed_get (ohci, ep, urb->dev, pipe, urb->interval))) + if (! (ed = ed_get (ohci, urb->ep, urb->dev, pipe, urb->interval))) return -ENOMEM; /* for the private part of the URB we need the number of TDs (size) */ @@ -199,22 +198,17 @@ static int ohci_urb_enqueue ( retval = -ENODEV; goto fail; } - - /* in case of unlink-during-submit */ - spin_lock (&urb->lock); - if (urb->status != -EINPROGRESS) { - spin_unlock (&urb->lock); - urb->hcpriv = urb_priv; - finish_urb (ohci, urb); - retval = 0; + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval) goto fail; - } /* schedule the ed if needed */ if (ed->state == ED_IDLE) { retval = ed_schedule (ohci, ed); - if (retval < 0) - goto fail0; + if (retval < 0) { + usb_hcd_unlink_urb_from_ep(hcd, urb); + goto fail; + } if (ed->type == PIPE_ISOCHRONOUS) { u16 frame = ohci_frame_no(ohci); @@ -238,8 +232,6 @@ static int ohci_urb_enqueue ( urb->hcpriv = urb_priv; td_submit_urb (ohci, urb); -fail0: - spin_unlock (&urb->lock); fail: if (retval) urb_free_priv (ohci, urb_priv); @@ -253,17 +245,21 @@ fail: * asynchronously, and we might be dealing with an urb that's * partially transferred, or an ED with other urbs being unlinked. */ -static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) +static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); unsigned long flags; + int rc; #ifdef OHCI_VERBOSE_DEBUG urb_print (urb, "UNLINK", 1); #endif spin_lock_irqsave (&ohci->lock, flags); - if (HC_IS_RUNNING(hcd->state)) { + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) { + ; /* Do nothing */ + } else if (HC_IS_RUNNING(hcd->state)) { urb_priv_t *urb_priv; /* Unless an IRQ completed the unlink while it was being @@ -284,7 +280,7 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) finish_urb (ohci, urb); } spin_unlock_irqrestore (&ohci->lock, flags); - return 0; + return rc; } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 547d39be3eb..889c0720743 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -74,6 +74,7 @@ __acquires(ohci->lock) #endif /* urb->complete() can reenter this HCD */ + usb_hcd_unlink_urb_from_ep(ohci_to_hcd(ohci), urb); spin_unlock (&ohci->lock); usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb); spin_lock (&ohci->lock); diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 40a1de4c256..94bb229df3b 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -784,6 +784,9 @@ static void force_dequeue(struct r8a66597 *r8a66597, u16 pipenum, u16 address) if (urb) { urb->status = -ENODEV; urb->hcpriv = NULL; + usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), + urb); + spin_unlock(&r8a66597->lock); usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb); spin_lock(&r8a66597->lock); @@ -1131,6 +1134,8 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td, urb->start_frame = r8a66597_get_frame(hcd); urb->hcpriv = NULL; + usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb); + spin_unlock(&r8a66597->lock); usb_hcd_giveback_urb(hcd, urb); spin_lock(&r8a66597->lock); @@ -1722,21 +1727,25 @@ static struct r8a66597_td *r8a66597_make_td(struct r8a66597 *r8a66597, } static int r8a66597_urb_enqueue(struct usb_hcd *hcd, - struct usb_host_endpoint *hep, struct urb *urb, gfp_t mem_flags) { + struct usb_host_endpoint *hep = urb->ep; struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd); struct r8a66597_td *td = NULL; - int ret = 0, request = 0; + int ret, request = 0; unsigned long flags; spin_lock_irqsave(&r8a66597->lock, flags); if (!get_urb_to_r8a66597_dev(r8a66597, urb)) { ret = -ENODEV; - goto error; + goto error_not_linked; } + ret = usb_hcd_link_urb_to_ep(hcd, urb); + if (ret) + goto error_not_linked; + if (!hep->hcpriv) { hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe), GFP_ATOMIC); @@ -1761,15 +1770,7 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd, if (list_empty(&r8a66597->pipe_queue[td->pipenum])) request = 1; list_add_tail(&td->queue, &r8a66597->pipe_queue[td->pipenum]); - - spin_lock(&urb->lock); - if (urb->status != -EINPROGRESS) { - spin_unlock(&urb->lock); - ret = -EPIPE; - goto error; - } urb->hcpriv = td; - spin_unlock(&urb->lock); if (request) { ret = start_transfer(r8a66597, td); @@ -1781,17 +1782,26 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd, set_td_timer(r8a66597, td); error: + if (ret) + usb_hcd_unlink_urb_from_ep(hcd, urb); +error_not_linked: spin_unlock_irqrestore(&r8a66597->lock, flags); return ret; } -static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, + int status) { struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd); struct r8a66597_td *td; unsigned long flags; + int rc; spin_lock_irqsave(&r8a66597->lock, flags); + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) + goto done; + if (urb->hcpriv) { td = urb->hcpriv; pipe_stop(r8a66597, td->pipe); @@ -1799,8 +1809,9 @@ static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) disable_irq_empty(r8a66597, td->pipenum); done(r8a66597, td, td->pipenum, urb); } + done: spin_unlock_irqrestore(&r8a66597->lock, flags); - return 0; + return rc; } static void r8a66597_endpoint_disable(struct usb_hcd *hcd, diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 4cfa3ff2c99..3d3a63d002c 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -441,6 +441,7 @@ static void finish_request( urb->hcpriv = NULL; spin_unlock(&urb->lock); + usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb); spin_unlock(&sl811->lock); usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb); spin_lock(&sl811->lock); @@ -807,7 +808,6 @@ static int balance(struct sl811 *sl811, u16 period, u16 load) static int sl811h_urb_enqueue( struct usb_hcd *hcd, - struct usb_host_endpoint *hep, struct urb *urb, gfp_t mem_flags ) { @@ -820,7 +820,8 @@ static int sl811h_urb_enqueue( struct sl811h_ep *ep = NULL; unsigned long flags; int i; - int retval = 0; + int retval; + struct usb_host_endpoint *hep = urb->ep; #ifdef DISABLE_ISO if (type == PIPE_ISOCHRONOUS) @@ -838,7 +839,12 @@ static int sl811h_urb_enqueue( || !HC_IS_RUNNING(hcd->state)) { retval = -ENODEV; kfree(ep); - goto fail; + goto fail_not_linked; + } + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval) { + kfree(ep); + goto fail_not_linked; } if (hep->hcpriv) { @@ -965,23 +971,27 @@ static int sl811h_urb_enqueue( start_transfer(sl811); sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable); fail: + if (retval) + usb_hcd_unlink_urb_from_ep(hcd, urb); +fail_not_linked: spin_unlock_irqrestore(&sl811->lock, flags); return retval; } -static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct sl811 *sl811 = hcd_to_sl811(hcd); struct usb_host_endpoint *hep; unsigned long flags; struct sl811h_ep *ep; - int retval = 0; + int retval; spin_lock_irqsave(&sl811->lock, flags); - hep = urb->hcpriv; - if (!hep) + retval = usb_hcd_check_unlink_urb(hcd, urb, status); + if (retval) goto fail; + hep = urb->hcpriv; ep = hep->hcpriv; if (ep) { /* finish right away if this urb can't be active ... @@ -1029,8 +1039,8 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) VDBG("dequeue, urb %p active %s; wait4irq\n", urb, (sl811->active_a == ep) ? "A" : "B"); } else -fail: retval = -EINVAL; + fail: spin_unlock_irqrestore(&sl811->lock, flags); return retval; } diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 598ad098aee..c87660b5edc 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -521,6 +521,7 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp, urb->status = status; urb->hcpriv = NULL; spin_lock_irqsave(&endp->queue_lock.slock, irqs); + usb_hcd_unlink_urb_from_ep(hcd, urb); endp->queue_next += 1; if (ENDP_QUEUE_SIZE > --endp->queue_size) { endp->active = 0; @@ -561,6 +562,7 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp, urb->status = status; urb->hcpriv = NULL; spin_lock_irqsave(&endp->queue_lock.slock, irqs); + usb_hcd_unlink_urb_from_ep(hcd, urb); endp->queue_next += 1; if (ENDP_QUEUE_SIZE > --endp->queue_size) { endp->active = 0; @@ -1876,20 +1878,32 @@ static int u132_hcd_reset(struct usb_hcd *hcd) } static int create_endpoint_and_queue_int(struct u132 *u132, - struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb, + struct u132_udev *udev, struct urb *urb, struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address, gfp_t mem_flags) { struct u132_ring *ring; unsigned long irqs; - u8 endp_number = ++u132->num_endpoints; - struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] = - kmalloc(sizeof(struct u132_endp), mem_flags); + int rc; + u8 endp_number; + struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); + if (!endp) { return -ENOMEM; } + + spin_lock_init(&endp->queue_lock.slock); + spin_lock_irqsave(&endp->queue_lock.slock, irqs); + rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); + if (rc) { + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + kfree(endp); + return rc; + } + + endp_number = ++u132->num_endpoints; + urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - spin_lock_init(&endp->queue_lock.slock); INIT_LIST_HEAD(&endp->urb_more); ring = endp->ring = &u132->ring[0]; if (ring->curr_endp) { @@ -1905,7 +1919,7 @@ static int create_endpoint_and_queue_int(struct u132 *u132, endp->delayed = 0; endp->endp_number = endp_number; endp->u132 = u132; - endp->hep = hep; + endp->hep = urb->ep; endp->pipetype = usb_pipetype(urb->pipe); u132_endp_init_kref(u132, endp); if (usb_pipein(urb->pipe)) { @@ -1924,7 +1938,6 @@ static int create_endpoint_and_queue_int(struct u132 *u132, u132_udev_get_kref(u132, udev); } urb->hcpriv = u132; - spin_lock_irqsave(&endp->queue_lock.slock, irqs); endp->delayed = 1; endp->jiffies = jiffies + msecs_to_jiffies(urb->interval); endp->udev_number = address; @@ -1939,8 +1952,8 @@ static int create_endpoint_and_queue_int(struct u132 *u132, return 0; } -static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev, - struct usb_host_endpoint *hep, struct urb *urb, +static int queue_int_on_old_endpoint(struct u132 *u132, + struct u132_udev *udev, struct urb *urb, struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, u8 usb_endp, u8 address) { @@ -1964,21 +1977,33 @@ static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev, } static int create_endpoint_and_queue_bulk(struct u132 *u132, - struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb, + struct u132_udev *udev, struct urb *urb, struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address, gfp_t mem_flags) { int ring_number; struct u132_ring *ring; unsigned long irqs; - u8 endp_number = ++u132->num_endpoints; - struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] = - kmalloc(sizeof(struct u132_endp), mem_flags); + int rc; + u8 endp_number; + struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); + if (!endp) { return -ENOMEM; } + + spin_lock_init(&endp->queue_lock.slock); + spin_lock_irqsave(&endp->queue_lock.slock, irqs); + rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); + if (rc) { + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + kfree(endp); + return rc; + } + + endp_number = ++u132->num_endpoints; + urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - spin_lock_init(&endp->queue_lock.slock); INIT_LIST_HEAD(&endp->urb_more); endp->dequeueing = 0; endp->edset_flush = 0; @@ -1986,7 +2011,7 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132, endp->delayed = 0; endp->endp_number = endp_number; endp->u132 = u132; - endp->hep = hep; + endp->hep = urb->ep; endp->pipetype = usb_pipetype(urb->pipe); u132_endp_init_kref(u132, endp); if (usb_pipein(urb->pipe)) { @@ -2015,7 +2040,6 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132, } ring->length += 1; urb->hcpriv = u132; - spin_lock_irqsave(&endp->queue_lock.slock, irqs); endp->udev_number = address; endp->usb_addr = usb_addr; endp->usb_endp = usb_endp; @@ -2029,7 +2053,7 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132, } static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev, - struct usb_host_endpoint *hep, struct urb *urb, + struct urb *urb, struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, u8 usb_endp, u8 address) { @@ -2051,19 +2075,32 @@ static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev, } static int create_endpoint_and_queue_control(struct u132 *u132, - struct usb_host_endpoint *hep, struct urb *urb, + struct urb *urb, struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, gfp_t mem_flags) { struct u132_ring *ring; - u8 endp_number = ++u132->num_endpoints; - struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] = - kmalloc(sizeof(struct u132_endp), mem_flags); + unsigned long irqs; + int rc; + u8 endp_number; + struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); + if (!endp) { return -ENOMEM; } + + spin_lock_init(&endp->queue_lock.slock); + spin_lock_irqsave(&endp->queue_lock.slock, irqs); + rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); + if (rc) { + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + kfree(endp); + return rc; + } + + endp_number = ++u132->num_endpoints; + urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - spin_lock_init(&endp->queue_lock.slock); INIT_LIST_HEAD(&endp->urb_more); ring = endp->ring = &u132->ring[0]; if (ring->curr_endp) { @@ -2079,11 +2116,10 @@ static int create_endpoint_and_queue_control(struct u132 *u132, endp->delayed = 0; endp->endp_number = endp_number; endp->u132 = u132; - endp->hep = hep; + endp->hep = urb->ep; u132_endp_init_kref(u132, endp); u132_endp_get_kref(u132, endp); if (usb_addr == 0) { - unsigned long irqs; u8 address = u132->addr[usb_addr].address; struct u132_udev *udev = &u132->udev[address]; endp->udev_number = address; @@ -2097,7 +2133,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132, udev->endp_number_in[usb_endp] = endp_number; udev->endp_number_out[usb_endp] = endp_number; urb->hcpriv = u132; - spin_lock_irqsave(&endp->queue_lock.slock, irqs); endp->queue_size = 1; endp->queue_last = 0; endp->queue_next = 0; @@ -2106,7 +2141,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132, u132_endp_queue_work(u132, endp, 0); return 0; } else { /*(usb_addr > 0) */ - unsigned long irqs; u8 address = u132->addr[usb_addr].address; struct u132_udev *udev = &u132->udev[address]; endp->udev_number = address; @@ -2120,7 +2154,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132, udev->endp_number_in[usb_endp] = endp_number; udev->endp_number_out[usb_endp] = endp_number; urb->hcpriv = u132; - spin_lock_irqsave(&endp->queue_lock.slock, irqs); endp->queue_size = 1; endp->queue_last = 0; endp->queue_next = 0; @@ -2132,7 +2165,7 @@ static int create_endpoint_and_queue_control(struct u132 *u132, } static int queue_control_on_old_endpoint(struct u132 *u132, - struct usb_host_endpoint *hep, struct urb *urb, + struct urb *urb, struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, u8 usb_endp) { @@ -2232,8 +2265,8 @@ static int queue_control_on_old_endpoint(struct u132 *u132, } } -static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, - struct urb *urb, gfp_t mem_flags) +static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, + gfp_t mem_flags) { struct u132 *u132 = hcd_to_u132(hcd); if (irqs_disabled()) { @@ -2258,16 +2291,24 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { u8 address = u132->addr[usb_addr].address; struct u132_udev *udev = &u132->udev[address]; - struct u132_endp *endp = hep->hcpriv; + struct u132_endp *endp = urb->ep->hcpriv; urb->actual_length = 0; if (endp) { unsigned long irqs; int retval; spin_lock_irqsave(&endp->queue_lock.slock, irqs); - retval = queue_int_on_old_endpoint(u132, udev, - hep, urb, usb_dev, endp, usb_addr, - usb_endp, address); + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval == 0) { + retval = queue_int_on_old_endpoint( + u132, udev, urb, + usb_dev, endp, + usb_addr, usb_endp, + address); + if (retval) + usb_hcd_unlink_urb_from_ep( + hcd, urb); + } spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); if (retval) { @@ -2282,8 +2323,8 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, return -EINVAL; } else { /*(endp == NULL) */ return create_endpoint_and_queue_int(u132, udev, - hep, urb, usb_dev, usb_addr, usb_endp, - address, mem_flags); + urb, usb_dev, usb_addr, + usb_endp, address, mem_flags); } } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { dev_err(&u132->platform_dev->dev, "the hardware does no" @@ -2292,16 +2333,24 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, } else if (usb_pipetype(urb->pipe) == PIPE_BULK) { u8 address = u132->addr[usb_addr].address; struct u132_udev *udev = &u132->udev[address]; - struct u132_endp *endp = hep->hcpriv; + struct u132_endp *endp = urb->ep->hcpriv; urb->actual_length = 0; if (endp) { unsigned long irqs; int retval; spin_lock_irqsave(&endp->queue_lock.slock, irqs); - retval = queue_bulk_on_old_endpoint(u132, udev, - hep, urb, usb_dev, endp, usb_addr, - usb_endp, address); + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval == 0) { + retval = queue_bulk_on_old_endpoint( + u132, udev, urb, + usb_dev, endp, + usb_addr, usb_endp, + address); + if (retval) + usb_hcd_unlink_urb_from_ep( + hcd, urb); + } spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); if (retval) { @@ -2314,10 +2363,10 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, return -EINVAL; } else return create_endpoint_and_queue_bulk(u132, - udev, hep, urb, usb_dev, usb_addr, + udev, urb, usb_dev, usb_addr, usb_endp, address, mem_flags); } else { - struct u132_endp *endp = hep->hcpriv; + struct u132_endp *endp = urb->ep->hcpriv; u16 urb_size = 8; u8 *b = urb->setup_packet; int i = 0; @@ -2340,9 +2389,16 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, int retval; spin_lock_irqsave(&endp->queue_lock.slock, irqs); - retval = queue_control_on_old_endpoint(u132, - hep, urb, usb_dev, endp, usb_addr, - usb_endp); + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval == 0) { + retval = queue_control_on_old_endpoint( + u132, urb, usb_dev, + endp, usb_addr, + usb_endp); + if (retval) + usb_hcd_unlink_urb_from_ep( + hcd, urb); + } spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); if (retval) { @@ -2355,7 +2411,7 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, return -EINVAL; } else return create_endpoint_and_queue_control(u132, - hep, urb, usb_dev, usb_addr, usb_endp, + urb, usb_dev, usb_addr, usb_endp, mem_flags); } } @@ -2390,10 +2446,17 @@ static int dequeue_from_overflow_chain(struct u132 *u132, } static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, - struct urb *urb) + struct urb *urb, int status) { unsigned long irqs; + int rc; + spin_lock_irqsave(&endp->queue_lock.slock, irqs); + rc = usb_hcd_check_unlink_urb(u132_to_hcd(u132), urb, status); + if (rc) { + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + return rc; + } if (endp->queue_size == 0) { dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]" "=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", urb, @@ -2438,6 +2501,8 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, } if (urb_slot) { struct usb_hcd *hcd = u132_to_hcd(u132); + + usb_hcd_unlink_urb_from_ep(hcd, urb); endp->queue_size -= 1; if (list_empty(&endp->urb_more)) { spin_unlock_irqrestore(&endp->queue_lock.slock, @@ -2467,7 +2532,10 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); return -EINVAL; } else { - int retval = dequeue_from_overflow_chain(u132, endp, + int retval; + + usb_hcd_unlink_urb_from_ep(u132_to_hcd(u132), urb); + retval = dequeue_from_overflow_chain(u132, endp, urb); spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); return retval; @@ -2475,7 +2543,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, } } -static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct u132 *u132 = hcd_to_u132(hcd); if (u132->going > 2) { @@ -2490,11 +2558,11 @@ static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) if (usb_pipein(urb->pipe)) { u8 endp_number = udev->endp_number_in[usb_endp]; struct u132_endp *endp = u132->endp[endp_number - 1]; - return u132_endp_urb_dequeue(u132, endp, urb); + return u132_endp_urb_dequeue(u132, endp, urb, status); } else { u8 endp_number = udev->endp_number_out[usb_endp]; struct u132_endp *endp = u132->endp[endp_number - 1]; - return u132_endp_urb_dequeue(u132, endp, urb); + return u132_endp_urb_dequeue(u132, endp, urb, status); } } } diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 3bb908ca38e..bff200cb3d2 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -1376,7 +1376,6 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) } static int uhci_urb_enqueue(struct usb_hcd *hcd, - struct usb_host_endpoint *hep, struct urb *urb, gfp_t mem_flags) { int ret; @@ -1387,19 +1386,19 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, spin_lock_irqsave(&uhci->lock, flags); - ret = urb->status; - if (ret != -EINPROGRESS) /* URB already unlinked! */ - goto done; + ret = usb_hcd_link_urb_to_ep(hcd, urb); + if (ret) + goto done_not_linked; ret = -ENOMEM; urbp = uhci_alloc_urb_priv(uhci, urb); if (!urbp) goto done; - if (hep->hcpriv) - qh = (struct uhci_qh *) hep->hcpriv; + if (urb->ep->hcpriv) + qh = urb->ep->hcpriv; else { - qh = uhci_alloc_qh(uhci, urb->dev, hep); + qh = uhci_alloc_qh(uhci, urb->dev, urb->ep); if (!qh) goto err_no_qh; } @@ -1440,27 +1439,29 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, err_submit_failed: if (qh->state == QH_STATE_IDLE) uhci_make_qh_idle(uhci, qh); /* Reclaim unused QH */ - err_no_qh: uhci_free_urb_priv(uhci, urbp); - done: + if (ret) + usb_hcd_unlink_urb_from_ep(hcd, urb); +done_not_linked: spin_unlock_irqrestore(&uhci->lock, flags); return ret; } -static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); unsigned long flags; - struct urb_priv *urbp; struct uhci_qh *qh; + int rc; spin_lock_irqsave(&uhci->lock, flags); - urbp = urb->hcpriv; - if (!urbp) /* URB was never linked! */ + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) goto done; - qh = urbp->qh; + + qh = ((struct urb_priv *) urb->hcpriv)->qh; /* Remove Isochronous TDs from the frame list ASAP */ if (qh->type == USB_ENDPOINT_XFER_ISOC) { @@ -1477,7 +1478,7 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) done: spin_unlock_irqrestore(&uhci->lock, flags); - return 0; + return rc; } /* @@ -1529,6 +1530,7 @@ __acquires(uhci->lock) } uhci_free_urb_priv(uhci, urbp); + usb_hcd_unlink_urb_from_ep(uhci_to_hcd(uhci), urb); spin_unlock(&uhci->lock); usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb); -- cgit v1.2.3-70-g09d2 From d74d4a69dc1cc7ddc0eabb9c9f1e45005e2984eb Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 8 Aug 2007 11:59:18 -0400 Subject: USB: don't touch sysfs stuff when altsetting is unchanged This patch (as955) prevents the interface-related sysfs files and endpoint pseudo-devices from being deleted and recreated when a call to usb_set_interface() specifies the current altsetting. Since the altsetting doesn't get changed, there's no need to do anything. Furthermore, avoiding changes to the endpoint devices will be necessary in the future. This code is called from usb_reset_device(), which gets invoked for reset-resume processing, but upcoming changes to the PM and driver cores will make it impossible to register devices while a suspend/resume transition is in progress. Since we don't need to re-register those endpoint devices anyhow, it's best to skip the whole thing. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index c905b35d4f8..d638375e22e 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1173,6 +1173,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) struct usb_host_interface *alt; int ret; int manual = 0; + int changed; if (dev->state == USB_STATE_SUSPENDED) return -EHOSTUNREACH; @@ -1212,7 +1213,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) */ /* prevent submissions using previous endpoint settings */ - if (device_is_registered(&iface->dev)) + changed = (iface->cur_altsetting != alt); + if (changed && device_is_registered(&iface->dev)) usb_remove_sysfs_intf_files(iface); usb_disable_interface(dev, iface); @@ -1249,7 +1251,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) * (Likewise, EP0 never "halts" on well designed devices.) */ usb_enable_interface(dev, iface); - if (device_is_registered(&iface->dev)) + if (changed && device_is_registered(&iface->dev)) usb_create_sysfs_intf_files(iface); return 0; -- cgit v1.2.3-70-g09d2 From 79a7d9ee1a2e8b8dc44dd217f07496911850ec0e Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 8 Aug 2007 17:10:11 -0400 Subject: USB: cleanups for g_file_storage This patch (as957) makes some minor cleanups to the g_file_storage driver: Update the copyright date and version string; Uniformize the logging macros for the gadget and the LUNs; Remove "inline" markers -- nowadays we rely on the compiler to decide which routines are best inlined; Use the print_hex_dump() library routines; Remove some unnecessary assignments within conditionals and fix some close-brace indenting levels; Fix some column-80 violations. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/file_storage.c | 129 ++++++++++++++++++-------------------- 1 file changed, 62 insertions(+), 67 deletions(-) diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 0019116ee41..9998cd7af41 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -1,7 +1,7 @@ /* * file_storage.c -- File-backed USB Storage Gadget, for USB development * - * Copyright (C) 2003-2005 Alan Stern + * Copyright (C) 2003-2007 Alan Stern * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -218,7 +218,7 @@ /* #define VERBOSE_DEBUG */ -#undef DUMP_MSGS +/* #define DUMP_MSGS */ #include @@ -249,7 +249,7 @@ #define DRIVER_DESC "File-backed Storage Gadget" #define DRIVER_NAME "g_file_storage" -#define DRIVER_VERSION "28 November 2005" +#define DRIVER_VERSION "7 August 2007" static const char longname[] = DRIVER_DESC; static const char shortname[] = DRIVER_NAME; @@ -275,12 +275,9 @@ MODULE_LICENSE("Dual BSD/GPL"); /*-------------------------------------------------------------------------*/ -#define yprintk(l,level,fmt,args...) \ - dev_printk(level , &(l)->dev , fmt , ## args) - #ifdef DEBUG #define LDBG(lun,fmt,args...) \ - yprintk(lun , KERN_DEBUG , fmt , ## args) + dev_dbg(&(lun)->dev , fmt , ## args) #define MDBG(fmt,args...) \ printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args) #else @@ -300,11 +297,11 @@ MODULE_LICENSE("Dual BSD/GPL"); #endif /* VERBOSE_DEBUG */ #define LERROR(lun,fmt,args...) \ - yprintk(lun , KERN_ERR , fmt , ## args) + dev_err(&(lun)->dev , fmt , ## args) #define LWARN(lun,fmt,args...) \ - yprintk(lun , KERN_WARNING , fmt , ## args) + dev_warn(&(lun)->dev , fmt , ## args) #define LINFO(lun,fmt,args...) \ - yprintk(lun , KERN_INFO , fmt , ## args) + dev_info(&(lun)->dev , fmt , ## args) #define MINFO(fmt,args...) \ printk(KERN_INFO DRIVER_NAME ": " fmt , ## args) @@ -558,7 +555,7 @@ struct lun { #define backing_file_is_open(curlun) ((curlun)->filp != NULL) -static inline struct lun *dev_to_lun(struct device *dev) +static struct lun *dev_to_lun(struct device *dev) { return container_of(dev, struct lun, dev); } @@ -691,13 +688,13 @@ struct fsg_dev { typedef void (*fsg_routine_t)(struct fsg_dev *); -static int inline exception_in_progress(struct fsg_dev *fsg) +static int exception_in_progress(struct fsg_dev *fsg) { return (fsg->state > FSG_STATE_IDLE); } /* Make bulk-out requests be divisible by the maxpacket size */ -static void inline set_bulk_out_req_length(struct fsg_dev *fsg, +static void set_bulk_out_req_length(struct fsg_dev *fsg, struct fsg_buffhd *bh, unsigned int length) { unsigned int rem; @@ -723,50 +720,36 @@ static void close_all_backing_files(struct fsg_dev *fsg); static void dump_msg(struct fsg_dev *fsg, const char *label, const u8 *buf, unsigned int length) { - unsigned int start, num, i; - char line[52], *p; - - if (length >= 512) - return; - DBG(fsg, "%s, length %u:\n", label, length); - - start = 0; - while (length > 0) { - num = min(length, 16u); - p = line; - for (i = 0; i < num; ++i) { - if (i == 8) - *p++ = ' '; - sprintf(p, " %02x", buf[i]); - p += 3; - } - *p = 0; - printk(KERN_DEBUG "%6x: %s\n", start, line); - buf += num; - start += num; - length -= num; + if (length < 512) { + DBG(fsg, "%s, length %u:\n", label, length); + print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, + 16, 1, buf, length, 0); } } -static void inline dump_cdb(struct fsg_dev *fsg) +static void dump_cdb(struct fsg_dev *fsg) {} #else -static void inline dump_msg(struct fsg_dev *fsg, const char *label, +static void dump_msg(struct fsg_dev *fsg, const char *label, const u8 *buf, unsigned int length) {} -static void inline dump_cdb(struct fsg_dev *fsg) -{ - int i; - char cmdbuf[3*MAX_COMMAND_SIZE + 1]; +#ifdef VERBOSE_DEBUG - for (i = 0; i < fsg->cmnd_size; ++i) - sprintf(cmdbuf + i*3, " %02x", fsg->cmnd[i]); - VDBG(fsg, "SCSI CDB: %s\n", cmdbuf); +static void dump_cdb(struct fsg_dev *fsg) +{ + print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE, + 16, 1, fsg->cmnd, fsg->cmnd_size, 0); } +#else + +static void dump_cdb(struct fsg_dev *fsg) +{} + +#endif /* VERBOSE_DEBUG */ #endif /* DUMP_MSGS */ @@ -789,24 +772,24 @@ static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep) /* Routines for unaligned data access */ -static u16 inline get_be16(u8 *buf) +static u16 get_be16(u8 *buf) { return ((u16) buf[0] << 8) | ((u16) buf[1]); } -static u32 inline get_be32(u8 *buf) +static u32 get_be32(u8 *buf) { return ((u32) buf[0] << 24) | ((u32) buf[1] << 16) | ((u32) buf[2] << 8) | ((u32) buf[3]); } -static void inline put_be16(u8 *buf, u16 val) +static void put_be16(u8 *buf, u16 val) { buf[0] = val >> 8; buf[1] = val; } -static void inline put_be32(u8 *buf, u32 val) +static void put_be32(u8 *buf, u32 val) { buf[0] = val >> 24; buf[1] = val >> 16; @@ -992,7 +975,7 @@ static const struct usb_descriptor_header *hs_function[] = { #define HS_FUNCTION_PRE_EP_ENTRIES 2 /* Maxpacket and other transfer characteristics vary by speed. */ -static inline struct usb_endpoint_descriptor * +static struct usb_endpoint_descriptor * ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs, struct usb_endpoint_descriptor *hs) { @@ -1616,7 +1599,8 @@ static int do_read(struct fsg_dev *fsg) /* Wait for the next buffer to become available */ bh = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } @@ -1855,7 +1839,8 @@ static int do_write(struct fsg_dev *fsg) } /* Wait for something to happen */ - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } @@ -2339,7 +2324,8 @@ static int pad_with_zeros(struct fsg_dev *fsg) /* Wait for the next buffer to be free */ while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } @@ -2399,7 +2385,8 @@ static int throw_away_data(struct fsg_dev *fsg) } /* Otherwise wait for something to happen */ - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } return 0; @@ -2521,7 +2508,8 @@ static int send_status(struct fsg_dev *fsg) /* Wait for the next buffer to become available */ bh = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } @@ -2741,9 +2729,10 @@ static int do_scsi_command(struct fsg_dev *fsg) /* Wait for the next buffer to become available for data or status */ bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; - } + } fsg->phase_error = 0; fsg->short_packet_received = 0; @@ -3015,9 +3004,10 @@ static int get_next_command(struct fsg_dev *fsg) /* Wait for the next buffer to become available */ bh = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; - } + } /* Queue a request to read a Bulk-only CBW */ set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN); @@ -3031,9 +3021,10 @@ static int get_next_command(struct fsg_dev *fsg) /* Wait for the CBW to arrive */ while (bh->state != BUF_STATE_FULL) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; - } + } smp_rmb(); rc = received_cbw(fsg, bh); bh->state = BUF_STATE_EMPTY; @@ -3042,9 +3033,10 @@ static int get_next_command(struct fsg_dev *fsg) /* Wait for the next command to arrive */ while (fsg->cbbuf_cmnd_size == 0) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; - } + } /* Is the previous status interrupt request still busy? * The host is allowed to skip reading the status, @@ -3565,7 +3557,8 @@ static ssize_t show_ro(struct device *dev, struct device_attribute *attr, char * return sprintf(buf, "%d\n", curlun->ro); } -static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_file(struct device *dev, struct device_attribute *attr, + char *buf) { struct lun *curlun = dev_to_lun(dev); struct fsg_dev *fsg = dev_get_drvdata(dev); @@ -3574,8 +3567,8 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, char down_read(&fsg->filesem); if (backing_file_is_open(curlun)) { // Get the complete pathname - p = d_path(curlun->filp->f_path.dentry, curlun->filp->f_path.mnt, - buf, PAGE_SIZE - 1); + p = d_path(curlun->filp->f_path.dentry, + curlun->filp->f_path.mnt, buf, PAGE_SIZE - 1); if (IS_ERR(p)) rc = PTR_ERR(p); else { @@ -3593,7 +3586,8 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, char } -static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t store_ro(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { ssize_t rc = count; struct lun *curlun = dev_to_lun(dev); @@ -3617,7 +3611,8 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const return rc; } -static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t store_file(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct lun *curlun = dev_to_lun(dev); struct fsg_dev *fsg = dev_get_drvdata(dev); -- cgit v1.2.3-70-g09d2 From ed86d97068c7d53561d3e9b59db6c6b11f6091c7 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 10 Aug 2007 09:34:24 -0400 Subject: USB: SisUSB2VGA: Whitespace Cleanups This patches clean some trailing whitespaces in sisusb2vga driver. Signed-off-by: Felipe Balbi Cc: Thomas Winischhofer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb.c | 26 +++++++++++++------------- drivers/usb/misc/sisusbvga/sisusb.h | 6 +++--- drivers/usb/misc/sisusbvga/sisusb_init.c | 2 +- drivers/usb/misc/sisusbvga/sisusb_init.h | 4 ++-- drivers/usb/misc/sisusbvga/sisusb_struct.h | 2 +- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index b64ca91d9b0..376f86cab4b 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -32,7 +32,7 @@ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Author: Thomas Winischhofer + * Author: Thomas Winischhofer * */ @@ -962,12 +962,12 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, packet.address = 0x00000194; packet.data = addr; ret = sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); + &packet, 0); packet.header = 0x001f; packet.address = 0x00000190; packet.data = (length & ~3); ret |= sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); + &packet, 0); if (sisusb->flagb0 != 0x16) { packet.header = 0x001f; packet.address = 0x00000180; @@ -1019,7 +1019,7 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, } if (ret) - break; + break; } @@ -1305,7 +1305,7 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, } if (ret) - break; + break; } return ret; @@ -1533,9 +1533,9 @@ sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length) #define SETIREGAND(r,i,a) sisusb_setidxregand(sisusb, r, i, a) #define SETIREGANDOR(r,i,a,o) sisusb_setidxregandor(sisusb, r, i, a, o) #define READL(a,d) sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d) -#define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d) +#define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d) #define READB(a,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d) -#define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d) +#define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d) static int sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype) @@ -2008,7 +2008,7 @@ sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines) SETIREG(SISSR, 0x26, 0x00); } - SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */ + SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */ return ret; } @@ -2942,7 +2942,7 @@ static int sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y, unsigned long arg) { - int retval, port, length; + int retval, port, length; u32 address; /* All our commands require the device @@ -3065,12 +3065,12 @@ sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y, static int sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) + unsigned long arg) { struct sisusb_usb_data *sisusb; struct sisusb_info x; struct sisusb_command y; - int retval = 0; + int retval = 0; u32 __user *argp = (u32 __user *)arg; if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) @@ -3095,7 +3095,7 @@ sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, case SISUSB_GET_CONFIG: - x.sisusb_id = SISUSB_ID; + x.sisusb_id = SISUSB_ID; x.sisusb_version = SISUSB_VERSION; x.sisusb_revision = SISUSB_REVISION; x.sisusb_patchlevel = SISUSB_PATCHLEVEL; @@ -3164,7 +3164,7 @@ static const struct file_operations usb_sisusb_fops = { .release = sisusb_release, .read = sisusb_read, .write = sisusb_write, - .llseek = sisusb_lseek, + .llseek = sisusb_lseek, #ifdef SISUSB_NEW_CONFIG_COMPAT .compat_ioctl = sisusb_compat_ioctl, #endif diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h index 8e1120a6480..555fed0ba0e 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.h +++ b/drivers/usb/misc/sisusbvga/sisusb.h @@ -30,7 +30,7 @@ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Author: Thomas Winischhofer + * Author: Thomas Winischhofer * */ @@ -53,7 +53,7 @@ /* Version Information */ #define SISUSB_VERSION 0 -#define SISUSB_REVISION 0 +#define SISUSB_REVISION 0 #define SISUSB_PATCHLEVEL 8 /* Include console and mode switching code? */ @@ -93,7 +93,7 @@ */ #ifdef __BIG_ENDIAN -#define SISUSB_CORRECT_ENDIANNESS_PACKET(p) \ +#define SISUSB_CORRECT_ENDIANNESS_PACKET(p) \ do { \ p->header = cpu_to_le16(p->header); \ p->address = cpu_to_le32(p->address); \ diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.c b/drivers/usb/misc/sisusbvga/sisusb_init.c index 9b30f896281..d51de0ff9e4 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.c +++ b/drivers/usb/misc/sisusbvga/sisusb_init.c @@ -32,7 +32,7 @@ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Author: Thomas Winischhofer + * Author: Thomas Winischhofer * */ diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.h b/drivers/usb/misc/sisusbvga/sisusb_init.h index 864bc0e9659..d47301eaca7 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.h +++ b/drivers/usb/misc/sisusbvga/sisusb_init.h @@ -46,7 +46,7 @@ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Author: Thomas Winischhofer + * Author: Thomas Winischhofer * */ @@ -82,7 +82,7 @@ /* Infoflag */ #define SupportTV 0x0008 #define SupportTV1024 0x0800 -#define SupportCHTV 0x0800 +#define SupportCHTV 0x0800 #define Support64048060Hz 0x0800 /* Special for 640x480 LCD */ #define SupportHiVision 0x0010 #define SupportYPbPr750p 0x1000 diff --git a/drivers/usb/misc/sisusbvga/sisusb_struct.h b/drivers/usb/misc/sisusbvga/sisusb_struct.h index f325ecb29a6..9def598192c 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_struct.h +++ b/drivers/usb/misc/sisusbvga/sisusb_struct.h @@ -44,7 +44,7 @@ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Author: Thomas Winischhofer + * Author: Thomas Winischhofer * */ -- cgit v1.2.3-70-g09d2 From 9dedd36778f9d9bd043df27c8fc62088ce93813f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 10 Aug 2007 09:34:26 -0400 Subject: USB: SisUSB2VGA: Remove if 0'ed code Unused code should be removed. We don't need to increase the size of the file with dead code inside if 0 statements. Signed-off-by: Felipe Balbi Cc: Thomas Winischhofer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb.c | 57 -------------------- drivers/usb/misc/sisusbvga/sisusb.h | 4 +- drivers/usb/misc/sisusbvga/sisusb_con.c | 47 ----------------- drivers/usb/misc/sisusbvga/sisusb_init.c | 90 -------------------------------- 4 files changed, 1 insertion(+), 197 deletions(-) diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 376f86cab4b..558b94fd209 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -1261,47 +1261,6 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, addr += 4; length -= 4; } -#if 0 /* That does not work, as EP 2 is an OUT EP! */ - default: - CLEARPACKET(&packet); - packet.header = 0x001f; - packet.address = 0x000001a0; - packet.data = 0x00000006; - ret |= sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); - packet.header = 0x001f; - packet.address = 0x000001b0; - packet.data = (length & ~3) | 0x40000000; - ret |= sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); - packet.header = 0x001f; - packet.address = 0x000001b4; - packet.data = addr; - ret |= sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); - packet.header = 0x001f; - packet.address = 0x000001a4; - packet.data = 0x00000001; - ret |= sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); - if (userbuffer) { - ret |= sisusb_recv_bulk_msg(sisusb, - SISUSB_EP_GFX_BULK_IN, - (length & ~3), - NULL, userbuffer, - bytes_read, 0); - if (!ret) userbuffer += (*bytes_read); - } else { - ret |= sisusb_recv_bulk_msg(sisusb, - SISUSB_EP_GFX_BULK_IN, - (length & ~3), - kernbuffer, NULL, - bytes_read, 0); - if (!ret) kernbuffer += (*bytes_read); - } - addr += (*bytes_read); - length -= (*bytes_read); -#endif } if (ret) @@ -1401,22 +1360,6 @@ sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data) return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data)); } -#if 0 - -int -sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data) -{ - return(sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data)); -} - -int -sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data) -{ - return(sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data)); -} - -#endif /* 0 */ - int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src, u32 dest, int length, size_t *bytes_written) diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h index 555fed0ba0e..dc0473921e3 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.h +++ b/drivers/usb/misc/sisusbvga/sisusb.h @@ -46,9 +46,7 @@ /* For older kernels, support for text consoles is by default * off. To ensable text console support, change the following: */ -#if 0 -#define CONFIG_USB_SISUSBVGA_CON -#endif +/* #define CONFIG_USB_SISUSBVGA_CON */ /* Version Information */ diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index 8d0edc867f3..20938cd09ed 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -373,14 +373,6 @@ sisusbcon_putc(struct vc_data *c, int ch, int y, int x) return; /* sisusb->lock is down */ - - /* Don't need to put the character into buffer ourselves, - * because the vt does this BEFORE calling us. - */ -#if 0 - sisusbcon_writew(ch, SISUSB_VADDR(x, y)); -#endif - if (sisusb_is_inactive(c, sisusb)) { mutex_unlock(&sisusb->lock); return; @@ -490,10 +482,6 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx, struct sisusb_usb_data *sisusb; ssize_t written; int cols, length; -#if 0 - u16 *src, *dest; - int i; -#endif if (width <= 0 || height <= 0) return; @@ -505,41 +493,6 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx, cols = sisusb->sisusb_num_columns; - /* Don't need to move data outselves, because - * vt does this BEFORE calling us. - * This is only used by vt's insert/deletechar. - */ -#if 0 - if (sx == 0 && dx == 0 && width >= c->vc_cols && width <= cols) { - - sisusbcon_memmovew(SISUSB_VADDR(0, dy), SISUSB_VADDR(0, sy), - height * width * 2); - - } else if (dy < sy || (dy == sy && dx < sx)) { - - src = SISUSB_VADDR(sx, sy); - dest = SISUSB_VADDR(dx, dy); - - for (i = height; i > 0; i--) { - sisusbcon_memmovew(dest, src, width * 2); - src += cols; - dest += cols; - } - - } else { - - src = SISUSB_VADDR(sx, sy + height - 1); - dest = SISUSB_VADDR(dx, dy + height - 1); - - for (i = height; i > 0; i--) { - sisusbcon_memmovew(dest, src, width * 2); - src -= cols; - dest -= cols; - } - - } -#endif - if (sisusb_is_inactive(c, sisusb)) { mutex_unlock(&sisusb->lock); return; diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.c b/drivers/usb/misc/sisusbvga/sisusb_init.c index d51de0ff9e4..5d8358295e7 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.c +++ b/drivers/usb/misc/sisusbvga/sisusb_init.c @@ -69,96 +69,6 @@ SiSUSB_InitPtr(struct SiS_Private *SiS_Pr) SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData; } -/*********************************************/ -/* HELPER: Get ModeID */ -/*********************************************/ - -#if 0 -unsigned short -SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth) -{ - unsigned short ModeIndex = 0; - - switch (HDisplay) - { - case 320: - if (VDisplay == 200) - ModeIndex = ModeIndex_320x200[Depth]; - else if (VDisplay == 240) - ModeIndex = ModeIndex_320x240[Depth]; - break; - case 400: - if (VDisplay == 300) - ModeIndex = ModeIndex_400x300[Depth]; - break; - case 512: - if (VDisplay == 384) - ModeIndex = ModeIndex_512x384[Depth]; - break; - case 640: - if (VDisplay == 480) - ModeIndex = ModeIndex_640x480[Depth]; - else if (VDisplay == 400) - ModeIndex = ModeIndex_640x400[Depth]; - break; - case 720: - if (VDisplay == 480) - ModeIndex = ModeIndex_720x480[Depth]; - else if (VDisplay == 576) - ModeIndex = ModeIndex_720x576[Depth]; - break; - case 768: - if (VDisplay == 576) - ModeIndex = ModeIndex_768x576[Depth]; - break; - case 800: - if (VDisplay == 600) - ModeIndex = ModeIndex_800x600[Depth]; - else if (VDisplay == 480) - ModeIndex = ModeIndex_800x480[Depth]; - break; - case 848: - if (VDisplay == 480) - ModeIndex = ModeIndex_848x480[Depth]; - break; - case 856: - if (VDisplay == 480) - ModeIndex = ModeIndex_856x480[Depth]; - break; - case 960: - if (VDisplay == 540) - ModeIndex = ModeIndex_960x540[Depth]; - else if (VDisplay == 600) - ModeIndex = ModeIndex_960x600[Depth]; - break; - case 1024: - if (VDisplay == 576) - ModeIndex = ModeIndex_1024x576[Depth]; - else if (VDisplay == 768) - ModeIndex = ModeIndex_1024x768[Depth]; - break; - case 1152: - if (VDisplay == 864) - ModeIndex = ModeIndex_1152x864[Depth]; - break; - case 1280: - switch (VDisplay) { - case 720: - ModeIndex = ModeIndex_1280x720[Depth]; - break; - case 768: - ModeIndex = ModeIndex_1280x768[Depth]; - break; - case 1024: - ModeIndex = ModeIndex_1280x1024[Depth]; - break; - } - } - - return ModeIndex; -} -#endif /* 0 */ - /*********************************************/ /* HELPER: SetReg, GetReg */ /*********************************************/ -- cgit v1.2.3-70-g09d2 From 2acbd647315017c07537287857ea2db36c70eacf Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 10 Aug 2007 09:34:27 -0400 Subject: USB: SisUSB2VGA: Mis-spelled word Trivial fix Signed-off-by: Felipe Balbi Cc: Thomas Winischhofer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h index dc0473921e3..7183e762fea 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.h +++ b/drivers/usb/misc/sisusbvga/sisusb.h @@ -44,7 +44,7 @@ #include /* For older kernels, support for text consoles is by default - * off. To ensable text console support, change the following: + * off. To enable text console support, change the following: */ /* #define CONFIG_USB_SISUSBVGA_CON */ -- cgit v1.2.3-70-g09d2 From 1c1772a2609a16b3b590f8390a337dbe25859118 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 10 Aug 2007 09:34:29 -0400 Subject: USB: SisUSB2VGA: Lindent drivers/usb/misc/sisusbvga/sisusb.h Better indentation Signed-off-by: Felipe Balbi Cc: Thomas Winischhofer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb.h | 118 ++++++++++++++++++------------------ 1 file changed, 58 insertions(+), 60 deletions(-) diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h index 7183e762fea..d2d7872cd02 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.h +++ b/drivers/usb/misc/sisusbvga/sisusb.h @@ -8,27 +8,27 @@ * * Otherwise, the following license terms apply: * - * * Redistribution and use in source and binary forms, with or without - * * modification, are permitted provided that the following conditions - * * are met: - * * 1) Redistributions of source code must retain the above copyright - * * notice, this list of conditions and the following disclaimer. - * * 2) Redistributions in binary form must reproduce the above copyright - * * notice, this list of conditions and the following disclaimer in the - * * documentation and/or other materials provided with the distribution. - * * 3) The name of the author may not be used to endorse or promote products - * * derived from this software without specific prior written permission. - * * - * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR - * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1) Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2) Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3) The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Author: Thomas Winischhofer * @@ -72,7 +72,7 @@ #define SISUSB_IBUF_SIZE 0x01000 #define SISUSB_OBUF_SIZE 0x10000 /* fixed */ -#define NUMOBUFS 8 /* max number of output buffers/output URBs */ +#define NUMOBUFS 8 /* max number of output buffers/output URBs */ /* About endianness: * @@ -103,7 +103,7 @@ struct sisusb_usb_data; -struct sisusb_urb_context { /* urb->context for outbound bulk URBs */ +struct sisusb_urb_context { /* urb->context for outbound bulk URBs */ struct sisusb_usb_data *sisusb; int urbindex; int *actual_length; @@ -114,16 +114,16 @@ struct sisusb_usb_data { struct usb_interface *interface; struct kref kref; wait_queue_head_t wait_q; /* for syncind and timeouts */ - struct mutex lock; /* general race avoidance */ - unsigned int ifnum; /* interface number of the USB device */ - int minor; /* minor (for logging clarity) */ - int isopen; /* !=0 if open */ - int present; /* !=0 if device is present on the bus */ - int ready; /* !=0 if device is ready for userland */ + struct mutex lock; /* general race avoidance */ + unsigned int ifnum; /* interface number of the USB device */ + int minor; /* minor (for logging clarity) */ + int isopen; /* !=0 if open */ + int present; /* !=0 if device is present on the bus */ + int ready; /* !=0 if device is ready for userland */ #ifdef SISUSB_OLD_CONFIG_COMPAT int ioctl32registered; #endif - int numobufs; /* number of obufs = number of out urbs */ + int numobufs; /* number of obufs = number of out urbs */ char *obuf[NUMOBUFS], *ibuf; /* transfer buffers */ int obufsize, ibufsize; dma_addr_t transfer_dma_out[NUMOBUFS]; @@ -134,13 +134,13 @@ struct sisusb_usb_data { unsigned char completein; struct sisusb_urb_context urbout_context[NUMOBUFS]; unsigned long flagb0; - unsigned long vrambase; /* framebuffer base */ - unsigned int vramsize; /* framebuffer size (bytes) */ + unsigned long vrambase; /* framebuffer base */ + unsigned int vramsize; /* framebuffer size (bytes) */ unsigned long mmiobase; unsigned int mmiosize; unsigned long ioportbase; - unsigned char devinit; /* device initialized? */ - unsigned char gfxinit; /* graphics core initialized? */ + unsigned char devinit; /* device initialized? */ + unsigned char gfxinit; /* graphics core initialized? */ unsigned short chipid, chipvendor; unsigned short chiprevision; #ifdef INCL_SISUSB_CON @@ -150,7 +150,7 @@ struct sisusb_usb_data { int haveconsole, con_first, con_last; int havethisconsole[MAX_NR_CONSOLES]; int textmodedestroyed; - unsigned int sisusb_num_columns; /* real number, not vt's idea */ + unsigned int sisusb_num_columns; /* real number, not vt's idea */ int cur_start_addr, con_rolled_over; int sisusb_cursor_loc, bad_cursor_pos; int sisusb_cursor_size_from; @@ -195,7 +195,7 @@ struct sisusb_packet { unsigned short header; u32 address; u32 data; -} __attribute__((__packed__)); +} __attribute__ ((__packed__)); #define CLEARPACKET(packet) memset(packet, 0, 10) @@ -263,36 +263,36 @@ struct sisusb_packet { /* Structure argument for SISUSB_GET_INFO ioctl */ struct sisusb_info { - __u32 sisusb_id; /* for identifying sisusb */ -#define SISUSB_ID 0x53495355 /* Identify myself with 'SISU' */ - __u8 sisusb_version; - __u8 sisusb_revision; - __u8 sisusb_patchlevel; - __u8 sisusb_gfxinit; /* graphics core initialized? */ + __u32 sisusb_id; /* for identifying sisusb */ +#define SISUSB_ID 0x53495355 /* Identify myself with 'SISU' */ + __u8 sisusb_version; + __u8 sisusb_revision; + __u8 sisusb_patchlevel; + __u8 sisusb_gfxinit; /* graphics core initialized? */ - __u32 sisusb_vrambase; - __u32 sisusb_mmiobase; - __u32 sisusb_iobase; - __u32 sisusb_pcibase; + __u32 sisusb_vrambase; + __u32 sisusb_mmiobase; + __u32 sisusb_iobase; + __u32 sisusb_pcibase; - __u32 sisusb_vramsize; /* framebuffer size in bytes */ + __u32 sisusb_vramsize; /* framebuffer size in bytes */ - __u32 sisusb_minor; + __u32 sisusb_minor; - __u32 sisusb_fbdevactive; /* != 0 if framebuffer device active */ + __u32 sisusb_fbdevactive; /* != 0 if framebuffer device active */ - __u32 sisusb_conactive; /* != 0 if console driver active */ + __u32 sisusb_conactive; /* != 0 if console driver active */ - __u8 sisusb_reserved[28]; /* for future use */ + __u8 sisusb_reserved[28]; /* for future use */ }; struct sisusb_command { - __u8 operation; /* see below */ - __u8 data0; /* operation dependent */ - __u8 data1; /* operation dependent */ - __u8 data2; /* operation dependent */ - __u32 data3; /* operation dependent */ - __u32 data4; /* for future use */ + __u8 operation; /* see below */ + __u8 data0; /* operation dependent */ + __u8 data1; /* operation dependent */ + __u8 data2; /* operation dependent */ + __u32 data3; /* operation dependent */ + __u32 data4; /* for future use */ }; #define SUCMD_GET 0x01 /* for all: data0 = index, data3 = port */ @@ -304,7 +304,7 @@ struct sisusb_command { #define SUCMD_CLRSCR 0x07 /* data0:1:2 = length, data3 = address */ -#define SUCMD_HANDLETEXTMODE 0x08 /* Reset/destroy text mode */ +#define SUCMD_HANDLETEXTMODE 0x08 /* Reset/destroy text mode */ #define SUCMD_SETMODE 0x09 /* Set a display mode (data3 = SiS mode) */ #define SUCMD_SETVESAMODE 0x0a /* Set a display mode (data3 = VESA mode) */ @@ -313,6 +313,4 @@ struct sisusb_command { #define SISUSB_GET_CONFIG_SIZE _IOR(0xF3,0x3E,__u32) #define SISUSB_GET_CONFIG _IOR(0xF3,0x3F,struct sisusb_info) - #endif /* SISUSB_H */ - -- cgit v1.2.3-70-g09d2 From 22b2c526e70741ce8a244cab339fe0f56ace8cb6 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 10 Aug 2007 09:34:31 -0400 Subject: USB: SisUSB2VGA: Lindent drivers/usb/misc/sisusbvga/sisusb_init.c Better indentation Signed-off-by: Felipe Balbi Cc: Thomas Winischhofer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb_init.c | 262 ++++++++++++++++--------------- 1 file changed, 133 insertions(+), 129 deletions(-) diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.c b/drivers/usb/misc/sisusbvga/sisusb_init.c index 5d8358295e7..273de5d0934 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.c +++ b/drivers/usb/misc/sisusbvga/sisusb_init.c @@ -55,18 +55,17 @@ /* POINTER INITIALIZATION */ /*********************************************/ -static void -SiSUSB_InitPtr(struct SiS_Private *SiS_Pr) +static void SiSUSB_InitPtr(struct SiS_Private *SiS_Pr) { - SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo; - SiS_Pr->SiS_StandTable = SiSUSB_StandTable; + SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo; + SiS_Pr->SiS_StandTable = SiSUSB_StandTable; - SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable; - SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable; - SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex; - SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table; + SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable; + SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable; + SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex; + SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table; - SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData; + SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData; } /*********************************************/ @@ -75,21 +74,20 @@ SiSUSB_InitPtr(struct SiS_Private *SiS_Pr) static void SiS_SetReg(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short index, unsigned short data) + unsigned short index, unsigned short data) { sisusb_setidxreg(SiS_Pr->sisusb, port, index, data); } static void SiS_SetRegByte(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short data) + unsigned short data) { sisusb_setreg(SiS_Pr->sisusb, port, data); } static unsigned char -SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short index) +SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port, unsigned short index) { u8 data; @@ -110,22 +108,22 @@ SiS_GetRegByte(struct SiS_Private *SiS_Pr, unsigned long port) static void SiS_SetRegANDOR(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short index, unsigned short DataAND, - unsigned short DataOR) + unsigned short index, unsigned short DataAND, + unsigned short DataOR) { sisusb_setidxregandor(SiS_Pr->sisusb, port, index, DataAND, DataOR); } static void SiS_SetRegAND(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short index, unsigned short DataAND) + unsigned short index, unsigned short DataAND) { sisusb_setidxregand(SiS_Pr->sisusb, port, index, DataAND); } static void -SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port, - unsigned short index, unsigned short DataOR) +SiS_SetRegOR(struct SiS_Private *SiS_Pr, unsigned long port, + unsigned short index, unsigned short DataOR) { sisusb_setidxregor(SiS_Pr->sisusb, port, index, DataOR); } @@ -134,8 +132,7 @@ SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port, /* HELPER: DisplayOn, DisplayOff */ /*********************************************/ -static void -SiS_DisplayOn(struct SiS_Private *SiS_Pr) +static void SiS_DisplayOn(struct SiS_Private *SiS_Pr) { SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0xDF); } @@ -144,8 +141,7 @@ SiS_DisplayOn(struct SiS_Private *SiS_Pr) /* HELPER: Init Port Addresses */ /*********************************************/ -static void -SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr) +static void SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr) { SiS_Pr->SiS_P3c4 = BaseAddr + 0x14; SiS_Pr->SiS_P3d4 = BaseAddr + 0x24; @@ -168,8 +164,7 @@ SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr) /* HELPER: GetSysFlags */ /*********************************************/ -static void -SiS_GetSysFlags(struct SiS_Private *SiS_Pr) +static void SiS_GetSysFlags(struct SiS_Private *SiS_Pr) { SiS_Pr->SiS_MyCR63 = 0x63; } @@ -178,8 +173,7 @@ SiS_GetSysFlags(struct SiS_Private *SiS_Pr) /* HELPER: Init PCI & Engines */ /*********************************************/ -static void -SiSInitPCIetc(struct SiS_Private *SiS_Pr) +static void SiSInitPCIetc(struct SiS_Private *SiS_Pr) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x20, 0xa1); /* - Enable 2D (0x40) @@ -195,8 +189,7 @@ SiSInitPCIetc(struct SiS_Private *SiS_Pr) /* HELPER: SET SEGMENT REGISTERS */ /*********************************************/ -static void -SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value) +static void SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value) { unsigned short temp; @@ -209,8 +202,7 @@ SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value) SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp); } -static void -SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value) +static void SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value) { unsigned short temp; @@ -223,15 +215,13 @@ SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value) SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp); } -static void -SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value) +static void SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value) { SiS_SetSegRegLower(SiS_Pr, value); SiS_SetSegRegUpper(SiS_Pr, value); } -static void -SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr) +static void SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr) { SiS_SetSegmentReg(SiS_Pr, 0); } @@ -247,14 +237,12 @@ SiS_SetSegmentRegOver(struct SiS_Private *SiS_Pr, unsigned short value) SiS_SetSegmentReg(SiS_Pr, value); } -static void -SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr) +static void SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr) { SiS_SetSegmentRegOver(SiS_Pr, 0); } -static void -SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr) +static void SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr) { SiS_ResetSegmentReg(SiS_Pr); SiS_ResetSegmentRegOver(SiS_Pr); @@ -266,7 +254,7 @@ SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr) static int SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo, - unsigned short *ModeIdIndex) + unsigned short *ModeIdIndex) { if ((*ModeNo) <= 0x13) { @@ -277,12 +265,14 @@ SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo, } else { - for(*ModeIdIndex = 0; ;(*ModeIdIndex)++) { + for (*ModeIdIndex = 0;; (*ModeIdIndex)++) { - if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == (*ModeNo)) + if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == + (*ModeNo)) break; - if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF) + if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == + 0xFF) return 0; } @@ -295,8 +285,7 @@ SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo, /* HELPER: ENABLE CRT1 */ /*********************************************/ -static void -SiS_HandleCRT1(struct SiS_Private *SiS_Pr) +static void SiS_HandleCRT1(struct SiS_Private *SiS_Pr) { /* Enable CRT1 gating */ SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, SiS_Pr->SiS_MyCR63, 0xbf); @@ -308,9 +297,9 @@ SiS_HandleCRT1(struct SiS_Private *SiS_Pr) static unsigned short SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex) + unsigned short ModeIdIndex) { - static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8}; + static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8 }; unsigned short modeflag; short index; @@ -321,7 +310,8 @@ SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo, } index = (modeflag & ModeTypeMask) - ModeEGA; - if (index < 0) index = 0; + if (index < 0) + index = 0; return ColorDepth[index]; } @@ -331,7 +321,7 @@ SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static unsigned short SiS_GetOffset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex, unsigned short rrti) + unsigned short ModeIdIndex, unsigned short rrti) { unsigned short xres, temp, colordepth, infoflag; @@ -368,8 +358,8 @@ SiS_SetSeqRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0] | 0x20; SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, SRdata); - for(i = 2; i <= 4; i++) { - SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i-1]; + for (i = 2; i <= 4; i++) { + SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i - 1]; SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, SRdata); } } @@ -398,7 +388,7 @@ SiS_SetCRTCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f); - for(i = 0; i <= 0x18; i++) { + for (i = 0; i <= 0x18; i++) { CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i]; SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, i, CRTCdata); } @@ -414,7 +404,7 @@ SiS_SetATTRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) unsigned char ARdata; unsigned short i; - for(i = 0; i <= 0x13; i++) { + for (i = 0; i <= 0x13; i++) { ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i]; SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da); SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, i); @@ -439,7 +429,7 @@ SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) unsigned char GRdata; unsigned short i; - for(i = 0; i <= 0x08; i++) { + for (i = 0; i <= 0x08; i++) { GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i]; SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3ce, i, GRdata); } @@ -454,12 +444,11 @@ SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) /* CLEAR EXTENDED REGISTERS */ /*********************************************/ -static void -SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo) +static void SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo) { int i; - for(i = 0x0A; i <= 0x0E; i++) { + for (i = 0x0A; i <= 0x0E; i++) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, 0x00); } @@ -472,15 +461,16 @@ SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo) static unsigned short SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex) + unsigned short ModeIdIndex) { unsigned short rrti, i, index, temp; if (ModeNo <= 0x13) return 0xFFFF; - index = SiS_GetReg(SiS_Pr,SiS_Pr->SiS_P3d4, 0x33) & 0x0F; - if (index > 0) index--; + index = SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x33) & 0x0F; + if (index > 0) + index--; rrti = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; ModeNo = SiS_Pr->SiS_RefIndex[rrti].ModeID; @@ -490,13 +480,14 @@ SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, if (SiS_Pr->SiS_RefIndex[rrti + i].ModeID != ModeNo) break; - temp = SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask; + temp = + SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask; if (temp < SiS_Pr->SiS_ModeType) break; i++; index--; - } while(index != 0xFFFF); + } while (index != 0xFFFF); i--; @@ -507,8 +498,7 @@ SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, /* SYNC */ /*********************************************/ -static void -SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti) +static void SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti) { unsigned short sync = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag >> 8; sync &= 0xC0; @@ -522,39 +512,40 @@ SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti) static void SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex, unsigned short rrti) + unsigned short ModeIdIndex, unsigned short rrti) { - unsigned char index; + unsigned char index; unsigned short temp, i, j, modeflag; - SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4,0x11,0x7f); + SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f); modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRT1CRTC; - for(i = 0,j = 0; i <= 7; i++, j++) { + for (i = 0, j = 0; i <= 7; i++, j++) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j, - SiS_Pr->SiS_CRT1Table[index].CR[i]); + SiS_Pr->SiS_CRT1Table[index].CR[i]); } - for(j = 0x10; i <= 10; i++, j++) { + for (j = 0x10; i <= 10; i++, j++) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j, - SiS_Pr->SiS_CRT1Table[index].CR[i]); + SiS_Pr->SiS_CRT1Table[index].CR[i]); } - for(j = 0x15; i <= 12; i++, j++) { + for (j = 0x15; i <= 12; i++, j++) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j, - SiS_Pr->SiS_CRT1Table[index].CR[i]); + SiS_Pr->SiS_CRT1Table[index].CR[i]); } - for(j = 0x0A; i <= 15; i++, j++) { + for (j = 0x0A; i <= 15; i++, j++) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, j, - SiS_Pr->SiS_CRT1Table[index].CR[i]); + SiS_Pr->SiS_CRT1Table[index].CR[i]); } temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0; - SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4, 0x0E, temp); + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0E, temp); temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5; - if (modeflag & DoubleScanMode) temp |= 0x80; + if (modeflag & DoubleScanMode) + temp |= 0x80; SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x09, 0x5F, temp); if (SiS_Pr->SiS_ModeType > ModeVGA) @@ -569,10 +560,10 @@ SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex, unsigned short rrti) + unsigned short ModeIdIndex, unsigned short rrti) { unsigned short du = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, rrti); - unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag; + unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag; unsigned short temp; temp = (du >> 8) & 0x0f; @@ -580,11 +571,13 @@ SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x13, (du & 0xFF)); - if (infoflag & InterlaceMode) du >>= 1; + if (infoflag & InterlaceMode) + du >>= 1; du <<= 5; temp = (du >> 8) & 0xff; - if (du & 0xff) temp++; + if (du & 0xff) + temp++; temp++; SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x10, temp); } @@ -595,17 +588,17 @@ SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short rrti) + unsigned short rrti) { unsigned short index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK; unsigned short clka = SiS_Pr->SiS_VCLKData[index].SR2B; unsigned short clkb = SiS_Pr->SiS_VCLKData[index].SR2C; - SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4,0x31,0xCF); + SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x31, 0xCF); - SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2B,clka); - SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2C,clkb); - SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2D,0x01); + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2B, clka); + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2C, clkb); + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2D, 0x01); } /*********************************************/ @@ -614,7 +607,7 @@ SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short mi) + unsigned short mi) { unsigned short modeflag = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag; @@ -639,7 +632,7 @@ SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short rrti) + unsigned short rrti) { unsigned short data = 0, VCLK = 0, index = 0; @@ -648,7 +641,8 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo, VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; } - if (VCLK >= 166) data |= 0x0c; + if (VCLK >= 166) + data |= 0x0c; SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x32, 0xf3, data); if (VCLK >= 166) @@ -668,7 +662,7 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex, unsigned short rrti) + unsigned short ModeIdIndex, unsigned short rrti) { unsigned short data, infoflag = 0, modeflag; @@ -688,17 +682,22 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, data |= 0x02; data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2); } - if (infoflag & InterlaceMode) data |= 0x20; + if (infoflag & InterlaceMode) + data |= 0x20; } SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x06, 0xC0, data); data = 0; if (infoflag & InterlaceMode) { /* data = (Hsync / 8) - ((Htotal / 8) / 2) + 3 */ - unsigned short hrs = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) | - ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2)) - 3; - unsigned short hto = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) | - ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8)) + 5; + unsigned short hrs = + (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) | + ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2)) + - 3; + unsigned short hto = + (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) | + ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8)) + + 5; data = hrs - (hto >> 1) + 3; } SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x19, (data & 0xFF)); @@ -739,20 +738,26 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData, - unsigned short shiftflag, unsigned short dl, unsigned short ah, - unsigned short al, unsigned short dh) + unsigned short shiftflag, unsigned short dl, unsigned short ah, + unsigned short al, unsigned short dh) { unsigned short d1, d2, d3; switch (dl) { - case 0: - d1 = dh; d2 = ah; d3 = al; - break; - case 1: - d1 = ah; d2 = al; d3 = dh; - break; - default: - d1 = al; d2 = dh; d3 = ah; + case 0: + d1 = dh; + d2 = ah; + d3 = al; + break; + case 1: + d1 = ah; + d2 = al; + d3 = dh; + break; + default: + d1 = al; + d2 = dh; + d3 = ah; } SiS_SetRegByte(SiS_Pr, DACData, (d1 << shiftflag)); SiS_SetRegByte(SiS_Pr, DACData, (d2 << shiftflag)); @@ -760,7 +765,8 @@ SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData, } static void -SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi) +SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short mi) { unsigned short data, data2, time, i, j, k, m, n, o; unsigned short si, di, bx, sf; @@ -794,41 +800,45 @@ SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi SiS_SetRegByte(SiS_Pr, DACAddr, 0x00); - for(i = 0; i < j; i++) { + for (i = 0; i < j; i++) { data = table[i]; - for(k = 0; k < 3; k++) { + for (k = 0; k < 3; k++) { data2 = 0; - if (data & 0x01) data2 += 0x2A; - if (data & 0x02) data2 += 0x15; + if (data & 0x01) + data2 += 0x2A; + if (data & 0x02) + data2 += 0x15; SiS_SetRegByte(SiS_Pr, DACData, (data2 << sf)); data >>= 2; } } if (time == 256) { - for(i = 16; i < 32; i++) { + for (i = 16; i < 32; i++) { data = table[i] << sf; - for(k = 0; k < 3; k++) + for (k = 0; k < 3; k++) SiS_SetRegByte(SiS_Pr, DACData, data); } si = 32; - for(m = 0; m < 9; m++) { + for (m = 0; m < 9; m++) { di = si; bx = si + 4; - for(n = 0; n < 3; n++) { - for(o = 0; o < 5; o++) { + for (n = 0; n < 3; n++) { + for (o = 0; o < 5; o++) { SiS_WriteDAC(SiS_Pr, DACData, sf, n, - table[di], table[bx], table[si]); + table[di], table[bx], + table[si]); si++; } si -= 2; - for(o = 0; o < 3; o++) { + for (o = 0; o < 3; o++) { SiS_WriteDAC(SiS_Pr, DACData, sf, n, - table[di], table[si], table[bx]); + table[di], table[si], + table[bx]); si--; } } - si += 5; + si += 5; } } } @@ -839,7 +849,7 @@ SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi static void SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex) + unsigned short ModeIdIndex) { unsigned short StandTableIndex, rrti; @@ -880,11 +890,10 @@ SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo, /* SiSSetMode() */ /*********************************************/ -int -SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) +int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) { unsigned short ModeIdIndex; - unsigned long BaseAddr = SiS_Pr->IOAddress; + unsigned long BaseAddr = SiS_Pr->IOAddress; SiSUSB_InitPtr(SiS_Pr); SiSUSBRegInit(SiS_Pr, BaseAddr); @@ -900,7 +909,7 @@ SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) ModeNo &= 0x7f; SiS_Pr->SiS_ModeType = - SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask; + SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask; SiS_Pr->SiS_SetFlag = LowModeTests; @@ -918,8 +927,7 @@ SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) return 1; } -int -SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo) +int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo) { unsigned short ModeNo = 0; int i; @@ -951,7 +959,3 @@ SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo) } #endif /* INCL_SISUSB_CON */ - - - - -- cgit v1.2.3-70-g09d2 From 7c59901421e22cff3fa9b8ea83e7a2fe37951497 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 10 Aug 2007 09:34:32 -0400 Subject: USB: SisUSB2VGA: Lindent drivers/usb/misc/sisusbvga/sisusb_init.h Better indentation Signed-off-by: Felipe Balbi Cc: Thomas Winischhofer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb_init.h | 1311 +++++++++++++++--------------- 1 file changed, 655 insertions(+), 656 deletions(-) diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.h b/drivers/usb/misc/sisusbvga/sisusb_init.h index d47301eaca7..c46ce42d448 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.h +++ b/drivers/usb/misc/sisusbvga/sisusb_init.h @@ -76,21 +76,21 @@ #define CRT2Mode 0x0800 #define HalfDCLK 0x1000 #define NoSupportSimuTV 0x2000 -#define NoSupportLCDScale 0x4000 /* SiS bridge: No scaling possible (no matter what panel) */ +#define NoSupportLCDScale 0x4000 /* SiS bridge: No scaling possible (no matter what panel) */ #define DoubleScanMode 0x8000 /* Infoflag */ #define SupportTV 0x0008 #define SupportTV1024 0x0800 #define SupportCHTV 0x0800 -#define Support64048060Hz 0x0800 /* Special for 640x480 LCD */ +#define Support64048060Hz 0x0800 /* Special for 640x480 LCD */ #define SupportHiVision 0x0010 #define SupportYPbPr750p 0x1000 #define SupportLCD 0x0020 #define SupportRAMDAC2 0x0040 /* All (<= 100Mhz) */ -#define SupportRAMDAC2_135 0x0100 /* All except DH (<= 135Mhz) */ -#define SupportRAMDAC2_162 0x0200 /* B, C (<= 162Mhz) */ -#define SupportRAMDAC2_202 0x0400 /* C (<= 202Mhz) */ +#define SupportRAMDAC2_135 0x0100 /* All except DH (<= 135Mhz) */ +#define SupportRAMDAC2_162 0x0200 /* B, C (<= 162Mhz) */ +#define SupportRAMDAC2_202 0x0400 /* C (<= 202Mhz) */ #define InterlaceMode 0x0080 #define SyncPP 0x0000 #define SyncPN 0x4000 @@ -129,7 +129,7 @@ #define SIS_RI_856x480 19 #define SIS_RI_1280x768 20 #define SIS_RI_1400x1050 21 -#define SIS_RI_1152x864 22 /* Up to here SiS conforming */ +#define SIS_RI_1152x864 22 /* Up to here SiS conforming */ #define SIS_RI_848x480 23 #define SIS_RI_1360x768 24 #define SIS_RI_1024x600 25 @@ -147,691 +147,691 @@ #define SIS_CRT2_PORT_04 0x04 - 0x30 /* Mode numbers */ -static const unsigned short ModeIndex_320x200[] = {0x59, 0x41, 0x00, 0x4f}; -static const unsigned short ModeIndex_320x240[] = {0x50, 0x56, 0x00, 0x53}; -static const unsigned short ModeIndex_400x300[] = {0x51, 0x57, 0x00, 0x54}; -static const unsigned short ModeIndex_512x384[] = {0x52, 0x58, 0x00, 0x5c}; -static const unsigned short ModeIndex_640x400[] = {0x2f, 0x5d, 0x00, 0x5e}; -static const unsigned short ModeIndex_640x480[] = {0x2e, 0x44, 0x00, 0x62}; -static const unsigned short ModeIndex_720x480[] = {0x31, 0x33, 0x00, 0x35}; -static const unsigned short ModeIndex_720x576[] = {0x32, 0x34, 0x00, 0x36}; -static const unsigned short ModeIndex_768x576[] = {0x5f, 0x60, 0x00, 0x61}; -static const unsigned short ModeIndex_800x480[] = {0x70, 0x7a, 0x00, 0x76}; -static const unsigned short ModeIndex_800x600[] = {0x30, 0x47, 0x00, 0x63}; -static const unsigned short ModeIndex_848x480[] = {0x39, 0x3b, 0x00, 0x3e}; -static const unsigned short ModeIndex_856x480[] = {0x3f, 0x42, 0x00, 0x45}; -static const unsigned short ModeIndex_960x540[] = {0x1d, 0x1e, 0x00, 0x1f}; -static const unsigned short ModeIndex_960x600[] = {0x20, 0x21, 0x00, 0x22}; -static const unsigned short ModeIndex_1024x768[] = {0x38, 0x4a, 0x00, 0x64}; -static const unsigned short ModeIndex_1024x576[] = {0x71, 0x74, 0x00, 0x77}; -static const unsigned short ModeIndex_1152x864[] = {0x29, 0x2a, 0x00, 0x2b}; -static const unsigned short ModeIndex_1280x720[] = {0x79, 0x75, 0x00, 0x78}; -static const unsigned short ModeIndex_1280x768[] = {0x23, 0x24, 0x00, 0x25}; -static const unsigned short ModeIndex_1280x1024[] = {0x3a, 0x4d, 0x00, 0x65}; +static const unsigned short ModeIndex_320x200[] = { 0x59, 0x41, 0x00, 0x4f }; +static const unsigned short ModeIndex_320x240[] = { 0x50, 0x56, 0x00, 0x53 }; +static const unsigned short ModeIndex_400x300[] = { 0x51, 0x57, 0x00, 0x54 }; +static const unsigned short ModeIndex_512x384[] = { 0x52, 0x58, 0x00, 0x5c }; +static const unsigned short ModeIndex_640x400[] = { 0x2f, 0x5d, 0x00, 0x5e }; +static const unsigned short ModeIndex_640x480[] = { 0x2e, 0x44, 0x00, 0x62 }; +static const unsigned short ModeIndex_720x480[] = { 0x31, 0x33, 0x00, 0x35 }; +static const unsigned short ModeIndex_720x576[] = { 0x32, 0x34, 0x00, 0x36 }; +static const unsigned short ModeIndex_768x576[] = { 0x5f, 0x60, 0x00, 0x61 }; +static const unsigned short ModeIndex_800x480[] = { 0x70, 0x7a, 0x00, 0x76 }; +static const unsigned short ModeIndex_800x600[] = { 0x30, 0x47, 0x00, 0x63 }; +static const unsigned short ModeIndex_848x480[] = { 0x39, 0x3b, 0x00, 0x3e }; +static const unsigned short ModeIndex_856x480[] = { 0x3f, 0x42, 0x00, 0x45 }; +static const unsigned short ModeIndex_960x540[] = { 0x1d, 0x1e, 0x00, 0x1f }; +static const unsigned short ModeIndex_960x600[] = { 0x20, 0x21, 0x00, 0x22 }; +static const unsigned short ModeIndex_1024x768[] = { 0x38, 0x4a, 0x00, 0x64 }; +static const unsigned short ModeIndex_1024x576[] = { 0x71, 0x74, 0x00, 0x77 }; +static const unsigned short ModeIndex_1152x864[] = { 0x29, 0x2a, 0x00, 0x2b }; +static const unsigned short ModeIndex_1280x720[] = { 0x79, 0x75, 0x00, 0x78 }; +static const unsigned short ModeIndex_1280x768[] = { 0x23, 0x24, 0x00, 0x25 }; +static const unsigned short ModeIndex_1280x1024[] = { 0x3a, 0x4d, 0x00, 0x65 }; -static const unsigned char SiS_MDA_DAC[] = -{ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, - 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, - 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, - 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, - 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F +static const unsigned char SiS_MDA_DAC[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F }; -static const unsigned char SiS_CGA_DAC[] = -{ - 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, - 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F +static const unsigned char SiS_CGA_DAC[] = { + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F }; -static const unsigned char SiS_EGA_DAC[] = -{ - 0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15, - 0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35, - 0x08,0x18,0x0C,0x1C,0x09,0x19,0x0D,0x1D, - 0x28,0x38,0x2C,0x3C,0x29,0x39,0x2D,0x3D, - 0x02,0x12,0x06,0x16,0x03,0x13,0x07,0x17, - 0x22,0x32,0x26,0x36,0x23,0x33,0x27,0x37, - 0x0A,0x1A,0x0E,0x1E,0x0B,0x1B,0x0F,0x1F, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F +static const unsigned char SiS_EGA_DAC[] = { + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x05, 0x15, + 0x20, 0x30, 0x24, 0x34, 0x21, 0x31, 0x25, 0x35, + 0x08, 0x18, 0x0C, 0x1C, 0x09, 0x19, 0x0D, 0x1D, + 0x28, 0x38, 0x2C, 0x3C, 0x29, 0x39, 0x2D, 0x3D, + 0x02, 0x12, 0x06, 0x16, 0x03, 0x13, 0x07, 0x17, + 0x22, 0x32, 0x26, 0x36, 0x23, 0x33, 0x27, 0x37, + 0x0A, 0x1A, 0x0E, 0x1E, 0x0B, 0x1B, 0x0F, 0x1F, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F }; -static const unsigned char SiS_VGA_DAC[] = -{ - 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, - 0x00,0x05,0x08,0x0B,0x0E,0x11,0x14,0x18, - 0x1C,0x20,0x24,0x28,0x2D,0x32,0x38,0x3F, - 0x00,0x10,0x1F,0x2F,0x3F,0x1F,0x27,0x2F, - 0x37,0x3F,0x2D,0x31,0x36,0x3A,0x3F,0x00, - 0x07,0x0E,0x15,0x1C,0x0E,0x11,0x15,0x18, - 0x1C,0x14,0x16,0x18,0x1A,0x1C,0x00,0x04, - 0x08,0x0C,0x10,0x08,0x0A,0x0C,0x0E,0x10, - 0x0B,0x0C,0x0D,0x0F,0x10 +static const unsigned char SiS_VGA_DAC[] = { + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x00, 0x05, 0x08, 0x0B, 0x0E, 0x11, 0x14, 0x18, + 0x1C, 0x20, 0x24, 0x28, 0x2D, 0x32, 0x38, 0x3F, + 0x00, 0x10, 0x1F, 0x2F, 0x3F, 0x1F, 0x27, 0x2F, + 0x37, 0x3F, 0x2D, 0x31, 0x36, 0x3A, 0x3F, 0x00, + 0x07, 0x0E, 0x15, 0x1C, 0x0E, 0x11, 0x15, 0x18, + 0x1C, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x00, 0x04, + 0x08, 0x0C, 0x10, 0x08, 0x0A, 0x0C, 0x0E, 0x10, + 0x0B, 0x0C, 0x0D, 0x0F, 0x10 }; -static const struct SiS_St SiSUSB_SModeIDTable[] = -{ - {0x03,0x0010,0x18,0x02,0x02,0x00,0x01,0x03,0x40}, - {0xff,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00} +static const struct SiS_St SiSUSB_SModeIDTable[] = { + {0x03, 0x0010, 0x18, 0x02, 0x02, 0x00, 0x01, 0x03, 0x40}, + {0xff, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }; -static const struct SiS_StResInfo_S SiSUSB_StResInfo[] = -{ - { 640,400}, - { 640,350}, - { 720,400}, - { 720,350}, - { 640,480} +static const struct SiS_StResInfo_S SiSUSB_StResInfo[] = { + {640, 400}, + {640, 350}, + {720, 400}, + {720, 350}, + {640, 480} }; -static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] = -{ - { 320, 200, 8, 8}, /* 0x00 */ - { 320, 240, 8, 8}, /* 0x01 */ - { 320, 400, 8, 8}, /* 0x02 */ - { 400, 300, 8, 8}, /* 0x03 */ - { 512, 384, 8, 8}, /* 0x04 */ - { 640, 400, 8,16}, /* 0x05 */ - { 640, 480, 8,16}, /* 0x06 */ - { 800, 600, 8,16}, /* 0x07 */ - { 1024, 768, 8,16}, /* 0x08 */ - { 1280,1024, 8,16}, /* 0x09 */ - { 1600,1200, 8,16}, /* 0x0a */ - { 1920,1440, 8,16}, /* 0x0b */ - { 2048,1536, 8,16}, /* 0x0c */ - { 720, 480, 8,16}, /* 0x0d */ - { 720, 576, 8,16}, /* 0x0e */ - { 1280, 960, 8,16}, /* 0x0f */ - { 800, 480, 8,16}, /* 0x10 */ - { 1024, 576, 8,16}, /* 0x11 */ - { 1280, 720, 8,16}, /* 0x12 */ - { 856, 480, 8,16}, /* 0x13 */ - { 1280, 768, 8,16}, /* 0x14 */ - { 1400,1050, 8,16}, /* 0x15 */ - { 1152, 864, 8,16}, /* 0x16 */ - { 848, 480, 8,16}, /* 0x17 */ - { 1360, 768, 8,16}, /* 0x18 */ - { 1024, 600, 8,16}, /* 0x19 */ - { 1152, 768, 8,16}, /* 0x1a */ - { 768, 576, 8,16}, /* 0x1b */ - { 1360,1024, 8,16}, /* 0x1c */ - { 1680,1050, 8,16}, /* 0x1d */ - { 1280, 800, 8,16}, /* 0x1e */ - { 1920,1080, 8,16}, /* 0x1f */ - { 960, 540, 8,16}, /* 0x20 */ - { 960, 600, 8,16} /* 0x21 */ +static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] = { + {320, 200, 8, 8}, /* 0x00 */ + {320, 240, 8, 8}, /* 0x01 */ + {320, 400, 8, 8}, /* 0x02 */ + {400, 300, 8, 8}, /* 0x03 */ + {512, 384, 8, 8}, /* 0x04 */ + {640, 400, 8, 16}, /* 0x05 */ + {640, 480, 8, 16}, /* 0x06 */ + {800, 600, 8, 16}, /* 0x07 */ + {1024, 768, 8, 16}, /* 0x08 */ + {1280, 1024, 8, 16}, /* 0x09 */ + {1600, 1200, 8, 16}, /* 0x0a */ + {1920, 1440, 8, 16}, /* 0x0b */ + {2048, 1536, 8, 16}, /* 0x0c */ + {720, 480, 8, 16}, /* 0x0d */ + {720, 576, 8, 16}, /* 0x0e */ + {1280, 960, 8, 16}, /* 0x0f */ + {800, 480, 8, 16}, /* 0x10 */ + {1024, 576, 8, 16}, /* 0x11 */ + {1280, 720, 8, 16}, /* 0x12 */ + {856, 480, 8, 16}, /* 0x13 */ + {1280, 768, 8, 16}, /* 0x14 */ + {1400, 1050, 8, 16}, /* 0x15 */ + {1152, 864, 8, 16}, /* 0x16 */ + {848, 480, 8, 16}, /* 0x17 */ + {1360, 768, 8, 16}, /* 0x18 */ + {1024, 600, 8, 16}, /* 0x19 */ + {1152, 768, 8, 16}, /* 0x1a */ + {768, 576, 8, 16}, /* 0x1b */ + {1360, 1024, 8, 16}, /* 0x1c */ + {1680, 1050, 8, 16}, /* 0x1d */ + {1280, 800, 8, 16}, /* 0x1e */ + {1920, 1080, 8, 16}, /* 0x1f */ + {960, 540, 8, 16}, /* 0x20 */ + {960, 600, 8, 16} /* 0x21 */ }; -static const struct SiS_StandTable SiSUSB_StandTable[] = -{ +static const struct SiS_StandTable SiSUSB_StandTable[] = { /* MD_3_400 - mode 0x03 - 400 */ { - 0x50,0x18,0x10,0x1000, - { 0x00,0x03,0x00,0x02 }, - 0x67, - { 0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, - 0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00, - 0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3, - 0xff }, - { 0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, - 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, - 0x0c,0x00,0x0f,0x08 }, - { 0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, 0xff } - }, + 0x50, 0x18, 0x10, 0x1000, + {0x00, 0x03, 0x00, 0x02}, + 0x67, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x0c, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff} + }, /* Generic for VGA and higher */ { - 0x00,0x00,0x00,0x0000, - { 0x01,0x0f,0x00,0x0e }, - 0x23, - { 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e, - 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, - 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3, - 0xff }, - { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, - 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, - 0x01,0x00,0x00,0x00 }, - { 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f, 0xff } - } + 0x00, 0x00, 0x00, 0x0000, + {0x01, 0x0f, 0x00, 0x0e}, + 0x23, + {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x01, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff} + } }; -static const struct SiS_Ext SiSUSB_EModeIDTable[] = -{ - {0x2e,0x0a1b,0x0101,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x8 */ - {0x2f,0x0a1b,0x0100,SIS_RI_640x400, 0x00,0x00,0x05,0x05,0x10, 0}, /* 640x400x8 */ - {0x30,0x2a1b,0x0103,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x8 */ - {0x31,0x4a1b,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x8 */ - {0x32,0x4a1b,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x8 */ - {0x33,0x4a1d,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x16 */ - {0x34,0x6a1d,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x16 */ - {0x35,0x4a1f,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x32 */ - {0x36,0x6a1f,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x32 */ - {0x38,0x0a1b,0x0105,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x8 */ - {0x3a,0x0e3b,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x8 */ - {0x41,0x9a1d,0x010e,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x16 */ - {0x44,0x0a1d,0x0111,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x16 */ - {0x47,0x2a1d,0x0114,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x16 */ - {0x4a,0x0a3d,0x0117,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x16 */ - {0x4d,0x0e7d,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x16 */ - {0x50,0x9a1b,0x0132,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x8 */ - {0x51,0xba1b,0x0133,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x8 */ - {0x52,0xba1b,0x0134,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x8 */ - {0x56,0x9a1d,0x0135,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x16 */ - {0x57,0xba1d,0x0136,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x16 */ - {0x58,0xba1d,0x0137,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x16 */ - {0x59,0x9a1b,0x0138,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x8 */ - {0x5c,0xba1f,0x0000,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x32 */ - {0x5d,0x0a1d,0x0139,SIS_RI_640x400, 0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x16 */ - {0x5e,0x0a1f,0x0000,SIS_RI_640x400, 0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x32 */ - {0x62,0x0a3f,0x013a,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x32 */ - {0x63,0x2a3f,0x013b,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x32 */ - {0x64,0x0a7f,0x013c,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x32 */ - {0x65,0x0eff,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x32 */ - {0x70,0x6a1b,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x8 */ - {0x71,0x4a1b,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x8 */ - {0x74,0x4a1d,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x16 */ - {0x75,0x0a3d,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x16 */ - {0x76,0x6a1f,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x32 */ - {0x77,0x4a1f,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x32 */ - {0x78,0x0a3f,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x32 */ - {0x79,0x0a3b,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x8 */ - {0x7a,0x6a1d,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x16 */ - {0x23,0x0e3b,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x8 */ - {0x24,0x0e7d,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x16 */ - {0x25,0x0eff,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x32 */ - {0x39,0x6a1b,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1}, /* 848x480 */ - {0x3b,0x6a3d,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1}, - {0x3e,0x6a7f,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1}, - {0x3f,0x6a1b,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1}, /* 856x480 */ - {0x42,0x6a3d,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1}, - {0x45,0x6a7f,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1}, - {0x4f,0x9a1f,0x0000,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x32 */ - {0x53,0x9a1f,0x0000,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x32 */ - {0x54,0xba1f,0x0000,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x32 */ - {0x5f,0x6a1b,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1}, /* 768x576 */ - {0x60,0x6a1d,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1}, - {0x61,0x6a3f,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1}, - {0x1d,0x6a1b,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1}, /* 960x540 */ - {0x1e,0x6a3d,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1}, - {0x1f,0x6a7f,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1}, - {0x20,0x6a1b,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1}, /* 960x600 */ - {0x21,0x6a3d,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1}, - {0x22,0x6a7f,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1}, - {0x29,0x4e1b,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1}, /* 1152x864 */ - {0x2a,0x4e3d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1}, - {0x2b,0x4e7f,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1}, - {0xff,0x0000,0x0000,0, 0x00,0x00,0x00,0x00,0x00,-1} +static const struct SiS_Ext SiSUSB_EModeIDTable[] = { + {0x2e, 0x0a1b, 0x0101, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x8 */ + {0x2f, 0x0a1b, 0x0100, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x05, 0x10, 0}, /* 640x400x8 */ + {0x30, 0x2a1b, 0x0103, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x8 */ + {0x31, 0x4a1b, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x8 */ + {0x32, 0x4a1b, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x8 */ + {0x33, 0x4a1d, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x16 */ + {0x34, 0x6a1d, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x16 */ + {0x35, 0x4a1f, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x32 */ + {0x36, 0x6a1f, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x32 */ + {0x38, 0x0a1b, 0x0105, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x8 */ + {0x3a, 0x0e3b, 0x0107, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x8 */ + {0x41, 0x9a1d, 0x010e, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x16 */ + {0x44, 0x0a1d, 0x0111, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x16 */ + {0x47, 0x2a1d, 0x0114, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x16 */ + {0x4a, 0x0a3d, 0x0117, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x16 */ + {0x4d, 0x0e7d, 0x011a, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x16 */ + {0x50, 0x9a1b, 0x0132, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x8 */ + {0x51, 0xba1b, 0x0133, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x8 */ + {0x52, 0xba1b, 0x0134, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x8 */ + {0x56, 0x9a1d, 0x0135, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x16 */ + {0x57, 0xba1d, 0x0136, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x16 */ + {0x58, 0xba1d, 0x0137, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x16 */ + {0x59, 0x9a1b, 0x0138, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x8 */ + {0x5c, 0xba1f, 0x0000, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x32 */ + {0x5d, 0x0a1d, 0x0139, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0}, /* 640x400x16 */ + {0x5e, 0x0a1f, 0x0000, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0}, /* 640x400x32 */ + {0x62, 0x0a3f, 0x013a, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x32 */ + {0x63, 0x2a3f, 0x013b, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x32 */ + {0x64, 0x0a7f, 0x013c, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x32 */ + {0x65, 0x0eff, 0x013d, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x32 */ + {0x70, 0x6a1b, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x8 */ + {0x71, 0x4a1b, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x8 */ + {0x74, 0x4a1d, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x16 */ + {0x75, 0x0a3d, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x16 */ + {0x76, 0x6a1f, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x32 */ + {0x77, 0x4a1f, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x32 */ + {0x78, 0x0a3f, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x32 */ + {0x79, 0x0a3b, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x8 */ + {0x7a, 0x6a1d, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x16 */ + {0x23, 0x0e3b, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x8 */ + {0x24, 0x0e7d, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x16 */ + {0x25, 0x0eff, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x32 */ + {0x39, 0x6a1b, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, -1}, /* 848x480 */ + {0x3b, 0x6a3d, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, + -1}, + {0x3e, 0x6a7f, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, + -1}, + {0x3f, 0x6a1b, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, -1}, /* 856x480 */ + {0x42, 0x6a3d, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, + -1}, + {0x45, 0x6a7f, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, + -1}, + {0x4f, 0x9a1f, 0x0000, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x32 */ + {0x53, 0x9a1f, 0x0000, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x32 */ + {0x54, 0xba1f, 0x0000, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x32 */ + {0x5f, 0x6a1b, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, -1}, /* 768x576 */ + {0x60, 0x6a1d, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, + -1}, + {0x61, 0x6a3f, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, + -1}, + {0x1d, 0x6a1b, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, -1}, /* 960x540 */ + {0x1e, 0x6a3d, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, + -1}, + {0x1f, 0x6a7f, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, + -1}, + {0x20, 0x6a1b, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, -1}, /* 960x600 */ + {0x21, 0x6a3d, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, + -1}, + {0x22, 0x6a7f, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, + -1}, + {0x29, 0x4e1b, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, -1}, /* 1152x864 */ + {0x2a, 0x4e3d, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, + -1}, + {0x2b, 0x4e7f, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, + -1}, + {0xff, 0x0000, 0x0000, 0, 0x00, 0x00, 0x00, 0x00, 0x00, -1} }; -static const struct SiS_Ext2 SiSUSB_RefIndex[] = -{ - {0x085f,0x0d,0x03,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x0 */ - {0x0067,0x0e,0x04,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x1 */ - {0x0067,0x0f,0x08,0x48,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x2 */ - {0x0067,0x10,0x07,0x8b,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x3 */ - {0x0047,0x11,0x0a,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x4 */ - {0x0047,0x12,0x0d,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x5 */ - {0x0047,0x13,0x13,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x6 */ - {0x0107,0x14,0x1c,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x7 */ - {0xc85f,0x05,0x00,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x8 */ - {0xc067,0x06,0x02,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x9 */ - {0xc067,0x07,0x02,0x47,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xa */ - {0xc067,0x08,0x03,0x8a,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xb */ - {0xc047,0x09,0x05,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xc */ - {0xc047,0x0a,0x09,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xd */ - {0xc047,0x0b,0x0e,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xe */ - {0xc047,0x0c,0x15,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xf */ - {0x487f,0x04,0x00,0x00,0x00,0x2f, 640, 400, 0x30, 0x55, 0x6e}, /* 0x10 */ - {0xc06f,0x3c,0x01,0x06,0x13,0x31, 720, 480, 0x30, 0x00, 0x00}, /* 0x11 */ - {0x006f,0x3d,0x6f,0x06,0x14,0x32, 720, 576, 0x30, 0x00, 0x00}, /* 0x12 (6f was 03) */ - {0x0087,0x15,0x06,0x00,0x06,0x38,1024, 768, 0x30, 0x00, 0x00}, /* 0x13 */ - {0xc877,0x16,0x0b,0x06,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x14 */ - {0xc067,0x17,0x0f,0x49,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x15 */ - {0x0067,0x18,0x11,0x00,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x16 */ - {0x0047,0x19,0x16,0x8c,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x17 */ - {0x0107,0x1a,0x1b,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x18 */ - {0x0107,0x1b,0x1f,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x19 */ - {0x407f,0x00,0x00,0x00,0x00,0x41, 320, 200, 0x30, 0x56, 0x4e}, /* 0x1a */ - {0xc07f,0x01,0x00,0x04,0x04,0x50, 320, 240, 0x30, 0x00, 0x00}, /* 0x1b */ - {0x007f,0x02,0x04,0x05,0x05,0x51, 400, 300, 0x30, 0x00, 0x00}, /* 0x1c */ - {0xc077,0x03,0x0b,0x06,0x06,0x52, 512, 384, 0x30, 0x00, 0x00}, /* 0x1d */ - {0x0077,0x32,0x40,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1e */ - {0x0047,0x33,0x07,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1f */ - {0x0047,0x34,0x0a,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x20 */ - {0x0077,0x35,0x0b,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x21 */ - {0x0047,0x36,0x11,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x22 */ - {0x0047,0x37,0x16,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x23 */ - {0x1137,0x38,0x19,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x24 */ - {0x1107,0x39,0x1e,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x25 */ - {0x1307,0x3a,0x20,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x26 */ - {0x0077,0x42,0x5b,0x08,0x11,0x23,1280, 768, 0x30, 0x00, 0x00}, /* 0x27 */ - {0x0087,0x45,0x57,0x00,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x28 38Hzi */ - {0xc067,0x46,0x55,0x0b,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x29 848x480-60Hz */ - {0x0087,0x47,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2a 856x480-38Hzi */ - {0xc067,0x48,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2b 856x480-60Hz */ - {0x006f,0x4d,0x71,0x06,0x15,0x5f, 768, 576, 0x30, 0x00, 0x00}, /* 0x2c 768x576-56Hz */ - {0x0067,0x52,0x6a,0x00,0x1c,0x1d, 960, 540, 0x30, 0x00, 0x00}, /* 0x2d 960x540 60Hz */ - {0x0077,0x53,0x6b,0x0b,0x1d,0x20, 960, 600, 0x30, 0x00, 0x00}, /* 0x2e 960x600 60Hz */ - {0x0087,0x1c,0x11,0x00,0x07,0x3a,1280,1024, 0x30, 0x00, 0x00}, /* 0x2f */ - {0x0137,0x1d,0x19,0x07,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x30 */ - {0x0107,0x1e,0x1e,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x31 */ - {0x0207,0x1f,0x20,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x32 */ - {0x0127,0x54,0x6d,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x33 1152x864-60Hz */ - {0x0127,0x44,0x19,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x34 1152x864-75Hz */ - {0x0127,0x4a,0x1e,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x35 1152x864-85Hz */ - {0xffff,0x00,0x00,0x00,0x00,0x00, 0, 0, 0, 0x00, 0x00} +static const struct SiS_Ext2 SiSUSB_RefIndex[] = { + {0x085f, 0x0d, 0x03, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x0 */ + {0x0067, 0x0e, 0x04, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x1 */ + {0x0067, 0x0f, 0x08, 0x48, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x2 */ + {0x0067, 0x10, 0x07, 0x8b, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x3 */ + {0x0047, 0x11, 0x0a, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x4 */ + {0x0047, 0x12, 0x0d, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x5 */ + {0x0047, 0x13, 0x13, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x6 */ + {0x0107, 0x14, 0x1c, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x7 */ + {0xc85f, 0x05, 0x00, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x8 */ + {0xc067, 0x06, 0x02, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x9 */ + {0xc067, 0x07, 0x02, 0x47, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xa */ + {0xc067, 0x08, 0x03, 0x8a, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xb */ + {0xc047, 0x09, 0x05, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xc */ + {0xc047, 0x0a, 0x09, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xd */ + {0xc047, 0x0b, 0x0e, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xe */ + {0xc047, 0x0c, 0x15, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xf */ + {0x487f, 0x04, 0x00, 0x00, 0x00, 0x2f, 640, 400, 0x30, 0x55, 0x6e}, /* 0x10 */ + {0xc06f, 0x3c, 0x01, 0x06, 0x13, 0x31, 720, 480, 0x30, 0x00, 0x00}, /* 0x11 */ + {0x006f, 0x3d, 0x6f, 0x06, 0x14, 0x32, 720, 576, 0x30, 0x00, 0x00}, /* 0x12 (6f was 03) */ + {0x0087, 0x15, 0x06, 0x00, 0x06, 0x38, 1024, 768, 0x30, 0x00, 0x00}, /* 0x13 */ + {0xc877, 0x16, 0x0b, 0x06, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x14 */ + {0xc067, 0x17, 0x0f, 0x49, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x15 */ + {0x0067, 0x18, 0x11, 0x00, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x16 */ + {0x0047, 0x19, 0x16, 0x8c, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x17 */ + {0x0107, 0x1a, 0x1b, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00}, /* 0x18 */ + {0x0107, 0x1b, 0x1f, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00}, /* 0x19 */ + {0x407f, 0x00, 0x00, 0x00, 0x00, 0x41, 320, 200, 0x30, 0x56, 0x4e}, /* 0x1a */ + {0xc07f, 0x01, 0x00, 0x04, 0x04, 0x50, 320, 240, 0x30, 0x00, 0x00}, /* 0x1b */ + {0x007f, 0x02, 0x04, 0x05, 0x05, 0x51, 400, 300, 0x30, 0x00, 0x00}, /* 0x1c */ + {0xc077, 0x03, 0x0b, 0x06, 0x06, 0x52, 512, 384, 0x30, 0x00, 0x00}, /* 0x1d */ + {0x0077, 0x32, 0x40, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1e */ + {0x0047, 0x33, 0x07, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1f */ + {0x0047, 0x34, 0x0a, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x20 */ + {0x0077, 0x35, 0x0b, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x21 */ + {0x0047, 0x36, 0x11, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x22 */ + {0x0047, 0x37, 0x16, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x23 */ + {0x1137, 0x38, 0x19, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x24 */ + {0x1107, 0x39, 0x1e, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x25 */ + {0x1307, 0x3a, 0x20, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x26 */ + {0x0077, 0x42, 0x5b, 0x08, 0x11, 0x23, 1280, 768, 0x30, 0x00, 0x00}, /* 0x27 */ + {0x0087, 0x45, 0x57, 0x00, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x28 38Hzi */ + {0xc067, 0x46, 0x55, 0x0b, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x29 848x480-60Hz */ + {0x0087, 0x47, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2a 856x480-38Hzi */ + {0xc067, 0x48, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2b 856x480-60Hz */ + {0x006f, 0x4d, 0x71, 0x06, 0x15, 0x5f, 768, 576, 0x30, 0x00, 0x00}, /* 0x2c 768x576-56Hz */ + {0x0067, 0x52, 0x6a, 0x00, 0x1c, 0x1d, 960, 540, 0x30, 0x00, 0x00}, /* 0x2d 960x540 60Hz */ + {0x0077, 0x53, 0x6b, 0x0b, 0x1d, 0x20, 960, 600, 0x30, 0x00, 0x00}, /* 0x2e 960x600 60Hz */ + {0x0087, 0x1c, 0x11, 0x00, 0x07, 0x3a, 1280, 1024, 0x30, 0x00, 0x00}, /* 0x2f */ + {0x0137, 0x1d, 0x19, 0x07, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x30 */ + {0x0107, 0x1e, 0x1e, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x31 */ + {0x0207, 0x1f, 0x20, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x32 */ + {0x0127, 0x54, 0x6d, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x33 1152x864-60Hz */ + {0x0127, 0x44, 0x19, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x34 1152x864-75Hz */ + {0x0127, 0x4a, 0x1e, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x35 1152x864-85Hz */ + {0xffff, 0x00, 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0x00, 0x00} }; -static const struct SiS_CRT1Table SiSUSB_CRT1Table[] = -{ - {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f, - 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00, - 0x00}}, /* 0x0 */ - {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e, - 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00, - 0x00}}, /* 0x1 */ - {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0, - 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05, - 0x01}}, /* 0x2 */ - {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5, - 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01, - 0x01}}, /* 0x3 */ - {{0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, - 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05, - 0x00}}, /* 0x4 */ - {{0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e, - 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05, - 0x00}}, /* 0x5 */ - {{0x63,0x4f,0x4f,0x87,0x56,0x9b,0x06,0x3e, - 0xe8,0x8a,0xdf,0xe7,0x07,0x00,0x00,0x01, - 0x00}}, /* 0x6 */ - {{0x64,0x4f,0x4f,0x88,0x55,0x9d,0xf2,0x1f, - 0xe0,0x83,0xdf,0xdf,0xf3,0x10,0x00,0x01, - 0x00}}, /* 0x7 */ - {{0x63,0x4f,0x4f,0x87,0x5a,0x81,0xfb,0x1f, - 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05, - 0x00}}, /* 0x8 */ - {{0x65,0x4f,0x4f,0x89,0x58,0x80,0xfb,0x1f, - 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05, - 0x61}}, /* 0x9 */ - {{0x65,0x4f,0x4f,0x89,0x58,0x80,0x01,0x3e, - 0xe0,0x83,0xdf,0xdf,0x02,0x00,0x00,0x05, - 0x61}}, /* 0xa */ - {{0x67,0x4f,0x4f,0x8b,0x58,0x81,0x0d,0x3e, - 0xe0,0x83,0xdf,0xdf,0x0e,0x00,0x00,0x05, - 0x61}}, /* 0xb */ - {{0x65,0x4f,0x4f,0x89,0x57,0x9f,0xfb,0x1f, - 0xe6,0x8a,0xdf,0xdf,0xfc,0x10,0x00,0x01, - 0x00}}, /* 0xc */ - {{0x7b,0x63,0x63,0x9f,0x6a,0x93,0x6f,0xf0, - 0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05, - 0x01}}, /* 0xd */ - {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xf0, - 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x06, - 0x01}}, /* 0xe */ - {{0x7d,0x63,0x63,0x81,0x6e,0x1d,0x98,0xf0, - 0x7c,0x82,0x57,0x57,0x99,0x00,0x00,0x06, - 0x01}}, /* 0xf */ - {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xf0, - 0x58,0x8b,0x57,0x57,0x70,0x20,0x00,0x06, - 0x01}}, /* 0x10 */ - {{0x7e,0x63,0x63,0x82,0x6b,0x13,0x75,0xf0, - 0x58,0x8b,0x57,0x57,0x76,0x20,0x00,0x06, - 0x01}}, /* 0x11 */ - {{0x81,0x63,0x63,0x85,0x6d,0x18,0x7a,0xf0, - 0x58,0x8b,0x57,0x57,0x7b,0x20,0x00,0x06, - 0x61}}, /* 0x12 */ - {{0x83,0x63,0x63,0x87,0x6e,0x19,0x81,0xf0, - 0x58,0x8b,0x57,0x57,0x82,0x20,0x00,0x06, - 0x61}}, /* 0x13 */ - {{0x85,0x63,0x63,0x89,0x6f,0x1a,0x91,0xf0, - 0x58,0x8b,0x57,0x57,0x92,0x20,0x00,0x06, - 0x61}}, /* 0x14 */ - {{0x99,0x7f,0x7f,0x9d,0x84,0x1a,0x96,0x1f, - 0x7f,0x83,0x7f,0x7f,0x97,0x10,0x00,0x02, - 0x00}}, /* 0x15 */ - {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5, - 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, - 0x01}}, /* 0x16 */ - {{0xa1,0x7f,0x7f,0x85,0x86,0x97,0x24,0xf5, - 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, - 0x01}}, /* 0x17 */ - {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf5, - 0x00,0x83,0xff,0xff,0x1f,0x10,0x00,0x02, - 0x01}}, /* 0x18 */ - {{0xa7,0x7f,0x7f,0x8b,0x89,0x95,0x26,0xf5, - 0x00,0x83,0xff,0xff,0x27,0x10,0x00,0x02, - 0x01}}, /* 0x19 */ - {{0xa9,0x7f,0x7f,0x8d,0x8c,0x9a,0x2c,0xf5, - 0x00,0x83,0xff,0xff,0x2d,0x14,0x00,0x02, - 0x62}}, /* 0x1a */ - {{0xab,0x7f,0x7f,0x8f,0x8d,0x9b,0x35,0xf5, - 0x00,0x83,0xff,0xff,0x36,0x14,0x00,0x02, - 0x62}}, /* 0x1b */ - {{0xcf,0x9f,0x9f,0x93,0xb2,0x01,0x14,0xba, - 0x00,0x83,0xff,0xff,0x15,0x00,0x00,0x03, - 0x00}}, /* 0x1c */ - {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0x5a, - 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07, - 0x01}}, /* 0x1d */ - {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a, - 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07, - 0x01}}, /* 0x1e */ - {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0x5a, - 0x00,0x83,0xff,0xff,0x2f,0x09,0x00,0x07, - 0x01}}, /* 0x1f */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x20 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x21 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x22 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x23 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x24 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x25 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x26 */ - {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, - 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, - 0x00}}, /* 0x27 */ - {{0x43,0xef,0xef,0x87,0x06,0x00,0xd4,0x1f, - 0xa0,0x83,0x9f,0x9f,0xd5,0x1f,0x41,0x05, - 0x63}}, /* 0x28 */ - {{0x45,0xef,0xef,0x89,0x07,0x01,0xd9,0x1f, - 0xa0,0x83,0x9f,0x9f,0xda,0x1f,0x41,0x05, - 0x63}}, /* 0x29 */ - {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, - 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, - 0x00}}, /* 0x2a */ - {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, - 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, - 0x00}}, /* 0x2b */ - {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, - 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, - 0x00}}, /* 0x2c */ - {{0x59,0xff,0xff,0x9d,0x17,0x13,0x33,0xba, - 0x00,0x83,0xff,0xff,0x34,0x0f,0x41,0x05, - 0x44}}, /* 0x2d */ - {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x38,0xba, - 0x00,0x83,0xff,0xff,0x39,0x0f,0x41,0x05, - 0x44}}, /* 0x2e */ - {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x3d,0xba, - 0x00,0x83,0xff,0xff,0x3e,0x0f,0x41,0x05, - 0x44}}, /* 0x2f */ - {{0x5d,0xff,0xff,0x81,0x19,0x95,0x41,0xba, - 0x00,0x84,0xff,0xff,0x42,0x0f,0x41,0x05, - 0x44}}, /* 0x30 */ - {{0x55,0xff,0xff,0x99,0x0d,0x0c,0x3e,0xba, - 0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05, - 0x00}}, /* 0x31 */ - {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba, - 0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06, - 0x01}}, /* 0x32 */ - {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba, - 0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06, - 0x01}}, /* 0x33 */ - {{0x7f,0x63,0x63,0x82,0x6b,0x13,0x75,0xba, - 0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06, - 0x01}}, /* 0x34 */ - {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf1, - 0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02, - 0x01}}, /* 0x35 */ - {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1, - 0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02, - 0x01}}, /* 0x36 */ - {{0xa7,0x7f,0x7f,0x88,0x89,0x95,0x26,0xf1, - 0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02, - 0x01}}, /* 0x37 */ - {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4, - 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07, - 0x01}}, /* 0x38 */ - {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xd4, - 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07, - 0x01}}, /* 0x39 */ - {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4, - 0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07, - 0x01}}, /* 0x3a */ - {{0xdc,0x9f,0x9f,0x80,0xaf,0x9d,0xe6,0xff, - 0xc0,0x83,0xbf,0xbf,0xe7,0x10,0x00,0x07, - 0x01}}, /* 0x3b */ - {{0x6b,0x59,0x59,0x8f,0x5e,0x8c,0x0b,0x3e, - 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05, - 0x00}}, /* 0x3c */ - {{0x6d,0x59,0x59,0x91,0x60,0x89,0x53,0xf0, - 0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05, - 0x41}}, /* 0x3d */ - {{0x86,0x6a,0x6a,0x8a,0x74,0x06,0x8c,0x15, - 0x4f,0x83,0xef,0xef,0x8d,0x30,0x00,0x02, - 0x00}}, /* 0x3e */ - {{0x81,0x6a,0x6a,0x85,0x70,0x00,0x0f,0x3e, - 0xeb,0x8e,0xdf,0xdf,0x10,0x00,0x00,0x02, - 0x00}}, /* 0x3f */ - {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1, - 0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02, - 0x01}}, /* 0x40 */ - {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5, - 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, - 0x01}}, /* 0x41 */ - {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x20,0xf5, - 0x03,0x88,0xff,0xff,0x21,0x10,0x00,0x07, - 0x01}}, /* 0x42 */ - {{0xe6,0xae,0xae,0x8a,0xbd,0x90,0x3d,0x10, - 0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x00,0x03, - 0x00}}, /* 0x43 */ - {{0xc3,0x8f,0x8f,0x87,0x9b,0x0b,0x82,0xef, - 0x60,0x83,0x5f,0x5f,0x83,0x10,0x00,0x07, - 0x01}}, /* 0x44 */ - {{0x86,0x69,0x69,0x8A,0x74,0x06,0x8C,0x15, - 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02, - 0x00}}, /* 0x45 */ - {{0x83,0x69,0x69,0x87,0x6f,0x1d,0x03,0x3E, - 0xE5,0x8d,0xDF,0xe4,0x04,0x00,0x00,0x06, - 0x00}}, /* 0x46 */ - {{0x86,0x6A,0x6A,0x8A,0x74,0x06,0x8C,0x15, - 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02, - 0x00}}, /* 0x47 */ - {{0x81,0x6A,0x6A,0x85,0x70,0x00,0x0F,0x3E, - 0xEB,0x8E,0xDF,0xDF,0x10,0x00,0x00,0x02, - 0x00}}, /* 0x48 */ - {{0xdd,0xa9,0xa9,0x81,0xb4,0x97,0x26,0xfd, - 0x01,0x8d,0xff,0x00,0x27,0x10,0x00,0x03, - 0x01}}, /* 0x49 */ - {{0xd9,0x8f,0x8f,0x9d,0xba,0x0a,0x8a,0xff, - 0x60,0x8b,0x5f,0x5f,0x8b,0x10,0x00,0x03, - 0x01}}, /* 0x4a */ - {{0xea,0xae,0xae,0x8e,0xba,0x82,0x40,0x10, - 0x1b,0x87,0x19,0x1a,0x41,0x0f,0x00,0x03, - 0x00}}, /* 0x4b */ - {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0xf1,0xff, - 0xc0,0x83,0xbf,0xbf,0xf2,0x10,0x00,0x07, - 0x01}}, /* 0x4c */ - {{0x75,0x5f,0x5f,0x99,0x66,0x90,0x53,0xf0, - 0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05, - 0x41}}, - {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e, - 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00, - 0x00}}, /* 0x4e */ - {{0xcd,0x9f,0x9f,0x91,0xab,0x1c,0x3a,0xff, - 0x20,0x83,0x1f,0x1f,0x3b,0x10,0x00,0x07, - 0x21}}, /* 0x4f */ - {{0x15,0xd1,0xd1,0x99,0xe2,0x19,0x3d,0x10, - 0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x01,0x0c, - 0x20}}, /* 0x50 */ - {{0x0e,0xef,0xef,0x92,0xfe,0x03,0x30,0xf0, - 0x1e,0x83,0x1b,0x1c,0x31,0x00,0x01,0x00, - 0x61}}, /* 0x51 */ - {{0x85,0x77,0x77,0x89,0x7d,0x01,0x31,0xf0, - 0x1e,0x84,0x1b,0x1c,0x32,0x00,0x00,0x02, - 0x41}}, /* 0x52 */ - {{0x87,0x77,0x77,0x8b,0x81,0x0b,0x68,0xf0, - 0x5a,0x80,0x57,0x57,0x69,0x00,0x00,0x02, - 0x01}}, /* 0x53 */ - {{0xcd,0x8f,0x8f,0x91,0x9b,0x1b,0x7a,0xff, - 0x64,0x8c,0x5f,0x62,0x7b,0x10,0x00,0x07, - 0x41}} /* 0x54 */ +static const struct SiS_CRT1Table SiSUSB_CRT1Table[] = { + {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f, + 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x00, + 0x00}}, /* 0x0 */ + {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00, + 0x00}}, /* 0x1 */ + {{0x3d, 0x31, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x05, + 0x01}}, /* 0x2 */ + {{0x4f, 0x3f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01}}, /* 0x3 */ + {{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x05, + 0x00}}, /* 0x4 */ + {{0x5f, 0x4f, 0x4f, 0x83, 0x55, 0x81, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe8, 0x0c, 0x00, 0x00, 0x05, + 0x00}}, /* 0x5 */ + {{0x63, 0x4f, 0x4f, 0x87, 0x56, 0x9b, 0x06, 0x3e, + 0xe8, 0x8a, 0xdf, 0xe7, 0x07, 0x00, 0x00, 0x01, + 0x00}}, /* 0x6 */ + {{0x64, 0x4f, 0x4f, 0x88, 0x55, 0x9d, 0xf2, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xf3, 0x10, 0x00, 0x01, + 0x00}}, /* 0x7 */ + {{0x63, 0x4f, 0x4f, 0x87, 0x5a, 0x81, 0xfb, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05, + 0x00}}, /* 0x8 */ + {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0xfb, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05, + 0x61}}, /* 0x9 */ + {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0x01, 0x3e, + 0xe0, 0x83, 0xdf, 0xdf, 0x02, 0x00, 0x00, 0x05, + 0x61}}, /* 0xa */ + {{0x67, 0x4f, 0x4f, 0x8b, 0x58, 0x81, 0x0d, 0x3e, + 0xe0, 0x83, 0xdf, 0xdf, 0x0e, 0x00, 0x00, 0x05, + 0x61}}, /* 0xb */ + {{0x65, 0x4f, 0x4f, 0x89, 0x57, 0x9f, 0xfb, 0x1f, + 0xe6, 0x8a, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x01, + 0x00}}, /* 0xc */ + {{0x7b, 0x63, 0x63, 0x9f, 0x6a, 0x93, 0x6f, 0xf0, + 0x58, 0x8a, 0x57, 0x57, 0x70, 0x20, 0x00, 0x05, + 0x01}}, /* 0xd */ + {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x06, + 0x01}}, /* 0xe */ + {{0x7d, 0x63, 0x63, 0x81, 0x6e, 0x1d, 0x98, 0xf0, + 0x7c, 0x82, 0x57, 0x57, 0x99, 0x00, 0x00, 0x06, + 0x01}}, /* 0xf */ + {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x70, 0x20, 0x00, 0x06, + 0x01}}, /* 0x10 */ + {{0x7e, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x76, 0x20, 0x00, 0x06, + 0x01}}, /* 0x11 */ + {{0x81, 0x63, 0x63, 0x85, 0x6d, 0x18, 0x7a, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x7b, 0x20, 0x00, 0x06, + 0x61}}, /* 0x12 */ + {{0x83, 0x63, 0x63, 0x87, 0x6e, 0x19, 0x81, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x82, 0x20, 0x00, 0x06, + 0x61}}, /* 0x13 */ + {{0x85, 0x63, 0x63, 0x89, 0x6f, 0x1a, 0x91, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x92, 0x20, 0x00, 0x06, + 0x61}}, /* 0x14 */ + {{0x99, 0x7f, 0x7f, 0x9d, 0x84, 0x1a, 0x96, 0x1f, + 0x7f, 0x83, 0x7f, 0x7f, 0x97, 0x10, 0x00, 0x02, + 0x00}}, /* 0x15 */ + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}}, /* 0x16 */ + {{0xa1, 0x7f, 0x7f, 0x85, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}}, /* 0x17 */ + {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x1f, 0x10, 0x00, 0x02, + 0x01}}, /* 0x18 */ + {{0xa7, 0x7f, 0x7f, 0x8b, 0x89, 0x95, 0x26, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x27, 0x10, 0x00, 0x02, + 0x01}}, /* 0x19 */ + {{0xa9, 0x7f, 0x7f, 0x8d, 0x8c, 0x9a, 0x2c, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x2d, 0x14, 0x00, 0x02, + 0x62}}, /* 0x1a */ + {{0xab, 0x7f, 0x7f, 0x8f, 0x8d, 0x9b, 0x35, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x36, 0x14, 0x00, 0x02, + 0x62}}, /* 0x1b */ + {{0xcf, 0x9f, 0x9f, 0x93, 0xb2, 0x01, 0x14, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x15, 0x00, 0x00, 0x03, + 0x00}}, /* 0x1c */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07, + 0x01}}, /* 0x1d */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07, + 0x01}}, /* 0x1e */ + {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x2f, 0x09, 0x00, 0x07, + 0x01}}, /* 0x1f */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x20 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x21 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x22 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x23 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x24 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x25 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x26 */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x27 */ + {{0x43, 0xef, 0xef, 0x87, 0x06, 0x00, 0xd4, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xd5, 0x1f, 0x41, 0x05, + 0x63}}, /* 0x28 */ + {{0x45, 0xef, 0xef, 0x89, 0x07, 0x01, 0xd9, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xda, 0x1f, 0x41, 0x05, + 0x63}}, /* 0x29 */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x2a */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x2b */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x2c */ + {{0x59, 0xff, 0xff, 0x9d, 0x17, 0x13, 0x33, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x34, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x2d */ + {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x38, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x39, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x2e */ + {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x3d, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x3e, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x2f */ + {{0x5d, 0xff, 0xff, 0x81, 0x19, 0x95, 0x41, 0xba, + 0x00, 0x84, 0xff, 0xff, 0x42, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x30 */ + {{0x55, 0xff, 0xff, 0x99, 0x0d, 0x0c, 0x3e, 0xba, + 0x00, 0x84, 0xff, 0xff, 0x3f, 0x0f, 0x41, 0x05, + 0x00}}, /* 0x31 */ + {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xba, + 0x27, 0x8b, 0xdf, 0xdf, 0x73, 0x00, 0x00, 0x06, + 0x01}}, /* 0x32 */ + {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xba, + 0x26, 0x89, 0xdf, 0xdf, 0x6f, 0x00, 0x00, 0x06, + 0x01}}, /* 0x33 */ + {{0x7f, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xba, + 0x29, 0x8c, 0xdf, 0xdf, 0x75, 0x00, 0x00, 0x06, + 0x01}}, /* 0x34 */ + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf1, + 0xaf, 0x85, 0x3f, 0x3f, 0x25, 0x30, 0x00, 0x02, + 0x01}}, /* 0x35 */ + {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf1, + 0xad, 0x81, 0x3f, 0x3f, 0x1f, 0x30, 0x00, 0x02, + 0x01}}, /* 0x36 */ + {{0xa7, 0x7f, 0x7f, 0x88, 0x89, 0x95, 0x26, 0xf1, + 0xb1, 0x85, 0x3f, 0x3f, 0x27, 0x30, 0x00, 0x02, + 0x01}}, /* 0x37 */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0xc4, + 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07, + 0x01}}, /* 0x38 */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0xd4, + 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07, + 0x01}}, /* 0x39 */ + {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0xd4, + 0x7d, 0x81, 0xcf, 0xcf, 0x2f, 0x21, 0x00, 0x07, + 0x01}}, /* 0x3a */ + {{0xdc, 0x9f, 0x9f, 0x80, 0xaf, 0x9d, 0xe6, 0xff, + 0xc0, 0x83, 0xbf, 0xbf, 0xe7, 0x10, 0x00, 0x07, + 0x01}}, /* 0x3b */ + {{0x6b, 0x59, 0x59, 0x8f, 0x5e, 0x8c, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x05, + 0x00}}, /* 0x3c */ + {{0x6d, 0x59, 0x59, 0x91, 0x60, 0x89, 0x53, 0xf0, + 0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05, + 0x41}}, /* 0x3d */ + {{0x86, 0x6a, 0x6a, 0x8a, 0x74, 0x06, 0x8c, 0x15, + 0x4f, 0x83, 0xef, 0xef, 0x8d, 0x30, 0x00, 0x02, + 0x00}}, /* 0x3e */ + {{0x81, 0x6a, 0x6a, 0x85, 0x70, 0x00, 0x0f, 0x3e, + 0xeb, 0x8e, 0xdf, 0xdf, 0x10, 0x00, 0x00, 0x02, + 0x00}}, /* 0x3f */ + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x1e, 0xf1, + 0xae, 0x85, 0x57, 0x57, 0x1f, 0x30, 0x00, 0x02, + 0x01}}, /* 0x40 */ + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}}, /* 0x41 */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x20, 0xf5, + 0x03, 0x88, 0xff, 0xff, 0x21, 0x10, 0x00, 0x07, + 0x01}}, /* 0x42 */ + {{0xe6, 0xae, 0xae, 0x8a, 0xbd, 0x90, 0x3d, 0x10, + 0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x00, 0x03, + 0x00}}, /* 0x43 */ + {{0xc3, 0x8f, 0x8f, 0x87, 0x9b, 0x0b, 0x82, 0xef, + 0x60, 0x83, 0x5f, 0x5f, 0x83, 0x10, 0x00, 0x07, + 0x01}}, /* 0x44 */ + {{0x86, 0x69, 0x69, 0x8A, 0x74, 0x06, 0x8C, 0x15, + 0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02, + 0x00}}, /* 0x45 */ + {{0x83, 0x69, 0x69, 0x87, 0x6f, 0x1d, 0x03, 0x3E, + 0xE5, 0x8d, 0xDF, 0xe4, 0x04, 0x00, 0x00, 0x06, + 0x00}}, /* 0x46 */ + {{0x86, 0x6A, 0x6A, 0x8A, 0x74, 0x06, 0x8C, 0x15, + 0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02, + 0x00}}, /* 0x47 */ + {{0x81, 0x6A, 0x6A, 0x85, 0x70, 0x00, 0x0F, 0x3E, + 0xEB, 0x8E, 0xDF, 0xDF, 0x10, 0x00, 0x00, 0x02, + 0x00}}, /* 0x48 */ + {{0xdd, 0xa9, 0xa9, 0x81, 0xb4, 0x97, 0x26, 0xfd, + 0x01, 0x8d, 0xff, 0x00, 0x27, 0x10, 0x00, 0x03, + 0x01}}, /* 0x49 */ + {{0xd9, 0x8f, 0x8f, 0x9d, 0xba, 0x0a, 0x8a, 0xff, + 0x60, 0x8b, 0x5f, 0x5f, 0x8b, 0x10, 0x00, 0x03, + 0x01}}, /* 0x4a */ + {{0xea, 0xae, 0xae, 0x8e, 0xba, 0x82, 0x40, 0x10, + 0x1b, 0x87, 0x19, 0x1a, 0x41, 0x0f, 0x00, 0x03, + 0x00}}, /* 0x4b */ + {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0xf1, 0xff, + 0xc0, 0x83, 0xbf, 0xbf, 0xf2, 0x10, 0x00, 0x07, + 0x01}}, /* 0x4c */ + {{0x75, 0x5f, 0x5f, 0x99, 0x66, 0x90, 0x53, 0xf0, + 0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05, + 0x41}}, + {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00, + 0x00}}, /* 0x4e */ + {{0xcd, 0x9f, 0x9f, 0x91, 0xab, 0x1c, 0x3a, 0xff, + 0x20, 0x83, 0x1f, 0x1f, 0x3b, 0x10, 0x00, 0x07, + 0x21}}, /* 0x4f */ + {{0x15, 0xd1, 0xd1, 0x99, 0xe2, 0x19, 0x3d, 0x10, + 0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x01, 0x0c, + 0x20}}, /* 0x50 */ + {{0x0e, 0xef, 0xef, 0x92, 0xfe, 0x03, 0x30, 0xf0, + 0x1e, 0x83, 0x1b, 0x1c, 0x31, 0x00, 0x01, 0x00, + 0x61}}, /* 0x51 */ + {{0x85, 0x77, 0x77, 0x89, 0x7d, 0x01, 0x31, 0xf0, + 0x1e, 0x84, 0x1b, 0x1c, 0x32, 0x00, 0x00, 0x02, + 0x41}}, /* 0x52 */ + {{0x87, 0x77, 0x77, 0x8b, 0x81, 0x0b, 0x68, 0xf0, + 0x5a, 0x80, 0x57, 0x57, 0x69, 0x00, 0x00, 0x02, + 0x01}}, /* 0x53 */ + {{0xcd, 0x8f, 0x8f, 0x91, 0x9b, 0x1b, 0x7a, 0xff, + 0x64, 0x8c, 0x5f, 0x62, 0x7b, 0x10, 0x00, 0x07, + 0x41}} /* 0x54 */ }; -static const struct SiS_VCLKData SiSUSB_VCLKData[] = -{ - { 0x1b,0xe1, 25}, /* 0x00 */ - { 0x4e,0xe4, 28}, /* 0x01 */ - { 0x57,0xe4, 31}, /* 0x02 */ - { 0xc3,0xc8, 36}, /* 0x03 */ - { 0x42,0xe2, 40}, /* 0x04 */ - { 0xfe,0xcd, 43}, /* 0x05 */ - { 0x5d,0xc4, 44}, /* 0x06 */ - { 0x52,0xe2, 49}, /* 0x07 */ - { 0x53,0xe2, 50}, /* 0x08 */ - { 0x74,0x67, 52}, /* 0x09 */ - { 0x6d,0x66, 56}, /* 0x0a */ - { 0x5a,0x64, 65}, /* 0x0b */ - { 0x46,0x44, 67}, /* 0x0c */ - { 0xb1,0x46, 68}, /* 0x0d */ - { 0xd3,0x4a, 72}, /* 0x0e */ - { 0x29,0x61, 75}, /* 0x0f */ - { 0x6e,0x46, 76}, /* 0x10 */ - { 0x2b,0x61, 78}, /* 0x11 */ - { 0x31,0x42, 79}, /* 0x12 */ - { 0xab,0x44, 83}, /* 0x13 */ - { 0x46,0x25, 84}, /* 0x14 */ - { 0x78,0x29, 86}, /* 0x15 */ - { 0x62,0x44, 94}, /* 0x16 */ - { 0x2b,0x41,104}, /* 0x17 */ - { 0x3a,0x23,105}, /* 0x18 */ - { 0x70,0x44,108}, /* 0x19 */ - { 0x3c,0x23,109}, /* 0x1a */ - { 0x5e,0x43,113}, /* 0x1b */ - { 0xbc,0x44,116}, /* 0x1c */ - { 0xe0,0x46,132}, /* 0x1d */ - { 0x54,0x42,135}, /* 0x1e */ - { 0xea,0x2a,139}, /* 0x1f */ - { 0x41,0x22,157}, /* 0x20 */ - { 0x70,0x24,162}, /* 0x21 */ - { 0x30,0x21,175}, /* 0x22 */ - { 0x4e,0x22,189}, /* 0x23 */ - { 0xde,0x26,194}, /* 0x24 */ - { 0x62,0x06,202}, /* 0x25 */ - { 0x3f,0x03,229}, /* 0x26 */ - { 0xb8,0x06,234}, /* 0x27 */ - { 0x34,0x02,253}, /* 0x28 */ - { 0x58,0x04,255}, /* 0x29 */ - { 0x24,0x01,265}, /* 0x2a */ - { 0x9b,0x02,267}, /* 0x2b */ - { 0x70,0x05,270}, /* 0x2c */ - { 0x25,0x01,272}, /* 0x2d */ - { 0x9c,0x02,277}, /* 0x2e */ - { 0x27,0x01,286}, /* 0x2f */ - { 0x3c,0x02,291}, /* 0x30 */ - { 0xef,0x0a,292}, /* 0x31 */ - { 0xf6,0x0a,310}, /* 0x32 */ - { 0x95,0x01,315}, /* 0x33 */ - { 0xf0,0x09,324}, /* 0x34 */ - { 0xfe,0x0a,331}, /* 0x35 */ - { 0xf3,0x09,332}, /* 0x36 */ - { 0xea,0x08,340}, /* 0x37 */ - { 0xe8,0x07,376}, /* 0x38 */ - { 0xde,0x06,389}, /* 0x39 */ - { 0x52,0x2a, 54}, /* 0x3a 301 TV */ - { 0x52,0x6a, 27}, /* 0x3b 301 TV */ - { 0x62,0x24, 70}, /* 0x3c 301 TV */ - { 0x62,0x64, 70}, /* 0x3d 301 TV */ - { 0xa8,0x4c, 30}, /* 0x3e 301 TV */ - { 0x20,0x26, 33}, /* 0x3f 301 TV */ - { 0x31,0xc2, 39}, /* 0x40 */ - { 0x60,0x36, 30}, /* 0x41 Chrontel */ - { 0x40,0x4a, 28}, /* 0x42 Chrontel */ - { 0x9f,0x46, 44}, /* 0x43 Chrontel */ - { 0x97,0x2c, 26}, /* 0x44 */ - { 0x44,0xe4, 25}, /* 0x45 Chrontel */ - { 0x7e,0x32, 47}, /* 0x46 Chrontel */ - { 0x8a,0x24, 31}, /* 0x47 Chrontel */ - { 0x97,0x2c, 26}, /* 0x48 Chrontel */ - { 0xce,0x3c, 39}, /* 0x49 */ - { 0x52,0x4a, 36}, /* 0x4a Chrontel */ - { 0x34,0x61, 95}, /* 0x4b */ - { 0x78,0x27,108}, /* 0x4c - was 102 */ - { 0x66,0x43,123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */ - { 0x41,0x4e, 21}, /* 0x4e */ - { 0xa1,0x4a, 29}, /* 0x4f Chrontel */ - { 0x19,0x42, 42}, /* 0x50 */ - { 0x54,0x46, 58}, /* 0x51 Chrontel */ - { 0x25,0x42, 61}, /* 0x52 */ - { 0x44,0x44, 66}, /* 0x53 Chrontel */ - { 0x3a,0x62, 70}, /* 0x54 Chrontel */ - { 0x62,0xc6, 34}, /* 0x55 848x480-60 */ - { 0x6a,0xc6, 37}, /* 0x56 848x480-75 - TEMP */ - { 0xbf,0xc8, 35}, /* 0x57 856x480-38i,60 */ - { 0x30,0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */ - { 0x52,0x07,149}, /* 0x59 1280x960-85 */ - { 0x56,0x07,156}, /* 0x5a 1400x1050-75 */ - { 0x70,0x29, 81}, /* 0x5b 1280x768 LCD */ - { 0x45,0x25, 83}, /* 0x5c 1280x800 */ - { 0x70,0x0a,147}, /* 0x5d 1680x1050 */ - { 0x70,0x24,162}, /* 0x5e 1600x1200 */ - { 0x5a,0x64, 65}, /* 0x5f 1280x720 - temp */ - { 0x63,0x46, 68}, /* 0x60 1280x768_2 */ - { 0x31,0x42, 79}, /* 0x61 1280x768_3 - temp */ - { 0, 0, 0}, /* 0x62 - custom (will be filled out at run-time) */ - { 0x5a,0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */ - { 0x70,0x28, 90}, /* 0x64 1152x864@60 */ - { 0x41,0xc4, 32}, /* 0x65 848x480@60 */ - { 0x5c,0xc6, 32}, /* 0x66 856x480@60 */ - { 0x76,0xe7, 27}, /* 0x67 720x480@60 */ - { 0x5f,0xc6, 33}, /* 0x68 720/768x576@60 */ - { 0x52,0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */ - { 0x7c,0x6b, 38}, /* 0x6a 960x540@60 */ - { 0xe3,0x56, 41}, /* 0x6b 960x600@60 */ - { 0x45,0x25, 83}, /* 0x6c 1280x800 */ - { 0x70,0x28, 90}, /* 0x6d 1152x864@60 */ - { 0x15,0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */ - { 0x5f,0xc6, 33}, /* 0x6f 720x576@60 */ - { 0x37,0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */ - { 0x2b,0xc2, 35} /* 0x71 768@576@60 */ +static const struct SiS_VCLKData SiSUSB_VCLKData[] = { + {0x1b, 0xe1, 25}, /* 0x00 */ + {0x4e, 0xe4, 28}, /* 0x01 */ + {0x57, 0xe4, 31}, /* 0x02 */ + {0xc3, 0xc8, 36}, /* 0x03 */ + {0x42, 0xe2, 40}, /* 0x04 */ + {0xfe, 0xcd, 43}, /* 0x05 */ + {0x5d, 0xc4, 44}, /* 0x06 */ + {0x52, 0xe2, 49}, /* 0x07 */ + {0x53, 0xe2, 50}, /* 0x08 */ + {0x74, 0x67, 52}, /* 0x09 */ + {0x6d, 0x66, 56}, /* 0x0a */ + {0x5a, 0x64, 65}, /* 0x0b */ + {0x46, 0x44, 67}, /* 0x0c */ + {0xb1, 0x46, 68}, /* 0x0d */ + {0xd3, 0x4a, 72}, /* 0x0e */ + {0x29, 0x61, 75}, /* 0x0f */ + {0x6e, 0x46, 76}, /* 0x10 */ + {0x2b, 0x61, 78}, /* 0x11 */ + {0x31, 0x42, 79}, /* 0x12 */ + {0xab, 0x44, 83}, /* 0x13 */ + {0x46, 0x25, 84}, /* 0x14 */ + {0x78, 0x29, 86}, /* 0x15 */ + {0x62, 0x44, 94}, /* 0x16 */ + {0x2b, 0x41, 104}, /* 0x17 */ + {0x3a, 0x23, 105}, /* 0x18 */ + {0x70, 0x44, 108}, /* 0x19 */ + {0x3c, 0x23, 109}, /* 0x1a */ + {0x5e, 0x43, 113}, /* 0x1b */ + {0xbc, 0x44, 116}, /* 0x1c */ + {0xe0, 0x46, 132}, /* 0x1d */ + {0x54, 0x42, 135}, /* 0x1e */ + {0xea, 0x2a, 139}, /* 0x1f */ + {0x41, 0x22, 157}, /* 0x20 */ + {0x70, 0x24, 162}, /* 0x21 */ + {0x30, 0x21, 175}, /* 0x22 */ + {0x4e, 0x22, 189}, /* 0x23 */ + {0xde, 0x26, 194}, /* 0x24 */ + {0x62, 0x06, 202}, /* 0x25 */ + {0x3f, 0x03, 229}, /* 0x26 */ + {0xb8, 0x06, 234}, /* 0x27 */ + {0x34, 0x02, 253}, /* 0x28 */ + {0x58, 0x04, 255}, /* 0x29 */ + {0x24, 0x01, 265}, /* 0x2a */ + {0x9b, 0x02, 267}, /* 0x2b */ + {0x70, 0x05, 270}, /* 0x2c */ + {0x25, 0x01, 272}, /* 0x2d */ + {0x9c, 0x02, 277}, /* 0x2e */ + {0x27, 0x01, 286}, /* 0x2f */ + {0x3c, 0x02, 291}, /* 0x30 */ + {0xef, 0x0a, 292}, /* 0x31 */ + {0xf6, 0x0a, 310}, /* 0x32 */ + {0x95, 0x01, 315}, /* 0x33 */ + {0xf0, 0x09, 324}, /* 0x34 */ + {0xfe, 0x0a, 331}, /* 0x35 */ + {0xf3, 0x09, 332}, /* 0x36 */ + {0xea, 0x08, 340}, /* 0x37 */ + {0xe8, 0x07, 376}, /* 0x38 */ + {0xde, 0x06, 389}, /* 0x39 */ + {0x52, 0x2a, 54}, /* 0x3a 301 TV */ + {0x52, 0x6a, 27}, /* 0x3b 301 TV */ + {0x62, 0x24, 70}, /* 0x3c 301 TV */ + {0x62, 0x64, 70}, /* 0x3d 301 TV */ + {0xa8, 0x4c, 30}, /* 0x3e 301 TV */ + {0x20, 0x26, 33}, /* 0x3f 301 TV */ + {0x31, 0xc2, 39}, /* 0x40 */ + {0x60, 0x36, 30}, /* 0x41 Chrontel */ + {0x40, 0x4a, 28}, /* 0x42 Chrontel */ + {0x9f, 0x46, 44}, /* 0x43 Chrontel */ + {0x97, 0x2c, 26}, /* 0x44 */ + {0x44, 0xe4, 25}, /* 0x45 Chrontel */ + {0x7e, 0x32, 47}, /* 0x46 Chrontel */ + {0x8a, 0x24, 31}, /* 0x47 Chrontel */ + {0x97, 0x2c, 26}, /* 0x48 Chrontel */ + {0xce, 0x3c, 39}, /* 0x49 */ + {0x52, 0x4a, 36}, /* 0x4a Chrontel */ + {0x34, 0x61, 95}, /* 0x4b */ + {0x78, 0x27, 108}, /* 0x4c - was 102 */ + {0x66, 0x43, 123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */ + {0x41, 0x4e, 21}, /* 0x4e */ + {0xa1, 0x4a, 29}, /* 0x4f Chrontel */ + {0x19, 0x42, 42}, /* 0x50 */ + {0x54, 0x46, 58}, /* 0x51 Chrontel */ + {0x25, 0x42, 61}, /* 0x52 */ + {0x44, 0x44, 66}, /* 0x53 Chrontel */ + {0x3a, 0x62, 70}, /* 0x54 Chrontel */ + {0x62, 0xc6, 34}, /* 0x55 848x480-60 */ + {0x6a, 0xc6, 37}, /* 0x56 848x480-75 - TEMP */ + {0xbf, 0xc8, 35}, /* 0x57 856x480-38i,60 */ + {0x30, 0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */ + {0x52, 0x07, 149}, /* 0x59 1280x960-85 */ + {0x56, 0x07, 156}, /* 0x5a 1400x1050-75 */ + {0x70, 0x29, 81}, /* 0x5b 1280x768 LCD */ + {0x45, 0x25, 83}, /* 0x5c 1280x800 */ + {0x70, 0x0a, 147}, /* 0x5d 1680x1050 */ + {0x70, 0x24, 162}, /* 0x5e 1600x1200 */ + {0x5a, 0x64, 65}, /* 0x5f 1280x720 - temp */ + {0x63, 0x46, 68}, /* 0x60 1280x768_2 */ + {0x31, 0x42, 79}, /* 0x61 1280x768_3 - temp */ + {0, 0, 0}, /* 0x62 - custom (will be filled out at run-time) */ + {0x5a, 0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */ + {0x70, 0x28, 90}, /* 0x64 1152x864@60 */ + {0x41, 0xc4, 32}, /* 0x65 848x480@60 */ + {0x5c, 0xc6, 32}, /* 0x66 856x480@60 */ + {0x76, 0xe7, 27}, /* 0x67 720x480@60 */ + {0x5f, 0xc6, 33}, /* 0x68 720/768x576@60 */ + {0x52, 0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */ + {0x7c, 0x6b, 38}, /* 0x6a 960x540@60 */ + {0xe3, 0x56, 41}, /* 0x6b 960x600@60 */ + {0x45, 0x25, 83}, /* 0x6c 1280x800 */ + {0x70, 0x28, 90}, /* 0x6d 1152x864@60 */ + {0x15, 0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */ + {0x5f, 0xc6, 33}, /* 0x6f 720x576@60 */ + {0x37, 0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */ + {0x2b, 0xc2, 35} /* 0x71 768@576@60 */ }; -int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo); -int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo); +int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo); +int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo); -extern int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data); -extern int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data); -extern int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, - u8 index, u8 data); -extern int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, - u8 index, u8 *data); -extern int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, - u8 idx, u8 myand, u8 myor); -extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, - u8 index, u8 myor); -extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, - u8 idx, u8 myand); +extern int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data); +extern int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 * data); +extern int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, + u8 index, u8 data); +extern int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, + u8 index, u8 * data); +extern int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, + u8 idx, u8 myand, u8 myor); +extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, + u8 index, u8 myor); +extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, + u8 idx, u8 myand); void sisusb_delete(struct kref *kref); int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data); -int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data); +int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 * data); int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src, - u32 dest, int length, size_t *bytes_written); + u32 dest, int length, size_t * bytes_written); int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init); int sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot, - u8 *arg, int cmapsz, int ch512, int dorecalc, + u8 * arg, int cmapsz, int ch512, int dorecalc, struct vc_data *c, int fh, int uplock); void sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location); int sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last); @@ -839,4 +839,3 @@ void sisusb_console_exit(struct sisusb_usb_data *sisusb); void sisusb_init_concode(void); #endif - -- cgit v1.2.3-70-g09d2 From ecb8b190bcf49e67a6bd955340ecc07d243b6efa Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 10 Aug 2007 16:04:56 -0400 Subject: USB: SisUSB2VGA: Lindent drivers/usb/misc/sisusbvga/sisusb_struct.h Better indentation Signed-off-by: Felipe Balbi Cc: Thomas Winischhofer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb_struct.h | 142 ++++++++++++++--------------- 1 file changed, 67 insertions(+), 75 deletions(-) diff --git a/drivers/usb/misc/sisusbvga/sisusb_struct.h b/drivers/usb/misc/sisusbvga/sisusb_struct.h index 9def598192c..1c4240e802c 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_struct.h +++ b/drivers/usb/misc/sisusbvga/sisusb_struct.h @@ -52,85 +52,78 @@ #define _SISUSB_STRUCT_H_ struct SiS_St { - unsigned char St_ModeID; - unsigned short St_ModeFlag; - unsigned char St_StTableIndex; - unsigned char St_CRT2CRTC; - unsigned char St_ResInfo; - unsigned char VB_StTVFlickerIndex; - unsigned char VB_StTVEdgeIndex; - unsigned char VB_StTVYFilterIndex; - unsigned char St_PDC; + unsigned char St_ModeID; + unsigned short St_ModeFlag; + unsigned char St_StTableIndex; + unsigned char St_CRT2CRTC; + unsigned char St_ResInfo; + unsigned char VB_StTVFlickerIndex; + unsigned char VB_StTVEdgeIndex; + unsigned char VB_StTVYFilterIndex; + unsigned char St_PDC; }; -struct SiS_StandTable -{ - unsigned char CRT_COLS; - unsigned char ROWS; - unsigned char CHAR_HEIGHT; - unsigned short CRT_LEN; - unsigned char SR[4]; - unsigned char MISC; - unsigned char CRTC[0x19]; - unsigned char ATTR[0x14]; - unsigned char GRC[9]; +struct SiS_StandTable { + unsigned char CRT_COLS; + unsigned char ROWS; + unsigned char CHAR_HEIGHT; + unsigned short CRT_LEN; + unsigned char SR[4]; + unsigned char MISC; + unsigned char CRTC[0x19]; + unsigned char ATTR[0x14]; + unsigned char GRC[9]; }; struct SiS_StResInfo_S { - unsigned short HTotal; - unsigned short VTotal; + unsigned short HTotal; + unsigned short VTotal; }; -struct SiS_Ext -{ - unsigned char Ext_ModeID; - unsigned short Ext_ModeFlag; - unsigned short Ext_VESAID; - unsigned char Ext_RESINFO; - unsigned char VB_ExtTVFlickerIndex; - unsigned char VB_ExtTVEdgeIndex; - unsigned char VB_ExtTVYFilterIndex; - unsigned char VB_ExtTVYFilterIndexROM661; - unsigned char REFindex; - char ROMMODEIDX661; +struct SiS_Ext { + unsigned char Ext_ModeID; + unsigned short Ext_ModeFlag; + unsigned short Ext_VESAID; + unsigned char Ext_RESINFO; + unsigned char VB_ExtTVFlickerIndex; + unsigned char VB_ExtTVEdgeIndex; + unsigned char VB_ExtTVYFilterIndex; + unsigned char VB_ExtTVYFilterIndexROM661; + unsigned char REFindex; + char ROMMODEIDX661; }; -struct SiS_Ext2 -{ - unsigned short Ext_InfoFlag; - unsigned char Ext_CRT1CRTC; - unsigned char Ext_CRTVCLK; - unsigned char Ext_CRT2CRTC; - unsigned char Ext_CRT2CRTC_NS; - unsigned char ModeID; - unsigned short XRes; - unsigned short YRes; - unsigned char Ext_PDC; - unsigned char Ext_FakeCRT2CRTC; - unsigned char Ext_FakeCRT2Clk; +struct SiS_Ext2 { + unsigned short Ext_InfoFlag; + unsigned char Ext_CRT1CRTC; + unsigned char Ext_CRTVCLK; + unsigned char Ext_CRT2CRTC; + unsigned char Ext_CRT2CRTC_NS; + unsigned char ModeID; + unsigned short XRes; + unsigned short YRes; + unsigned char Ext_PDC; + unsigned char Ext_FakeCRT2CRTC; + unsigned char Ext_FakeCRT2Clk; }; -struct SiS_CRT1Table -{ - unsigned char CR[17]; +struct SiS_CRT1Table { + unsigned char CR[17]; }; -struct SiS_VCLKData -{ - unsigned char SR2B,SR2C; - unsigned short CLOCK; +struct SiS_VCLKData { + unsigned char SR2B, SR2C; + unsigned short CLOCK; }; -struct SiS_ModeResInfo -{ - unsigned short HTotal; - unsigned short VTotal; - unsigned char XChar; - unsigned char YChar; +struct SiS_ModeResInfo { + unsigned short HTotal; + unsigned short VTotal; + unsigned char XChar; + unsigned char YChar; }; -struct SiS_Private -{ +struct SiS_Private { void *sisusb; unsigned long IOAddress; @@ -151,19 +144,18 @@ struct SiS_Private unsigned long SiS_P3da; unsigned long SiS_Part1Port; - unsigned char SiS_MyCR63; - unsigned short SiS_CRT1Mode; - unsigned short SiS_ModeType; - unsigned short SiS_SetFlag; - - const struct SiS_StandTable *SiS_StandTable; - const struct SiS_St *SiS_SModeIDTable; - const struct SiS_Ext *SiS_EModeIDTable; - const struct SiS_Ext2 *SiS_RefIndex; - const struct SiS_CRT1Table *SiS_CRT1Table; - const struct SiS_VCLKData *SiS_VCLKData; - const struct SiS_ModeResInfo *SiS_ModeResInfo; + unsigned char SiS_MyCR63; + unsigned short SiS_CRT1Mode; + unsigned short SiS_ModeType; + unsigned short SiS_SetFlag; + + const struct SiS_StandTable *SiS_StandTable; + const struct SiS_St *SiS_SModeIDTable; + const struct SiS_Ext *SiS_EModeIDTable; + const struct SiS_Ext2 *SiS_RefIndex; + const struct SiS_CRT1Table *SiS_CRT1Table; + const struct SiS_VCLKData *SiS_VCLKData; + const struct SiS_ModeResInfo *SiS_ModeResInfo; }; #endif - -- cgit v1.2.3-70-g09d2 From 7b5cd5fefbe023625a7ff7604e8beb9a15a9efab Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 15 Aug 2007 10:38:12 -0400 Subject: USB: SisUSB2VGA: Convert printk to dev_* macros This patch convert printk entries to dev_* macros, this provide better debugging and better readability to the code. Signed-off-by: Felipe Balbi Cc: Thomas Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb.c | 111 +++++++++----------------------- drivers/usb/misc/sisusbvga/sisusb_con.c | 13 ++-- 2 files changed, 36 insertions(+), 88 deletions(-) diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 558b94fd209..4d6b89336e6 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -1003,16 +1003,10 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, if (ret) { msgcount++; if (msgcount < 500) - printk(KERN_ERR - "sisusbvga[%d]: Wrote %zd of " - "%d bytes, error %d\n", - sisusb->minor, *bytes_written, - length, ret); + dev_err(&sisusb->sisusb_dev->dev, "Wrote %zd of %d bytes, error %d\n", + *bytes_written, length, ret); else if (msgcount == 500) - printk(KERN_ERR - "sisusbvga[%d]: Too many errors" - ", logging stopped\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Too many errors, logging stopped\n"); } addr += (*bytes_written); length -= (*bytes_written); @@ -1389,10 +1383,10 @@ sisusb_testreadwrite(struct sisusb_usb_data *sisusb) sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy); for(i = 1; i <= 7; i++) { - printk(KERN_DEBUG "sisusb: rwtest %d bytes\n", i); + dev_dbg(&sisusb->sisusb_dev->dev, "sisusb: rwtest %d bytes\n", i); sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy); for(j = 0; j < i; j++) { - printk(KERN_DEBUG "sisusb: rwtest read[%d] = %x\n", j, destbuffer[j]); + dev_dbg(&sisusb->sisusb_dev->dev, "rwtest read[%d] = %x\n", j, destbuffer[j]); } } } @@ -2111,17 +2105,12 @@ sisusb_init_gfxcore(struct sisusb_usb_data *sisusb) if (ramtype <= 1) { ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab); if (iret) { - printk(KERN_ERR "sisusbvga[%d]: RAM size " - "detection failed, " - "assuming 8MB video RAM\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev,"RAM size detection failed, assuming 8MB video RAM\n"); ret |= SETIREG(SISSR,0x14,0x31); /* TODO */ } } else { - printk(KERN_ERR "sisusbvga[%d]: DDR RAM device found, " - "assuming 8MB video RAM\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "DDR RAM device found, assuming 8MB video RAM\n"); ret |= SETIREG(SISSR,0x14,0x31); /* *** TODO *** */ } @@ -2192,8 +2181,7 @@ sisusb_get_ramconfig(struct sisusb_usb_data *sisusb) break; } - printk(KERN_INFO "sisusbvga[%d]: %dMB %s %s, bus width %d\n", - sisusb->minor, (sisusb->vramsize >> 20), ramtypetext1, + dev_info(&sisusb->sisusb_dev->dev, "%dMB %s %s, bus width %d\n", (sisusb->vramsize >> 20), ramtypetext1, ramtypetext2[ramtype], bw); } @@ -2453,8 +2441,7 @@ sisusb_open(struct inode *inode, struct file *file) int subminor = iminor(inode); if (!(interface = usb_find_interface(&sisusb_driver, subminor))) { - printk(KERN_ERR "sisusb[%d]: Failed to find interface\n", - subminor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to find interface\n"); return -ENODEV; } @@ -2477,18 +2464,12 @@ sisusb_open(struct inode *inode, struct file *file) if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) { if (sisusb_init_gfxdevice(sisusb, 0)) { mutex_unlock(&sisusb->lock); - printk(KERN_ERR - "sisusbvga[%d]: Failed to initialize " - "device\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to initialize device\n"); return -EIO; } } else { mutex_unlock(&sisusb->lock); - printk(KERN_ERR - "sisusbvga[%d]: Device not attached to " - "USB 2.0 hub\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Device not attached to USB 2.0 hub\n"); return -EIO; } } @@ -2529,7 +2510,6 @@ static int sisusb_release(struct inode *inode, struct file *file) { struct sisusb_usb_data *sisusb; - int myminor; if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) return -ENODEV; @@ -2542,8 +2522,6 @@ sisusb_release(struct inode *inode, struct file *file) sisusb_kill_all_busy(sisusb); } - myminor = sisusb->minor; - sisusb->isopen = 0; file->private_data = NULL; @@ -3126,17 +3104,13 @@ static int sisusb_probe(struct usb_interface *intf, struct usb_device *dev = interface_to_usbdev(intf); struct sisusb_usb_data *sisusb; int retval = 0, i; - const char *memfail = - KERN_ERR - "sisusbvga[%d]: Failed to allocate memory for %s buffer\n"; - printk(KERN_INFO "sisusb: USB2VGA dongle found at address %d\n", + dev_info(&dev->dev, "USB2VGA dongle found at address %d\n", dev->devnum); /* Allocate memory for our private */ if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) { - printk(KERN_ERR - "sisusb: Failed to allocate memory for private data\n"); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for private data\n"); return -ENOMEM; } kref_init(&sisusb->kref); @@ -3145,8 +3119,7 @@ static int sisusb_probe(struct usb_interface *intf, /* Register device */ if ((retval = usb_register_dev(intf, &usb_sisusb_class))) { - printk(KERN_ERR - "sisusb: Failed to get a minor for device %d\n", + dev_err(&sisusb->sisusb_dev->dev, "Failed to get a minor for device %d\n", dev->devnum); retval = -ENODEV; goto error_1; @@ -3164,7 +3137,7 @@ static int sisusb_probe(struct usb_interface *intf, sisusb->ibufsize = SISUSB_IBUF_SIZE; if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE, GFP_KERNEL, &sisusb->transfer_dma_in))) { - printk(memfail, "input", sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for input buffer"); retval = -ENOMEM; goto error_2; } @@ -3176,7 +3149,7 @@ static int sisusb_probe(struct usb_interface *intf, GFP_KERNEL, &sisusb->transfer_dma_out[i]))) { if (i == 0) { - printk(memfail, "output", sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for output buffer\n"); retval = -ENOMEM; goto error_3; } @@ -3188,9 +3161,7 @@ static int sisusb_probe(struct usb_interface *intf, /* Allocate URBs */ if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) { - printk(KERN_ERR - "sisusbvga[%d]: Failed to allocate URBs\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n"); retval = -ENOMEM; goto error_3; } @@ -3198,9 +3169,7 @@ static int sisusb_probe(struct usb_interface *intf, for (i = 0; i < sisusb->numobufs; i++) { if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) { - printk(KERN_ERR - "sisusbvga[%d]: Failed to allocate URBs\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n"); retval = -ENOMEM; goto error_4; } @@ -3209,15 +3178,12 @@ static int sisusb_probe(struct usb_interface *intf, sisusb->urbstatus[i] = 0; } - printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n", - sisusb->minor, sisusb->numobufs); + dev_info(&sisusb->sisusb_dev->dev, "Allocated %d output buffers\n", sisusb->numobufs); #ifdef INCL_SISUSB_CON /* Allocate our SiS_Pr */ if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) { - printk(KERN_ERR - "sisusbvga[%d]: Failed to allocate SiS_Pr\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate SiS_Pr\n"); } #endif @@ -3239,10 +3205,7 @@ static int sisusb_probe(struct usb_interface *intf, ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG, NULL); ret |= register_ioctl32_conversion(SISUSB_COMMAND, NULL); if (ret) - printk(KERN_ERR - "sisusbvga[%d]: Error registering ioctl32 " - "translations\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Error registering ioctl32 translations\n"); else sisusb->ioctl32registered = 1; } @@ -3258,23 +3221,17 @@ static int sisusb_probe(struct usb_interface *intf, initscreen = 0; #endif if (sisusb_init_gfxdevice(sisusb, initscreen)) - printk(KERN_ERR - "sisusbvga[%d]: Failed to early " - "initialize device\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to early initialize device\n"); } else - printk(KERN_INFO - "sisusbvga[%d]: Not attached to USB 2.0 hub, " - "deferring init\n", - sisusb->minor); + dev_info(&sisusb->sisusb_dev->dev, "Not attached to USB 2.0 hub, deferring init\n"); sisusb->ready = 1; #ifdef SISUSBENDIANTEST - printk(KERN_DEBUG "sisusb: *** RWTEST ***\n"); + dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST ***\n"); sisusb_testreadwrite(sisusb); - printk(KERN_DEBUG "sisusb: *** RWTEST END ***\n"); + dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST END ***\n"); #endif #ifdef INCL_SISUSB_CON @@ -3297,7 +3254,6 @@ error_1: static void sisusb_disconnect(struct usb_interface *intf) { struct sisusb_usb_data *sisusb; - int minor; /* This should *not* happen */ if (!(sisusb = usb_get_intfdata(intf))) @@ -3307,8 +3263,6 @@ static void sisusb_disconnect(struct usb_interface *intf) sisusb_console_exit(sisusb); #endif - minor = sisusb->minor; - usb_deregister_dev(intf, &usb_sisusb_class); mutex_lock(&sisusb->lock); @@ -3327,10 +3281,7 @@ static void sisusb_disconnect(struct usb_interface *intf) ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG); ret |= unregister_ioctl32_conversion(SISUSB_COMMAND); if (ret) { - printk(KERN_ERR - "sisusbvga[%d]: Error unregistering " - "ioctl32 translations\n", - minor); + dev_err(&sisusb->sisusb_dev->dev, "Error unregistering ioctl32 translations\n"); } } #endif @@ -3343,7 +3294,7 @@ static void sisusb_disconnect(struct usb_interface *intf) /* decrement our usage count */ kref_put(&sisusb->kref, sisusb_delete); - printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor); + dev_info(&sisusb->sisusb_dev->dev, "Disconnected\n"); } static struct usb_device_id sisusb_table [] = { @@ -3368,6 +3319,7 @@ static struct usb_driver sisusb_driver = { static int __init usb_sisusb_init(void) { int retval; + struct sisusb_usb_data *sisusb; #ifdef INCL_SISUSB_CON sisusb_init_concode(); @@ -3375,10 +3327,9 @@ static int __init usb_sisusb_init(void) if (!(retval = usb_register(&sisusb_driver))) { - printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n", - SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL); - printk(KERN_INFO - "sisusb: Copyright (C) 2005 Thomas Winischhofer\n"); + dev_info(&sisusb->sisusb_dev->dev, "Driver version %d.%d.%d\n", SISUSB_VERSION, + SISUSB_REVISION, SISUSB_PATCHLEVEL); + dev_info(&sisusb->sisusb_dev->dev, "sisusb: Copyright (C) 2005 Thomas Winischhofer\n"); } diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index 20938cd09ed..43722e5a49d 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -537,7 +538,7 @@ sisusbcon_switch(struct vc_data *c) */ if (c->vc_origin == (unsigned long)c->vc_screenbuf) { mutex_unlock(&sisusb->lock); - printk(KERN_DEBUG "sisusb: ASSERT ORIGIN != SCREENBUF!\n"); + dev_dbg(&sisusb->sisusb_dev->dev, "ASSERT ORIGIN != SCREENBUF!\n"); return 0; } @@ -1428,7 +1429,7 @@ static const struct consw sisusb_dummy_con = { int sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last) { - int i, ret, minor = sisusb->minor; + int i, ret; mutex_lock(&sisusb->lock); @@ -1461,9 +1462,7 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last) /* Set up text mode (and upload default font) */ if (sisusb_reset_text_mode(sisusb, 1)) { mutex_unlock(&sisusb->lock); - printk(KERN_ERR - "sisusbvga[%d]: Failed to set up text mode\n", - minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to set up text mode\n"); return 1; } @@ -1484,9 +1483,7 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last) /* Allocate screen buffer */ if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) { mutex_unlock(&sisusb->lock); - printk(KERN_ERR - "sisusbvga[%d]: Failed to allocate screen buffer\n", - minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate screen buffer\n"); return 1; } -- cgit v1.2.3-70-g09d2 From fc401e697f8c00ad1178a6758e86e3881dfa3181 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Mon, 13 Aug 2007 22:50:13 -0700 Subject: usblp: mutex in usblp_check_status Add a mutex to protect the ->statusbuf. Not really an issue, because CUPS is single-threaded when it talks to the printer, but I feel safer this way. This should be deadlock-free, but I kept this as a separate patch in case someone ends running a git bisect. Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usblp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 9696668e575..2c4a359355b 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -345,16 +345,17 @@ static int usblp_check_status(struct usblp *usblp, int err) unsigned char status, newerr = 0; int error; - error = usblp_read_status (usblp, usblp->statusbuf); - if (error < 0) { + mutex_lock(&usblp->mut); + if ((error = usblp_read_status(usblp, usblp->statusbuf)) < 0) { + mutex_unlock(&usblp->mut); if (printk_ratelimit()) printk(KERN_ERR "usblp%d: error %d reading printer status\n", usblp->minor, error); return 0; } - status = *usblp->statusbuf; + mutex_unlock(&usblp->mut); if (~status & LP_PERRORP) newerr = 3; -- cgit v1.2.3-70-g09d2 From 283face86b002e670053e9189604852ccb81d357 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Mon, 13 Aug 2007 22:54:29 -0700 Subject: usblp: Cosmetics This is a small bunch of cosmetic fixes: - Timeout is not a write timeout anymore, rename - Condition in poll was confusingly backwards, invert and simplify - The comment log gave a wrong impression of version 0.13, terminate it. Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usblp.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 2c4a359355b..3a0f8186d4b 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -28,6 +28,7 @@ * v0.12 - add hpoj.sourceforge.net ioctls (David Paschal) * v0.13 - alloc space for statusbuf ( not on stack); * use usb_buffer_alloc() for read buf & write buf; + * none - Maintained in Linux kernel after v0.13 */ /* @@ -114,7 +115,7 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H #define USBLP_MINORS 16 #define USBLP_MINOR_BASE 0 -#define USBLP_WRITE_TIMEOUT (5000) /* 5 seconds */ +#define USBLP_CTL_TIMEOUT 5000 /* 5 seconds */ #define USBLP_FIRST_PROTOCOL 1 #define USBLP_LAST_PROTOCOL 3 @@ -260,7 +261,7 @@ static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, i retval = usb_control_msg(usblp->dev, dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0), - request, type | dir | recip, value, index, buf, len, USBLP_WRITE_TIMEOUT); + request, type | dir | recip, value, index, buf, len, USBLP_CTL_TIMEOUT); dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d", request, !!dir, recip, value, index, len, retval); return retval < 0 ? retval : 0; @@ -479,8 +480,8 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait poll_wait(file, &usblp->rwait, wait); poll_wait(file, &usblp->wwait, wait); spin_lock_irqsave(&usblp->lock, flags); - ret = ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN | POLLRDNORM) - | ((usblp->no_paper || usblp->wcomplete) ? POLLOUT | POLLWRNORM : 0); + ret = ((usblp->bidir && usblp->rcomplete) ? POLLIN | POLLRDNORM : 0) | + ((usblp->no_paper || usblp->wcomplete) ? POLLOUT | POLLWRNORM : 0); spin_unlock_irqrestore(&usblp->lock, flags); return ret; } -- cgit v1.2.3-70-g09d2 From 30c7431de3631d6a5482a87b7c2453b937e8aa51 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Tue, 14 Aug 2007 00:33:40 -0700 Subject: usbmon: Update pipe removal to suit my taste This is a set of small updates to Alan's work to make the code more to my liking. Mostly premature optimizations, but also direction of control transfers in the binary interface was always out. Signed-off-by: Pete Zaitcev Cc: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mon/mon_bin.c | 44 ++++++++++++++------------------------------ drivers/usb/mon/mon_text.c | 8 ++++---- 2 files changed, 18 insertions(+), 34 deletions(-) diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index 0b0d77c669d..5185e93dede 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -172,6 +172,10 @@ static inline struct mon_bin_hdr *MON_OFF2HDR(const struct mon_reader_bin *rp, #define MON_RING_EMPTY(rp) ((rp)->b_cnt == 0) +static unsigned char xfer_to_pipe[4] = { + PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT +}; + static struct class *mon_bin_class; static dev_t mon_bin_dev0; static struct cdev mon_bin_cdev; @@ -388,11 +392,13 @@ static char mon_bin_get_data(const struct mon_reader_bin *rp, static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, char ev_type) { + const struct usb_endpoint_descriptor *epd = &urb->ep->desc; unsigned long flags; struct timeval ts; unsigned int urb_length; unsigned int offset; unsigned int length; + unsigned char dir; struct mon_bin_hdr *ep; char data_tag = 0; @@ -415,11 +421,14 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, length = 0; data_tag = '<'; } + /* Cannot rely on endpoint number in case of control ep.0 */ + dir = USB_DIR_IN; } else { if (ev_type == 'C') { length = 0; data_tag = '>'; } + dir = 0; } if (rp->mmap_active) @@ -440,21 +449,8 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, */ memset(ep, 0, PKT_SIZE); ep->type = ev_type; - switch (usb_endpoint_type(&urb->ep->desc)) { - case USB_ENDPOINT_XFER_CONTROL: - ep->xfer_type = PIPE_CONTROL; - break; - case USB_ENDPOINT_XFER_BULK: - ep->xfer_type = PIPE_BULK; - break; - case USB_ENDPOINT_XFER_INT: - ep->xfer_type = PIPE_INTERRUPT; - break; - default: - ep->xfer_type = PIPE_ISOCHRONOUS; - break; - } - ep->epnum = urb->ep->desc.bEndpointAddress; + ep->xfer_type = xfer_to_pipe[usb_endpoint_type(epd)]; + ep->epnum = dir | usb_endpoint_num(epd); ep->devnum = urb->dev->devnum; ep->busnum = urb->dev->bus->busnum; ep->id = (unsigned long) urb; @@ -512,21 +508,9 @@ static void mon_bin_error(void *data, struct urb *urb, int error) memset(ep, 0, PKT_SIZE); ep->type = 'E'; - switch (usb_endpoint_type(&urb->ep->desc)) { - case USB_ENDPOINT_XFER_CONTROL: - ep->xfer_type = PIPE_CONTROL; - break; - case USB_ENDPOINT_XFER_BULK: - ep->xfer_type = PIPE_BULK; - break; - case USB_ENDPOINT_XFER_INT: - ep->xfer_type = PIPE_INTERRUPT; - break; - default: - ep->xfer_type = PIPE_ISOCHRONOUS; - break; - } - ep->epnum = urb->ep->desc.bEndpointAddress; + ep->xfer_type = xfer_to_pipe[usb_endpoint_type(&urb->ep->desc)]; + ep->epnum = usb_urb_dir_in(urb) ? USB_DIR_IN : 0; + ep->epnum |= usb_endpoint_num(&urb->ep->desc); ep->devnum = urb->dev->devnum; ep->busnum = urb->dev->bus->busnum; ep->id = (unsigned long) urb; diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 9d0070ceef5..a74069c2e82 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -52,10 +52,11 @@ struct mon_event_text { int type; /* submit, complete, etc. */ unsigned long id; /* From pointer, most of the time */ unsigned int tstamp; - int xfertype; int busnum; - int devnum; - int epnum; + char devnum; + char epnum; + char is_in; + char xfertype; int length; /* Depends on type: xfer length or act length */ int status; int interval; @@ -63,7 +64,6 @@ struct mon_event_text { int error_count; char setup_flag; char data_flag; - char is_in; int numdesc; /* Full number */ struct mon_iso_desc isodesc[ISODESC_MAX]; unsigned char setup[SETUP_MAX]; -- cgit v1.2.3-70-g09d2 From cdd5a8fd24f5be43417a25c6feb8e7ebdce63098 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Tue, 14 Aug 2007 00:37:51 -0700 Subject: usbmon: Drop DMA mapping for setup packet Setup packet must be visible in virtual space. There's absolutely no good reason to implement any kind of zero-copy transfer of 8 bytes, and the documentation in usb.h is explicit about it. So, drop DMA remapping. Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mon/mon_bin.c | 4 ---- drivers/usb/mon/mon_text.c | 4 ---- 2 files changed, 8 deletions(-) diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index 5185e93dede..3d6f03819ff 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -361,10 +361,6 @@ static inline char mon_bin_get_setup(unsigned char *setupb, if (!usb_endpoint_xfer_control(&urb->ep->desc) || ev_type != 'S') return '-'; - if (urb->dev->bus->uses_dma && - (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) { - return mon_dmapeek(setupb, urb->setup_dma, SETUP_LEN); - } if (urb->setup_packet == NULL) return 'Z'; diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index a74069c2e82..663a702a17d 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -127,10 +127,6 @@ static inline char mon_text_get_setup(struct mon_event_text *ep, if (ep->xfertype != USB_ENDPOINT_XFER_CONTROL || ev_type != 'S') return '-'; - if (urb->dev->bus->uses_dma && - (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) { - return mon_dmapeek(ep->setup, urb->setup_dma, SETUP_MAX); - } if (urb->setup_packet == NULL) return 'Z'; /* '0' would be not as pretty. */ -- cgit v1.2.3-70-g09d2 From c36d54ab380fb8edeaa22776af869c64bfda43bd Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Tue, 14 Aug 2007 00:42:53 -0700 Subject: usbmon: Smooth the core code Two things: - mbus can be NULL (in case of bus removal while reader is reading) - Remove a useless assignment Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mon/mon_main.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c index e58f761d060..2e317bd79e9 100644 --- a/drivers/usb/mon/mon_main.c +++ b/drivers/usb/mon/mon_main.c @@ -148,18 +148,8 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb) { struct mon_bus *mbus; - mbus = ubus->mon_bus; - if (mbus == NULL) { - /* - * This should not happen. - * At this point we do not even know the bus number... - */ - printk(KERN_ERR TAG ": Null mon bus in URB, address %p\n", - urb); - return; - } - - mon_bus_complete(mbus, urb); + if ((mbus = ubus->mon_bus) != NULL) + mon_bus_complete(mbus, urb); mon_bus_complete(&mon_bus0, urb); } @@ -170,7 +160,7 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb) */ static void mon_stop(struct mon_bus *mbus) { - struct usb_bus *ubus = mbus->u_bus; + struct usb_bus *ubus; struct list_head *p; if (mbus == &mon_bus0) { -- cgit v1.2.3-70-g09d2 From 42cb967fd01b1f50374fdfa811f86db103eea532 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Tue, 14 Aug 2007 13:19:16 -0700 Subject: usblp: Fix a double kfree If submit fails, slab hits a BUG() because of a double kfree. The today's lesson is, you cannot just slap USB_FREE_BUFFER on code without adjusting the error paths. The patch is made bigger by opportunistic refactoring. Signed-Off-By: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usblp.c | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 3a0f8186d4b..ad632f2d6f9 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -686,10 +686,30 @@ done: return retval; } +static struct urb *usblp_new_writeurb(struct usblp *usblp, int transfer_length) +{ + struct urb *urb; + char *writebuf; + + if ((writebuf = kmalloc(transfer_length, GFP_KERNEL)) == NULL) + return NULL; + if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) { + kfree(writebuf); + return NULL; + } + + usb_fill_bulk_urb(urb, usblp->dev, + usb_sndbulkpipe(usblp->dev, + usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress), + writebuf, transfer_length, usblp_bulk_write, usblp); + urb->transfer_flags |= URB_FREE_BUFFER; + + return urb; +} + static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { struct usblp *usblp = file->private_data; - char *writebuf; struct urb *writeurb; int rv; int transfer_length; @@ -710,18 +730,11 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t transfer_length = USBLP_BUF_SIZE; rv = -ENOMEM; - if ((writebuf = kmalloc(USBLP_BUF_SIZE, GFP_KERNEL)) == NULL) - goto raise_buf; - if ((writeurb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) + if ((writeurb = usblp_new_writeurb(usblp, transfer_length)) == NULL) goto raise_urb; - usb_fill_bulk_urb(writeurb, usblp->dev, - usb_sndbulkpipe(usblp->dev, - usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress), - writebuf, transfer_length, usblp_bulk_write, usblp); - writeurb->transfer_flags |= URB_FREE_BUFFER; usb_anchor_urb(writeurb, &usblp->urbs); - if (copy_from_user(writebuf, + if (copy_from_user(writeurb->transfer_buffer, buffer + writecount, transfer_length)) { rv = -EFAULT; goto raise_badaddr; @@ -780,8 +793,6 @@ raise_badaddr: usb_unanchor_urb(writeurb); usb_free_urb(writeurb); raise_urb: - kfree(writebuf); -raise_buf: raise_wait: collect_error: /* Out of raise sequence */ mutex_unlock(&usblp->wmut); -- cgit v1.2.3-70-g09d2 From 3f6ff6ef044bc7078daa01412c911015d6cbaa39 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 10 Aug 2007 14:53:34 -0700 Subject: USB: kl5kusb105: witch to new speed API Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/kl5kusb105.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 5a4127e62c4..90e3216abd1 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -728,24 +728,32 @@ static void klsi_105_set_termios (struct usb_serial_port *port, #endif } - switch(cflag & CBAUD) { - case B0: /* handled below */ + switch(tty_get_baud_rate(port->tty)) { + case 0: /* handled below */ break; - case B1200: priv->cfg.baudrate = kl5kusb105a_sio_b1200; + case 1200: + priv->cfg.baudrate = kl5kusb105a_sio_b1200; break; - case B2400: priv->cfg.baudrate = kl5kusb105a_sio_b2400; + case 2400: + priv->cfg.baudrate = kl5kusb105a_sio_b2400; break; - case B4800: priv->cfg.baudrate = kl5kusb105a_sio_b4800; + case 4800: + priv->cfg.baudrate = kl5kusb105a_sio_b4800; break; - case B9600: priv->cfg.baudrate = kl5kusb105a_sio_b9600; + case 9600: + priv->cfg.baudrate = kl5kusb105a_sio_b9600; break; - case B19200: priv->cfg.baudrate = kl5kusb105a_sio_b19200; + case 19200: + priv->cfg.baudrate = kl5kusb105a_sio_b19200; break; - case B38400: priv->cfg.baudrate = kl5kusb105a_sio_b38400; + case 38400: + priv->cfg.baudrate = kl5kusb105a_sio_b38400; break; - case B57600: priv->cfg.baudrate = kl5kusb105a_sio_b57600; + case 57600: + priv->cfg.baudrate = kl5kusb105a_sio_b57600; break; - case B115200: priv->cfg.baudrate = kl5kusb105a_sio_b115200; + case 115200: + priv->cfg.baudrate = kl5kusb105a_sio_b115200; break; default: err("KLSI USB->Serial converter:" -- cgit v1.2.3-70-g09d2 From b3aceb2bab988e514e65dd37f385221a095ad477 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 10 Aug 2007 14:53:35 -0700 Subject: USB: mct_u232-convert-to-proper-speed-handling-api-fix Make Pete happy Cc: Alan Cox Cc: Pete Zaitcev Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/mct_u232.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index e08c9bb403d..0dc99f75bb0 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -206,20 +206,20 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value } } else { switch (value) { - case 300: break; - case 600: break; - case 1200: break; - case 2400: break; - case 4800: break; - case 9600: break; - case 19200: break; - case 38400: break; - case 57600: break; - case 115200: break; - default: - err("MCT USB-RS232: unsupported baudrate request 0x%x," - " using default of B9600", value); - value = 9600; + case 300: break; + case 600: break; + case 1200: break; + case 2400: break; + case 4800: break; + case 9600: break; + case 19200: break; + case 38400: break; + case 57600: break; + case 115200: break; + default: + err("MCT USB-RS232: unsupported baudrate request 0x%x," + " using default of B9600", value); + value = 9600; } return 115200/value; } -- cgit v1.2.3-70-g09d2 From 5280d6083a77cc06a8c8360a2c461fd12d780fb8 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Fri, 10 Aug 2007 14:53:35 -0700 Subject: USB: ftdi-elan.c: kmalloc + memset conversion to kzalloc drivers/usb/misc/ftdi-elan.c | 121253 -> 121196 (-57 bytes) drivers/usb/misc/ftdi-elan.o | 209425 -> 209265 (-160 bytes) Signed-off-by: Mariusz Kozlowski Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/ftdi-elan.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 538b535e955..d3d8cd6ff10 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -2777,12 +2777,14 @@ static int ftdi_elan_probe(struct usb_interface *interface, size_t buffer_size; int i; int retval = -ENOMEM; - struct usb_ftdi *ftdi = kmalloc(sizeof(struct usb_ftdi), GFP_KERNEL); - if (ftdi == NULL) { + struct usb_ftdi *ftdi; + + ftdi = kzalloc(sizeof(struct usb_ftdi), GFP_KERNEL); + if (!ftdi) { printk(KERN_ERR "Out of memory\n"); return -ENOMEM; } - memset(ftdi, 0x00, sizeof(struct usb_ftdi)); + mutex_lock(&ftdi_module_lock); list_add_tail(&ftdi->ftdi_list, &ftdi_static_list); ftdi->sequence_num = ++ftdi_instances; -- cgit v1.2.3-70-g09d2 From 60b69a966fddeb3bdd79712d52b34b8696a27f88 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Fri, 10 Aug 2007 14:53:37 -0700 Subject: usb: remove redundant memset from amd5536udc Remove redundant memset() call from udc_pci_probe(). No functional change. Signed-off-by: Mariusz Kozlowski Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/amd5536udc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index 714156ca8fe..e95ffc9eee3 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -3244,7 +3244,6 @@ static int udc_pci_probe( retval = -ENOMEM; goto finished; } - memset(dev, 0, sizeof(struct udc)); /* pci setup */ if (pci_enable_device(pdev) < 0) { -- cgit v1.2.3-70-g09d2 From f6c1ceaa3844b7a7787816cc97d15b9fea8b0909 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 16 Aug 2007 16:02:08 +0200 Subject: USB: missing test for ESHUTDOWN in adutux driver this driver lacks a test for unlink due to ESHUTDOWN Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/adutux.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index e9fdbc8997b..5131cbfb2f5 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -188,7 +188,8 @@ static void adu_interrupt_in_callback(struct urb *urb) spin_lock(&dev->buflock); if (status != 0) { - if ((status != -ENOENT) && (status != -ECONNRESET)) { + if ((status != -ENOENT) && (status != -ECONNRESET) && + (status != -ESHUTDOWN)) { dbg(1," %s : nonzero status received: %d", __FUNCTION__, status); } -- cgit v1.2.3-70-g09d2 From f311cf58bd04adc683067f8d66daa5925b80f082 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 14 Aug 2007 23:22:50 +0200 Subject: USB: ark3116.c: fix check-after-use The Coverity checker spotted that we'd have already oops'ed if one of these was NULL. Signed-off-by: Adrian Bunk Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ark3116.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index c9fd486c1c7..2a8e537cb04 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -172,11 +172,6 @@ static void ark3116_set_termios(struct usb_serial_port *port, dbg("%s - port %d", __FUNCTION__, port->number); - if (!port->tty || !port->tty->termios) { - dbg("%s - no tty structures", __FUNCTION__); - return; - } - spin_lock_irqsave(&priv->lock, flags); if (!priv->termios_initialized) { *(port->tty->termios) = tty_std_termios; -- cgit v1.2.3-70-g09d2 From e39ab592f182cd0be48acc4ad49f93ef4100017c Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 16 Aug 2007 16:17:49 -0400 Subject: USB: remove unnecessary tests in isp116x and sl811 This patch (as962) cleans up some code I forgot to remove earlier in the isp116x and sl811 HCDs. There is no longer any need to check for unlink-during-submit; it can't happen since the endpoint queues are now under the protection of the HCD-private spinlock. Signed-off-by: Alan Stern CC: David Brownell CC: Olav Kongas Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/isp116x-hcd.c | 6 ------ drivers/usb/host/sl811-hcd.c | 10 ---------- 2 files changed, 16 deletions(-) diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index d5027dc75a5..f2b5d6281c5 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -815,12 +815,6 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, } } - /* in case of unlink-during-submit */ - if (urb->status != -EINPROGRESS) { - finish_request(isp116x, ep, urb); - ret = 0; - goto fail; - } urb->hcpriv = hep; start_atl_transfers(isp116x); diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 3d3a63d002c..15a93f946af 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -957,17 +957,7 @@ static int sl811h_urb_enqueue( sofirq_on(sl811); } - /* in case of unlink-during-submit */ - spin_lock(&urb->lock); - if (urb->status != -EINPROGRESS) { - spin_unlock(&urb->lock); - finish_request(sl811, ep, urb, 0); - retval = 0; - goto fail; - } urb->hcpriv = hep; - spin_unlock(&urb->lock); - start_transfer(sl811); sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable); fail: -- cgit v1.2.3-70-g09d2 From c8e463796c7ae6d8dda39b0c7eb3d627600ffe2e Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 20 Aug 2007 23:23:12 +0200 Subject: UEAGLE: Eagle IV chipset support Add support to newest chipset of eagle family. It is compatible with older chipsets at USB level. However DSP firmware and CMVs (Configuration and Management Variables) have different format of data and are sent/received by different way. Signed-off-by: Stanislaw Gruszka Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/ueagle-atm.c | 1191 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 978 insertions(+), 213 deletions(-) diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 29807d048b0..b5e8cbad223 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -107,12 +107,42 @@ #define uea_info(usb_dev, format,args...) \ dev_info(&(usb_dev)->dev ,"[ueagle-atm] " format, ##args) -struct uea_cmvs { +struct intr_pkt; + +/* cmv's from firmware */ +struct uea_cmvs_v1 { u32 address; u16 offset; u32 data; } __attribute__ ((packed)); +struct uea_cmvs_v2 { + u32 group; + u32 address; + u32 offset; + u32 data; +} __attribute__ ((packed)); + +/* information about currently processed cmv */ +struct cmv_dsc_e1 { + u8 function; + u16 idx; + u32 address; + u16 offset; +}; + +struct cmv_dsc_e4 { + u16 function; + u16 offset; + u16 address; + u16 group; +}; + +union cmv_dsc { + struct cmv_dsc_e1 e1; + struct cmv_dsc_e4 e4; +}; + struct uea_softc { struct usb_device *usb_dev; struct usbatm_data *usbatm; @@ -127,8 +157,11 @@ struct uea_softc { struct task_struct *kthread; u32 data; + u32 data1; wait_queue_head_t cmv_ack_wait; + int cmv_ack; + union cmv_dsc cmv_dsc; struct work_struct task; u16 pageno; @@ -137,10 +170,10 @@ struct uea_softc { const struct firmware *dsp_firm; struct urb *urb_int; - u8 cmv_function; - u16 cmv_idx; - u32 cmv_address; - u16 cmv_offset; + void (*dispatch_cmv) (struct uea_softc *, struct intr_pkt *); + void (*schedule_load_page) (struct uea_softc *, struct intr_pkt *); + int (*stat) (struct uea_softc *); + int (*send_cmvs) (struct uea_softc *); /* keep in sync with eaglectl */ struct uea_stats { @@ -187,12 +220,12 @@ struct uea_softc { #define EAGLE_II_PID_PREFIRM 0x9022 /* Eagle II */ #define EAGLE_II_PID_PSTFIRM 0x9021 /* Eagle II */ -/* - * Eagle III Pid - */ #define EAGLE_III_PID_PREFIRM 0x9032 /* Eagle III */ #define EAGLE_III_PID_PSTFIRM 0x9031 /* Eagle III */ +#define EAGLE_IV_PID_PREFIRM 0x9042 /* Eagle IV */ +#define EAGLE_IV_PID_PSTFIRM 0x9041 /* Eagle IV */ + /* * USR USB IDs */ @@ -212,7 +245,8 @@ enum { ADI930 = 0, EAGLE_I, EAGLE_II, - EAGLE_III + EAGLE_III, + EAGLE_IV }; /* macros for both struct usb_device_id and struct uea_softc */ @@ -228,8 +262,11 @@ enum { #define GET_STATUS(data) \ ((data >> 8) & 0xf) + #define IS_OPERATIONAL(sc) \ - (GET_STATUS(sc->stats.phy.state) == 2) + ((UEA_CHIP_VERSION(sc) != EAGLE_IV) ? \ + (GET_STATUS(sc->stats.phy.state) == 2) : \ + (sc->stats.phy.state == 7)) /* * Set of macros to handle unaligned data in the firmware blob. @@ -259,7 +296,8 @@ enum { #define UEA_INTR_PIPE 0x04 #define UEA_ISO_DATA_PIPE 0x08 -#define UEA_SET_BLOCK 0x0001 +#define UEA_E1_SET_BLOCK 0x0001 +#define UEA_E4_SET_BLOCK 0x002c #define UEA_SET_MODE 0x0003 #define UEA_SET_2183_DATA 0x0004 #define UEA_SET_TIMEOUT 0x0011 @@ -275,71 +313,179 @@ enum { #define UEA_MPTX_MAILBOX (0x3fd6 | 0x4000) #define UEA_MPRX_MAILBOX (0x3fdf | 0x4000) -/* structure describing a block within a DSP page */ -struct block_info { +/* block information in eagle4 dsp firmware */ +struct block_index { + __le32 PageOffset; + __le32 NotLastBlock; + __le32 dummy; + __le32 PageSize; + __le32 PageAddress; + __le16 dummy1; + __le16 PageNumber; +} __attribute__ ((packed)); + +#define E4_IS_BOOT_PAGE(PageSize) ((le32_to_cpu(PageSize)) & 0x80000000) +#define E4_PAGE_BYTES(PageSize) ((le32_to_cpu(PageSize) & 0x7fffffff) * 4) + +#define E4_L1_STRING_HEADER 0x10 +#define E4_MAX_PAGE_NUMBER 0x58 +#define E4_NO_SWAPPAGE_HEADERS 0x31 + +/* l1_code is eagle4 dsp firmware format */ +struct l1_code { + u8 string_header[E4_L1_STRING_HEADER]; + u8 page_number_to_block_index[E4_MAX_PAGE_NUMBER]; + struct block_index page_header[E4_NO_SWAPPAGE_HEADERS]; + u8 code [0]; +} __attribute__ ((packed)); + +/* structures describing a block within a DSP page */ +struct block_info_e1 { __le16 wHdr; -#define UEA_BIHDR 0xabcd __le16 wAddress; __le16 wSize; __le16 wOvlOffset; __le16 wOvl; /* overlay */ __le16 wLast; } __attribute__ ((packed)); -#define BLOCK_INFO_SIZE 12 +#define E1_BLOCK_INFO_SIZE 12 + +struct block_info_e4 { + __be16 wHdr; + __u8 bBootPage; + __u8 bPageNumber; + __be32 dwSize; + __be32 dwAddress; + __be16 wReserved; +} __attribute__ ((packed)); +#define E4_BLOCK_INFO_SIZE 14 -/* structure representing a CMV (Configuration and Management Variable) */ -struct cmv { - __le16 wPreamble; -#define PREAMBLE 0x535c - __u8 bDirection; -#define MODEMTOHOST 0x01 -#define HOSTTOMODEM 0x10 - __u8 bFunction; -#define FUNCTION_TYPE(f) ((f) >> 4) -#define MEMACCESS 0x1 -#define ADSLDIRECTIVE 0x7 +#define UEA_BIHDR 0xabcd +#define UEA_RESERVED 0xffff + +/* constants describing cmv type */ +#define E1_PREAMBLE 0x535c +#define E1_MODEMTOHOST 0x01 +#define E1_HOSTTOMODEM 0x10 + +#define E1_MEMACCESS 0x1 +#define E1_ADSLDIRECTIVE 0x7 +#define E1_FUNCTION_TYPE(f) ((f) >> 4) +#define E1_FUNCTION_SUBTYPE(f) ((f) & 0x0f) + +#define E4_MEMACCESS 0 +#define E4_ADSLDIRECTIVE 0xf +#define E4_FUNCTION_TYPE(f) ((f) >> 8) +#define E4_FUNCTION_SIZE(f) ((f) & 0x0f) +#define E4_FUNCTION_SUBTYPE(f) (((f) >> 4) & 0x0f) -#define FUNCTION_SUBTYPE(f) ((f) & 0x0f) /* for MEMACCESS */ -#define REQUESTREAD 0x0 -#define REQUESTWRITE 0x1 -#define REPLYREAD 0x2 -#define REPLYWRITE 0x3 +#define E1_REQUESTREAD 0x0 +#define E1_REQUESTWRITE 0x1 +#define E1_REPLYREAD 0x2 +#define E1_REPLYWRITE 0x3 + +#define E4_REQUESTREAD 0x0 +#define E4_REQUESTWRITE 0x4 +#define E4_REPLYREAD (E4_REQUESTREAD | 1) +#define E4_REPLYWRITE (E4_REQUESTWRITE | 1) + /* for ADSLDIRECTIVE */ -#define KERNELREADY 0x0 -#define MODEMREADY 0x1 +#define E1_KERNELREADY 0x0 +#define E1_MODEMREADY 0x1 -#define MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf)) - __le16 wIndex; - __le32 dwSymbolicAddress; -#define MAKESA(a, b, c, d) \ +#define E4_KERNELREADY 0x0 +#define E4_MODEMREADY 0x1 + +#define E1_MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf)) +#define E4_MAKEFUNCTION(t, st, s) (((t) & 0xf) << 8 | ((st) & 0xf) << 4 | ((s) & 0xf)) + +#define E1_MAKESA(a, b, c, d) \ (((c) & 0xff) << 24 | \ ((d) & 0xff) << 16 | \ ((a) & 0xff) << 8 | \ ((b) & 0xff)) -#define GETSA1(a) ((a >> 8) & 0xff) -#define GETSA2(a) (a & 0xff) -#define GETSA3(a) ((a >> 24) & 0xff) -#define GETSA4(a) ((a >> 16) & 0xff) - -#define SA_CNTL MAKESA('C', 'N', 'T', 'L') -#define SA_DIAG MAKESA('D', 'I', 'A', 'G') -#define SA_INFO MAKESA('I', 'N', 'F', 'O') -#define SA_OPTN MAKESA('O', 'P', 'T', 'N') -#define SA_RATE MAKESA('R', 'A', 'T', 'E') -#define SA_STAT MAKESA('S', 'T', 'A', 'T') + +#define E1_GETSA1(a) ((a >> 8) & 0xff) +#define E1_GETSA2(a) (a & 0xff) +#define E1_GETSA3(a) ((a >> 24) & 0xff) +#define E1_GETSA4(a) ((a >> 16) & 0xff) + +#define E1_SA_CNTL E1_MAKESA('C', 'N', 'T', 'L') +#define E1_SA_DIAG E1_MAKESA('D', 'I', 'A', 'G') +#define E1_SA_INFO E1_MAKESA('I', 'N', 'F', 'O') +#define E1_SA_OPTN E1_MAKESA('O', 'P', 'T', 'N') +#define E1_SA_RATE E1_MAKESA('R', 'A', 'T', 'E') +#define E1_SA_STAT E1_MAKESA('S', 'T', 'A', 'T') + +#define E4_SA_CNTL 1 +#define E4_SA_STAT 2 +#define E4_SA_INFO 3 +#define E4_SA_TEST 4 +#define E4_SA_OPTN 5 +#define E4_SA_RATE 6 +#define E4_SA_DIAG 7 +#define E4_SA_CNFG 8 + +/* structures representing a CMV (Configuration and Management Variable) */ +struct cmv_e1 { + __le16 wPreamble; + __u8 bDirection; + __u8 bFunction; + __le16 wIndex; + __le32 dwSymbolicAddress; __le16 wOffsetAddress; __le32 dwData; } __attribute__ ((packed)); -#define CMV_SIZE 16 -/* structure representing swap information */ -struct swap_info { +struct cmv_e4 { + __be16 wGroup; + __be16 wFunction; + __be16 wOffset; + __be16 wAddress; + __be32 dwData [6]; +} __attribute__ ((packed)); + +/* structures representing swap information */ +struct swap_info_e1 { __u8 bSwapPageNo; __u8 bOvl; /* overlay */ } __attribute__ ((packed)); -/* structure representing interrupt data */ +struct swap_info_e4 { + __u8 bSwapPageNo; +} __attribute__ ((packed)); + +/* structures representing interrupt data */ +#define e1_bSwapPageNo u.e1.s1.swapinfo.bSwapPageNo +#define e1_bOvl u.e1.s1.swapinfo.bOvl +#define e4_bSwapPageNo u.e4.s1.swapinfo.bSwapPageNo + +#define INT_LOADSWAPPAGE 0x0001 +#define INT_INCOMINGCMV 0x0002 + +union intr_data_e1 { + struct { + struct swap_info_e1 swapinfo; + __le16 wDataSize; + } __attribute__ ((packed)) s1; + struct { + struct cmv_e1 cmv; + __le16 wDataSize; + } __attribute__ ((packed)) s2; +} __attribute__ ((packed)); + +union intr_data_e4 { + struct { + struct swap_info_e4 swapinfo; + __le16 wDataSize; + } __attribute__ ((packed)) s1; + struct { + struct cmv_e4 cmv; + __le16 wDataSize; + } __attribute__ ((packed)) s2; +} __attribute__ ((packed)); + struct intr_pkt { __u8 bType; __u8 bNotification; @@ -347,27 +493,18 @@ struct intr_pkt { __le16 wIndex; __le16 wLength; __le16 wInterrupt; -#define INT_LOADSWAPPAGE 0x0001 -#define INT_INCOMINGCMV 0x0002 union { - struct { - struct swap_info swapinfo; - __le16 wDataSize; - } __attribute__ ((packed)) s1; - - struct { - struct cmv cmv; - __le16 wDataSize; - } __attribute__ ((packed)) s2; - } __attribute__ ((packed)) u; -#define bSwapPageNo u.s1.swapinfo.bSwapPageNo -#define bOvl u.s1.swapinfo.bOvl + union intr_data_e1 e1; + union intr_data_e4 e4; + } u; } __attribute__ ((packed)); -#define INTR_PKT_SIZE 28 + +#define E1_INTR_PKT_SIZE 28 +#define E4_INTR_PKT_SIZE 64 static struct usb_driver uea_driver; static DEFINE_MUTEX(uea_mutex); -static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III"}; +static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III", "Eagle IV"}; static int modem_index; static unsigned int debug; @@ -519,6 +656,9 @@ static int uea_load_firmware(struct usb_device *usb, unsigned int ver) case EAGLE_III: fw_name = FW_DIR "eagleIII.fw"; break; + case EAGLE_IV: + fw_name = FW_DIR "eagleIV.fw"; + break; } ret = request_firmware_nowait(THIS_MODULE, 1, fw_name, &usb->dev, usb, uea_upload_pre_firmware); @@ -537,7 +677,7 @@ static int uea_load_firmware(struct usb_device *usb, unsigned int ver) /* * Make sure that the DSP code provided is safe to use. */ -static int check_dsp(u8 *dsp, unsigned int len) +static int check_dsp_e1(u8 *dsp, unsigned int len) { u8 pagecount, blockcount; u16 blocksize; @@ -588,6 +728,51 @@ static int check_dsp(u8 *dsp, unsigned int len) return 0; } +static int check_dsp_e4(u8 *dsp, int len) +{ + int i; + struct l1_code *p = (struct l1_code *) dsp; + unsigned int sum = p->code - dsp; + + if (len < sum) + return 1; + + if (strcmp("STRATIPHY ANEXA", p->string_header) != 0 && + strcmp("STRATIPHY ANEXB", p->string_header) != 0) + return 1; + + for (i = 0; i < E4_MAX_PAGE_NUMBER; i++) { + struct block_index *blockidx; + u8 blockno = p->page_number_to_block_index[i]; + if (blockno >= E4_NO_SWAPPAGE_HEADERS) + continue; + + do { + u64 l; + + if (blockno >= E4_NO_SWAPPAGE_HEADERS) + return 1; + + blockidx = &p->page_header[blockno++]; + if ((u8 *)(blockidx + 1) - dsp >= len) + return 1; + + if (le16_to_cpu(blockidx->PageNumber) != i) + return 1; + + l = E4_PAGE_BYTES(blockidx->PageSize); + sum += l; + l += le32_to_cpu(blockidx->PageOffset); + if (l > len) + return 1; + + /* zero is zero regardless endianes */ + } while (blockidx->NotLastBlock); + } + + return (sum == len) ? 0 : 1; +} + /* * send data to the idma pipe * */ @@ -624,7 +809,12 @@ static int request_dsp(struct uea_softc *sc) int ret; char *dsp_name; - if (UEA_CHIP_VERSION(sc) == ADI930) { + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { + if (IS_ISDN(sc->usb_dev)) + dsp_name = FW_DIR "DSP4i.bin"; + else + dsp_name = FW_DIR "DSP4p.bin"; + } else if (UEA_CHIP_VERSION(sc) == ADI930) { if (IS_ISDN(sc->usb_dev)) dsp_name = FW_DIR "DSP9i.bin"; else @@ -640,11 +830,16 @@ static int request_dsp(struct uea_softc *sc) if (ret < 0) { uea_err(INS_TO_USBDEV(sc), "requesting firmware %s failed with error %d\n", - dsp_name, ret); + dsp_name, ret); return ret; } - if (check_dsp(sc->dsp_firm->data, sc->dsp_firm->size)) { + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) + ret = check_dsp_e4(sc->dsp_firm->data, sc->dsp_firm->size); + else + ret = check_dsp_e1(sc->dsp_firm->data, sc->dsp_firm->size); + + if (ret) { uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", dsp_name); release_firmware(sc->dsp_firm); @@ -658,12 +853,12 @@ static int request_dsp(struct uea_softc *sc) /* * The uea_load_page() function must be called within a process context */ -static void uea_load_page(struct work_struct *work) +static void uea_load_page_e1(struct work_struct *work) { struct uea_softc *sc = container_of(work, struct uea_softc, task); u16 pageno = sc->pageno; u16 ovl = sc->ovl; - struct block_info bi; + struct block_info_e1 bi; u8 *p; u8 pagecount, blockcount; @@ -716,7 +911,7 @@ static void uea_load_page(struct work_struct *work) bi.wLast = cpu_to_le16((i == blockcount - 1) ? 1 : 0); /* send block info through the IDMA pipe */ - if (uea_idma_write(sc, &bi, BLOCK_INFO_SIZE)) + if (uea_idma_write(sc, &bi, E1_BLOCK_INFO_SIZE)) goto bad2; /* send block data through the IDMA pipe */ @@ -735,6 +930,103 @@ bad1: uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno); } +static void __uea_load_page_e4(struct uea_softc *sc, u8 pageno, int boot) +{ + struct block_info_e4 bi; + struct block_index *blockidx; + struct l1_code *p = (struct l1_code *) sc->dsp_firm->data; + u8 blockno = p->page_number_to_block_index[pageno]; + + bi.wHdr = cpu_to_be16(UEA_BIHDR); + bi.bBootPage = boot; + bi.bPageNumber = pageno; + bi.wReserved = cpu_to_be16(UEA_RESERVED); + + do { + u8 *blockoffset; + unsigned int blocksize; + + blockidx = &p->page_header[blockno]; + blocksize = E4_PAGE_BYTES(blockidx->PageSize); + blockoffset = sc->dsp_firm->data + le32_to_cpu(blockidx->PageOffset); + + bi.dwSize = cpu_to_be32(blocksize); + bi.dwAddress = swab32(blockidx->PageAddress); + + uea_dbg(INS_TO_USBDEV(sc), + "sending block %u for DSP page %u size %u adress %x\n", + blockno, pageno, blocksize, le32_to_cpu(blockidx->PageAddress)); + + /* send block info through the IDMA pipe */ + if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE)) + goto bad; + + /* send block data through the IDMA pipe */ + if (uea_idma_write(sc, blockoffset, blocksize)) + goto bad; + + blockno++; + } while (blockidx->NotLastBlock); + + return; + +bad: + uea_err(INS_TO_USBDEV(sc), "sending DSP block %u failed\n", blockno); + return; +} + +static void uea_load_page_e4(struct work_struct *work) +{ + struct uea_softc *sc = container_of(work, struct uea_softc, task); + u8 pageno = sc->pageno; + int i; + struct block_info_e4 bi; + struct l1_code *p; + + uea_dbg(INS_TO_USBDEV(sc), "sending DSP page %u\n", pageno); + + /* reload firmware when reboot start and it's loaded already */ + if (pageno == 0 && sc->dsp_firm) { + release_firmware(sc->dsp_firm); + sc->dsp_firm = NULL; + } + + if (sc->dsp_firm == NULL && request_dsp(sc) < 0) + return; + + p = (struct l1_code *) sc->dsp_firm->data; + if (pageno >= p->page_header[0].PageNumber) { + uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno); + return; + } + + if (pageno != 0) { + __uea_load_page_e4(sc, pageno, 0); + return; + } + + uea_dbg(INS_TO_USBDEV(sc), + "sending Main DSP page %u\n", p->page_header[0].PageNumber); + + for (i = 0; i < le16_to_cpu(p->page_header[0].PageNumber); i++) { + if (E4_IS_BOOT_PAGE(p->page_header[i].PageSize)) + __uea_load_page_e4(sc, i, 1); + } + + uea_dbg(INS_TO_USBDEV(sc),"sending start bi\n"); + + bi.wHdr = cpu_to_be16(UEA_BIHDR); + bi.bBootPage = 0; + bi.bPageNumber = 0xff; + bi.wReserved = cpu_to_be16(UEA_RESERVED); + bi.dwSize = cpu_to_be32(E4_PAGE_BYTES(p->page_header[0].PageSize)); + bi.dwAddress = swab32(p->page_header[0].PageAddress); + + /* send block info through the IDMA pipe */ + if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE)) + uea_err(INS_TO_USBDEV(sc), "sending DSP start bi failed\n"); +} + static inline void wake_up_cmv_ack(struct uea_softc *sc) { BUG_ON(sc->cmv_ack); @@ -792,33 +1084,68 @@ static int uea_request(struct uea_softc *sc, return 0; } -static int uea_cmv(struct uea_softc *sc, +static int uea_cmv_e1(struct uea_softc *sc, u8 function, u32 address, u16 offset, u32 data) { - struct cmv cmv; + struct cmv_e1 cmv; int ret; uea_enters(INS_TO_USBDEV(sc)); uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Address : %c%c%c%c, " "offset : 0x%04x, data : 0x%08x\n", - FUNCTION_TYPE(function), FUNCTION_SUBTYPE(function), - GETSA1(address), GETSA2(address), GETSA3(address), - GETSA4(address), offset, data); + E1_FUNCTION_TYPE(function), E1_FUNCTION_SUBTYPE(function), + E1_GETSA1(address), E1_GETSA2(address), E1_GETSA3(address), + E1_GETSA4(address), offset, data); + /* we send a request, but we expect a reply */ - sc->cmv_function = function | 0x2; - sc->cmv_idx++; - sc->cmv_address = address; - sc->cmv_offset = offset; + sc->cmv_dsc.e1.function = function | 0x2; + sc->cmv_dsc.e1.idx++; + sc->cmv_dsc.e1.address = address; + sc->cmv_dsc.e1.offset = offset; - cmv.wPreamble = cpu_to_le16(PREAMBLE); - cmv.bDirection = HOSTTOMODEM; + cmv.wPreamble = cpu_to_le16(E1_PREAMBLE); + cmv.bDirection = E1_HOSTTOMODEM; cmv.bFunction = function; - cmv.wIndex = cpu_to_le16(sc->cmv_idx); + cmv.wIndex = cpu_to_le16(sc->cmv_dsc.e1.idx); put_unaligned(cpu_to_le32(address), &cmv.dwSymbolicAddress); cmv.wOffsetAddress = cpu_to_le16(offset); put_unaligned(cpu_to_le32(data >> 16 | data << 16), &cmv.dwData); - ret = uea_request(sc, UEA_SET_BLOCK, UEA_MPTX_START, CMV_SIZE, &cmv); + ret = uea_request(sc, UEA_E1_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv); + if (ret < 0) + return ret; + ret = wait_cmv_ack(sc); + uea_leaves(INS_TO_USBDEV(sc)); + return ret; +} + +static int uea_cmv_e4(struct uea_softc *sc, + u16 function, u16 group, u16 address, u16 offset, u32 data) +{ + struct cmv_e4 cmv; + int ret; + + uea_enters(INS_TO_USBDEV(sc)); + memset(&cmv, 0, sizeof(cmv)); + + uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Group : 0x%04x, " + "Address : 0x%04x, offset : 0x%04x, data : 0x%08x\n", + E4_FUNCTION_TYPE(function), E4_FUNCTION_SUBTYPE(function), + group, address, offset, data); + + /* we send a request, but we expect a reply */ + sc->cmv_dsc.e4.function = function | (0x1 << 4); + sc->cmv_dsc.e4.offset = offset; + sc->cmv_dsc.e4.address = address; + sc->cmv_dsc.e4.group = group; + + cmv.wFunction = cpu_to_be16(function); + cmv.wGroup = cpu_to_be16(group); + cmv.wAddress = cpu_to_be16(address); + cmv.wOffset = cpu_to_be16(offset); + cmv.dwData[0] = cpu_to_be32(data); + + ret = uea_request(sc, UEA_E4_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv); if (ret < 0) return ret; ret = wait_cmv_ack(sc); @@ -826,10 +1153,10 @@ static int uea_cmv(struct uea_softc *sc, return ret; } -static inline int uea_read_cmv(struct uea_softc *sc, +static inline int uea_read_cmv_e1(struct uea_softc *sc, u32 address, u16 offset, u32 *data) { - int ret = uea_cmv(sc, MAKEFUNCTION(MEMACCESS, REQUESTREAD), + int ret = uea_cmv_e1(sc, E1_MAKEFUNCTION(E1_MEMACCESS, E1_REQUESTREAD), address, offset, 0); if (ret < 0) uea_err(INS_TO_USBDEV(sc), @@ -840,10 +1167,27 @@ static inline int uea_read_cmv(struct uea_softc *sc, return ret; } -static inline int uea_write_cmv(struct uea_softc *sc, +static inline int uea_read_cmv_e4(struct uea_softc *sc, + u8 size, u16 group, u16 address, u16 offset, u32 *data) +{ + int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTREAD, size), + group, address, offset, 0); + if (ret < 0) + uea_err(INS_TO_USBDEV(sc), + "reading cmv failed with error %d\n", ret); + else { + *data = sc->data; + /* size is in 16-bit word quantities */ + if (size > 2) + *(data + 1) = sc->data1; + } + return ret; +} + +static inline int uea_write_cmv_e1(struct uea_softc *sc, u32 address, u16 offset, u32 data) { - int ret = uea_cmv(sc, MAKEFUNCTION(MEMACCESS, REQUESTWRITE), + int ret = uea_cmv_e1(sc, E1_MAKEFUNCTION(E1_MEMACCESS, E1_REQUESTWRITE), address, offset, data); if (ret < 0) uea_err(INS_TO_USBDEV(sc), @@ -852,12 +1196,48 @@ static inline int uea_write_cmv(struct uea_softc *sc, return ret; } +static inline int uea_write_cmv_e4(struct uea_softc *sc, + u8 size, u16 group, u16 address, u16 offset, u32 data) +{ + int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTWRITE, size), + group, address, offset, data); + if (ret < 0) + uea_err(INS_TO_USBDEV(sc), + "writing cmv failed with error %d\n", ret); + + return ret; +} + +static void uea_set_bulk_timeout(struct uea_softc *sc, u32 dsrate) +{ + int ret; + u16 timeout; + + /* in bulk mode the modem have problem with high rate + * changing internal timing could improve things, but the + * value is misterious. + * ADI930 don't support it (-EPIPE error). + */ + + if (UEA_CHIP_VERSION(sc) == ADI930 || + use_iso[sc->modem_index] > 0 || + sc->stats.phy.dsrate == dsrate) + return; + + /* Original timming (1Mbit/s) from ADI (used in windows driver) */ + timeout = (dsrate <= 1024*1024) ? 0 : 1; + ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL); + uea_info(INS_TO_USBDEV(sc), "setting new timeout %d%s\n", + timeout, ret < 0 ? " failed" : ""); + +} + /* * Monitor the modem and update the stat * return 0 if everything is ok * return < 0 if an error occurs (-EAGAIN reboot needed) */ -static int uea_stat(struct uea_softc *sc) +static int uea_stat_e1(struct uea_softc *sc) { u32 data; int ret; @@ -865,7 +1245,7 @@ static int uea_stat(struct uea_softc *sc) uea_enters(INS_TO_USBDEV(sc)); data = sc->stats.phy.state; - ret = uea_read_cmv(sc, SA_STAT, 0, &sc->stats.phy.state); + ret = uea_read_cmv_e1(sc, E1_SA_STAT, 0, &sc->stats.phy.state); if (ret < 0) return ret; @@ -885,7 +1265,7 @@ static int uea_stat(struct uea_softc *sc) case 3: /* fail ... */ uea_info(INS_TO_USBDEV(sc), "modem synchronization failed" - " (may be try other cmv/dsp)\n"); + " (may be try other cmv/dsp)\n"); return -EAGAIN; case 4 ... 6: /* test state */ @@ -923,7 +1303,7 @@ static int uea_stat(struct uea_softc *sc) /* wake up processes waiting for synchronization */ wake_up(&sc->sync_q); - ret = uea_read_cmv(sc, SA_DIAG, 2, &sc->stats.phy.flags); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 2, &sc->stats.phy.flags); if (ret < 0) return ret; sc->stats.phy.mflags |= sc->stats.phy.flags; @@ -937,105 +1317,223 @@ static int uea_stat(struct uea_softc *sc) return 0; } - ret = uea_read_cmv(sc, SA_RATE, 0, &data); + ret = uea_read_cmv_e1(sc, E1_SA_RATE, 0, &data); if (ret < 0) return ret; - /* in bulk mode the modem have problem with high rate - * changing internal timing could improve things, but the - * value is misterious. - * ADI930 don't support it (-EPIPE error). - */ - if (UEA_CHIP_VERSION(sc) != ADI930 - && !use_iso[sc->modem_index] - && sc->stats.phy.dsrate != (data >> 16) * 32) { - /* Original timming from ADI(used in windows driver) - * 0x20ffff>>16 * 32 = 32 * 32 = 1Mbits - */ - u16 timeout = (data <= 0x20ffff) ? 0 : 1; - ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL); - uea_info(INS_TO_USBDEV(sc), - "setting new timeout %d%s\n", timeout, - ret < 0?" failed":""); - } + uea_set_bulk_timeout(sc, (data >> 16) * 32); sc->stats.phy.dsrate = (data >> 16) * 32; sc->stats.phy.usrate = (data & 0xffff) * 32; UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424); - ret = uea_read_cmv(sc, SA_DIAG, 23, &data); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 23, &data); if (ret < 0) return ret; sc->stats.phy.dsattenuation = (data & 0xff) / 2; - ret = uea_read_cmv(sc, SA_DIAG, 47, &data); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 47, &data); if (ret < 0) return ret; sc->stats.phy.usattenuation = (data & 0xff) / 2; - ret = uea_read_cmv(sc, SA_DIAG, 25, &sc->stats.phy.dsmargin); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 25, &sc->stats.phy.dsmargin); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_DIAG, 49, &sc->stats.phy.usmargin); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 49, &sc->stats.phy.usmargin); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_DIAG, 51, &sc->stats.phy.rxflow); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 51, &sc->stats.phy.rxflow); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_DIAG, 52, &sc->stats.phy.txflow); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 52, &sc->stats.phy.txflow); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_DIAG, 54, &sc->stats.phy.dsunc); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 54, &sc->stats.phy.dsunc); if (ret < 0) return ret; /* only for atu-c */ - ret = uea_read_cmv(sc, SA_DIAG, 58, &sc->stats.phy.usunc); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 58, &sc->stats.phy.usunc); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_DIAG, 53, &sc->stats.phy.dscorr); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 53, &sc->stats.phy.dscorr); if (ret < 0) return ret; /* only for atu-c */ - ret = uea_read_cmv(sc, SA_DIAG, 57, &sc->stats.phy.uscorr); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 57, &sc->stats.phy.uscorr); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_INFO, 8, &sc->stats.phy.vidco); + ret = uea_read_cmv_e1(sc, E1_SA_INFO, 8, &sc->stats.phy.vidco); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_INFO, 13, &sc->stats.phy.vidcpe); + ret = uea_read_cmv_e1(sc, E1_SA_INFO, 13, &sc->stats.phy.vidcpe); if (ret < 0) return ret; return 0; } -static int request_cmvs(struct uea_softc *sc, - struct uea_cmvs **cmvs, const struct firmware **fw) +static int uea_stat_e4(struct uea_softc *sc) { - int ret, size; - u8 *data; + u32 data; + u32 tmp_arr[2]; + int ret; + + uea_enters(INS_TO_USBDEV(sc)); + data = sc->stats.phy.state; + + /* XXX only need to be done before operationnal... */ + ret = uea_read_cmv_e4(sc, 1, E4_SA_STAT, 0, 0, &sc->stats.phy.state); + if (ret < 0) + return ret; + + switch (sc->stats.phy.state) { + case 0x0: /* not yet synchronized */ + case 0x1: + case 0x3: + case 0x4: + uea_dbg(INS_TO_USBDEV(sc), "modem not yet synchronized\n"); + return 0; + case 0x5: /* initialization */ + case 0x6: + case 0x9: + case 0xa: + uea_dbg(INS_TO_USBDEV(sc), "modem initializing\n"); + return 0; + case 0x2: /* fail ... */ + uea_info(INS_TO_USBDEV(sc), "modem synchronization failed" + " (may be try other cmv/dsp)\n"); + return -EAGAIN; + case 0x7: /* operational */ + break; + default: + uea_warn(INS_TO_USBDEV(sc), "unknown state: %x\n", sc->stats.phy.state); + return 0; + } + + if (data != 7) { + uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_OFF, 0, NULL); + uea_info(INS_TO_USBDEV(sc), "modem operational\n"); + + /* release the dsp firmware as it is not needed until + * the next failure + */ + if (sc->dsp_firm) { + release_firmware(sc->dsp_firm); + sc->dsp_firm = NULL; + } + } + + /* always update it as atm layer could not be init when we switch to + * operational state + */ + UPDATE_ATM_STAT(signal, ATM_PHY_SIG_FOUND); + + /* wake up processes waiting for synchronization */ + wake_up(&sc->sync_q); + + /* TODO improve this state machine : + * we need some CMV info : what they do and their unit + * we should find the equivalent of eagle3- CMV + */ + /* check flags */ + ret = uea_read_cmv_e4(sc, 1, E4_SA_DIAG, 0, 0, &sc->stats.phy.flags); + if (ret < 0) + return ret; + sc->stats.phy.mflags |= sc->stats.phy.flags; + + /* in case of a flags ( for example delineation LOSS (& 0x10)), + * we check the status again in order to detect the failure earlier + */ + if (sc->stats.phy.flags) { + uea_dbg(INS_TO_USBDEV(sc), "Stat flag = 0x%x\n", + sc->stats.phy.flags); + if (sc->stats.phy.flags & 1) //delineation LOSS + return -EAGAIN; + if (sc->stats.phy.flags & 0x4000) //Reset Flag + return -EAGAIN; + return 0; + } + + /* rate data may be in upper or lower half of 64 bit word, strange */ + ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 0, 0, tmp_arr); + if (ret < 0) + return ret; + data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1]; + sc->stats.phy.usrate = data / 1000; + + ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 1, 0, tmp_arr); + if (ret < 0) + return ret; + data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1]; + uea_set_bulk_timeout(sc, data / 1000); + sc->stats.phy.dsrate = data / 1000; + UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424); + + ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 1, &data); + if (ret < 0) + return ret; + sc->stats.phy.dsattenuation = data / 10; + + ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 1, &data); + if (ret < 0) + return ret; + sc->stats.phy.usattenuation = data / 10; + + ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 3, &data); + if (ret < 0) + return ret; + sc->stats.phy.dsmargin = data / 2; + + ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 3, &data); + if (ret < 0) + return ret; + sc->stats.phy.usmargin = data / 10; + + return 0; +} + +static void cmvs_file_name(struct uea_softc *sc, char *const cmv_name, int ver) +{ + char file_arr[] = "CMVxy.bin"; char *file; - char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */ + /* set proper name corresponding modem version and line type */ if (cmv_file[sc->modem_index] == NULL) { if (UEA_CHIP_VERSION(sc) == ADI930) - file = (IS_ISDN(sc->usb_dev)) ? "CMV9i.bin" : "CMV9p.bin"; + file_arr[3] = '9'; + else if (UEA_CHIP_VERSION(sc) == EAGLE_IV) + file_arr[3] = '4'; else - file = (IS_ISDN(sc->usb_dev)) ? "CMVei.bin" : "CMVep.bin"; + file_arr[3] = 'e'; + + file_arr[4] = IS_ISDN(sc->usb_dev) ? 'i' : 'p'; + file = file_arr; } else file = cmv_file[sc->modem_index]; strcpy(cmv_name, FW_DIR); - strlcat(cmv_name, file, sizeof(cmv_name)); + strlcat(cmv_name, file, FIRMWARE_NAME_MAX); + if (ver == 2) + strlcat(cmv_name, ".v2", FIRMWARE_NAME_MAX); +} + +static int request_cmvs_old(struct uea_softc *sc, + void **cmvs, const struct firmware **fw) +{ + int ret, size; + u8 *data; + char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */ + cmvs_file_name(sc, cmv_name, 1); ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev); if (ret < 0) { uea_err(INS_TO_USBDEV(sc), @@ -1045,16 +1543,197 @@ static int request_cmvs(struct uea_softc *sc, } data = (u8 *) (*fw)->data; - size = *data * sizeof(struct uea_cmvs) + 1; - if (size != (*fw)->size) { - uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", - cmv_name); - release_firmware(*fw); - return -EILSEQ; + size = (*fw)->size; + if (size < 1) + goto err_fw_corrupted; + + if (size != *data * sizeof(struct uea_cmvs_v1) + 1) + goto err_fw_corrupted; + + *cmvs = (void *)(data + 1); + return *data; + +err_fw_corrupted: + uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name); + release_firmware(*fw); + return -EILSEQ; +} + +static int request_cmvs(struct uea_softc *sc, + void **cmvs, const struct firmware **fw, int *ver) +{ + int ret, size; + u32 crc; + u8 *data; + char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */ + + cmvs_file_name(sc, cmv_name, 2); + ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev); + if (ret < 0) { + /* if caller can handle old version, try to provide it */ + if (*ver == 1) { + uea_warn(INS_TO_USBDEV(sc), "requesting firmware %s failed, " + "try to get older cmvs\n", cmv_name); + return request_cmvs_old(sc, cmvs, fw); + } + uea_err(INS_TO_USBDEV(sc), + "requesting firmware %s failed with error %d\n", + cmv_name, ret); + return ret; + } + + size = (*fw)->size; + data = (u8 *) (*fw)->data; + if (size < 4 || strncmp(data, "cmv2", 4) != 0) { + if (*ver == 1) { + uea_warn(INS_TO_USBDEV(sc), "firmware %s is corrupted, " + "try to get older cmvs\n", cmv_name); + release_firmware(*fw); + return request_cmvs_old(sc, cmvs, fw); + } + goto err_fw_corrupted; } - *cmvs = (struct uea_cmvs *)(data + 1); + *ver = 2; + + data += 4; + size -= 4; + if (size < 5) + goto err_fw_corrupted; + + crc = FW_GET_LONG(data); + data += 4; + size -= 4; + if (crc32_be(0, data, size) != crc) + goto err_fw_corrupted; + + if (size != *data * sizeof(struct uea_cmvs_v2) + 1) + goto err_fw_corrupted; + + *cmvs = (void *) (data + 1); return *data; + +err_fw_corrupted: + uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name); + release_firmware(*fw); + return -EILSEQ; +} + +static int uea_send_cmvs_e1(struct uea_softc *sc) +{ + int i, ret, len; + void *cmvs_ptr; + const struct firmware *cmvs_fw; + int ver = 1; // we can handle v1 cmv firmware version; + + /* Enter in R-IDLE (cmv) until instructed otherwise */ + ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 1); + if (ret < 0) + return ret; + + /* Dump firmware version */ + ret = uea_read_cmv_e1(sc, E1_SA_INFO, 10, &sc->stats.phy.firmid); + if (ret < 0) + return ret; + uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n", + sc->stats.phy.firmid); + + /* get options */ + ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver); + if (ret < 0) + return ret; + + /* send options */ + if (ver == 1) { + struct uea_cmvs_v1 *cmvs_v1 = cmvs_ptr; + + uea_warn(INS_TO_USBDEV(sc), "use deprecated cmvs version, " + "please update your firmware\n"); + + for (i = 0; i < len; i++) { + ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v1[i].address), + FW_GET_WORD(&cmvs_v1[i].offset), + FW_GET_LONG(&cmvs_v1[i].data)); + if (ret < 0) + goto out; + } + } else if (ver == 2) { + struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr; + + for (i = 0; i < len; i++) { + ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v2[i].address), + (u16) FW_GET_LONG(&cmvs_v2[i].offset), + FW_GET_LONG(&cmvs_v2[i].data)); + if (ret < 0) + goto out; + } + } else { + /* This realy should not happen */ + uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver); + goto out; + } + + /* Enter in R-ACT-REQ */ + ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 2); + uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n"); + uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n"); +out: + release_firmware(cmvs_fw); + return ret; +} + +static int uea_send_cmvs_e4(struct uea_softc *sc) +{ + int i, ret, len; + void *cmvs_ptr; + const struct firmware *cmvs_fw; + int ver = 2; // we can only handle v2 cmv firmware version; + + /* Enter in R-IDLE (cmv) until instructed otherwise */ + ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 1); + if (ret < 0) + return ret; + + /* Dump firmware version */ + /* XXX don't read the 3th byte as it is always 6 */ + ret = uea_read_cmv_e4(sc, 2, E4_SA_INFO, 55, 0, &sc->stats.phy.firmid); + if (ret < 0) + return ret; + uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n", + sc->stats.phy.firmid); + + + /* get options */ + ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver); + if (ret < 0) + return ret; + + /* send options */ + if (ver == 2) { + struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr; + + for (i = 0; i < len; i++) { + ret = uea_write_cmv_e4(sc, 1, + FW_GET_LONG(&cmvs_v2[i].group), + FW_GET_LONG(&cmvs_v2[i].address), + FW_GET_LONG(&cmvs_v2[i].offset), + FW_GET_LONG(&cmvs_v2[i].data)); + if (ret < 0) + goto out; + } + } else { + /* This realy should not happen */ + uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver); + goto out; + } + + /* Enter in R-ACT-REQ */ + ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 2); + uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n"); + uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n"); +out: + release_firmware(cmvs_fw); + return ret; } /* Start boot post firmware modem: @@ -1066,9 +1745,7 @@ static int request_cmvs(struct uea_softc *sc, static int uea_start_reset(struct uea_softc *sc) { u16 zero = 0; /* ;-) */ - int i, len, ret; - struct uea_cmvs *cmvs; - const struct firmware *cmvs_fw; + int ret; uea_enters(INS_TO_USBDEV(sc)); uea_info(INS_TO_USBDEV(sc), "(re)booting started\n"); @@ -1098,13 +1775,20 @@ static int uea_start_reset(struct uea_softc *sc) /* leave reset mode */ uea_request(sc, UEA_SET_MODE, UEA_END_RESET, 0, NULL); - /* clear tx and rx mailboxes */ - uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero); - uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero); - uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero); + if (UEA_CHIP_VERSION(sc) != EAGLE_IV) { + /* clear tx and rx mailboxes */ + uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero); + uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero); + uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero); + } msleep(1000); - sc->cmv_function = MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY); + + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) + sc->cmv_dsc.e4.function = E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1); + else + sc->cmv_dsc.e1.function = E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY); + /* demask interrupt */ sc->booting = 0; @@ -1120,38 +1804,10 @@ static int uea_start_reset(struct uea_softc *sc) uea_vdbg(INS_TO_USBDEV(sc), "Ready CMV received\n"); - /* Enter in R-IDLE (cmv) until instructed otherwise */ - ret = uea_write_cmv(sc, SA_CNTL, 0, 1); - if (ret < 0) - return ret; - - /* Dump firmware version */ - ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid); - if (ret < 0) - return ret; - uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n", - sc->stats.phy.firmid); - - /* get options */ - ret = len = request_cmvs(sc, &cmvs, &cmvs_fw); + ret = sc->send_cmvs(sc); if (ret < 0) return ret; - /* send options */ - for (i = 0; i < len; i++) { - ret = uea_write_cmv(sc, FW_GET_LONG(&cmvs[i].address), - FW_GET_WORD(&cmvs[i].offset), - FW_GET_LONG(&cmvs[i].data)); - if (ret < 0) - goto out; - } - /* Enter in R-ACT-REQ */ - ret = uea_write_cmv(sc, SA_CNTL, 0, 2); - uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n"); - uea_info(INS_TO_USBDEV(sc), "Modem started, " - "waiting synchronization\n"); -out: - release_firmware(cmvs_fw); sc->reset = 0; uea_leaves(INS_TO_USBDEV(sc)); return ret; @@ -1174,7 +1830,7 @@ static int uea_kthread(void *data) if (ret < 0 || sc->reset) ret = uea_start_reset(sc); if (!ret) - ret = uea_stat(sc); + ret = sc->stat(sc); if (ret != -EAGAIN) msleep_interruptible(1000); if (try_to_freeze()) @@ -1234,7 +1890,6 @@ static int load_XILINX_firmware(struct uea_softc *sc) if (ret < 0) uea_err(sc->usb_dev, "elsa de-assert failed with error %d\n", ret); - err1: release_firmware(fw_entry); err0: @@ -1243,40 +1898,41 @@ err0: } /* The modem send us an ack. First with check if it right */ -static void uea_dispatch_cmv(struct uea_softc *sc, struct cmv* cmv) +static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr) { + struct cmv_dsc_e1 *dsc = &sc->cmv_dsc.e1; + struct cmv_e1 *cmv = &intr->u.e1.s2.cmv; + uea_enters(INS_TO_USBDEV(sc)); - if (le16_to_cpu(cmv->wPreamble) != PREAMBLE) + if (le16_to_cpu(cmv->wPreamble) != E1_PREAMBLE) goto bad1; - if (cmv->bDirection != MODEMTOHOST) + if (cmv->bDirection != E1_MODEMTOHOST) goto bad1; /* FIXME : ADI930 reply wrong preambule (func = 2, sub = 2) to * the first MEMACESS cmv. Ignore it... */ - if (cmv->bFunction != sc->cmv_function) { + if (cmv->bFunction != dsc->function) { if (UEA_CHIP_VERSION(sc) == ADI930 - && cmv->bFunction == MAKEFUNCTION(2, 2)) { - cmv->wIndex = cpu_to_le16(sc->cmv_idx); - put_unaligned(cpu_to_le32(sc->cmv_address), &cmv->dwSymbolicAddress); - cmv->wOffsetAddress = cpu_to_le16(sc->cmv_offset); - } - else + && cmv->bFunction == E1_MAKEFUNCTION(2, 2)) { + cmv->wIndex = cpu_to_le16(dsc->idx); + put_unaligned(cpu_to_le32(dsc->address), &cmv->dwSymbolicAddress); + cmv->wOffsetAddress = cpu_to_le16(dsc->offset); + } else goto bad2; } - if (cmv->bFunction == MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY)) { + if (cmv->bFunction == E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY)) { wake_up_cmv_ack(sc); uea_leaves(INS_TO_USBDEV(sc)); return; } /* in case of MEMACCESS */ - if (le16_to_cpu(cmv->wIndex) != sc->cmv_idx || - le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) != - sc->cmv_address - || le16_to_cpu(cmv->wOffsetAddress) != sc->cmv_offset) + if (le16_to_cpu(cmv->wIndex) != dsc->idx || + le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) != dsc->address || + le16_to_cpu(cmv->wOffsetAddress) != dsc->offset) goto bad2; sc->data = le32_to_cpu(get_unaligned(&cmv->dwData)); @@ -1289,8 +1945,8 @@ static void uea_dispatch_cmv(struct uea_softc *sc, struct cmv* cmv) bad2: uea_err(INS_TO_USBDEV(sc), "unexpected cmv received," "Function : %d, Subfunction : %d\n", - FUNCTION_TYPE(cmv->bFunction), - FUNCTION_SUBTYPE(cmv->bFunction)); + E1_FUNCTION_TYPE(cmv->bFunction), + E1_FUNCTION_SUBTYPE(cmv->bFunction)); uea_leaves(INS_TO_USBDEV(sc)); return; @@ -1301,6 +1957,61 @@ bad1: uea_leaves(INS_TO_USBDEV(sc)); } +/* The modem send us an ack. First with check if it right */ +static void uea_dispatch_cmv_e4(struct uea_softc *sc, struct intr_pkt *intr) +{ + struct cmv_dsc_e4 *dsc = &sc->cmv_dsc.e4; + struct cmv_e4 *cmv = &intr->u.e4.s2.cmv; + + uea_enters(INS_TO_USBDEV(sc)); + uea_dbg(INS_TO_USBDEV(sc), "cmv %x %x %x %x %x %x\n", + be16_to_cpu(cmv->wGroup), be16_to_cpu(cmv->wFunction), + be16_to_cpu(cmv->wOffset), be16_to_cpu(cmv->wAddress), + be32_to_cpu(cmv->dwData[0]), be32_to_cpu(cmv->dwData[1])); + + if (be16_to_cpu(cmv->wFunction) != dsc->function) + goto bad2; + + if (be16_to_cpu(cmv->wFunction) == E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1)) { + wake_up_cmv_ack(sc); + uea_leaves(INS_TO_USBDEV(sc)); + return; + } + + /* in case of MEMACCESS */ + if (be16_to_cpu(cmv->wOffset) != dsc->offset || + be16_to_cpu(cmv->wGroup) != dsc->group || + be16_to_cpu(cmv->wAddress) != dsc->address) + goto bad2; + + sc->data = be32_to_cpu(cmv->dwData[0]); + sc->data1 = be32_to_cpu(cmv->dwData[1]); + wake_up_cmv_ack(sc); + uea_leaves(INS_TO_USBDEV(sc)); + return; + +bad2: + uea_err(INS_TO_USBDEV(sc), "unexpected cmv received," + "Function : %d, Subfunction : %d\n", + E4_FUNCTION_TYPE(cmv->wFunction), + E4_FUNCTION_SUBTYPE(cmv->wFunction)); + uea_leaves(INS_TO_USBDEV(sc)); + return; +} + +static void uea_schedule_load_page_e1(struct uea_softc *sc, struct intr_pkt *intr) +{ + sc->pageno = intr->e1_bSwapPageNo; + sc->ovl = intr->e1_bOvl >> 4 | intr->e1_bOvl << 4; + schedule_work(&sc->task); +} + +static void uea_schedule_load_page_e4(struct uea_softc *sc, struct intr_pkt *intr) +{ + sc->pageno = intr->e4_bSwapPageNo; + schedule_work(&sc->task); +} + /* * interrupt handler */ @@ -1326,13 +2037,11 @@ static void uea_intr(struct urb *urb) switch (le16_to_cpu(intr->wInterrupt)) { case INT_LOADSWAPPAGE: - sc->pageno = intr->bSwapPageNo; - sc->ovl = intr->bOvl >> 4 | intr->bOvl << 4; - schedule_work(&sc->task); + sc->schedule_load_page(sc, intr); break; case INT_INCOMINGCMV: - uea_dispatch_cmv(sc, &intr->u.s2.cmv); + sc->dispatch_cmv(sc, intr); break; default: @@ -1349,19 +2058,34 @@ resubmit: */ static int uea_boot(struct uea_softc *sc) { - int ret; + int ret, size; struct intr_pkt *intr; uea_enters(INS_TO_USBDEV(sc)); - INIT_WORK(&sc->task, uea_load_page); + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { + size = E4_INTR_PKT_SIZE; + sc->dispatch_cmv = uea_dispatch_cmv_e4; + sc->schedule_load_page = uea_schedule_load_page_e4; + sc->stat = uea_stat_e4; + sc->send_cmvs = uea_send_cmvs_e4; + INIT_WORK(&sc->task, uea_load_page_e4); + } else { + size = E1_INTR_PKT_SIZE; + sc->dispatch_cmv = uea_dispatch_cmv_e1; + sc->schedule_load_page = uea_schedule_load_page_e1; + sc->stat = uea_stat_e1; + sc->send_cmvs = uea_send_cmvs_e1; + INIT_WORK(&sc->task, uea_load_page_e1); + } + init_waitqueue_head(&sc->sync_q); init_waitqueue_head(&sc->cmv_ack_wait); if (UEA_CHIP_VERSION(sc) == ADI930) load_XILINX_firmware(sc); - intr = kmalloc(INTR_PKT_SIZE, GFP_KERNEL); + intr = kmalloc(size, GFP_KERNEL); if (!intr) { uea_err(INS_TO_USBDEV(sc), "cannot allocate interrupt package\n"); @@ -1377,7 +2101,7 @@ static int uea_boot(struct uea_softc *sc) usb_fill_int_urb(sc->urb_int, sc->usb_dev, usb_rcvintpipe(sc->usb_dev, UEA_INTR_PIPE), - intr, INTR_PKT_SIZE, uea_intr, sc, + intr, size, uea_intr, sc, sc->usb_dev->actconfig->interface[0]->altsetting[0]. endpoint[0].desc.bInterval); @@ -1487,6 +2211,7 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at char *buf) { int ret = -ENODEV; + int modem_state; struct uea_softc *sc; mutex_lock(&uea_mutex); @@ -1494,7 +2219,34 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at if (!sc) goto out; - switch (GET_STATUS(sc->stats.phy.state)) { + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { + switch (sc->stats.phy.state) { + case 0x0: /* not yet synchronized */ + case 0x1: + case 0x3: + case 0x4: + modem_state = 0; + break; + case 0x5: /* initialization */ + case 0x6: + case 0x9: + case 0xa: + modem_state = 1; + break; + case 0x7: /* operational */ + modem_state = 2; + break; + case 0x2: /* fail ... */ + modem_state = 3; + break; + default: /* unknown */ + modem_state = 4; + break; + } + } else + modem_state = GET_STATUS(sc->stats.phy.state); + + switch (modem_state) { case 0: ret = sprintf(buf, "Modem is booting\n"); break; @@ -1504,9 +2256,12 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at case 2: ret = sprintf(buf, "Modem is operational\n"); break; - default: + case 3: ret = sprintf(buf, "Modem synchronization failed\n"); break; + default: + ret = sprintf(buf, "Modem state is unknown\n"); + break; } out: mutex_unlock(&uea_mutex); @@ -1520,18 +2275,26 @@ static ssize_t read_delin(struct device *dev, struct device_attribute *attr, { int ret = -ENODEV; struct uea_softc *sc; + char *delin = "GOOD"; mutex_lock(&uea_mutex); sc = dev_to_uea(dev); if (!sc) goto out; - if (sc->stats.phy.flags & 0x0C00) - ret = sprintf(buf, "ERROR\n"); - else if (sc->stats.phy.flags & 0x0030) - ret = sprintf(buf, "LOSS\n"); - else - ret = sprintf(buf, "GOOD\n"); + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { + if (sc->stats.phy.flags & 0x4000) + delin = "RESET"; + else if (sc->stats.phy.flags & 0x0001) + delin = "LOSS"; + } else { + if (sc->stats.phy.flags & 0x0C00) + delin = "ERROR"; + else if (sc->stats.phy.flags & 0x0030) + delin = "LOSS"; + } + + ret = sprintf(buf, "%s\n", delin); out: mutex_unlock(&uea_mutex); return ret; @@ -1803,6 +2566,8 @@ static const struct usb_device_id uea_ids[] = { {USB_DEVICE(EAGLE_VID, EAGLE_IIC_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM}, {USB_DEVICE(EAGLE_VID, EAGLE_III_PID_PREFIRM), .driver_info = EAGLE_III | PREFIRM}, {USB_DEVICE(EAGLE_VID, EAGLE_III_PID_PSTFIRM), .driver_info = EAGLE_III | PSTFIRM}, + {USB_DEVICE(EAGLE_VID, EAGLE_IV_PID_PREFIRM), .driver_info = EAGLE_IV | PREFIRM}, + {USB_DEVICE(EAGLE_VID, EAGLE_IV_PID_PSTFIRM), .driver_info = EAGLE_IV | PSTFIRM}, {USB_DEVICE(USR_VID, MILLER_A_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, {USB_DEVICE(USR_VID, MILLER_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM}, {USB_DEVICE(USR_VID, MILLER_B_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, -- cgit v1.2.3-70-g09d2 From 603cf6087c5f3ee054bb257195b023848d26d76f Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 20 Aug 2007 23:21:01 +0200 Subject: UEAGLE: Devolo and Elsa chipsets support Support for Devolo and Elsa chipsets. These chipsets have no information about ADSL annex (line type) encoded in USB descriptors. Driver try to get this information from USB VID and PID or it can be explicitly set by the user through module parameter. Thanks to Johann Hanne, whose make most of this patch. Signed-off-by: Stanislaw Gruszka Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/ueagle-atm.c | 114 +++++++++++++++++++++++++++++++++---------- 1 file changed, 88 insertions(+), 26 deletions(-) diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index b5e8cbad223..2cdabd3421e 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -149,6 +149,9 @@ struct uea_softc { int modem_index; unsigned int driver_info; + int annex; +#define ANNEXA 0 +#define ANNEXB 1 int booting; int reset; @@ -207,10 +210,34 @@ struct uea_softc { #define ELSA_PID_PSTFIRM 0x3350 #define ELSA_PID_PREFIRM 0x3351 +#define ELSA_PID_A_PREFIRM 0x3352 +#define ELSA_PID_A_PSTFIRM 0x3353 +#define ELSA_PID_B_PREFIRM 0x3362 +#define ELSA_PID_B_PSTFIRM 0x3363 + /* - * Sagem USB IDs + * Devolo IDs : pots if (pid & 0x10) */ -#define EAGLE_VID 0x1110 +#define DEVOLO_VID 0x1039 +#define DEVOLO_EAGLE_I_A_PID_PSTFIRM 0x2110 +#define DEVOLO_EAGLE_I_A_PID_PREFIRM 0x2111 + +#define DEVOLO_EAGLE_I_B_PID_PSTFIRM 0x2100 +#define DEVOLO_EAGLE_I_B_PID_PREFIRM 0x2101 + +#define DEVOLO_EAGLE_II_A_PID_PSTFIRM 0x2130 +#define DEVOLO_EAGLE_II_A_PID_PREFIRM 0x2131 + +#define DEVOLO_EAGLE_II_B_PID_PSTFIRM 0x2120 +#define DEVOLO_EAGLE_II_B_PID_PREFIRM 0x2121 + +/* + * Reference design USB IDs + */ +#define ANALOG_VID 0x1110 +#define ADI930_PID_PREFIRM 0x9001 +#define ADI930_PID_PSTFIRM 0x9000 + #define EAGLE_I_PID_PREFIRM 0x9010 /* Eagle I */ #define EAGLE_I_PID_PSTFIRM 0x900F /* Eagle I */ @@ -241,6 +268,9 @@ struct uea_softc { #define PREFIRM 0 #define PSTFIRM (1<<7) +#define AUTO_ANNEX_A (1<<8) +#define AUTO_ANNEX_B (1<<9) + enum { ADI930 = 0, EAGLE_I, @@ -255,8 +285,8 @@ enum { #define UEA_CHIP_VERSION(x) \ ((x)->driver_info & 0xf) -#define IS_ISDN(usb_dev) \ - (le16_to_cpu((usb_dev)->descriptor.bcdDevice) & 0x80) +#define IS_ISDN(x) \ + ((x)->annex & ANNEXB) #define INS_TO_USBDEV(ins) ins->usb_dev @@ -511,6 +541,7 @@ static unsigned int debug; static int use_iso[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = 1}; static int sync_wait[NB_MODEM]; static char *cmv_file[NB_MODEM]; +static int annex[NB_MODEM]; module_param(debug, uint, 0644); MODULE_PARM_DESC(debug, "module debug level (0=off,1=on,2=verbose)"); @@ -521,6 +552,9 @@ MODULE_PARM_DESC(sync_wait, "wait the synchronisation before starting ATM"); module_param_array(cmv_file, charp, NULL, 0644); MODULE_PARM_DESC(cmv_file, "file name with configuration and management variables"); +module_param_array(annex, uint, NULL, 0644); +MODULE_PARM_DESC(annex, + "manually set annex a/b (0=auto, 1=annex a, 2=annex b)"); #define UPDATE_ATM_STAT(type, val) \ do { \ @@ -810,17 +844,17 @@ static int request_dsp(struct uea_softc *sc) char *dsp_name; if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { - if (IS_ISDN(sc->usb_dev)) + if (IS_ISDN(sc)) dsp_name = FW_DIR "DSP4i.bin"; else dsp_name = FW_DIR "DSP4p.bin"; } else if (UEA_CHIP_VERSION(sc) == ADI930) { - if (IS_ISDN(sc->usb_dev)) + if (IS_ISDN(sc)) dsp_name = FW_DIR "DSP9i.bin"; else dsp_name = FW_DIR "DSP9p.bin"; } else { - if (IS_ISDN(sc->usb_dev)) + if (IS_ISDN(sc)) dsp_name = FW_DIR "DSPei.bin"; else dsp_name = FW_DIR "DSPep.bin"; @@ -1515,7 +1549,7 @@ static void cmvs_file_name(struct uea_softc *sc, char *const cmv_name, int ver) else file_arr[3] = 'e'; - file_arr[4] = IS_ISDN(sc->usb_dev) ? 'i' : 'p'; + file_arr[4] = IS_ISDN(sc) ? 'i' : 'p'; file = file_arr; } else file = cmv_file[sc->modem_index]; @@ -2459,6 +2493,19 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf, sc->modem_index = (modem_index < NB_MODEM) ? modem_index++ : 0; sc->driver_info = id->driver_info; + /* first try to use module parameter */ + if (annex[sc->modem_index] == 1) + sc->annex = ANNEXA; + else if (annex[sc->modem_index] == 2) + sc->annex = ANNEXB; + /* try to autodetect annex */ + else if (sc->driver_info & AUTO_ANNEX_A) + sc->annex = ANNEXA; + else if (sc->driver_info & AUTO_ANNEX_B) + sc->annex = ANNEXB; + else + sc->annex = (le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80)?ANNEXB:ANNEXA; + /* ADI930 don't support iso */ if (UEA_CHIP_VERSION(id) != ADI930 && use_iso[sc->modem_index]) { int i; @@ -2520,10 +2567,11 @@ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id) struct usb_device *usb = interface_to_usbdev(intf); uea_enters(usb); - uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s %s\n", - le16_to_cpu(usb->descriptor.idVendor), - le16_to_cpu(usb->descriptor.idProduct), - chip_name[UEA_CHIP_VERSION(id)], IS_ISDN(usb)?"isdn":"pots"); + uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) Rev (%#X): %s\n", + le16_to_cpu(usb->descriptor.idVendor), + le16_to_cpu(usb->descriptor.idProduct), + le16_to_cpu(usb->descriptor.bcdDevice), + chip_name[UEA_CHIP_VERSION(id)]); usb_reset_device(usb); @@ -2556,26 +2604,40 @@ static void uea_disconnect(struct usb_interface *intf) * List of supported VID/PID */ static const struct usb_device_id uea_ids[] = { + {USB_DEVICE(ANALOG_VID, ADI930_PID_PREFIRM), .driver_info = ADI930 | PREFIRM}, + {USB_DEVICE(ANALOG_VID, ADI930_PID_PSTFIRM), .driver_info = ADI930 | PSTFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PREFIRM), .driver_info = EAGLE_III | PREFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PSTFIRM), .driver_info = EAGLE_III | PSTFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_IV_PID_PREFIRM), .driver_info = EAGLE_IV | PREFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_IV_PID_PSTFIRM), .driver_info = EAGLE_IV | PSTFIRM}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_A_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_B_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_A_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_A_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_A}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_B_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_B_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_B}, {USB_DEVICE(ELSA_VID, ELSA_PID_PREFIRM), .driver_info = ADI930 | PREFIRM}, {USB_DEVICE(ELSA_VID, ELSA_PID_PSTFIRM), .driver_info = ADI930 | PSTFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_I_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_I_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_II_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_II_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_IIC_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_IIC_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_III_PID_PREFIRM), .driver_info = EAGLE_III | PREFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_III_PID_PSTFIRM), .driver_info = EAGLE_III | PSTFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_IV_PID_PREFIRM), .driver_info = EAGLE_IV | PREFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_IV_PID_PSTFIRM), .driver_info = EAGLE_IV | PSTFIRM}, + {USB_DEVICE(ELSA_VID, ELSA_PID_A_PREFIRM), .driver_info = ADI930 | PREFIRM}, + {USB_DEVICE(ELSA_VID, ELSA_PID_A_PSTFIRM), .driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_A}, + {USB_DEVICE(ELSA_VID, ELSA_PID_B_PREFIRM), .driver_info = ADI930 | PREFIRM}, + {USB_DEVICE(ELSA_VID, ELSA_PID_B_PSTFIRM), .driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_B}, {USB_DEVICE(USR_VID, MILLER_A_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(USR_VID, MILLER_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM}, + {USB_DEVICE(USR_VID, MILLER_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A}, {USB_DEVICE(USR_VID, MILLER_B_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(USR_VID, MILLER_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM}, + {USB_DEVICE(USR_VID, MILLER_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B}, {USB_DEVICE(USR_VID, HEINEKEN_A_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(USR_VID, HEINEKEN_A_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM}, + {USB_DEVICE(USR_VID, HEINEKEN_A_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A}, {USB_DEVICE(USR_VID, HEINEKEN_B_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(USR_VID, HEINEKEN_B_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM}, + {USB_DEVICE(USR_VID, HEINEKEN_B_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B}, {} }; -- cgit v1.2.3-70-g09d2 From 503add467d4dd2355fe16ebffa7f6d5e9fcd10a8 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 20 Aug 2007 23:21:06 +0200 Subject: UEAGLE: Allow user to choose input interface alternate setting Let's user control how much USB bus bandwidth will be reserved by ueagle-atm device. This make possible to share bus with other devices when ueagle-atm driver works in isochronous mode. Signed-off-by: Stanislaw Gruszka Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/ueagle-atm.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 2cdabd3421e..dee5f798946 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -538,15 +538,16 @@ static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III", static int modem_index; static unsigned int debug; -static int use_iso[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = 1}; +static unsigned int altsetting[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = FASTEST_ISO_INTF}; static int sync_wait[NB_MODEM]; static char *cmv_file[NB_MODEM]; static int annex[NB_MODEM]; module_param(debug, uint, 0644); MODULE_PARM_DESC(debug, "module debug level (0=off,1=on,2=verbose)"); -module_param_array(use_iso, bool, NULL, 0644); -MODULE_PARM_DESC(use_iso, "use isochronous usb pipe for incoming traffic"); +module_param_array(altsetting, uint, NULL, 0644); +MODULE_PARM_DESC(altsetting, "alternate setting for incoming traffic: 0=bulk, " + "1=isoc slowest, ... , 8=isoc fastest (default)"); module_param_array(sync_wait, bool, NULL, 0644); MODULE_PARM_DESC(sync_wait, "wait the synchronisation before starting ATM"); module_param_array(cmv_file, charp, NULL, 0644); @@ -1254,7 +1255,7 @@ static void uea_set_bulk_timeout(struct uea_softc *sc, u32 dsrate) */ if (UEA_CHIP_VERSION(sc) == ADI930 || - use_iso[sc->modem_index] > 0 || + altsetting[sc->modem_index] > 0 || sc->stats.phy.dsrate == dsrate) return; @@ -2459,6 +2460,7 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf, struct usb_device *usb = interface_to_usbdev(intf); struct uea_softc *sc; int ret, ifnum = intf->altsetting->desc.bInterfaceNumber; + unsigned int alt; uea_enters(usb); @@ -2506,22 +2508,16 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf, else sc->annex = (le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80)?ANNEXB:ANNEXA; + alt = altsetting[sc->modem_index]; /* ADI930 don't support iso */ - if (UEA_CHIP_VERSION(id) != ADI930 && use_iso[sc->modem_index]) { - int i; - - /* try set fastest alternate for inbound traffic interface */ - for (i = FASTEST_ISO_INTF; i > 0; i--) - if (usb_set_interface(usb, UEA_DS_IFACE_NO, i) == 0) - break; - - if (i > 0) { - uea_dbg(usb, "set alternate %d for 2 interface\n", i); + if (UEA_CHIP_VERSION(id) != ADI930 && alt > 0) { + if (alt <= 8 && usb_set_interface(usb, UEA_DS_IFACE_NO, alt) == 0) { + uea_dbg(usb, "set alternate %u for 2 interface\n", alt); uea_info(usb, "using iso mode\n"); usbatm->flags |= UDSL_USE_ISOC | UDSL_IGNORE_EILSEQ; } else { - uea_err(usb, "setting any alternate failed for " - "2 interface, using bulk mode\n"); + uea_err(usb, "setting alternate %u failed for " + "2 interface, using bulk mode\n", alt); } } -- cgit v1.2.3-70-g09d2 From 04ea02f5746a2e01a38edae2de3eafc40eac17aa Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 20 Aug 2007 23:21:10 +0200 Subject: UEAGLE: Avoid keyboard driver blocking Ueagle-atm driver load DSP firmware in function, which is running from common workqueue. In some (error) circumstances loading firmware may sleep for long periods (even 60 seconds, depending on timeout). This block keyboard driver, which also use common workqueue. To fix problem use custom workqueue in ueagle-atm. Signed-off-by: Stanislaw Gruszka Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/ueagle-atm.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index dee5f798946..648c6b79ff4 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -167,6 +167,7 @@ struct uea_softc { union cmv_dsc cmv_dsc; struct work_struct task; + struct workqueue_struct *work_q; u16 pageno; u16 ovl; @@ -1830,7 +1831,7 @@ static int uea_start_reset(struct uea_softc *sc) /* start loading DSP */ sc->pageno = 0; sc->ovl = 0; - schedule_work(&sc->task); + queue_work(sc->work_q, &sc->task); /* wait for modem ready CMV */ ret = wait_cmv_ack(sc); @@ -2038,13 +2039,13 @@ static void uea_schedule_load_page_e1(struct uea_softc *sc, struct intr_pkt *int { sc->pageno = intr->e1_bSwapPageNo; sc->ovl = intr->e1_bOvl >> 4 | intr->e1_bOvl << 4; - schedule_work(&sc->task); + queue_work(sc->work_q, &sc->task); } static void uea_schedule_load_page_e4(struct uea_softc *sc, struct intr_pkt *intr) { sc->pageno = intr->e4_bSwapPageNo; - schedule_work(&sc->task); + queue_work(sc->work_q, &sc->task); } /* @@ -2117,6 +2118,13 @@ static int uea_boot(struct uea_softc *sc) init_waitqueue_head(&sc->sync_q); init_waitqueue_head(&sc->cmv_ack_wait); + sc->work_q = create_workqueue("ueagle-dsp"); + if (!sc->work_q) { + uea_err(INS_TO_USBDEV(sc), "cannot allocate workqueue\n"); + uea_leaves(INS_TO_USBDEV(sc)); + return -ENOMEM; + } + if (UEA_CHIP_VERSION(sc) == ADI930) load_XILINX_firmware(sc); @@ -2124,14 +2132,13 @@ static int uea_boot(struct uea_softc *sc) if (!intr) { uea_err(INS_TO_USBDEV(sc), "cannot allocate interrupt package\n"); - uea_leaves(INS_TO_USBDEV(sc)); - return -ENOMEM; + goto err0; } sc->urb_int = usb_alloc_urb(0, GFP_KERNEL); if (!sc->urb_int) { uea_err(INS_TO_USBDEV(sc), "cannot allocate interrupt URB\n"); - goto err; + goto err1; } usb_fill_int_urb(sc->urb_int, sc->usb_dev, @@ -2144,7 +2151,7 @@ static int uea_boot(struct uea_softc *sc) if (ret < 0) { uea_err(INS_TO_USBDEV(sc), "urb submition failed with error %d\n", ret); - goto err; + goto err1; } sc->kthread = kthread_run(uea_kthread, sc, "ueagle-atm"); @@ -2158,10 +2165,12 @@ static int uea_boot(struct uea_softc *sc) err2: usb_kill_urb(sc->urb_int); -err: +err1: usb_free_urb(sc->urb_int); sc->urb_int = NULL; kfree(intr); +err0: + destroy_workqueue(sc->work_q); uea_leaves(INS_TO_USBDEV(sc)); return -ENOMEM; } @@ -2176,15 +2185,15 @@ static void uea_stop(struct uea_softc *sc) ret = kthread_stop(sc->kthread); uea_dbg(INS_TO_USBDEV(sc), "kthread finish with status %d\n", ret); - /* stop any pending boot process */ - flush_scheduled_work(); - uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_ON, 0, NULL); usb_kill_urb(sc->urb_int); kfree(sc->urb_int->transfer_buffer); usb_free_urb(sc->urb_int); + /* stop any pending boot process, when no one can schedule work */ + destroy_workqueue(sc->work_q); + if (sc->dsp_firm) release_firmware(sc->dsp_firm); uea_leaves(INS_TO_USBDEV(sc)); -- cgit v1.2.3-70-g09d2 From 337427f91f844ebe84442dc0b5e24577a8139600 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 20 Aug 2007 23:21:14 +0200 Subject: UEAGLE: Do not sleep when device is disconnected Do not sleep in kernel thread when device is disconnected, this make faster suspending and module unloading. Use one wait queue for sleeping. Signed-off-by: Stanislaw Gruszka Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/ueagle-atm.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 648c6b79ff4..4aa41a97bf6 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -161,7 +161,6 @@ struct uea_softc { struct task_struct *kthread; u32 data; u32 data1; - wait_queue_head_t cmv_ack_wait; int cmv_ack; union cmv_dsc cmv_dsc; @@ -558,6 +557,15 @@ module_param_array(annex, uint, NULL, 0644); MODULE_PARM_DESC(annex, "manually set annex a/b (0=auto, 1=annex a, 2=annex b)"); +#define uea_wait(sc, cond, timeo) \ +({ \ + int _r = wait_event_interruptible_timeout(sc->sync_q, \ + (cond) || kthread_should_stop(), timeo); \ + if (kthread_should_stop()) \ + _r = -ENODEV; \ + _r; \ +}) + #define UPDATE_ATM_STAT(type, val) \ do { \ if (sc->usbatm->atm_dev) \ @@ -1067,13 +1075,13 @@ static inline void wake_up_cmv_ack(struct uea_softc *sc) { BUG_ON(sc->cmv_ack); sc->cmv_ack = 1; - wake_up(&sc->cmv_ack_wait); + wake_up(&sc->sync_q); } static inline int wait_cmv_ack(struct uea_softc *sc) { - int ret = wait_event_interruptible_timeout(sc->cmv_ack_wait, - sc->cmv_ack, ACK_TIMEOUT); + int ret = uea_wait(sc, sc->cmv_ack , ACK_TIMEOUT); + sc->cmv_ack = 0; uea_dbg(INS_TO_USBDEV(sc), "wait_event_timeout : %d ms\n", @@ -1806,7 +1814,9 @@ static int uea_start_reset(struct uea_softc *sc) uea_request(sc, UEA_SET_MODE, UEA_START_RESET, 0, NULL); /* original driver use 200ms, but windows driver use 100ms */ - msleep(100); + ret = uea_wait(sc, 0, msecs_to_jiffies(100)); + if (ret < 0) + return ret; /* leave reset mode */ uea_request(sc, UEA_SET_MODE, UEA_END_RESET, 0, NULL); @@ -1818,7 +1828,9 @@ static int uea_start_reset(struct uea_softc *sc) uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero); } - msleep(1000); + ret = uea_wait(sc, 0, msecs_to_jiffies(1000)); + if (ret < 0) + return ret; if (UEA_CHIP_VERSION(sc) == EAGLE_IV) sc->cmv_dsc.e4.function = E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1); @@ -1868,7 +1880,7 @@ static int uea_kthread(void *data) if (!ret) ret = sc->stat(sc); if (ret != -EAGAIN) - msleep_interruptible(1000); + uea_wait(sc, 0, msecs_to_jiffies(1000)); if (try_to_freeze()) uea_err(INS_TO_USBDEV(sc), "suspend/resume not supported, " "please unplug/replug your modem\n"); @@ -2116,7 +2128,6 @@ static int uea_boot(struct uea_softc *sc) } init_waitqueue_head(&sc->sync_q); - init_waitqueue_head(&sc->cmv_ack_wait); sc->work_q = create_workqueue("ueagle-dsp"); if (!sc->work_q) { -- cgit v1.2.3-70-g09d2 From 0eb0226c9d819fd2af31ae4fc52bbca81c215369 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 20 Aug 2007 23:21:19 +0200 Subject: UEAGLE: Cosmetic Update copyrights and remove not necessary warning (ueagle-atm works well on suspend/resume). Signed-off-by: Stanislaw Gruszka Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/ueagle-atm.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 4aa41a97bf6..389c5b164eb 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -2,7 +2,8 @@ * Copyright (c) 2003, 2004 * Damien Bergamini . All rights reserved. * - * Copyright (c) 2005 Matthieu Castet + * Copyright (c) 2005-2007 Matthieu Castet + * Copyright (c) 2005-2007 Stanislaw Gruszka * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -1881,9 +1882,7 @@ static int uea_kthread(void *data) ret = sc->stat(sc); if (ret != -EAGAIN) uea_wait(sc, 0, msecs_to_jiffies(1000)); - if (try_to_freeze()) - uea_err(INS_TO_USBDEV(sc), "suspend/resume not supported, " - "please unplug/replug your modem\n"); + try_to_freeze(); } uea_leaves(INS_TO_USBDEV(sc)); return ret; -- cgit v1.2.3-70-g09d2 From af1c51fcb2aea23ec2dfe73b7d66515d1622e689 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Mon, 20 Aug 2007 18:13:27 -0700 Subject: USB: EHCI restart speedup It is not necessary to powerdown the ports on ehci_pci_reinit() when the chip reset already did that. Removing this saves 20ms during restart after poweroff paths (which OLPC uses a lot). To ensure driver startup then behaves consistently, force a reset during driver startup. (Not doing this was an accident of some previous changes to the init sequence.) Make the corresponding change in the PS3 support. It's not clear what ehci-fsl should do here; it has similar code to the PS3. Signed-off-by: Marcelo Tosatti Signed-off-by: David Brownell Cc: Acked-by: Geoff Levand Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-pci.c | 5 +---- drivers/usb/host/ehci-ps3.c | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index a7816e392a8..ad0d4965f2f 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -58,8 +58,6 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev) if (!retval) ehci_dbg(ehci, "MWI active\n"); - ehci_port_power(ehci, 0); - return 0; } @@ -156,8 +154,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd) break; } - if (ehci_is_TDI(ehci)) - ehci_reset(ehci); + ehci_reset(ehci); /* at least the Genesys GL880S needs fixup here */ temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params); diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c index 829fe649a98..03a6b2f4e6e 100644 --- a/drivers/usb/host/ehci-ps3.c +++ b/drivers/usb/host/ehci-ps3.c @@ -47,7 +47,7 @@ static int ps3_ehci_hc_reset(struct usb_hcd *hcd) if (result) return result; - ehci_port_power(ehci, 0); + ehci_reset(ehci); return result; } -- cgit v1.2.3-70-g09d2 From dfd1e53777afe1050e3a0a3f0dd063a64242b818 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 21 Aug 2007 15:36:52 -0400 Subject: USB: minor fixes for r8a66597 driver This patch (as967) makes a few relatively minor changes to the r8a66597 driver: finish_request() does nothing but call done(), so merge the two routines. Detect and report -EOVERFLOW errors. Fix the calculation that checks for short packets. Signed-off-by: Alan Stern CC: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/r8a66597-hcd.c | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 94bb229df3b..49cf998c172 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -1109,8 +1109,9 @@ static void set_td_timer(struct r8a66597 *r8a66597, struct r8a66597_td *td) } /* this function must be called with interrupt disabled */ -static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td, - u16 pipenum, struct urb *urb) +static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td, + u16 pipenum, struct urb *urb) +__releases(r8a66597->lock) __acquires(r8a66597->lock) { int restart = 0; struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597); @@ -1151,14 +1152,6 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td, } } -/* this function must be called with interrupt disabled */ -static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td, - u16 pipenum, struct urb *urb) -__releases(r8a66597->lock) __acquires(r8a66597->lock) -{ - done(r8a66597, td, pipenum, urb); -} - static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) { u16 tmp; @@ -1167,6 +1160,7 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum); struct urb *urb; int finish = 0; + int status = 0; if (unlikely(!td)) return; @@ -1185,7 +1179,6 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) /* prepare parameters */ rcv_len = tmp & DTLN; - bufsize = td->maxpacket; if (usb_pipeisoc(urb->pipe)) { buf = (u16 *)(urb->transfer_buffer + urb->iso_frame_desc[td->iso_cnt].offset); @@ -1194,25 +1187,30 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) buf = (void *)urb->transfer_buffer + urb->actual_length; urb_len = urb->transfer_buffer_length - urb->actual_length; } - if (rcv_len < bufsize) - size = min(rcv_len, urb_len); - else - size = min(bufsize, urb_len); + bufsize = min(urb_len, (int) td->maxpacket); + if (rcv_len <= bufsize) { + size = rcv_len; + } else { + size = bufsize; + status = -EOVERFLOW; + finish = 1; + } /* update parameters */ urb->actual_length += size; if (rcv_len == 0) td->zero_packet = 1; - if ((size % td->maxpacket) > 0) { + if (rcv_len < bufsize) { td->short_packet = 1; if (urb->transfer_buffer_length != urb->actual_length && urb->transfer_flags & URB_SHORT_NOT_OK) - td->urb->status = -EREMOTEIO; + status = -EREMOTEIO; } if (usb_pipeisoc(urb->pipe)) { urb->iso_frame_desc[td->iso_cnt].actual_length = size; - urb->iso_frame_desc[td->iso_cnt].status = 0; + urb->iso_frame_desc[td->iso_cnt].status = status; td->iso_cnt++; + finish = 0; } /* check transfer finish */ @@ -1233,7 +1231,7 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) if (finish && pipenum != 0) { if (td->urb->status == -EINPROGRESS) - td->urb->status = 0; + td->urb->status = status; finish_request(r8a66597, td, pipenum, urb); } } @@ -1807,7 +1805,7 @@ static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, pipe_stop(r8a66597, td->pipe); pipe_irq_disable(r8a66597, td->pipenum); disable_irq_empty(r8a66597, td->pipenum); - done(r8a66597, td, td->pipenum, urb); + finish_request(r8a66597, td, td->pipenum, urb); } done: spin_unlock_irqrestore(&r8a66597->lock, flags); @@ -1841,7 +1839,7 @@ static void r8a66597_endpoint_disable(struct usb_hcd *hcd, td = r8a66597_get_td(r8a66597, pipenum); if (td) urb = td->urb; - done(r8a66597, td, pipenum, urb); + finish_request(r8a66597, td, pipenum, urb); kfree(hep->hcpriv); hep->hcpriv = NULL; spin_unlock_irqrestore(&r8a66597->lock, flags); -- cgit v1.2.3-70-g09d2 From ee7d1f3f0c32d8abe9627aa73dc62ee5bf2daf7f Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 21 Aug 2007 15:37:50 -0400 Subject: USB: remove Iso status value in uhci-hcd This patch (968) changes the way uhci-hcd reports status for Isochronous URBs. Until now urb->status has been set to the last detected error code. But other HCDs don't do this; they leave the status set to 0 and report errors only in the individual iso packet descriptors. So this patch removes the extra computation and makes uhci-hcd behave like the others. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-hcd.h | 1 - drivers/usb/host/uhci-q.c | 11 +++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 1b3d23406ac..e46d2b0203c 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -146,7 +146,6 @@ struct uhci_qh { short phase; /* Between 0 and period-1 */ short load; /* Periodic time requirement, in us */ unsigned int iso_frame; /* Frame # for iso_packet_desc */ - int iso_status; /* Status for Isochronous URBs */ int state; /* QH_STATE_xxx; see above */ int type; /* Queue type (control, bulk, etc) */ diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index bff200cb3d2..793a04685ef 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -1324,7 +1324,6 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, if (list_empty(&qh->queue)) { qh->iso_packet_desc = &urb->iso_frame_desc[0]; qh->iso_frame = urb->start_frame; - qh->iso_status = 0; } qh->skel = SKEL_ISO; @@ -1361,18 +1360,15 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) qh->iso_packet_desc->actual_length = actlength; qh->iso_packet_desc->status = status; } - - if (status) { + if (status) urb->error_count++; - qh->iso_status = status; - } uhci_remove_td_from_urbp(td); uhci_free_td(uhci, td); qh->iso_frame += qh->period; ++qh->iso_packet_desc; } - return qh->iso_status; + return 0; } static int uhci_urb_enqueue(struct usb_hcd *hcd, @@ -1517,7 +1513,6 @@ __acquires(uhci->lock) qh->iso_packet_desc = &nurb->iso_frame_desc[0]; qh->iso_frame = nurb->start_frame; - qh->iso_status = 0; } /* Take the URB off the QH's queue. If the queue is now empty, @@ -1586,7 +1581,7 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) } uhci_giveback_urb(uhci, qh, urb); - if (status < 0 && qh->type != USB_ENDPOINT_XFER_ISOC) + if (status < 0) break; } -- cgit v1.2.3-70-g09d2 From b0d9efba3ec53468984aecef8eeaf079089f2e5a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 21 Aug 2007 15:39:21 -0400 Subject: USB: centralize -EREMOTEIO handling This patch (as969) continues the ongoing changes to the way HCDs report URB statuses. The programming interface has been simplified by making usbcore responsible for clearing urb->hcpriv and for setting -EREMOTEIO status when an URB with the URB_SHORT_NOT_OK flag ends up as a short transfer. By moving the work out of the HCDs, this removes a fair amount of repeated code. Signed-off-by: Alan Stern CC: David Brownell CC: Olav Kongas CC: Yoshihiro Shimoda CC: Tony Olech Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 9 +++++++-- drivers/usb/gadget/dummy_hcd.c | 9 ++------- drivers/usb/host/ehci-q.c | 7 ++++--- drivers/usb/host/isp116x-hcd.c | 8 +------- drivers/usb/host/ohci-q.c | 11 ----------- drivers/usb/host/r8a66597-hcd.c | 7 +------ drivers/usb/host/sl811-hcd.c | 14 +++----------- drivers/usb/host/u132-hcd.c | 5 ----- drivers/usb/host/uhci-q.c | 8 -------- 9 files changed, 18 insertions(+), 60 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index a853f63b925..22a098b318c 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -366,6 +366,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) spin_unlock_irq(&hcd_root_hub_lock); if (status) return status; + urb->hcpriv = hcd; /* Indicate it's queued */ cmd = (struct usb_ctrlrequest *) urb->setup_packet; typeReq = (cmd->bRequestType << 8) | cmd->bRequest; @@ -579,7 +580,6 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd) hcd->poll_pending = 0; hcd->status_urb = NULL; urb->status = 0; - urb->hcpriv = NULL; urb->actual_length = length; memcpy(urb->transfer_buffer, buffer, length); @@ -675,7 +675,6 @@ static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) del_timer (&hcd->rh_timer); if (urb == hcd->status_urb) { hcd->status_urb = NULL; - urb->hcpriv = NULL; usb_hcd_unlink_urb_from_ep(hcd, urb); spin_unlock(&hcd_root_hub_lock); @@ -1192,6 +1191,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) if (unlikely(status)) { usbmon_urb_submit_error(&hcd->self, urb, status); unmap_urb_for_dma(hcd, urb); + urb->hcpriv = NULL; INIT_LIST_HEAD(&urb->urb_list); atomic_dec(&urb->use_count); if (urb->reject) @@ -1265,6 +1265,11 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) unmap_urb_for_dma(hcd, urb); usbmon_urb_complete (&hcd->self, urb); usb_unanchor_urb(urb); + urb->hcpriv = NULL; + if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && + urb->actual_length < urb->transfer_buffer_length && + !urb->status)) + urb->status = -EREMOTEIO; /* pass ownership to the completion handler */ urb->complete (urb); diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index c441d10c087..0cb032526ca 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -1099,8 +1099,7 @@ top: * * partially filling a buffer optionally blocks queue advances * (so completion handlers can clean up the queue) but we don't - * need to emulate such data-in-flight. so we only show part - * of the URB_SHORT_NOT_OK effect: completion status. + * need to emulate such data-in-flight. */ if (is_short) { if (host_len == dev_len) { @@ -1111,10 +1110,7 @@ top: if (dev_len > host_len) maybe_set_status (urb, -EOVERFLOW); else - maybe_set_status (urb, - (urb->transfer_flags - & URB_SHORT_NOT_OK) - ? -EREMOTEIO : 0); + maybe_set_status (urb, 0); } else if (!to_host) { maybe_set_status (urb, 0); if (host_len > dev_len) @@ -1516,7 +1512,6 @@ restart: continue; return_urb: - urb->hcpriv = NULL; list_del (&urbp->urbp_list); kfree (urbp); if (ep) diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 1da2de4d34e..e80b5c417d7 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -232,7 +232,6 @@ __acquires(ehci->lock) } spin_lock (&urb->lock); - urb->hcpriv = NULL; switch (urb->status) { case -EINPROGRESS: /* success */ urb->status = 0; @@ -395,8 +394,10 @@ halt: /* remove it from the queue */ spin_lock (&urb->lock); qtd_copy_status (ehci, urb, qtd->length, token); - do_status = (urb->status == -EREMOTEIO) - && usb_pipecontrol (urb->pipe); + if (unlikely(urb->status == -EREMOTEIO)) { + do_status = usb_pipecontrol(urb->pipe); + urb->status = 0; + } spin_unlock (&urb->lock); if (stopped && qtd->qtd_list.prev != &qh->qtd_list) { diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index f2b5d6281c5..c2919dbc3f5 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -282,7 +282,6 @@ __releases(isp116x->lock) __acquires(isp116x->lock) { unsigned i; - urb->hcpriv = NULL; ep->error_count = 0; if (usb_pipecontrol(urb->pipe)) @@ -446,12 +445,7 @@ static void postproc_atl_queue(struct isp116x *isp116x) if (PTD_GET_ACTIVE(ptd) || (cc != TD_CC_NOERROR && cc < 0x0E)) break; - if ((urb->transfer_flags & URB_SHORT_NOT_OK) && - urb->actual_length < - urb->transfer_buffer_length) - status = -EREMOTEIO; - else - status = 0; + status = 0; ep->nextpid = 0; break; default: diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 889c0720743..8aad6199cdc 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -43,21 +43,10 @@ __acquires(ohci->lock) // ASSERT (urb->hcpriv != 0); urb_free_priv (ohci, urb->hcpriv); - urb->hcpriv = NULL; spin_lock (&urb->lock); if (likely (urb->status == -EINPROGRESS)) urb->status = 0; - /* report short control reads right even though the data TD always - * has TD_R set. (much simpler, but creates the 1-td limit.) - */ - if (unlikely (urb->transfer_flags & URB_SHORT_NOT_OK) - && unlikely (usb_pipecontrol (urb->pipe)) - && urb->actual_length < urb->transfer_buffer_length - && usb_pipein (urb->pipe) - && urb->status == 0) { - urb->status = -EREMOTEIO; - } spin_unlock (&urb->lock); switch (usb_pipetype (urb->pipe)) { diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 49cf998c172..60248b01ce1 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -783,7 +783,6 @@ static void force_dequeue(struct r8a66597 *r8a66597, u16 pipenum, u16 address) if (urb) { urb->status = -ENODEV; - urb->hcpriv = NULL; usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb); @@ -1134,7 +1133,6 @@ __releases(r8a66597->lock) __acquires(r8a66597->lock) if (usb_pipeisoc(urb->pipe)) urb->start_frame = r8a66597_get_frame(hcd); - urb->hcpriv = NULL; usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb); spin_unlock(&r8a66597->lock); @@ -1202,9 +1200,6 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) td->zero_packet = 1; if (rcv_len < bufsize) { td->short_packet = 1; - if (urb->transfer_buffer_length != urb->actual_length && - urb->transfer_flags & URB_SHORT_NOT_OK) - status = -EREMOTEIO; } if (usb_pipeisoc(urb->pipe)) { urb->iso_frame_desc[td->iso_cnt].actual_length = size; @@ -1214,7 +1209,7 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) } /* check transfer finish */ - if (check_transfer_finish(td, urb)) { + if (finish || check_transfer_finish(td, urb)) { pipe_stop(r8a66597, td->pipe); pipe_irq_disable(r8a66597, pipenum); finish = 1; diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 15a93f946af..e90953a9c9f 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -438,7 +438,6 @@ static void finish_request( spin_lock(&urb->lock); if (urb->status == -EINPROGRESS) urb->status = status; - urb->hcpriv = NULL; spin_unlock(&urb->lock); usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb); @@ -545,17 +544,10 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank) sl811_read_buf(sl811, SL811HS_PACKET_BUF(bank == 0), buf, len); usb_dotoggle(udev, ep->epnum, 0); - if (urb->actual_length == urb->transfer_buffer_length) + if (urb->actual_length == urb->transfer_buffer_length + || len < ep->maxpacket) urbstat = 0; - else if (len < ep->maxpacket) { - if (urb->transfer_flags & URB_SHORT_NOT_OK) - urbstat = -EREMOTEIO; - else - urbstat = 0; - } - if (usb_pipecontrol(urb->pipe) - && (urbstat == -EREMOTEIO - || urbstat == 0)) { + if (usb_pipecontrol(urb->pipe) && urbstat == 0) { /* NOTE if the status stage STALLs (why?), * this reports the wrong urb status. diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index c87660b5edc..1381275d448 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -519,7 +519,6 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp, struct usb_hcd *hcd = u132_to_hcd(u132); urb->error_count = 0; urb->status = status; - urb->hcpriv = NULL; spin_lock_irqsave(&endp->queue_lock.slock, irqs); usb_hcd_unlink_urb_from_ep(hcd, urb); endp->queue_next += 1; @@ -560,7 +559,6 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp, struct usb_hcd *hcd = u132_to_hcd(u132); urb->error_count = 0; urb->status = status; - urb->hcpriv = NULL; spin_lock_irqsave(&endp->queue_lock.slock, irqs); usb_hcd_unlink_urb_from_ep(hcd, urb); endp->queue_next += 1; @@ -2430,7 +2428,6 @@ static int dequeue_from_overflow_chain(struct u132 *u132, list_del(scan); endp->queue_size -= 1; urb->error_count = 0; - urb->hcpriv = NULL; usb_hcd_giveback_urb(hcd, urb); return 0; } else @@ -2472,7 +2469,6 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, endp->edset_flush = 1; u132_endp_queue_work(u132, endp, 0); spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - urb->hcpriv = NULL; return 0; } else { spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); @@ -2517,7 +2513,6 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, irqs); kfree(urbq); } urb->error_count = 0; - urb->hcpriv = NULL; usb_hcd_giveback_urb(hcd, urb); return 0; } else if (list_empty(&endp->urb_more)) { diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 793a04685ef..fbc3af392c2 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -757,7 +757,6 @@ static void uhci_free_urb_priv(struct uhci_hcd *uhci, uhci_free_td(uhci, td); } - urbp->urb->hcpriv = NULL; kmem_cache_free(uhci_up_cachep, urbp); } @@ -1494,13 +1493,6 @@ __acquires(uhci->lock) * unlinked first. Regardless, don't confuse people with a * negative length. */ urb->actual_length = max(urb->actual_length, 0); - - /* Report erroneous short transfers */ - if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && - urb->actual_length < - urb->transfer_buffer_length && - urb->status == 0)) - urb->status = -EREMOTEIO; } /* When giving back the first URB in an Isochronous queue, -- cgit v1.2.3-70-g09d2 From eb23105462304fd35571fd0cab1de7aec79a9ec5 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 21 Aug 2007 15:40:36 -0400 Subject: USB: add urb->unlinked field This patch (as970) adds a new urb->unlinked field, which is used to store the status of unlinked URBs since we can't use urb->status for that purpose any more. To help simplify the HCDs, usbcore will check urb->unlinked before calling the completion handler; if the value is set it will automatically override the status reported by the HCD. Signed-off-by: Alan Stern CC: David Brownell CC: Olav Kongas CC: Yoshihiro Shimoda CC: Tony Olech Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 19 +++--- drivers/usb/gadget/dummy_hcd.c | 8 +-- drivers/usb/host/ehci-q.c | 29 ++++------ drivers/usb/host/isp116x-hcd.c | 5 +- drivers/usb/host/ohci-q.c | 5 +- drivers/usb/host/r8a66597-hcd.c | 24 +++----- drivers/usb/host/sl811-hcd.c | 5 +- drivers/usb/host/u132-hcd.c | 124 ++++++++++++++++++++-------------------- drivers/usb/host/uhci-debug.c | 4 +- drivers/usb/host/uhci-q.c | 9 +-- include/linux/usb.h | 1 + 11 files changed, 108 insertions(+), 125 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 22a098b318c..ec17fc4d286 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -532,8 +532,7 @@ error: /* any errors get returned through the urb completion */ spin_lock_irq(&hcd_root_hub_lock); - if (urb->status == -EINPROGRESS) - urb->status = status; + urb->status = status; usb_hcd_unlink_urb_from_ep(hcd, urb); /* This peculiar use of spinlocks echoes what real HC drivers do. @@ -1024,6 +1023,7 @@ int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb) switch (hcd->state) { case HC_STATE_RUNNING: case HC_STATE_RESUMING: + urb->unlinked = 0; list_add_tail(&urb->urb_list, &urb->ep->urb_list); break; default: @@ -1071,9 +1071,9 @@ int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb, /* Any status except -EINPROGRESS means something already started to * unlink this URB from the hardware. So there's no more work to do. */ - if (urb->status != -EINPROGRESS) + if (urb->unlinked) return -EBUSY; - urb->status = status; + urb->unlinked = status; /* IRQ setup can easily be broken so that USB controllers * never get completion IRQs ... maybe even the ones we need to @@ -1259,6 +1259,10 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) * (and is done using urb->hcpriv). It also released all HCD locks; * the device driver won't cause problems if it frees, modifies, * or resubmits this URB. + * + * If @urb was unlinked, the value of @urb->status will be overridden by + * @urb->unlinked. Erroneous short transfers are detected in case + * the HCD hasn't checked for them. */ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) { @@ -1266,7 +1270,9 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) usbmon_urb_complete (&hcd->self, urb); usb_unanchor_urb(urb); urb->hcpriv = NULL; - if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && + if (unlikely(urb->unlinked)) + urb->status = urb->unlinked; + else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && urb->actual_length < urb->transfer_buffer_length && !urb->status)) urb->status = -EREMOTEIO; @@ -1305,8 +1311,7 @@ rescan: list_for_each_entry (urb, &ep->urb_list, urb_list) { int is_in; - /* the urb may already have been unlinked */ - if (urb->status != -EINPROGRESS) + if (urb->unlinked) continue; usb_get_urb (urb); is_in = usb_urb_dir_in(urb); diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 0cb032526ca..f2b124cf320 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -1029,8 +1029,7 @@ static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) static void maybe_set_status (struct urb *urb, int status) { spin_lock (&urb->lock); - if (urb->status == -EINPROGRESS) - urb->status = status; + urb->status = status; spin_unlock (&urb->lock); } @@ -1257,10 +1256,9 @@ restart: int type; urb = urbp->urb; - if (urb->status != -EINPROGRESS) { - /* likely it was just unlinked */ + if (urb->unlinked) goto return_urb; - } else if (dum->rh_state != DUMMY_RH_RUNNING) + else if (dum->rh_state != DUMMY_RH_RUNNING) continue; type = usb_pipetype (urb->pipe); diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index e80b5c417d7..a8f5408c161 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -151,7 +151,7 @@ static void qtd_copy_status ( urb->actual_length += length - QTD_LENGTH (token); /* don't modify error codes */ - if (unlikely (urb->status != -EINPROGRESS)) + if (unlikely(urb->unlinked)) return; /* force cleanup after short read; not always an error */ @@ -232,21 +232,14 @@ __acquires(ehci->lock) } spin_lock (&urb->lock); - switch (urb->status) { - case -EINPROGRESS: /* success */ - urb->status = 0; - default: /* fault */ - COUNT (ehci->stats.complete); - break; - case -EREMOTEIO: /* fault or normal */ - if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) + if (unlikely(urb->unlinked)) { + COUNT(ehci->stats.unlink); + } else { + if (likely(urb->status == -EINPROGRESS || + (urb->status == -EREMOTEIO && + !(urb->transfer_flags & URB_SHORT_NOT_OK)))) urb->status = 0; - COUNT (ehci->stats.complete); - break; - case -ECONNRESET: /* canceled */ - case -ENOENT: - COUNT (ehci->stats.unlink); - break; + COUNT(ehci->stats.complete); } spin_unlock (&urb->lock); @@ -364,7 +357,8 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) * for the urb faulted (including short read) or * its urb was canceled. we may patch qh or qtds. */ - if (likely (urb->status == -EINPROGRESS)) + if (likely(urb->status == -EINPROGRESS && + !urb->unlinked)) continue; /* issue status after short control reads */ @@ -395,7 +389,8 @@ halt: spin_lock (&urb->lock); qtd_copy_status (ehci, urb, qtd->length, token); if (unlikely(urb->status == -EREMOTEIO)) { - do_status = usb_pipecontrol(urb->pipe); + do_status = (!urb->unlinked && + usb_pipecontrol(urb->pipe)); urb->status = 0; } spin_unlock (&urb->lock); diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index c2919dbc3f5..35b3507ff40 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -455,11 +455,10 @@ static void postproc_atl_queue(struct isp116x *isp116x) done: if (status != -EINPROGRESS) { spin_lock(&urb->lock); - if (urb->status == -EINPROGRESS) - urb->status = status; + urb->status = status; spin_unlock(&urb->lock); } - if (urb->status != -EINPROGRESS) + if (urb->status != -EINPROGRESS || urb->unlinked) finish_request(isp116x, ep, urb); } } diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 8aad6199cdc..3c793fad178 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -758,8 +758,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) cc = TD_CC_NOERROR; if (cc != TD_CC_NOERROR && cc < 0x0E) { spin_lock (&urb->lock); - if (urb->status == -EINPROGRESS) - urb->status = cc_to_error [cc]; + urb->status = cc_to_error[cc]; spin_unlock (&urb->lock); } @@ -972,7 +971,7 @@ rescan_this: urb = td->urb; urb_priv = td->urb->hcpriv; - if (urb->status == -EINPROGRESS) { + if (!urb->unlinked) { prev = &td->hwNextTD; continue; } diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 60248b01ce1..98b9e054754 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -1118,7 +1118,7 @@ __releases(r8a66597->lock) __acquires(r8a66597->lock) r8a66597->timeout_map &= ~(1 << pipenum); if (likely(td)) { - if (td->set_address && urb->status != 0) + if (td->set_address && (urb->status != 0 || urb->unlinked)) r8a66597->address_map &= ~(1 << urb->setup_packet[2]); pipe_toggle_save(r8a66597, td->pipe, urb); @@ -1225,8 +1225,7 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) } if (finish && pipenum != 0) { - if (td->urb->status == -EINPROGRESS) - td->urb->status = status; + td->urb->status = status; finish_request(r8a66597, td, pipenum, urb); } } @@ -1308,32 +1307,24 @@ static void check_next_phase(struct r8a66597 *r8a66597) switch (td->type) { case USB_PID_IN: case USB_PID_OUT: - if (urb->status != -EINPROGRESS) { - finish = 1; - break; - } if (check_transfer_finish(td, urb)) td->type = USB_PID_ACK; break; case USB_PID_SETUP: - if (urb->status != -EINPROGRESS) - finish = 1; - else if (urb->transfer_buffer_length == urb->actual_length) { + if (urb->transfer_buffer_length == urb->actual_length) td->type = USB_PID_ACK; - urb->status = 0; - } else if (usb_pipeout(urb->pipe)) + else if (usb_pipeout(urb->pipe)) td->type = USB_PID_OUT; else td->type = USB_PID_IN; break; case USB_PID_ACK: finish = 1; - if (urb->status == -EINPROGRESS) - urb->status = 0; + urb->status = 0; break; } - if (finish) + if (finish || urb->unlinked) finish_request(r8a66597, td, 0, urb); else start_transfer(r8a66597, td); @@ -1418,8 +1409,7 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597) if ((tmp & INBUFM) == 0) { disable_irq_empty(r8a66597, pipenum); pipe_irq_disable(r8a66597, pipenum); - if (td->urb->status == -EINPROGRESS) - td->urb->status = 0; + td->urb->status = 0; finish_request(r8a66597, td, pipenum, td->urb); } } diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index e90953a9c9f..f0fa94148d9 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -436,8 +436,7 @@ static void finish_request( ep->nextpid = USB_PID_SETUP; spin_lock(&urb->lock); - if (urb->status == -EINPROGRESS) - urb->status = status; + urb->status = status; spin_unlock(&urb->lock); usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb); @@ -598,7 +597,7 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank) bank, status, ep, urbstat); } - if (urb && (urbstat != -EINPROGRESS || urb->status != -EINPROGRESS)) + if (urb && (urbstat != -EINPROGRESS || urb->unlinked)) finish_request(sl811, ep, urb, urbstat); } diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 1381275d448..db800a434b8 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -645,12 +645,12 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { struct u132_ring *ring = endp->ring; u8 *u = urb->transfer_buffer + urb->actual_length; u8 *b = buf; @@ -716,8 +716,8 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf, return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -744,12 +744,12 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { struct u132_ring *ring = endp->ring; urb->actual_length += len; endp->toggle_bits = toggle_bits; @@ -768,8 +768,8 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf, return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -797,12 +797,12 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { struct u132_ring *ring = endp->ring; u8 *u = urb->transfer_buffer + urb->actual_length; u8 *b = buf; @@ -871,8 +871,8 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf, return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -898,18 +898,18 @@ static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -936,12 +936,12 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { struct u132_ring *ring = endp->ring; u8 *u = urb->transfer_buffer; u8 *b = buf; @@ -980,8 +980,8 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf, return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -1007,18 +1007,18 @@ static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -1045,12 +1045,12 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { if (usb_pipein(urb->pipe)) { int retval; struct u132_ring *ring = endp->ring; @@ -1077,8 +1077,8 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf, return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -1106,20 +1106,20 @@ static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { u132->addr[0].address = 0; endp->usb_addr = udev->usb_addr; up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -1145,12 +1145,12 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { int retval; struct u132_ring *ring = endp->ring; up(&u132->scheduler_lock); @@ -1162,8 +1162,8 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb, u132_hcd_giveback_urb(u132, endp, urb, retval); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -1189,18 +1189,18 @@ static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -1227,12 +1227,12 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { int retval; struct u132_ring *ring = endp->ring; u8 *u = urb->transfer_buffer; @@ -1251,8 +1251,8 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, retval); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -1279,12 +1279,12 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { int retval; struct u132_ring *ring = endp->ring; up(&u132->scheduler_lock); @@ -1296,8 +1296,8 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, retval); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -2279,8 +2279,8 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, , u132->going); return -ENODEV; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); return -ESHUTDOWN; } else { u8 usb_addr = usb_pipedevice(urb->pipe); diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index 1497371583b..20cc58b9780 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c @@ -120,8 +120,8 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space) out += sprintf(out, "%s%s", ptype, (urbp->fsbr ? " FSBR" : "")); out += sprintf(out, " Actlen=%d", urbp->urb->actual_length); - if (urbp->urb->status != -EINPROGRESS) - out += sprintf(out, " Status=%d", urbp->urb->status); + if (urbp->urb->unlinked) + out += sprintf(out, " Unlinked=%d", urbp->urb->unlinked); out += sprintf(out, "\n"); i = nactive = ninactive = 0; diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index fbc3af392c2..bab56726655 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -1557,15 +1557,12 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) break; spin_lock(&urb->lock); - if (urb->status == -EINPROGRESS) /* Not dequeued */ - urb->status = status; - else - status = ECONNRESET; /* Not -ECONNRESET */ + urb->status = status; spin_unlock(&urb->lock); /* Dequeued but completed URBs can't be given back unless * the QH is stopped or has finished unlinking. */ - if (status == ECONNRESET) { + if (urb->unlinked) { if (QH_FINISHED_UNLINKING(qh)) qh->is_stopped = 1; else if (!qh->is_stopped) @@ -1588,7 +1585,7 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) restart: list_for_each_entry(urbp, &qh->queue, node) { urb = urbp->urb; - if (urb->status != -EINPROGRESS) { + if (urb->unlinked) { /* Fix up the TD links and save the toggles for * non-Isochronous queues. For Isochronous queues, diff --git a/include/linux/usb.h b/include/linux/usb.h index 92d63c6b6fc..5c7b79088ad 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1245,6 +1245,7 @@ struct urb void *hcpriv; /* private data for host controller */ atomic_t use_count; /* concurrent submissions counter */ u8 reject; /* submissions will fail */ + int unlinked; /* unlink error code */ /* public: documented fields in the urb that can be used by drivers */ struct list_head urb_list; /* list head for use by the urb's -- cgit v1.2.3-70-g09d2 From ed6e52829c113ca18f042ac55cc77b1b90745eab Mon Sep 17 00:00:00 2001 From: "Andrew M. Bishop" Date: Tue, 21 Aug 2007 19:08:56 +0100 Subject: USB: ftdi_sio: Handle FT232RL devices like FT232BM devices Handle the FT232RL device type in exactly the same way as FT232BM devices (FT232RL detection was added around kernel 2.6.20 but not code for handling it). Signed-off-by: Andrew M. Bishop Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 2d045857b18..e4c248c98e8 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1169,7 +1169,9 @@ static void remove_sysfs_attrs(struct usb_serial_port *port) /* XXX see create_sysfs_attrs */ if (priv->chip_type != SIO) { device_remove_file(&port->dev, &dev_attr_event_char); - if (priv->chip_type == FT232BM || priv->chip_type == FT2232C) { + if (priv->chip_type == FT232BM || + priv->chip_type == FT2232C || + priv->chip_type == FT232RL) { device_remove_file(&port->dev, &dev_attr_latency_timer); } } @@ -2102,6 +2104,7 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file) case FT8U232AM: case FT232BM: case FT2232C: + case FT232RL: /* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same format as the data returned from the in point */ if ((ret = usb_control_msg(port->serial->dev, -- cgit v1.2.3-70-g09d2 From 1f5a3d0f34fd5719081c6b8f3dbbcbe328d4da31 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 22 Aug 2007 13:06:53 -0400 Subject: USB: fix mistake in usb_hcd_giveback_urb This patch (as971) fixes a small mistake: The URB's completion status needs to be adjusted before the URB is passed to usmon_urb_complete(), not afterward. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index ec17fc4d286..8b17babf5c5 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1266,9 +1266,6 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) */ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) { - unmap_urb_for_dma(hcd, urb); - usbmon_urb_complete (&hcd->self, urb); - usb_unanchor_urb(urb); urb->hcpriv = NULL; if (unlikely(urb->unlinked)) urb->status = urb->unlinked; @@ -1277,6 +1274,10 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) !urb->status)) urb->status = -EREMOTEIO; + unmap_urb_for_dma(hcd, urb); + usbmon_urb_complete(&hcd->self, urb); + usb_unanchor_urb(urb); + /* pass ownership to the completion handler */ urb->complete (urb); atomic_dec (&urb->use_count); -- cgit v1.2.3-70-g09d2 From 6e8fe43b26085a64327d1cbb751ab895f3ad3f5d Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 22 Aug 2007 13:08:40 -0400 Subject: USB: avoid the donelist after an error in ohci-hcd This patch (as972) changes ohci-hcd so that after an error occurs, the remaining TDs for the URB will be skipped over entirely instead of going through the donelist. This enables the driver to give back the URB as soon as the error is detected, avoiding the need to store the error status in urb->status. Signed-off-by: Alan Stern CC: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-q.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 3c793fad178..860e55ff67a 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -783,10 +783,10 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) /*-------------------------------------------------------------------------*/ -static inline struct td * -ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) +static void ed_halted(struct ohci_hcd *ohci, struct td *td, int cc) { struct urb *urb = td->urb; + urb_priv_t *urb_priv = urb->hcpriv; struct ed *ed = td->ed; struct list_head *tmp = td->td_list.next; __hc32 toggle = ed->hwHeadP & cpu_to_hc32 (ohci, ED_C); @@ -798,13 +798,12 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) wmb (); ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_H); - /* put any later tds from this urb onto the donelist, after 'td', - * order won't matter here: no errors, and nothing was transferred. - * also patch the ed so it looks as if those tds completed normally. + /* Get rid of all later tds from this urb. We don't have + * to be careful: no errors and nothing was transferred. + * Also patch the ed so it looks as if those tds completed normally. */ while (tmp != &ed->td_list) { struct td *next; - __hc32 info; next = list_entry (tmp, struct td, td_list); tmp = next->td_list.next; @@ -819,14 +818,9 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) * then we need to leave the control STATUS packet queued * and clear ED_SKIP. */ - info = next->hwINFO; - info |= cpu_to_hc32 (ohci, TD_DONE); - info &= ~cpu_to_hc32 (ohci, TD_CC); - next->hwINFO = info; - - next->next_dl_td = rev; - rev = next; + list_del(&next->td_list); + urb_priv->td_cnt++; ed->hwHeadP = next->hwNextTD | toggle; } @@ -852,8 +846,6 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) hc32_to_cpu (ohci, td->hwINFO), cc, cc_to_error [cc]); } - - return rev; } /* replies to the request have to be on a FIFO basis so @@ -890,7 +882,7 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci) */ if (cc != TD_CC_NOERROR && (td->ed->hwHeadP & cpu_to_hc32 (ohci, ED_H))) - td_rev = ed_halted (ohci, td, cc, td_rev); + ed_halted(ohci, td, cc); td->next_dl_td = td_rev; td_rev = td; -- cgit v1.2.3-70-g09d2 From c4e41562e09961df6ba72b49269793d21c0034dc Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 22 Aug 2007 23:06:48 +0100 Subject: USB: cp2101: Coding style police Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp2101.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 33f6ee50b8d..883625126d6 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -521,7 +521,7 @@ static void cp2101_set_termios (struct usb_serial_port *port, 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__); return; } -- cgit v1.2.3-70-g09d2 From 94d0f7eac77a84da2cee41b8038796891f75f09e Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 22 Aug 2007 23:09:16 +0100 Subject: USB: kobil_sct: Rework driver No hardware but this driver is currently totally broken so we can't make it much worse. Remove all tbe broken invalid termios handling and replace it with a proper set_termios method. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/kobil_sct.c | 144 ++++++++++++++++------------------------- 1 file changed, 55 insertions(+), 89 deletions(-) diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index 02a86dbc0e9..6f224195bd2 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -82,6 +82,7 @@ static int kobil_tiocmset(struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear); static void kobil_read_int_callback( struct urb *urb ); static void kobil_write_callback( struct urb *purb ); +static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old); static struct usb_device_id id_table [] = { @@ -119,6 +120,7 @@ static struct usb_serial_driver kobil_device = { .attach = kobil_startup, .shutdown = kobil_shutdown, .ioctl = kobil_ioctl, + .set_termios = kobil_set_termios, .tiocmget = kobil_tiocmget, .tiocmset = kobil_tiocmset, .open = kobil_open, @@ -137,7 +139,6 @@ struct kobil_private { int cur_pos; // index of the next char to send in buf __u16 device_type; int line_state; - struct ktermios internal_termios; }; @@ -216,7 +217,7 @@ static void kobil_shutdown (struct usb_serial *serial) static int kobil_open (struct usb_serial_port *port, struct file *filp) { - int i, result = 0; + int result = 0; struct kobil_private *priv; unsigned char *transfer_buffer; int transfer_buffer_length = 8; @@ -242,16 +243,6 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp) port->tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF; port->tty->termios->c_oflag &= ~ONLCR; // do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) - // set up internal termios structure - priv->internal_termios.c_iflag = port->tty->termios->c_iflag; - priv->internal_termios.c_oflag = port->tty->termios->c_oflag; - priv->internal_termios.c_cflag = port->tty->termios->c_cflag; - priv->internal_termios.c_lflag = port->tty->termios->c_lflag; - - for (i=0; iinternal_termios.c_cc[i] = port->tty->termios->c_cc[i]; - } - // allocate memory for transfer buffer transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL); if (! transfer_buffer) { @@ -607,102 +598,79 @@ static int kobil_tiocmset(struct usb_serial_port *port, struct file *file, return (result < 0) ? result : 0; } - -static int kobil_ioctl(struct usb_serial_port *port, struct file *file, - unsigned int cmd, unsigned long arg) +static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old) { struct kobil_private * priv; int result; unsigned short urb_val = 0; - unsigned char *transfer_buffer; - int transfer_buffer_length = 8; - char *settings; - void __user *user_arg = (void __user *)arg; + int c_cflag = port->tty->termios->c_cflag; + speed_t speed; + void * settings; priv = usb_get_serial_port_data(port); - if ((priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) || (priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)) { + if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) // This device doesn't support ioctl calls - return 0; - } - - switch (cmd) { - case TCGETS: // 0x5401 - if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct ktermios))) { - dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number); - return -EFAULT; - } - if (kernel_termios_to_user_termios((struct ktermios __user *)arg, - &priv->internal_termios)) - return -EFAULT; - return 0; - - case TCSETS: // 0x5402 - if (!(port->tty->termios)) { - dbg("%s - port %d Error: port->tty->termios is NULL", __FUNCTION__, port->number); - return -ENOTTY; - } - if (!access_ok(VERIFY_READ, user_arg, sizeof(struct ktermios))) { - dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number); - return -EFAULT; - } - if (user_termios_to_kernel_termios(&priv->internal_termios, - (struct ktermios __user *)arg)) - return -EFAULT; - - settings = kzalloc(50, GFP_KERNEL); - if (! settings) { - return -ENOBUFS; - } + return; - switch (priv->internal_termios.c_cflag & CBAUD) { - case B1200: + switch (speed = tty_get_baud_rate(port->tty)) { + case 1200: urb_val = SUSBCR_SBR_1200; - strcat(settings, "1200 "); break; - case B9600: + case 9600: default: urb_val = SUSBCR_SBR_9600; - strcat(settings, "9600 "); break; - } + } + urb_val |= (c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit; + + settings = kzalloc(50, GFP_KERNEL); + if (! settings) + return; - urb_val |= (priv->internal_termios.c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit; - strcat(settings, (priv->internal_termios.c_cflag & CSTOPB) ? "2 StopBits " : "1 StopBit "); + sprintf(settings, "%d ", speed); - if (priv->internal_termios.c_cflag & PARENB) { - if (priv->internal_termios.c_cflag & PARODD) { - urb_val |= SUSBCR_SPASB_OddParity; - strcat(settings, "Odd Parity"); - } else { - urb_val |= SUSBCR_SPASB_EvenParity; - strcat(settings, "Even Parity"); - } + if (c_cflag & PARENB) { + if (c_cflag & PARODD) { + urb_val |= SUSBCR_SPASB_OddParity; + strcat(settings, "Odd Parity"); } else { - urb_val |= SUSBCR_SPASB_NoParity; - strcat(settings, "No Parity"); + urb_val |= SUSBCR_SPASB_EvenParity; + strcat(settings, "Even Parity"); } - dbg("%s - port %d setting port to: %s", __FUNCTION__, port->number, settings ); + } else { + urb_val |= SUSBCR_SPASB_NoParity; + strcat(settings, "No Parity"); + } - result = usb_control_msg( port->serial->dev, - usb_rcvctrlpipe(port->serial->dev, 0 ), - SUSBCRequest_SetBaudRateParityAndStopBits, - USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, - urb_val, - 0, - settings, - 0, - KOBIL_TIMEOUT - ); + result = usb_control_msg( port->serial->dev, + usb_rcvctrlpipe(port->serial->dev, 0 ), + SUSBCRequest_SetBaudRateParityAndStopBits, + USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, + urb_val, + 0, + settings, + 0, + KOBIL_TIMEOUT + ); + kfree(settings); +} - dbg("%s - port %d Send set_baudrate URB returns: %i", __FUNCTION__, port->number, result); - kfree(settings); +static int kobil_ioctl(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg) +{ + struct kobil_private * priv = usb_get_serial_port_data(port); + unsigned char *transfer_buffer; + int transfer_buffer_length = 8; + int result; + + if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) + // This device doesn't support ioctl calls return 0; + switch (cmd) { case TCFLSH: // 0x540B transfer_buffer = kmalloc(transfer_buffer_length, GFP_KERNEL); - if (! transfer_buffer) { + if (! transfer_buffer) return -ENOBUFS; - } result = usb_control_msg( port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0 ), @@ -716,15 +684,13 @@ static int kobil_ioctl(struct usb_serial_port *port, struct file *file, ); dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __FUNCTION__, port->number, result); - kfree(transfer_buffer); - return ((result < 0) ? -EFAULT : 0); - + return (result < 0) ? -EFAULT : 0; + default: + return -ENOIOCTLCMD; } - return -ENOIOCTLCMD; } - static int __init kobil_init (void) { int retval; -- cgit v1.2.3-70-g09d2 From 12943f097e5a4a0550f52f98ab8f476435e2ce15 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 16:27:50 -0400 Subject: USB: less-restrictive command checking in g-file-storage This patch (as983) makes a test for minimum-length command sizes in g_file_storage less restrictive. It doesn't matter because commands with bad lengths will be detected later on anyway, and doing it like this makes the driver interoperable with certain buggy hosts such as the JVC HiFi (reported by Samuel Hangouet). Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/file_storage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 9998cd7af41..0551140010e 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -2964,7 +2964,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) /* Is the CBW meaningful? */ if (cbw->Lun >= MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG || - cbw->Length < 6 || cbw->Length > MAX_COMMAND_SIZE) { + cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) { DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, " "cmdlen %u\n", cbw->Lun, cbw->Flags, cbw->Length); -- cgit v1.2.3-70-g09d2 From fdf99c9ec10cb9cd44be3ac0bd007a49ac6dc751 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 23 Aug 2007 15:55:34 -0700 Subject: USB: fix memory leak in berry_charge driver This fixes a small memory leak that happens every time the device is plugged in. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/berry_charge.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/usb/misc/berry_charge.c b/drivers/usb/misc/berry_charge.c index 92c1d2768df..24e2dc3148a 100644 --- a/drivers/usb/misc/berry_charge.c +++ b/drivers/usb/misc/berry_charge.c @@ -71,7 +71,7 @@ static int magic_charge(struct usb_device *udev) if (retval != 2) { dev_err(&udev->dev, "First magic command failed: %d.\n", retval); - return retval; + goto exit; } dbg(&udev->dev, "Sending second magic command\n"); @@ -80,7 +80,7 @@ static int magic_charge(struct usb_device *udev) if (retval != 0) { dev_err(&udev->dev, "Second magic command failed: %d.\n", retval); - return retval; + goto exit; } dbg(&udev->dev, "Calling set_configuration\n"); @@ -88,6 +88,8 @@ static int magic_charge(struct usb_device *udev) if (retval) dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval); +exit: + kfree(dummy_buffer); return retval; } @@ -112,6 +114,7 @@ static int magic_dual_mode(struct usb_device *udev) if (retval) dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval); + kfree(dummy_buffer); return retval; } -- cgit v1.2.3-70-g09d2 From ce0d9325b19555f05b08cbb1ea4c2393eec188ec Mon Sep 17 00:00:00 2001 From: Roman Kagan Date: Fri, 24 Aug 2007 20:22:52 +0400 Subject: usb-serial: show port number in sysfs Some usb-serial devices (e.g. certain Edgeport models) have more than one serial port on the same USB device/interface. Currently the only way to distinguish these ports in userspace is by their minor device number: the driver makes them consecutive and in stable order. However, for the purpose of stable naming with udev this is insufficient: when udev handles the ADD event for one of the ports it doesn't know what minor number the other one has. To make stable naming easier, export the port number via sysfs. Signed-off-by: Roman Kagan Signed-off-by: Dmitry Guryanov Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/bus.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index a47a24f8820..0b14aea8ebd 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -36,6 +36,16 @@ static int usb_serial_device_match (struct device *dev, struct device_driver *dr return 0; } +static ssize_t show_port_number(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_serial_port *port = to_usb_serial_port(dev); + + return sprintf(buf, "%d\n", port->number - port->serial->minor); +} + +static DEVICE_ATTR(port_number, S_IRUGO, show_port_number, NULL); + static int usb_serial_device_probe (struct device *dev) { struct usb_serial_driver *driver; @@ -62,6 +72,10 @@ static int usb_serial_device_probe (struct device *dev) goto exit; } + retval = device_create_file(dev, &dev_attr_port_number); + if (retval) + goto exit; + minor = port->number; tty_register_device (usb_serial_tty_driver, minor, dev); dev_info(&port->serial->dev->dev, @@ -84,6 +98,8 @@ static int usb_serial_device_remove (struct device *dev) return -ENODEV; } + device_remove_file(&port->dev, &dev_attr_port_number); + driver = port->serial->type; if (driver->port_remove) { if (!try_module_get(driver->driver.owner)) { -- cgit v1.2.3-70-g09d2 From 092a212e8e3eb49ab7360d652f457d0a360d5383 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Fri, 24 Aug 2007 12:19:22 +0200 Subject: USB: usbmon doc update - mention new wildcard ('0') bus Update usbmon documentation, mentioning the "zero" (wildcard) bus. Possibly, in my first hunk, the 'either ... or ...' should be rephrased a bit to be expressed better. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Cc: Pete Zaitcev Cc: Alan Stern Signed-off-by: Greg Kroah-Hartman --- Documentation/usb/usbmon.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Documentation/usb/usbmon.txt b/Documentation/usb/usbmon.txt index 53ae866ae37..2917ce4ffdc 100644 --- a/Documentation/usb/usbmon.txt +++ b/Documentation/usb/usbmon.txt @@ -34,9 +34,12 @@ if usbmon is built into the kernel. Verify that bus sockets are present. # ls /sys/kernel/debug/usbmon -1s 1t 1u 2s 2t 2u 3s 3t 3u 4s 4t 4u +0s 0t 0u 1s 1t 1u 2s 2t 2u 3s 3t 3u 4s 4t 4u # +Now you can choose to either use the sockets numbered '0' (to capture packets on +all buses), and skip to step #3, or find the bus used by your device with step #2. + 2. Find which bus connects to the desired device Run "cat /proc/bus/usb/devices", and find the T-line which corresponds to @@ -56,6 +59,10 @@ Bus=03 means it's bus 3. # cat /sys/kernel/debug/usbmon/3u > /tmp/1.mon.out +to listen on a single bus, otherwise, to listen on all buses, type: + +# cat /sys/kernel/debug/usbmon/0u > /tmp/1.mon.out + This process will be reading until killed. Naturally, the output can be redirected to a desirable location. This is preferred, because it is going to be quite long. -- cgit v1.2.3-70-g09d2 From b84d2bf07ffb962733ba56307c61539a301a742e Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Fri, 24 Aug 2007 02:35:14 +0200 Subject: usb: avoid redundant cast of kmalloc() return value in OTi-6858 driver In drivers/usb/serial/oti6858.c::pl2303_buf_alloc() the return value of kmalloc() is being cast to "struct pl2303_buf *", but that need not be done here since kmalloc() returns "void *". Signed-off-by: Jesper Juhl Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/oti6858.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index 64f3f66a7a3..d19861166b5 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -1144,7 +1144,7 @@ static struct pl2303_buf *pl2303_buf_alloc(unsigned int size) if (size == 0) return NULL; - pb = (struct pl2303_buf *)kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL); + pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL); if (pb == NULL) return NULL; -- cgit v1.2.3-70-g09d2 From e7beb667842ad0f6ec95a22e7c88e71dfbd60649 Mon Sep 17 00:00:00 2001 From: Andreas Loibl Date: Fri, 24 Aug 2007 01:51:11 +0200 Subject: usb: serial/pl2303: support for BenQ Siemens Mobile Phone EF81 This patch adds support for the BenQ Mobile Phone EF81 to pl2303 Signed-off-by: Andreas Loibl Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/pl2303.c | 1 + drivers/usb/serial/pl2303.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index f9f85f56f0d..1da57fd9ea2 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -73,6 +73,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) }, { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) }, { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) }, { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) }, { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) }, { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) }, diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index f9a71d0c102..c39bace5cbc 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -59,6 +59,7 @@ #define SIEMENS_PRODUCT_ID_SX1 0x0001 #define SIEMENS_PRODUCT_ID_X65 0x0003 #define SIEMENS_PRODUCT_ID_X75 0x0004 +#define SIEMENS_PRODUCT_ID_EF81 0x0005 #define SYNTECH_VENDOR_ID 0x0745 #define SYNTECH_PRODUCT_ID 0x0001 -- cgit v1.2.3-70-g09d2 From 4d2f110c51eec853c50f68cf068888a77551c8d3 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 15:40:10 -0400 Subject: USB: reorganize urb->status use in dummy-hcd This patch (as973) reorganizes the way dummy-hcd sets urb->status. It now keeps the information in a local variable until the last moment. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 53 +++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index f2b124cf320..c1af7bab26f 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -1026,16 +1026,10 @@ static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) return rc; } -static void maybe_set_status (struct urb *urb, int status) -{ - spin_lock (&urb->lock); - urb->status = status; - spin_unlock (&urb->lock); -} - /* transfer up to a frame's worth; caller must own lock */ static int -transfer (struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit) +transfer(struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit, + int *status) { struct dummy_request *req; @@ -1103,15 +1097,15 @@ top: if (is_short) { if (host_len == dev_len) { req->req.status = 0; - maybe_set_status (urb, 0); + *status = 0; } else if (to_host) { req->req.status = 0; if (dev_len > host_len) - maybe_set_status (urb, -EOVERFLOW); + *status = -EOVERFLOW; else - maybe_set_status (urb, 0); + *status = 0; } else if (!to_host) { - maybe_set_status (urb, 0); + *status = 0; if (host_len > dev_len) req->req.status = -EOVERFLOW; else @@ -1125,9 +1119,8 @@ top: req->req.status = 0; if (urb->transfer_buffer_length == urb->actual_length && !(urb->transfer_flags - & URB_ZERO_PACKET)) { - maybe_set_status (urb, 0); - } + & URB_ZERO_PACKET)) + *status = 0; } /* device side completion --> continuable */ @@ -1143,7 +1136,7 @@ top: } /* host side completion --> terminate */ - if (urb->status != -EINPROGRESS) + if (*status != -EINPROGRESS) break; /* rescan to continue with any other queued i/o */ @@ -1254,6 +1247,7 @@ restart: u8 address; struct dummy_ep *ep = NULL; int type; + int status = -EINPROGRESS; urb = urbp->urb; if (urb->unlinked) @@ -1279,7 +1273,7 @@ restart: dev_dbg (dummy_dev(dum), "no ep configured for urb %p\n", urb); - maybe_set_status (urb, -EPROTO); + status = -EPROTO; goto return_urb; } @@ -1294,7 +1288,7 @@ restart: /* NOTE: must not be iso! */ dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n", ep->ep.name, urb); - maybe_set_status (urb, -EPIPE); + status = -EPIPE; goto return_urb; } /* FIXME make sure both ends agree on maxpacket */ @@ -1312,7 +1306,7 @@ restart: w_value = le16_to_cpu(setup.wValue); if (le16_to_cpu(setup.wLength) != urb->transfer_buffer_length) { - maybe_set_status (urb, -EOVERFLOW); + status = -EOVERFLOW; goto return_urb; } @@ -1342,7 +1336,7 @@ restart: if (setup.bRequestType != Dev_Request) break; dum->address = w_value; - maybe_set_status (urb, 0); + status = 0; dev_dbg (udc_dev(dum), "set_address = %d\n", w_value); value = 0; @@ -1369,7 +1363,7 @@ restart: if (value == 0) { dum->devstatus |= (1 << w_value); - maybe_set_status (urb, 0); + status = 0; } } else if (setup.bRequestType == Ep_Request) { @@ -1381,7 +1375,7 @@ restart: } ep2->halted = 1; value = 0; - maybe_set_status (urb, 0); + status = 0; } break; case USB_REQ_CLEAR_FEATURE: @@ -1391,7 +1385,7 @@ restart: dum->devstatus &= ~(1 << USB_DEVICE_REMOTE_WAKEUP); value = 0; - maybe_set_status (urb, 0); + status = 0; break; default: value = -EOPNOTSUPP; @@ -1406,7 +1400,7 @@ restart: } ep2->halted = 0; value = 0; - maybe_set_status (urb, 0); + status = 0; } break; case USB_REQ_GET_STATUS: @@ -1443,7 +1437,7 @@ restart: urb->actual_length = min (2, urb->transfer_buffer_length); value = 0; - maybe_set_status (urb, 0); + status = 0; } break; } @@ -1470,7 +1464,7 @@ restart: dev_dbg (udc_dev(dum), "setup --> %d\n", value); - maybe_set_status (urb, -EPIPE); + status = -EPIPE; urb->actual_length = 0; } @@ -1487,7 +1481,7 @@ restart: * report random errors, to debug drivers. */ limit = max (limit, periodic_bytes (dum, ep)); - maybe_set_status (urb, -ENOSYS); + status = -ENOSYS; break; case PIPE_INTERRUPT: @@ -1501,12 +1495,12 @@ restart: default: treat_control_like_bulk: ep->last_io = jiffies; - total = transfer (dum, urb, ep, limit); + total = transfer(dum, urb, ep, limit, &status); break; } /* incomplete transfer? */ - if (urb->status == -EINPROGRESS) + if (status == -EINPROGRESS) continue; return_urb: @@ -1517,6 +1511,7 @@ return_urb: usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb); spin_unlock (&dum->lock); + urb->status = status; usb_hcd_giveback_urb (dummy_to_hcd(dum), urb); spin_lock (&dum->lock); -- cgit v1.2.3-70-g09d2 From 14c04c0f88f228fee1f412be91d6edcb935c78aa Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 15:40:19 -0400 Subject: USB: reorganize urb->status use in ehci-hcd This patch (as974) reorganizes the way ehci-hcd sets urb->status. It now keeps the information in a local variable until the last moment. The patch also simplifies the handling of -EREMOTEIO, since the only use of that code is to set the do_status flag. Signed-off-by: Alan Stern CC: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-q.c | 62 +++++++++++++++++++++++-------------------- drivers/usb/host/ehci-sched.c | 4 +-- 2 files changed, 35 insertions(+), 31 deletions(-) diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index a8f5408c161..794d27e0780 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -139,63 +139,65 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh) /*-------------------------------------------------------------------------*/ -static void qtd_copy_status ( +static int qtd_copy_status ( struct ehci_hcd *ehci, struct urb *urb, size_t length, u32 token ) { + int status = -EINPROGRESS; + /* count IN/OUT bytes, not SETUP (even short packets) */ if (likely (QTD_PID (token) != 2)) urb->actual_length += length - QTD_LENGTH (token); /* don't modify error codes */ if (unlikely(urb->unlinked)) - return; + return status; /* force cleanup after short read; not always an error */ if (unlikely (IS_SHORT_READ (token))) - urb->status = -EREMOTEIO; + status = -EREMOTEIO; /* serious "can't proceed" faults reported by the hardware */ if (token & QTD_STS_HALT) { if (token & QTD_STS_BABBLE) { /* FIXME "must" disable babbling device's port too */ - urb->status = -EOVERFLOW; + status = -EOVERFLOW; } else if (token & QTD_STS_MMF) { /* fs/ls interrupt xfer missed the complete-split */ - urb->status = -EPROTO; + status = -EPROTO; } else if (token & QTD_STS_DBE) { - urb->status = (QTD_PID (token) == 1) /* IN ? */ + status = (QTD_PID (token) == 1) /* IN ? */ ? -ENOSR /* hc couldn't read data */ : -ECOMM; /* hc couldn't write data */ } else if (token & QTD_STS_XACT) { /* timeout, bad crc, wrong PID, etc; retried */ if (QTD_CERR (token)) - urb->status = -EPIPE; + status = -EPIPE; else { ehci_dbg (ehci, "devpath %s ep%d%s 3strikes\n", urb->dev->devpath, usb_pipeendpoint (urb->pipe), usb_pipein (urb->pipe) ? "in" : "out"); - urb->status = -EPROTO; + status = -EPROTO; } /* CERR nonzero + no errors + halt --> stall */ } else if (QTD_CERR (token)) - urb->status = -EPIPE; + status = -EPIPE; else /* unknown */ - urb->status = -EPROTO; + status = -EPROTO; ehci_vdbg (ehci, "dev%d ep%d%s qtd token %08x --> status %d\n", usb_pipedevice (urb->pipe), usb_pipeendpoint (urb->pipe), usb_pipein (urb->pipe) ? "in" : "out", - token, urb->status); + token, status); /* if async CSPLIT failed, try cleaning out the TT buffer */ - if (urb->status != -EPIPE + if (status != -EPIPE && urb->dev->tt && !usb_pipeint (urb->pipe) && ((token & QTD_STS_MMF) != 0 || QTD_CERR(token) == 0) @@ -212,10 +214,12 @@ static void qtd_copy_status ( usb_hub_tt_clear_buffer (urb->dev, urb->pipe); } } + + return status; } static void -ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb) +ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status) __releases(ehci->lock) __acquires(ehci->lock) { @@ -231,17 +235,13 @@ __acquires(ehci->lock) qh_put (qh); } - spin_lock (&urb->lock); if (unlikely(urb->unlinked)) { COUNT(ehci->stats.unlink); } else { - if (likely(urb->status == -EINPROGRESS || - (urb->status == -EREMOTEIO && - !(urb->transfer_flags & URB_SHORT_NOT_OK)))) - urb->status = 0; + if (likely(status == -EINPROGRESS)) + status = 0; COUNT(ehci->stats.complete); } - spin_unlock (&urb->lock); #ifdef EHCI_URB_TRACE ehci_dbg (ehci, @@ -249,13 +249,14 @@ __acquires(ehci->lock) __FUNCTION__, urb->dev->devpath, urb, usb_pipeendpoint (urb->pipe), usb_pipein (urb->pipe) ? "in" : "out", - urb->status, + status, urb->actual_length, urb->transfer_buffer_length); #endif /* complete() can reenter this HCD */ usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); spin_unlock (&ehci->lock); + urb->status = status; usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb); spin_lock (&ehci->lock); } @@ -276,6 +277,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) { struct ehci_qtd *last = NULL, *end = qh->dummy; struct list_head *entry, *tmp; + int last_status = -EINPROGRESS; int stopped; unsigned count = 0; int do_status = 0; @@ -304,6 +306,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) struct ehci_qtd *qtd; struct urb *urb; u32 token = 0; + int qtd_status; qtd = list_entry (entry, struct ehci_qtd, qtd_list); urb = qtd->urb; @@ -311,11 +314,12 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) /* clean up any state from previous QTD ...*/ if (last) { if (likely (last->urb != urb)) { - ehci_urb_done (ehci, last->urb); + ehci_urb_done(ehci, last->urb, last_status); count++; } ehci_qtd_free (ehci, last); last = NULL; + last_status = -EINPROGRESS; } /* ignore urbs submitted during completions we reported */ @@ -351,13 +355,13 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) stopped = 1; if (unlikely (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))) - urb->status = -ESHUTDOWN; + last_status = -ESHUTDOWN; /* ignore active urbs unless some previous qtd * for the urb faulted (including short read) or * its urb was canceled. we may patch qh or qtds. */ - if (likely(urb->status == -EINPROGRESS && + if (likely(last_status == -EINPROGRESS && !urb->unlinked)) continue; @@ -386,14 +390,14 @@ halt: } /* remove it from the queue */ - spin_lock (&urb->lock); - qtd_copy_status (ehci, urb, qtd->length, token); - if (unlikely(urb->status == -EREMOTEIO)) { + qtd_status = qtd_copy_status(ehci, urb, qtd->length, token); + if (unlikely(qtd_status == -EREMOTEIO)) { do_status = (!urb->unlinked && usb_pipecontrol(urb->pipe)); - urb->status = 0; + qtd_status = 0; } - spin_unlock (&urb->lock); + if (likely(last_status == -EINPROGRESS)) + last_status = qtd_status; if (stopped && qtd->qtd_list.prev != &qh->qtd_list) { last = list_entry (qtd->qtd_list.prev, @@ -406,7 +410,7 @@ halt: /* last urb's completion might still need calling */ if (likely (last != NULL)) { - ehci_urb_done (ehci, last->urb); + ehci_urb_done(ehci, last->urb, last_status); count++; ehci_qtd_free (ehci, last); } diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 8b267b3fd2b..80d99bce2b3 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1627,7 +1627,7 @@ itd_complete ( /* give urb back to the driver ... can be out-of-order */ dev = urb->dev; - ehci_urb_done (ehci, urb); + ehci_urb_done(ehci, urb, 0); urb = NULL; /* defer stopping schedule; completion can submit */ @@ -2000,7 +2000,7 @@ sitd_complete ( /* give urb back to the driver */ dev = urb->dev; - ehci_urb_done (ehci, urb); + ehci_urb_done(ehci, urb, 0); urb = NULL; /* defer stopping schedule; completion can submit */ -- cgit v1.2.3-70-g09d2 From 55d8496837cf124f68656e4242a5e20eb592fd54 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 15:40:34 -0400 Subject: USB: reorganize urb->status use in ohci-hcd This patch (as975) reorganizes the way ohci-hcd sets urb->status. It now keeps the information in a local variable until the last moment. Signed-off-by: Alan Stern CC: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-dbg.c | 8 ++++---- drivers/usb/host/ohci-hcd.c | 15 +++++++-------- drivers/usb/host/ohci-q.c | 38 +++++++++++++++++--------------------- 3 files changed, 28 insertions(+), 33 deletions(-) diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index f61c6cdd06f..ebab5ce8f5c 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -24,7 +24,7 @@ * small: 0) header + data packets 1) just header */ static void __maybe_unused -urb_print (struct urb * urb, char * str, int small) +urb_print(struct urb * urb, char * str, int small, int status) { unsigned int pipe= urb->pipe; @@ -34,7 +34,7 @@ urb_print (struct urb * urb, char * str, int small) } #ifndef OHCI_VERBOSE_DEBUG - if (urb->status != 0) + if (status != 0) #endif dbg("%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d", str, @@ -46,7 +46,7 @@ urb_print (struct urb * urb, char * str, int small) urb->transfer_flags, urb->actual_length, urb->transfer_buffer_length, - urb->status); + status); #ifdef OHCI_VERBOSE_DEBUG if (!small) { @@ -66,7 +66,7 @@ urb_print (struct urb * urb, char * str, int small) urb->transfer_buffer_length: urb->actual_length; for (i = 0; i < 16 && i < len; i++) printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]); - printk ("%s stat:%d\n", i < len? "...": "", urb->status); + printk ("%s stat:%d\n", i < len? "...": "", status); } } #endif diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 6b06ab69938..f7c6ced2bc0 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -129,7 +129,7 @@ static int ohci_urb_enqueue ( int retval = 0; #ifdef OHCI_VERBOSE_DEBUG - urb_print (urb, "SUB", usb_pipein (pipe)); + urb_print(urb, "SUB", usb_pipein(pipe), -EINPROGRESS); #endif /* every endpoint has a ed, locate and maybe (re)initialize it */ @@ -240,8 +240,8 @@ fail: } /* - * decouple the URB from the HC queues (TDs, urb_priv); it's - * already marked using urb->status. reporting is always done + * decouple the URB from the HC queues (TDs, urb_priv). + * reporting is always done * asynchronously, and we might be dealing with an urb that's * partially transferred, or an ED with other urbs being unlinked. */ @@ -252,7 +252,7 @@ static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) int rc; #ifdef OHCI_VERBOSE_DEBUG - urb_print (urb, "UNLINK", 1); + urb_print(urb, "UNLINK", 1, status); #endif spin_lock_irqsave (&ohci->lock, flags); @@ -277,7 +277,7 @@ static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) * any more ... just clean up every urb's memory. */ if (urb->hcpriv) - finish_urb (ohci, urb); + finish_urb(ohci, urb, status); } spin_unlock_irqrestore (&ohci->lock, flags); return rc; @@ -927,9 +927,8 @@ static int ohci_restart (struct ohci_hcd *ohci) ed, ed->state); } - spin_lock (&urb->lock); - urb->status = -ESHUTDOWN; - spin_unlock (&urb->lock); + if (!urb->unlinked) + urb->unlinked = -ESHUTDOWN; } finish_unlinks (ohci, 0); spin_unlock_irq(&ohci->lock); diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 860e55ff67a..13d31edd1a8 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -36,18 +36,15 @@ static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv) * PRECONDITION: ohci lock held, irqs blocked. */ static void -finish_urb (struct ohci_hcd *ohci, struct urb *urb) +finish_urb(struct ohci_hcd *ohci, struct urb *urb, int status) __releases(ohci->lock) __acquires(ohci->lock) { // ASSERT (urb->hcpriv != 0); urb_free_priv (ohci, urb->hcpriv); - - spin_lock (&urb->lock); - if (likely (urb->status == -EINPROGRESS)) - urb->status = 0; - spin_unlock (&urb->lock); + if (likely(status == -EINPROGRESS)) + status = 0; switch (usb_pipetype (urb->pipe)) { case PIPE_ISOCHRONOUS: @@ -59,12 +56,13 @@ __acquires(ohci->lock) } #ifdef OHCI_VERBOSE_DEBUG - urb_print (urb, "RET", usb_pipeout (urb->pipe)); + urb_print(urb, "RET", usb_pipeout (urb->pipe), status); #endif /* urb->complete() can reenter this HCD */ usb_hcd_unlink_urb_from_ep(ohci_to_hcd(ohci), urb); spin_unlock (&ohci->lock); + urb->status = status; usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb); spin_lock (&ohci->lock); @@ -702,19 +700,18 @@ static void td_submit_urb ( * Done List handling functions *-------------------------------------------------------------------------*/ -/* calculate transfer length/status and update the urb - * PRECONDITION: irqsafe (only for urb->status locking) - */ -static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) +/* calculate transfer length/status and update the urb */ +static int td_done(struct ohci_hcd *ohci, struct urb *urb, struct td *td) { u32 tdINFO = hc32_to_cpup (ohci, &td->hwINFO); int cc = 0; + int status = -EINPROGRESS; list_del (&td->td_list); /* ISO ... drivers see per-TD length/status */ if (tdINFO & TD_ISO) { - u16 tdPSW = ohci_hwPSW (ohci, td, 0); + u16 tdPSW = ohci_hwPSW(ohci, td, 0); int dlen = 0; /* NOTE: assumes FC in tdINFO == 0, and that @@ -723,7 +720,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) cc = (tdPSW >> 12) & 0xF; if (tdINFO & TD_CC) /* hc didn't touch? */ - return; + return status; if (usb_pipeout (urb->pipe)) dlen = urb->iso_frame_desc [td->index].length; @@ -756,11 +753,8 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) if (cc == TD_DATAUNDERRUN && !(urb->transfer_flags & URB_SHORT_NOT_OK)) cc = TD_CC_NOERROR; - if (cc != TD_CC_NOERROR && cc < 0x0E) { - spin_lock (&urb->lock); - urb->status = cc_to_error[cc]; - spin_unlock (&urb->lock); - } + if (cc != TD_CC_NOERROR && cc < 0x0E) + status = cc_to_error[cc]; /* count all non-empty packets except control SETUP packet */ if ((type != PIPE_CONTROL || td->index != 0) && tdBE != 0) { @@ -779,6 +773,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) urb->actual_length, urb->transfer_buffer_length); } + return status; } /*-------------------------------------------------------------------------*/ @@ -979,7 +974,7 @@ rescan_this: /* if URB is done, clean up */ if (urb_priv->td_cnt == urb_priv->length) { modified = completed = 1; - finish_urb (ohci, urb); + finish_urb(ohci, urb, 0); } } if (completed && !list_empty (&ed->td_list)) @@ -1062,14 +1057,15 @@ static void takeback_td(struct ohci_hcd *ohci, struct td *td) struct urb *urb = td->urb; urb_priv_t *urb_priv = urb->hcpriv; struct ed *ed = td->ed; + int status; /* update URB's length and status from TD */ - td_done(ohci, urb, td); + status = td_done(ohci, urb, td); urb_priv->td_cnt++; /* If all this urb's TDs are done, call complete() */ if (urb_priv->td_cnt == urb_priv->length) - finish_urb(ohci, urb); + finish_urb(ohci, urb, status); /* clean schedule: unlink EDs that are no longer busy */ if (list_empty(&ed->td_list)) { -- cgit v1.2.3-70-g09d2 From 65e51098d9094c7e840b6d6291867b95538d9442 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 15:40:47 -0400 Subject: USB: reorganize urb->status use in sl811-hcd This patch (as976) reorganizes the way sl811-hcd sets urb->status. It now keeps the information in a local variable until the last moment. The patch also improves the handling of faults during the status stage of a control transfer, since it no longer needs to retain the error information from the earlier stages. Signed-off-by: Alan Stern CC: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/sl811-hcd.c | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index f0fa94148d9..515152809d3 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -435,11 +435,8 @@ static void finish_request( if (usb_pipecontrol(urb->pipe)) ep->nextpid = USB_PID_SETUP; - spin_lock(&urb->lock); - urb->status = status; - spin_unlock(&urb->lock); - usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb); + urb->status = status; spin_unlock(&sl811->lock); usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb); spin_lock(&sl811->lock); @@ -537,27 +534,20 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank) bank + SL11H_XFERCNTREG); if (len > ep->length) { len = ep->length; - urb->status = -EOVERFLOW; + urbstat = -EOVERFLOW; } urb->actual_length += len; sl811_read_buf(sl811, SL811HS_PACKET_BUF(bank == 0), buf, len); usb_dotoggle(udev, ep->epnum, 0); - if (urb->actual_length == urb->transfer_buffer_length - || len < ep->maxpacket) - urbstat = 0; - if (usb_pipecontrol(urb->pipe) && urbstat == 0) { - - /* NOTE if the status stage STALLs (why?), - * this reports the wrong urb status. - */ - spin_lock(&urb->lock); - if (urb->status == -EINPROGRESS) - urb->status = urbstat; - spin_unlock(&urb->lock); - - urb = NULL; - ep->nextpid = USB_PID_ACK; + if (urbstat == -EINPROGRESS && + (len < ep->maxpacket || + urb->actual_length == + urb->transfer_buffer_length)) { + if (usb_pipecontrol(urb->pipe)) + ep->nextpid = USB_PID_ACK; + else + urbstat = 0; } break; case USB_PID_SETUP: @@ -597,7 +587,7 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank) bank, status, ep, urbstat); } - if (urb && (urbstat != -EINPROGRESS || urb->unlinked)) + if (urbstat != -EINPROGRESS || urb->unlinked) finish_request(sl811, ep, urb, urbstat); } -- cgit v1.2.3-70-g09d2 From 888fda47051716765175d0008450126c837adb32 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 15:41:18 -0400 Subject: USB: reorganize urb->status use in r8a66597-hcd This patch (as977) reorganizes the way r8a66597-hcd sets urb->status. It now keeps the information in a local variable until the last moment. Parts of this patch were written by Yoshihiro Shimoda. Signed-off-by: Alan Stern CC: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/r8a66597-hcd.c | 61 ++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 98b9e054754..fea6036771f 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -1109,7 +1109,7 @@ static void set_td_timer(struct r8a66597 *r8a66597, struct r8a66597_td *td) /* this function must be called with interrupt disabled */ static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td, - u16 pipenum, struct urb *urb) + u16 pipenum, struct urb *urb, int status) __releases(r8a66597->lock) __acquires(r8a66597->lock) { int restart = 0; @@ -1118,7 +1118,7 @@ __releases(r8a66597->lock) __acquires(r8a66597->lock) r8a66597->timeout_map &= ~(1 << pipenum); if (likely(td)) { - if (td->set_address && (urb->status != 0 || urb->unlinked)) + if (td->set_address && (status != 0 || urb->unlinked)) r8a66597->address_map &= ~(1 << urb->setup_packet[2]); pipe_toggle_save(r8a66597, td->pipe, urb); @@ -1135,6 +1135,7 @@ __releases(r8a66597->lock) __acquires(r8a66597->lock) usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb); + urb->status = status; spin_unlock(&r8a66597->lock); usb_hcd_giveback_urb(hcd, urb); spin_lock(&r8a66597->lock); @@ -1167,11 +1168,10 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) fifo_change_from_pipe(r8a66597, td->pipe); tmp = r8a66597_read(r8a66597, td->pipe->fifoctr); if (unlikely((tmp & FRDY) == 0)) { - urb->status = -EPIPE; pipe_stop(r8a66597, td->pipe); pipe_irq_disable(r8a66597, pipenum); err("in fifo not ready (%d)", pipenum); - finish_request(r8a66597, td, pipenum, td->urb); + finish_request(r8a66597, td, pipenum, td->urb, -EPIPE); return; } @@ -1224,10 +1224,8 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) buf, size); } - if (finish && pipenum != 0) { - td->urb->status = status; - finish_request(r8a66597, td, pipenum, urb); - } + if (finish && pipenum != 0) + finish_request(r8a66597, td, pipenum, urb, status); } static void packet_write(struct r8a66597 *r8a66597, u16 pipenum) @@ -1245,11 +1243,10 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum) fifo_change_from_pipe(r8a66597, td->pipe); tmp = r8a66597_read(r8a66597, td->pipe->fifoctr); if (unlikely((tmp & FRDY) == 0)) { - urb->status = -EPIPE; pipe_stop(r8a66597, td->pipe); pipe_irq_disable(r8a66597, pipenum); err("out write fifo not ready. (%d)", pipenum); - finish_request(r8a66597, td, pipenum, td->urb); + finish_request(r8a66597, td, pipenum, urb, -EPIPE); return; } @@ -1294,7 +1291,7 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum) } -static void check_next_phase(struct r8a66597 *r8a66597) +static void check_next_phase(struct r8a66597 *r8a66597, int status) { struct r8a66597_td *td = r8a66597_get_td(r8a66597, 0); struct urb *urb; @@ -1320,28 +1317,28 @@ static void check_next_phase(struct r8a66597 *r8a66597) break; case USB_PID_ACK: finish = 1; - urb->status = 0; break; } - if (finish || urb->unlinked) - finish_request(r8a66597, td, 0, urb); + if (finish || status != 0 || urb->unlinked) + finish_request(r8a66597, td, 0, urb, status); else start_transfer(r8a66597, td); } -static void set_urb_error(struct r8a66597 *r8a66597, u16 pipenum) +static int get_urb_error(struct r8a66597 *r8a66597, u16 pipenum) { struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum); - if (td && td->urb) { + if (td) { u16 pid = r8a66597_read(r8a66597, td->pipe->pipectr) & PID; if (pid == PID_NAK) - td->urb->status = -ECONNRESET; + return -ECONNRESET; else - td->urb->status = -EPIPE; + return -EPIPE; } + return 0; } static void irq_pipe_ready(struct r8a66597 *r8a66597) @@ -1360,7 +1357,7 @@ static void irq_pipe_ready(struct r8a66597 *r8a66597) packet_read(r8a66597, 0); else pipe_irq_disable(r8a66597, 0); - check_next_phase(r8a66597); + check_next_phase(r8a66597, 0); } for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) { @@ -1394,7 +1391,7 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597) td = r8a66597_get_td(r8a66597, 0); if (td && td->type != USB_PID_OUT) disable_irq_empty(r8a66597, 0); - check_next_phase(r8a66597); + check_next_phase(r8a66597, 0); } for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) { @@ -1409,8 +1406,8 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597) if ((tmp & INBUFM) == 0) { disable_irq_empty(r8a66597, pipenum); pipe_irq_disable(r8a66597, pipenum); - td->urb->status = 0; - finish_request(r8a66597, td, pipenum, td->urb); + finish_request(r8a66597, td, pipenum, td->urb, + 0); } } } @@ -1421,15 +1418,16 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597) u16 check; u16 pipenum; u16 mask; + int status; mask = r8a66597_read(r8a66597, NRDYSTS) & r8a66597_read(r8a66597, NRDYENB); r8a66597_write(r8a66597, ~mask, NRDYSTS); if (mask & NRDY0) { cfifo_change(r8a66597, 0); - set_urb_error(r8a66597, 0); + status = get_urb_error(r8a66597, 0); pipe_irq_disable(r8a66597, 0); - check_next_phase(r8a66597); + check_next_phase(r8a66597, status); } for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) { @@ -1440,10 +1438,10 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597) if (unlikely(!td)) continue; - set_urb_error(r8a66597, pipenum); + status = get_urb_error(r8a66597, pipenum); pipe_irq_disable(r8a66597, pipenum); pipe_stop(r8a66597, td->pipe); - finish_request(r8a66597, td, pipenum, td->urb); + finish_request(r8a66597, td, pipenum, td->urb, status); } } } @@ -1463,6 +1461,7 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd) u16 intsts0, intsts1, intsts2; u16 intenb0, intenb1, intenb2; u16 mask0, mask1, mask2; + int status; spin_lock(&r8a66597->lock); @@ -1506,12 +1505,12 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd) } if (mask1 & SIGN) { r8a66597_write(r8a66597, ~SIGN, INTSTS1); - set_urb_error(r8a66597, 0); - check_next_phase(r8a66597); + status = get_urb_error(r8a66597, 0); + check_next_phase(r8a66597, status); } if (mask1 & SACK) { r8a66597_write(r8a66597, ~SACK, INTSTS1); - check_next_phase(r8a66597); + check_next_phase(r8a66597, 0); } } if (mask0) { @@ -1790,7 +1789,7 @@ static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, pipe_stop(r8a66597, td->pipe); pipe_irq_disable(r8a66597, td->pipenum); disable_irq_empty(r8a66597, td->pipenum); - finish_request(r8a66597, td, td->pipenum, urb); + finish_request(r8a66597, td, td->pipenum, urb, status); } done: spin_unlock_irqrestore(&r8a66597->lock, flags); @@ -1824,7 +1823,7 @@ static void r8a66597_endpoint_disable(struct usb_hcd *hcd, td = r8a66597_get_td(r8a66597, pipenum); if (td) urb = td->urb; - finish_request(r8a66597, td, pipenum, urb); + finish_request(r8a66597, td, pipenum, urb, -ESHUTDOWN); kfree(hep->hcpriv); hep->hcpriv = NULL; spin_unlock_irqrestore(&r8a66597->lock, flags); -- cgit v1.2.3-70-g09d2 From 9347d51c52afcf1a77d2104f162cf8a085624c83 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 15:41:41 -0400 Subject: USB: reorganize urb->status use in usbmon This patch (as978) reorganizes the way usbmon uses urb->status. It now accepts the status value as an argument. Signed-off-by: Alan Stern Acked-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 2 +- drivers/usb/core/hcd.h | 10 ++++++---- drivers/usb/mon/mon_bin.c | 10 +++++----- drivers/usb/mon/mon_main.c | 11 ++++++----- drivers/usb/mon/mon_text.c | 10 +++++----- drivers/usb/mon/usb_mon.h | 2 +- 6 files changed, 24 insertions(+), 21 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 8b17babf5c5..4ac021e42cd 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1275,7 +1275,7 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) urb->status = -EREMOTEIO; unmap_urb_for_dma(hcd, urb); - usbmon_urb_complete(&hcd->self, urb); + usbmon_urb_complete(&hcd->self, urb, urb->status); usb_unanchor_urb(urb); /* pass ownership to the completion handler */ diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 745be2566f6..729b7a03acd 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -413,7 +413,7 @@ static inline void usbfs_cleanup(void) { } struct usb_mon_operations { void (*urb_submit)(struct usb_bus *bus, struct urb *urb); void (*urb_submit_error)(struct usb_bus *bus, struct urb *urb, int err); - void (*urb_complete)(struct usb_bus *bus, struct urb *urb); + void (*urb_complete)(struct usb_bus *bus, struct urb *urb, int status); /* void (*urb_unlink)(struct usb_bus *bus, struct urb *urb); */ }; @@ -432,10 +432,11 @@ static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb, (*mon_ops->urb_submit_error)(bus, urb, error); } -static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) +static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb, + int status) { if (bus->monitored) - (*mon_ops->urb_complete)(bus, urb); + (*mon_ops->urb_complete)(bus, urb, status); } int usb_mon_register(struct usb_mon_operations *ops); @@ -446,7 +447,8 @@ void usb_mon_deregister(void); static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb) {} static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb, int error) {} -static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {} +static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb, + int status) {} #endif /* CONFIG_USB_MON */ diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index 3d6f03819ff..f06e4e2b49d 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -386,7 +386,7 @@ static char mon_bin_get_data(const struct mon_reader_bin *rp, } static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, - char ev_type) + char ev_type, int status) { const struct usb_endpoint_descriptor *epd = &urb->ep->desc; unsigned long flags; @@ -452,7 +452,7 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, ep->id = (unsigned long) urb; ep->ts_sec = ts.tv_sec; ep->ts_usec = ts.tv_usec; - ep->status = urb->status; + ep->status = status; ep->len_urb = urb_length; ep->len_cap = length; @@ -475,13 +475,13 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, static void mon_bin_submit(void *data, struct urb *urb) { struct mon_reader_bin *rp = data; - mon_bin_event(rp, urb, 'S'); + mon_bin_event(rp, urb, 'S', -EINPROGRESS); } -static void mon_bin_complete(void *data, struct urb *urb) +static void mon_bin_complete(void *data, struct urb *urb, int status) { struct mon_reader_bin *rp = data; - mon_bin_event(rp, urb, 'C'); + mon_bin_event(rp, urb, 'C', status); } static void mon_bin_error(void *data, struct urb *urb, int error) diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c index 2e317bd79e9..b371ffd39d3 100644 --- a/drivers/usb/mon/mon_main.c +++ b/drivers/usb/mon/mon_main.c @@ -129,7 +129,8 @@ static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error) /* */ -static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb) +static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb, + int status) { unsigned long flags; struct list_head *pos; @@ -139,18 +140,18 @@ static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb) mbus->cnt_events++; list_for_each (pos, &mbus->r_list) { r = list_entry(pos, struct mon_reader, r_link); - r->rnf_complete(r->r_data, urb); + r->rnf_complete(r->r_data, urb, status); } spin_unlock_irqrestore(&mbus->lock, flags); } -static void mon_complete(struct usb_bus *ubus, struct urb *urb) +static void mon_complete(struct usb_bus *ubus, struct urb *urb, int status) { struct mon_bus *mbus; if ((mbus = ubus->mon_bus) != NULL) - mon_bus_complete(mbus, urb); - mon_bus_complete(&mon_bus0, urb); + mon_bus_complete(mbus, urb, status); + mon_bus_complete(&mon_bus0, urb, status); } /* int (*unlink_urb) (struct urb *urb, int status); */ diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 663a702a17d..ebb04ac4857 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -183,7 +183,7 @@ static inline unsigned int mon_get_timestamp(void) } static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, - char ev_type) + char ev_type, int status) { struct mon_event_text *ep; unsigned int stamp; @@ -210,7 +210,7 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, ep->length = (ev_type == 'S') ? urb->transfer_buffer_length : urb->actual_length; /* Collecting status makes debugging sense for submits, too */ - ep->status = urb->status; + ep->status = status; if (ep->xfertype == USB_ENDPOINT_XFER_INT) { ep->interval = urb->interval; @@ -248,13 +248,13 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, static void mon_text_submit(void *data, struct urb *urb) { struct mon_reader_text *rp = data; - mon_text_event(rp, urb, 'S'); + mon_text_event(rp, urb, 'S', -EINPROGRESS); } -static void mon_text_complete(void *data, struct urb *urb) +static void mon_text_complete(void *data, struct urb *urb, int status) { struct mon_reader_text *rp = data; - mon_text_event(rp, urb, 'C'); + mon_text_event(rp, urb, 'C', status); } static void mon_text_error(void *data, struct urb *urb, int error) diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h index f68ad6d99ad..f5d84ff8c10 100644 --- a/drivers/usb/mon/usb_mon.h +++ b/drivers/usb/mon/usb_mon.h @@ -46,7 +46,7 @@ struct mon_reader { void (*rnf_submit)(void *data, struct urb *urb); void (*rnf_error)(void *data, struct urb *urb, int error); - void (*rnf_complete)(void *data, struct urb *urb); + void (*rnf_complete)(void *data, struct urb *urb, int status); }; void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r); -- cgit v1.2.3-70-g09d2 From 4a00027dcb088bf90fa8fb14a7e8ba3506d78f22 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 15:42:24 -0400 Subject: USB: Eliminate urb->status usage! This patch (as979) removes the last vestiges of urb->status from the host controller drivers and the root-hub emulator. Now the field doesn't get set until just before the URB's completion routine is called. Signed-off-by: Alan Stern CC: David Brownell CC: Olav Kongas CC: Yoshihiro Shimoda CC: Tony Olech Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 22 +++++++++++----------- drivers/usb/core/hcd.h | 3 ++- drivers/usb/gadget/dummy_hcd.c | 3 +-- drivers/usb/host/ehci-q.c | 3 +-- drivers/usb/host/isp116x-hcd.c | 15 +++++---------- drivers/usb/host/ohci-q.c | 3 +-- drivers/usb/host/r8a66597-hcd.c | 8 +++----- drivers/usb/host/sl811-hcd.c | 3 +-- drivers/usb/host/u132-hcd.c | 36 +++++++++++++++++------------------- drivers/usb/host/uhci-hcd.h | 15 --------------- drivers/usb/host/uhci-q.c | 12 ++++-------- 11 files changed, 46 insertions(+), 77 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 4ac021e42cd..1c5e5d35e08 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -532,7 +532,6 @@ error: /* any errors get returned through the urb completion */ spin_lock_irq(&hcd_root_hub_lock); - urb->status = status; usb_hcd_unlink_urb_from_ep(hcd, urb); /* This peculiar use of spinlocks echoes what real HC drivers do. @@ -540,7 +539,7 @@ error: * RT-friendly. */ spin_unlock(&hcd_root_hub_lock); - usb_hcd_giveback_urb(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, status); spin_lock(&hcd_root_hub_lock); spin_unlock_irq(&hcd_root_hub_lock); @@ -578,13 +577,12 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd) if (urb) { hcd->poll_pending = 0; hcd->status_urb = NULL; - urb->status = 0; urb->actual_length = length; memcpy(urb->transfer_buffer, buffer, length); usb_hcd_unlink_urb_from_ep(hcd, urb); spin_unlock(&hcd_root_hub_lock); - usb_hcd_giveback_urb(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, 0); spin_lock(&hcd_root_hub_lock); } else { length = 0; @@ -677,7 +675,7 @@ static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) usb_hcd_unlink_urb_from_ep(hcd, urb); spin_unlock(&hcd_root_hub_lock); - usb_hcd_giveback_urb(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, status); spin_lock(&hcd_root_hub_lock); } } @@ -1252,6 +1250,7 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) * usb_hcd_giveback_urb - return URB from HCD to device driver * @hcd: host controller returning the URB * @urb: urb being returned to the USB device driver. + * @status: completion status code for the URB. * Context: in_interrupt() * * This hands the URB from HCD to its USB device driver, using its @@ -1260,25 +1259,26 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) * the device driver won't cause problems if it frees, modifies, * or resubmits this URB. * - * If @urb was unlinked, the value of @urb->status will be overridden by + * If @urb was unlinked, the value of @status will be overridden by * @urb->unlinked. Erroneous short transfers are detected in case * the HCD hasn't checked for them. */ -void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) +void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status) { urb->hcpriv = NULL; if (unlikely(urb->unlinked)) - urb->status = urb->unlinked; + status = urb->unlinked; else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && urb->actual_length < urb->transfer_buffer_length && - !urb->status)) - urb->status = -EREMOTEIO; + !status)) + status = -EREMOTEIO; unmap_urb_for_dma(hcd, urb); - usbmon_urb_complete(&hcd->self, urb, urb->status); + usbmon_urb_complete(&hcd->self, urb, status); usb_unanchor_urb(urb); /* pass ownership to the completion handler */ + urb->status = status; urb->complete (urb); atomic_dec (&urb->use_count); if (unlikely (urb->reject)) diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 729b7a03acd..0fc7b95259f 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -217,7 +217,8 @@ extern void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb); extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags); extern int usb_hcd_unlink_urb (struct urb *urb, int status); -extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb); +extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, + int status); extern void usb_hcd_endpoint_disable (struct usb_device *udev, struct usb_host_endpoint *ep); extern int usb_hcd_get_frame_number (struct usb_device *udev); diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index c1af7bab26f..58e4d720880 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -1511,8 +1511,7 @@ return_urb: usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb); spin_unlock (&dum->lock); - urb->status = status; - usb_hcd_giveback_urb (dummy_to_hcd(dum), urb); + usb_hcd_giveback_urb(dummy_to_hcd(dum), urb, status); spin_lock (&dum->lock); goto restart; diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 794d27e0780..b10f39c047e 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -256,8 +256,7 @@ __acquires(ehci->lock) /* complete() can reenter this HCD */ usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); spin_unlock (&ehci->lock); - urb->status = status; - usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb); + usb_hcd_giveback_urb(ehci_to_hcd(ehci), urb, status); spin_lock (&ehci->lock); } diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 35b3507ff40..c27417f5b9d 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -277,7 +277,7 @@ static void preproc_atl_queue(struct isp116x *isp116x) processed urbs. */ static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep, - struct urb *urb) + struct urb *urb, int status) __releases(isp116x->lock) __acquires(isp116x->lock) { unsigned i; @@ -291,7 +291,7 @@ __releases(isp116x->lock) __acquires(isp116x->lock) usb_hcd_unlink_urb_from_ep(isp116x_to_hcd(isp116x), urb); spin_unlock(&isp116x->lock); - usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb); + usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb, status); spin_lock(&isp116x->lock); /* take idle endpoints out of the schedule */ @@ -453,13 +453,8 @@ static void postproc_atl_queue(struct isp116x *isp116x) } done: - if (status != -EINPROGRESS) { - spin_lock(&urb->lock); - urb->status = status; - spin_unlock(&urb->lock); - } - if (urb->status != -EINPROGRESS || urb->unlinked) - finish_request(isp116x, ep, urb); + if (status != -EINPROGRESS || urb->unlinked) + finish_request(isp116x, ep, urb, status); } } @@ -853,7 +848,7 @@ static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, } if (urb) - finish_request(isp116x, ep, urb); + finish_request(isp116x, ep, urb, status); done: spin_unlock_irqrestore(&isp116x->lock, flags); return rc; diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 13d31edd1a8..51817322232 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -62,8 +62,7 @@ __acquires(ohci->lock) /* urb->complete() can reenter this HCD */ usb_hcd_unlink_urb_from_ep(ohci_to_hcd(ohci), urb); spin_unlock (&ohci->lock); - urb->status = status; - usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb); + usb_hcd_giveback_urb(ohci_to_hcd(ohci), urb, status); spin_lock (&ohci->lock); /* stop periodic dma if it's not needed */ diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index fea6036771f..fd00f1e33fb 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -782,12 +782,12 @@ static void force_dequeue(struct r8a66597 *r8a66597, u16 pipenum, u16 address) kfree(td); if (urb) { - urb->status = -ENODEV; usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb); spin_unlock(&r8a66597->lock); - usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb); + usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb, + -ENODEV); spin_lock(&r8a66597->lock); } break; @@ -1134,10 +1134,8 @@ __releases(r8a66597->lock) __acquires(r8a66597->lock) urb->start_frame = r8a66597_get_frame(hcd); usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb); - - urb->status = status; spin_unlock(&r8a66597->lock); - usb_hcd_giveback_urb(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, status); spin_lock(&r8a66597->lock); } diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 515152809d3..94d859aa73f 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -436,9 +436,8 @@ static void finish_request( ep->nextpid = USB_PID_SETUP; usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb); - urb->status = status; spin_unlock(&sl811->lock); - usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb); + usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb, status); spin_lock(&sl811->lock); /* leave active endpoints in the schedule */ diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index db800a434b8..2b379a78d0d 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -518,7 +518,6 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp, unsigned long irqs; struct usb_hcd *hcd = u132_to_hcd(u132); urb->error_count = 0; - urb->status = status; spin_lock_irqsave(&endp->queue_lock.slock, irqs); usb_hcd_unlink_urb_from_ep(hcd, urb); endp->queue_next += 1; @@ -542,7 +541,7 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp, u132_ring_queue_work(u132, ring, 0); up(&u132->scheduler_lock); u132_endp_put_kref(u132, endp); - usb_hcd_giveback_urb(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, status); return; } @@ -558,7 +557,6 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp, unsigned long irqs; struct usb_hcd *hcd = u132_to_hcd(u132); urb->error_count = 0; - urb->status = status; spin_lock_irqsave(&endp->queue_lock.slock, irqs); usb_hcd_unlink_urb_from_ep(hcd, urb); endp->queue_next += 1; @@ -575,7 +573,7 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp, endp->active = 0; spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); kfree(urbq); - } usb_hcd_giveback_urb(hcd, urb); + } usb_hcd_giveback_urb(hcd, urb, status); return; } @@ -719,7 +717,7 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -771,7 +769,7 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -874,7 +872,7 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -911,7 +909,7 @@ static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -983,7 +981,7 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1020,7 +1018,7 @@ static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1080,7 +1078,7 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1121,7 +1119,7 @@ static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1165,7 +1163,7 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1202,7 +1200,7 @@ static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1254,7 +1252,7 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1299,7 +1297,7 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -2428,7 +2426,7 @@ static int dequeue_from_overflow_chain(struct u132 *u132, list_del(scan); endp->queue_size -= 1; urb->error_count = 0; - usb_hcd_giveback_urb(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, 0); return 0; } else continue; @@ -2472,7 +2470,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, return 0; } else { spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - u132_hcd_abandon_urb(u132, endp, urb, urb->status); + u132_hcd_abandon_urb(u132, endp, urb, status); return 0; } } else { @@ -2513,7 +2511,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, irqs); kfree(urbq); } urb->error_count = 0; - usb_hcd_giveback_urb(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, status); return 0; } else if (list_empty(&endp->urb_more)) { dev_err(&u132->platform_dev->dev, "urb=%p not found in " diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index e46d2b0203c..340d6ed3e6e 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -456,21 +456,6 @@ struct urb_priv { }; -/* - * Locking in uhci.c - * - * Almost everything relating to the hardware schedule and processing - * of URBs is protected by uhci->lock. urb->status is protected by - * urb->lock; that's the one exception. - * - * To prevent deadlocks, never lock uhci->lock while holding urb->lock. - * The safe order of locking is: - * - * #1 uhci->lock - * #2 urb->lock - */ - - /* Some special IDs */ #define PCI_VENDOR_ID_GENESYS 0x17a0 diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index bab56726655..e5d60d5b105 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -1480,7 +1480,7 @@ done: * Finish unlinking an URB and give it back */ static void uhci_giveback_urb(struct uhci_hcd *uhci, struct uhci_qh *qh, - struct urb *urb) + struct urb *urb, int status) __releases(uhci->lock) __acquires(uhci->lock) { @@ -1520,7 +1520,7 @@ __acquires(uhci->lock) usb_hcd_unlink_urb_from_ep(uhci_to_hcd(uhci), urb); spin_unlock(&uhci->lock); - usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb); + usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb, status); spin_lock(&uhci->lock); /* If the queue is now empty, we can unlink the QH and give up its @@ -1556,10 +1556,6 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) if (status == -EINPROGRESS) break; - spin_lock(&urb->lock); - urb->status = status; - spin_unlock(&urb->lock); - /* Dequeued but completed URBs can't be given back unless * the QH is stopped or has finished unlinking. */ if (urb->unlinked) { @@ -1569,7 +1565,7 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) return; } - uhci_giveback_urb(uhci, qh, urb); + uhci_giveback_urb(uhci, qh, urb, status); if (status < 0) break; } @@ -1594,7 +1590,7 @@ restart: qh->is_stopped = 0; return; } - uhci_giveback_urb(uhci, qh, urb); + uhci_giveback_urb(uhci, qh, urb, 0); goto restart; } } -- cgit v1.2.3-70-g09d2 From 1431d2a44ccf68a547094976f363f94177ab00c6 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 15:42:39 -0400 Subject: USB: get rid of urb->lock Now that urb->status isn't used, urb->lock doesn't protect anything. This patch (as980) removes it and replaces it with a private mutex in the one remaining place it was still used: usb_kill_urb. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/urb.c | 11 ++++++----- include/linux/usb.h | 4 ---- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 19f5f66c273..76db76fdb4e 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -39,7 +39,6 @@ void usb_init_urb(struct urb *urb) if (urb) { memset(urb, 0, sizeof(*urb)); kref_init(&urb->kref); - spin_lock_init(&urb->lock); INIT_LIST_HEAD(&urb->anchor_list); } } @@ -541,19 +540,21 @@ int usb_unlink_urb(struct urb *urb) */ void usb_kill_urb(struct urb *urb) { + static DEFINE_MUTEX(reject_mutex); + might_sleep(); if (!(urb && urb->dev && urb->ep)) return; - spin_lock_irq(&urb->lock); + mutex_lock(&reject_mutex); ++urb->reject; - spin_unlock_irq(&urb->lock); + mutex_unlock(&reject_mutex); usb_hcd_unlink_urb(urb, -ENOENT); wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0); - spin_lock_irq(&urb->lock); + mutex_lock(&reject_mutex); --urb->reject; - spin_unlock_irq(&urb->lock); + mutex_unlock(&reject_mutex); } /** diff --git a/include/linux/usb.h b/include/linux/usb.h index 5c7b79088ad..5b14b4c81fd 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1241,7 +1241,6 @@ struct urb { /* private: usb core and host controller only fields in the urb */ struct kref kref; /* reference count of the URB */ - spinlock_t lock; /* lock for the URB */ void *hcpriv; /* private data for host controller */ atomic_t use_count; /* concurrent submissions counter */ u8 reject; /* submissions will fail */ @@ -1299,7 +1298,6 @@ static inline void usb_fill_control_urb (struct urb *urb, usb_complete_t complete_fn, void *context) { - spin_lock_init(&urb->lock); urb->dev = dev; urb->pipe = pipe; urb->setup_packet = setup_packet; @@ -1330,7 +1328,6 @@ static inline void usb_fill_bulk_urb (struct urb *urb, usb_complete_t complete_fn, void *context) { - spin_lock_init(&urb->lock); urb->dev = dev; urb->pipe = pipe; urb->transfer_buffer = transfer_buffer; @@ -1366,7 +1363,6 @@ static inline void usb_fill_int_urb (struct urb *urb, void *context, int interval) { - spin_lock_init(&urb->lock); urb->dev = dev; urb->pipe = pipe; urb->transfer_buffer = transfer_buffer; -- cgit v1.2.3-70-g09d2 From e015268d2fcfcaef70a1ec535e6381f75aafbf81 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 15:42:52 -0400 Subject: USB: remove traces of urb->status from usbcore This patch (as981) removes the remaining nontrivial usages of urb->status from usbcore. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 8 +++++--- drivers/usb/core/hub.c | 8 ++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index b9f1edd6af5..e5ad76b4a73 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -71,6 +71,7 @@ struct async { void __user *userbuffer; void __user *userurb; struct urb *urb; + int status; u32 secid; }; @@ -310,9 +311,10 @@ static void async_completed(struct urb *urb) spin_lock(&ps->lock); list_move_tail(&as->asynclist, &ps->async_completed); spin_unlock(&ps->lock); + as->status = urb->status; if (as->signr) { sinfo.si_signo = as->signr; - sinfo.si_errno = as->urb->status; + sinfo.si_errno = as->status; sinfo.si_code = SI_ASYNCIO; sinfo.si_addr = as->userurb; kill_pid_info_as_uid(as->signr, &sinfo, as->pid, as->uid, @@ -1132,7 +1134,7 @@ static int processcompl(struct async *as, void __user * __user *arg) if (as->userbuffer) if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length)) return -EFAULT; - if (put_user(urb->status, &userurb->status)) + if (put_user(as->status, &userurb->status)) return -EFAULT; if (put_user(urb->actual_length, &userurb->actual_length)) return -EFAULT; @@ -1246,7 +1248,7 @@ static int processcompl_compat(struct async *as, void __user * __user *arg) if (as->userbuffer) if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length)) return -EFAULT; - if (put_user(urb->status, &userurb->status)) + if (put_user(as->status, &userurb->status)) return -EFAULT; if (put_user(urb->actual_length, &userurb->actual_length)) return -EFAULT; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 4c495c4d505..bd08d51d7f4 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -347,11 +347,11 @@ void usb_kick_khubd(struct usb_device *hdev) static void hub_irq(struct urb *urb) { struct usb_hub *hub = urb->context; - int status; + int status = urb->status; int i; unsigned long bits; - switch (urb->status) { + switch (status) { case -ENOENT: /* synchronous unlink */ case -ECONNRESET: /* async unlink */ case -ESHUTDOWN: /* hardware going away */ @@ -359,10 +359,10 @@ static void hub_irq(struct urb *urb) default: /* presumably an error */ /* Cause a hub reset after 10 consecutive errors */ - dev_dbg (hub->intfdev, "transfer --> %d\n", urb->status); + dev_dbg (hub->intfdev, "transfer --> %d\n", status); if ((++hub->nerrors < 10) || hub->error) goto resubmit; - hub->error = urb->status; + hub->error = status; /* FALL THROUGH */ /* let khubd handle things */ -- cgit v1.2.3-70-g09d2 From 63f991b2871bdb1431e8ff62cae2b7b94b4e5b0c Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 4 Sep 2007 09:53:24 -0400 Subject: USB: fix location of statement label in dummy-hcd This patch (as984) fixes a rather elementary mistake in dummy_hcd. The new statement label should come before the spin_unlock_irqrestore, not after it. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 58e4d720880..6479a36d6f0 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -1001,8 +1001,8 @@ static int dummy_urb_enqueue ( if (!timer_pending (&dum->timer)) mod_timer (&dum->timer, jiffies + 1); - spin_unlock_irqrestore (&dum->lock, flags); done: + spin_unlock_irqrestore(&dum->lock, flags); return rc; } -- cgit v1.2.3-70-g09d2 From d853d872c14b9adc4adad29e56cd378b291f86e0 Mon Sep 17 00:00:00 2001 From: Johann Wilhelm Date: Wed, 5 Sep 2007 13:49:29 +0200 Subject: USB: usb-storage: Initialize Huawei E220 properly This is a reworked version of this patch: http://www.mail-archive.com/linux-usb-devel%40lists.sourceforge.net/msg55094/activate_huawei_dev.patch That properly initializes the HUAWEI E220 devices into multi-port mode. Signed-off-by: Johann Wilhelm Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/initializers.c | 14 ++++++++++++++ drivers/usb/storage/initializers.h | 3 +++ drivers/usb/storage/unusual_devs.h | 11 +++++++++++ 3 files changed, 28 insertions(+) diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c index 3a41740cad9..ee5b42aa536 100644 --- a/drivers/usb/storage/initializers.c +++ b/drivers/usb/storage/initializers.c @@ -90,3 +90,17 @@ int usb_stor_ucr61s2b_init(struct us_data *us) return (res ? -1 : 0); } + +/* This places the HUAWEI E220 devices in multi-port mode */ +int usb_stor_huawei_e220_init(struct us_data *us) +{ + int result; + + us->iobuf[0] = 0x1; + result = usb_stor_control_msg(us, us->send_ctrl_pipe, + USB_REQ_SET_FEATURE, + USB_TYPE_STANDARD | USB_RECIP_DEVICE, + 0x01, 0x0, us->iobuf, 0x1, 1000); + US_DEBUGP("usb_control_msg performing result is %d\n", result); + return (result ? 0 : -1); +} diff --git a/drivers/usb/storage/initializers.h b/drivers/usb/storage/initializers.h index e2967a4d48a..ad3ffd4236c 100644 --- a/drivers/usb/storage/initializers.h +++ b/drivers/usb/storage/initializers.h @@ -47,3 +47,6 @@ int usb_stor_euscsi_init(struct us_data *us); /* This function is required to activate all four slots on the UCR-61S2B * flash reader */ int usb_stor_ucr61s2b_init(struct us_data *us); + +/* This places the HUAWEI E220 devices in multi-port mode */ +int usb_stor_huawei_e220_init(struct us_data *us); diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index c6b78ba815e..94b1dd2aeb3 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1463,6 +1463,17 @@ UNUSUAL_DEV( 0x1210, 0x0003, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), +/* Reported by fangxiaozhi + * and by linlei + * Patch reworked by Johann Wilhelm + * This brings the HUAWEI E220 devices into multi-port mode + */ +UNUSUAL_DEV( 0x12d1, 0x1003, 0x0000, 0x0000, + "HUAWEI MOBILE", + "Mass Storage", + US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init, + 0), + /* Reported by Vilius Bilinkevicius Date: Thu, 6 Sep 2007 23:18:15 +0200 Subject: USB: ELAN U132 Host Controller Driver: convert sw_lock to mutex The ELAN U132 Host Controller Driver uses the semaphore sw_lock as mutex. Use the mutex API instead of the (binary) semaphore. Signed-off-by: Matthias Kaehlcke Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/u132-hcd.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 2b379a78d0d..ac283b09a63 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -183,7 +183,7 @@ struct u132_ring { struct u132 { struct kref kref; struct list_head u132_list; - struct semaphore sw_lock; + struct mutex sw_lock; struct semaphore scheduler_lock; struct u132_platform_data *board; struct platform_device *platform_dev; @@ -492,20 +492,20 @@ static void u132_hcd_monitor_work(struct work_struct *work) return; } else { int retval; - down(&u132->sw_lock); + mutex_lock(&u132->sw_lock); retval = read_roothub_info(u132); if (retval) { struct usb_hcd *hcd = u132_to_hcd(u132); u132_disable(u132); u132->going = 1; - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); usb_hc_died(hcd); ftdi_elan_gone_away(u132->platform_dev); u132_monitor_put_kref(u132); return; } else { u132_monitor_requeue_work(u132, 500); - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); return; } } @@ -1802,10 +1802,10 @@ static void u132_hcd_stop(struct usb_hcd *hcd) dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov" "ed\n", hcd); } else { - down(&u132->sw_lock); + mutex_lock(&u132->sw_lock); msleep(100); u132_power(u132, 0); - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); } } @@ -1827,7 +1827,7 @@ static int u132_hcd_start(struct usb_hcd *hcd) (pdev->dev.platform_data))->vendor; u16 device = ((struct u132_platform_data *) (pdev->dev.platform_data))->device; - down(&u132->sw_lock); + mutex_lock(&u132->sw_lock); msleep(10); if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) { u132->flags = OHCI_QUIRK_AMD756; @@ -1842,7 +1842,7 @@ static int u132_hcd_start(struct usb_hcd *hcd) u132->going = 1; } msleep(100); - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); return retval; } else { dev_err(&u132->platform_dev->dev, "platform_device missing\n"); @@ -1862,13 +1862,13 @@ static int u132_hcd_reset(struct usb_hcd *hcd) return -ESHUTDOWN; } else { int retval; - down(&u132->sw_lock); + mutex_lock(&u132->sw_lock); retval = u132_init(u132); if (retval) { u132_disable(u132); u132->going = 1; } - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); return retval; } } @@ -2865,7 +2865,7 @@ static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, return -ESHUTDOWN; } else { int retval = 0; - down(&u132->sw_lock); + mutex_lock(&u132->sw_lock); switch (typeReq) { case ClearHubFeature: switch (wValue) { @@ -2928,7 +2928,7 @@ static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, stall:retval = -EPIPE; break; } - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); return retval; } } @@ -3064,7 +3064,7 @@ static int __devexit u132_remove(struct platform_device *pdev) dev_err(&u132->platform_dev->dev, "removing device u132" ".%d\n", u132->sequence_num); msleep(100); - down(&u132->sw_lock); + mutex_lock(&u132->sw_lock); u132_monitor_cancel_work(u132); while (rings-- > 0) { struct u132_ring *ring = &u132->ring[rings]; @@ -3077,7 +3077,7 @@ static int __devexit u132_remove(struct platform_device *pdev) u132->going += 1; printk(KERN_INFO "removing device u132.%d\n", u132->sequence_num); - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); usb_remove_hcd(hcd); u132_u132_put_kref(u132); return 0; @@ -3097,7 +3097,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev) u132->platform_dev = pdev; u132->power = 0; u132->reset = 0; - init_MUTEX(&u132->sw_lock); + mutex_init(&u132->sw_lock); init_MUTEX(&u132->scheduler_lock); while (rings-- > 0) { struct u132_ring *ring = &u132->ring[rings]; @@ -3107,7 +3107,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev) ring->curr_endp = NULL; INIT_DELAYED_WORK(&ring->scheduler, u132_hcd_ring_work_scheduler); - } down(&u132->sw_lock); + } mutex_lock(&u132->sw_lock); INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work); while (ports-- > 0) { struct u132_port *port = &u132->port[ports]; @@ -3137,7 +3137,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev) while (endps-- > 0) { u132->endp[endps] = NULL; } - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); return; } -- cgit v1.2.3-70-g09d2 From 5adceac5da3d353dd1318d0482cab94a79472adf Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 17 Aug 2007 14:01:38 +0200 Subject: USB: fix errornous assumption in the usb serial framework revealed by iuu_phoenix the iuu_phoenix driver submits another URB from a completion handler. This dictates a certain order of calls to usb_kill_urb() in kill_traffic(). As other drivers may do it the other way round, we need to use both orders in kill_traffic(). This patch does so and should be merged before iuu_phoenix is merged. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/usb-serial.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 9bf01a5efc8..26e015c39a3 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -578,6 +578,17 @@ static void kill_traffic(struct usb_serial_port *port) { usb_kill_urb(port->read_urb); usb_kill_urb(port->write_urb); + /* + * This is tricky. + * Some drivers submit the read_urb in the + * handler for the write_urb or vice versa + * this order determines the order in which + * usb_kill_urb() must be used to reliably + * kill the URBs. As it is unknown here, + * both orders must be used in turn. + * The call below is not redundant. + */ + usb_kill_urb(port->read_urb); usb_kill_urb(port->interrupt_in_urb); usb_kill_urb(port->interrupt_out_urb); } -- cgit v1.2.3-70-g09d2 From e6d42f0e962390e956545aa282efb05a9d6a41d1 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Mon, 3 Sep 2007 01:37:31 +0530 Subject: USB: sisusbvga: Fix bug drivers/usb/misc/sisusbvga/sisusb.c: In function sisusb_open drivers/usb/misc/sisusbvga/sisusb.c:2444: warning: sisusb is used uninitialized in this function is a genuine bug (which will cause oops). We cannot use "sisusb" in error path for (!interface), because sisusb will itself be derived from "interface" later. Signed-off-by: Satyam Sharma Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 4d6b89336e6..033bdfe9b21 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -2440,10 +2440,8 @@ sisusb_open(struct inode *inode, struct file *file) struct usb_interface *interface; int subminor = iminor(inode); - if (!(interface = usb_find_interface(&sisusb_driver, subminor))) { - dev_err(&sisusb->sisusb_dev->dev, "Failed to find interface\n"); + if (!(interface = usb_find_interface(&sisusb_driver, subminor))) return -ENODEV; - } if (!(sisusb = usb_get_intfdata(interface))) return -ENODEV; -- cgit v1.2.3-70-g09d2 From 1d3ee41e9549609a6151216a0bcb06b758a64b6b Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 27 Aug 2007 16:16:13 -0700 Subject: USB: AMD5536: use pdev->revision Signed-off-by: Auke Kok Cc: Thomas Dahlmann Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/amd5536udc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index e95ffc9eee3..bdd5f2284b3 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -3285,14 +3285,12 @@ static int udc_pci_probe( pci_set_drvdata(pdev, dev); - /* chip revision */ - dev->chiprev = 0; + /* chip revision for Hs AMD5536 */ + dev->chiprev = pdev->revision; pci_set_master(pdev); pci_set_mwi(pdev); - /* chip rev for Hs AMD5536 */ - pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) &dev->chiprev); /* init dma pools */ if (use_dma) { retval = init_dma_pools(dev); -- cgit v1.2.3-70-g09d2 From 7477120e34eef65a530cfb3fea5fe612c89669e5 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 10 Sep 2007 11:35:14 -0400 Subject: USB: Get rid of annoying endpoint-release message This patch (as990) removes an annoying debugging message. Nobody really cares when endpoint pseudo-devices are released. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/endpoint.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c index e0ec7045e86..7dc123d6b2d 100644 --- a/drivers/usb/core/endpoint.c +++ b/drivers/usb/core/endpoint.c @@ -267,7 +267,6 @@ static void ep_device_release(struct device *dev) { struct ep_device *ep_dev = to_ep_device(dev); - dev_dbg(dev, "%s called for %s\n", __FUNCTION__, dev->bus_id); endpoint_free_minor(ep_dev); kfree(ep_dev); } -- cgit v1.2.3-70-g09d2 From 5ad4f71e2f19a06f738463da1f09ea7fda3a3db2 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 10 Sep 2007 11:31:43 -0400 Subject: USB: move decision to ignore FREEZE events This patch (as987) changes the way FREEZE and PRETHAW suspend events are handled in usbcore. The decision about whether or not to ignore them for non-root devices is pushed down into the USB-device driver, instead of being made in the core code. This is appropriate, since devices exported to a virtualized guest or over a network may indeed need to handle these types of suspend, even though normal devices don't. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 9 +-------- drivers/usb/core/generic.c | 5 +++++ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 8da4801bb92..ca43a6f824a 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1088,15 +1088,8 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) break; } } - if (status == 0) { - - /* Non-root devices don't need to do anything for FREEZE - * or PRETHAW. */ - if (udev->parent && (msg.event == PM_EVENT_FREEZE || - msg.event == PM_EVENT_PRETHAW)) - goto done; + if (status == 0) status = usb_suspend_device(udev, msg); - } /* If the suspend failed, resume interfaces that did get suspended */ if (status != 0) { diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 9148b69785c..c1cb94e9f24 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -206,8 +206,13 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg) */ if (!udev->parent) rc = hcd_bus_suspend(udev); + + /* Non-root devices don't need to do anything for FREEZE or PRETHAW */ + else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW) + rc = 0; else rc = usb_port_suspend(udev); + return rc; } -- cgit v1.2.3-70-g09d2 From 95cf82f99cfbd697c15572c444bd4f54f19745b0 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 10 Sep 2007 11:33:05 -0400 Subject: USB: break apart flush_endpoint and disable_endpoint This patch (as988) breaks usb_hcd_endpoint_disable() apart into two routines. The first, usb_hcd_flush_endpoint() does the -ESHUTDOWN unlinking of all URBs in the endpoint's queue and waits for them to complete. The second, usb_hcd_disable_endpoint() -- renamed for better grammatical style -- merely calls the HCD's endpoint_disable method. The changeover is easy because the routine currently has only one caller. This separation of function will be exploited in the following patch: When a device is suspended, the core will be able to cancel all outstanding URBs for that device while leaving the HCD's endpoint-related data structures intact for later. As an added benefit, HCDs no longer need to check for existing URBs in their endpoint_disable methods. It is now guaranteed that there will be none. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 48 ++++++++++++++++++++++++++-------------------- drivers/usb/core/hcd.h | 4 +++- drivers/usb/core/message.c | 3 ++- 3 files changed, 32 insertions(+), 23 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 1c5e5d35e08..e5874e8b8cb 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1289,24 +1289,22 @@ EXPORT_SYMBOL (usb_hcd_giveback_urb); /*-------------------------------------------------------------------------*/ -/* disables the endpoint: cancels any pending urbs, then synchronizes with - * the hcd to make sure all endpoint state is gone from hardware, and then - * waits until the endpoint's queue is completely drained. use for - * set_configuration, set_interface, driver removal, physical disconnect. - * - * example: a qh stored in ep->hcpriv, holding state related to endpoint - * type, maxpacket size, toggle, halt status, and scheduling. +/* Cancel all URBs pending on this endpoint and wait for the endpoint's + * queue to drain completely. The caller must first insure that no more + * URBs can be submitted for this endpoint. */ -void usb_hcd_endpoint_disable (struct usb_device *udev, +void usb_hcd_flush_endpoint(struct usb_device *udev, struct usb_host_endpoint *ep) { struct usb_hcd *hcd; struct urb *urb; + if (!ep) + return; might_sleep(); hcd = bus_to_hcd(udev->bus); - /* ep is already gone from udev->ep_{in,out}[]; no more submits */ + /* No more submits can occur */ rescan: spin_lock_irq(&hcd_urb_list_lock); list_for_each_entry (urb, &ep->urb_list, urb_list) { @@ -1345,18 +1343,7 @@ rescan: } spin_unlock_irq(&hcd_urb_list_lock); - /* synchronize with the hardware, so old configuration state - * clears out immediately (and will be freed). - */ - if (hcd->driver->endpoint_disable) - hcd->driver->endpoint_disable (hcd, ep); - - /* Wait until the endpoint queue is completely empty. Most HCDs - * will have done this already in their endpoint_disable method, - * but some might not. And there could be root-hub control URBs - * still pending since they aren't affected by the HCDs' - * endpoint_disable methods. - */ + /* Wait until the endpoint queue is completely empty */ while (!list_empty (&ep->urb_list)) { spin_lock_irq(&hcd_urb_list_lock); @@ -1376,6 +1363,25 @@ rescan: } } +/* Disables the endpoint: synchronizes with the hcd to make sure all + * endpoint state is gone from hardware. usb_hcd_flush_endpoint() must + * have been called previously. Use for set_configuration, set_interface, + * driver removal, physical disconnect. + * + * example: a qh stored in ep->hcpriv, holding state related to endpoint + * type, maxpacket size, toggle, halt status, and scheduling. + */ +void usb_hcd_disable_endpoint(struct usb_device *udev, + struct usb_host_endpoint *ep) +{ + struct usb_hcd *hcd; + + might_sleep(); + hcd = bus_to_hcd(udev->bus); + if (hcd->driver->endpoint_disable) + hcd->driver->endpoint_disable(hcd, ep); +} + /*-------------------------------------------------------------------------*/ /* called in any context */ diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 0fc7b95259f..1396141274f 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -219,7 +219,9 @@ extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags); extern int usb_hcd_unlink_urb (struct urb *urb, int status); extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status); -extern void usb_hcd_endpoint_disable (struct usb_device *udev, +extern void usb_hcd_flush_endpoint(struct usb_device *udev, + struct usb_host_endpoint *ep); +extern void usb_hcd_disable_endpoint(struct usb_device *udev, struct usb_host_endpoint *ep); extern int usb_hcd_get_frame_number (struct usb_device *udev); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index d638375e22e..98fcddba690 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1017,7 +1017,8 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr) } if (ep) { ep->enabled = 0; - usb_hcd_endpoint_disable(dev, ep); + usb_hcd_flush_endpoint(dev, ep); + usb_hcd_disable_endpoint(dev, ep); } } -- cgit v1.2.3-70-g09d2 From 6840d2555afd66290be7a39b400b5e66a840b82d Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 10 Sep 2007 11:34:26 -0400 Subject: USB: flush outstanding URBs when suspending This patch (as989) makes usbcore flush all outstanding URBs for each device as the device is suspended. This will be true even when CONFIG_USB_SUSPEND is not enabled. In addition, an extra can_submit flag is added to the usb_device structure. That flag will be turned off whenever a suspend request has been received for the device, even if the device isn't actually suspended because CONFIG_USB_SUSPEND isn't set. It's no longer necessary to check for the device state being equal to USB_STATE_SUSPENDED during URB submission; that check can be replaced by a check of the can_submit flag. This also permits us to remove some questionable references to the deprecated power.power_state field. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 10 +++++++++- drivers/usb/core/hcd.c | 5 +++++ drivers/usb/core/hub.c | 9 +-------- drivers/usb/core/urb.c | 3 --- drivers/usb/core/usb.c | 1 + include/linux/usb.h | 1 + 6 files changed, 17 insertions(+), 12 deletions(-) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index ca43a6f824a..ba5bbc7eedc 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1102,9 +1102,16 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) if (udev->auto_pm) autosuspend_check(udev); - /* If the suspend succeeded, propagate it up the tree */ + /* If the suspend succeeded then prevent any more URB submissions, + * flush any outstanding URBs, and propagate the suspend up the tree. + */ } else { cancel_delayed_work(&udev->autosuspend); + udev->can_submit = 0; + for (i = 0; i < 16; ++i) { + usb_hcd_flush_endpoint(udev, udev->ep_out[i]); + usb_hcd_flush_endpoint(udev, udev->ep_in[i]); + } if (parent) usb_autosuspend_device(parent); } @@ -1154,6 +1161,7 @@ static int usb_resume_both(struct usb_device *udev) status = -ENODEV; goto done; } + udev->can_submit = 1; /* Propagate the resume up the tree, if necessary */ if (udev->state == USB_STATE_SUSPENDED) { diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index e5874e8b8cb..2c79aa6ca2b 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1014,6 +1014,11 @@ int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb) goto done; } + if (unlikely(!urb->dev->can_submit)) { + rc = -EHOSTUNREACH; + goto done; + } + /* * Check the host controller's state and add the URB to the * endpoint's queue. diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index bd08d51d7f4..691acf2223c 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1955,14 +1955,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) struct usb_device *udev; udev = hdev->children [port1-1]; - if (udev && msg.event == PM_EVENT_SUSPEND && -#ifdef CONFIG_USB_SUSPEND - udev->state != USB_STATE_SUSPENDED -#else - udev->dev.power.power_state.event - == PM_EVENT_ON -#endif - ) { + if (udev && udev->can_submit) { if (!hdev->auto_pm) dev_dbg(&intf->dev, "port %d nyet suspended\n", port1); diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 76db76fdb4e..c20c03aaf01 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -286,9 +286,6 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) return -EINVAL; if (!(dev = urb->dev) || dev->state < USB_STATE_DEFAULT) return -ENODEV; - if (dev->bus->controller->power.power_state.event != PM_EVENT_ON - || dev->state == USB_STATE_SUSPENDED) - return -EHOSTUNREACH; /* For now, get the endpoint from the pipe. Eventually drivers * will be required to set urb->ep directly and we will eliminate diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index e5ff161776f..8121edbd149 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -272,6 +272,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT; /* ep0 maxpacket comes later, from device descriptor */ usb_enable_endpoint(dev, &dev->ep0); + dev->can_submit = 1; /* Save readable and stable topology id, distinguishing devices * by location for diagnostics, tools, driver model, etc. The diff --git a/include/linux/usb.h b/include/linux/usb.h index 5b14b4c81fd..e5b35e0dca2 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -383,6 +383,7 @@ struct usb_device { u8 portnum; /* Parent port number (origin 1) */ u8 level; /* Number of USB hub ancestors */ + unsigned can_submit:1; /* URBs may be submitted */ unsigned discon_suspended:1; /* Disconnected while suspended */ unsigned have_langid:1; /* whether string_langid is valid */ unsigned authorized:1; /* Policy has determined we can use it */ -- cgit v1.2.3-70-g09d2 From f7294055a7a5bf1ea7da16dffb0cb0f7a282c04b Mon Sep 17 00:00:00 2001 From: Mark Gross Date: Mon, 24 Sep 2007 09:28:14 -0700 Subject: USB: usb-skeleton leaking locks on open This weekend I was hacking around with a trivial USB driver for talking to the boot load firmware of a USB Bit Whacker. It's running the MicroChip Pic18 boot loader firmware and I'm putting together a flash program for writing new FW to the thing. Anyway in my use of the usb-skeleton.c as my starting point I discovered my test program was getting hung up after attempting to write a buffer. The application and driver where hung in a way that required me to reboot to get it to clean up so I could try again. It turned out the code path through skel_open can grap the driver's io_mutex lock and forget to release it. The following patch fixes the problem for me. Signed-off-by: Mark Gross Cc: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usb-skeleton.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index 8de11deb5d1..c815a40e167 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -125,6 +125,7 @@ static int skel_open(struct inode *inode, struct file *file) /* save our object in the file's private structure */ file->private_data = dev; + mutex_unlock(&dev->io_mutex); exit: return retval; -- cgit v1.2.3-70-g09d2 From 0e66fb3492442faa17fc7f27a3eba35b3c811e38 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 11 Sep 2007 19:10:21 +0200 Subject: USB: always visit drivers/usb/misc/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, every driver under drivers/usb/misc/ also has to be listed in drivers/usb/Makefile. This has been forgotten more than once, and this patch changes drivers/usb/Makefile to simply always visit drivers/usb/misc/ when building the USB code. Signed-off-by: Adrian Bunk Cc: Toralf Förster Acked-by: Satyam Sharma Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Makefile | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index cce216517ca..516a6400db4 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -28,28 +28,7 @@ obj-$(CONFIG_USB_MICROTEK) += image/ obj-$(CONFIG_USB_SERIAL) += serial/ -obj-$(CONFIG_USB_ADUTUX) += misc/ -obj-$(CONFIG_USB_APPLEDISPLAY) += misc/ -obj-$(CONFIG_USB_AUERSWALD) += misc/ -obj-$(CONFIG_USB_BERRY_CHARGE) += misc/ -obj-$(CONFIG_USB_CYPRESS_CY7C63)+= misc/ -obj-$(CONFIG_USB_CYTHERM) += misc/ -obj-$(CONFIG_USB_EMI26) += misc/ -obj-$(CONFIG_USB_EMI62) += misc/ -obj-$(CONFIG_USB_FTDI_ELAN) += misc/ -obj-$(CONFIG_USB_IDMOUSE) += misc/ -obj-$(CONFIG_USB_IOWARRIOR) += misc/ -obj-$(CONFIG_USB_LCD) += misc/ -obj-$(CONFIG_USB_LD) += misc/ -obj-$(CONFIG_USB_LED) += misc/ -obj-$(CONFIG_USB_LEGOTOWER) += misc/ -obj-$(CONFIG_USB_PHIDGETSERVO) += misc/ -obj-$(CONFIG_USB_RIO500) += misc/ -obj-$(CONFIG_USB_SISUSBVGA) += misc/ -obj-$(CONFIG_USB_TEST) += misc/ -obj-$(CONFIG_USB_TRANCEVIBRATOR)+= misc/ -obj-$(CONFIG_USB_USS720) += misc/ -obj-$(CONFIG_USB_IOWARRIOR) += misc/ +obj-$(CONFIG_USB) += misc/ obj-$(CONFIG_USB_ATM) += atm/ obj-$(CONFIG_USB_SPEEDTOUCH) += atm/ -- cgit v1.2.3-70-g09d2 From ed6590a861a16276db34ee626375fa79f3369ac3 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Mon, 17 Sep 2007 20:15:53 +0200 Subject: USB: fix double frees in error code paths of ipaq driver the error code paths can be enter with buffers to freed buffers. Serial core would do a kfree() on memory already freed. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ipaq.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 6a3a704b584..c1a6484f652 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -646,11 +646,13 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp) kfree(port->bulk_out_buffer); port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL); if (port->bulk_in_buffer == NULL) { + port->bulk_out_buffer = NULL; /* prevent double free */ goto enomem; } port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL); if (port->bulk_out_buffer == NULL) { kfree(port->bulk_in_buffer); + port->bulk_in_buffer = NULL; goto enomem; } port->read_urb->transfer_buffer = port->bulk_in_buffer; -- cgit v1.2.3-70-g09d2 From 403fae78d7388876b96fbe30ccf2cb551c49ae5a Mon Sep 17 00:00:00 2001 From: jidong xiao Date: Fri, 14 Sep 2007 00:08:51 +0800 Subject: USB: fix limited_power setting mistake in hub.c This patch (jx001) fixes a variable assignment mistake in hub driver. limited_power should be set to 0 if the hub is self-powered,and 1 if the hub is bus-powered. However, the effect of the code was exactly opposite to the spec's statement for the Local Power Source field. The spec says, this field is 1 meaning Local power supply lost while this field is 0 indicating Local power supply good.(This statement is very confusing.) So this patch switchs the 0 and 1. Signed-off-by: Jason Xiao Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 691acf2223c..481dca641ea 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2818,9 +2818,9 @@ static void hub_events(void) clear_hub_feature(hdev, C_HUB_LOCAL_POWER); if (hubstatus & HUB_STATUS_LOCAL_POWER) /* FIXME: Is this always true? */ - hub->limited_power = 0; - else hub->limited_power = 1; + else + hub->limited_power = 0; } if (hubchange & HUB_CHANGE_OVERCURRENT) { dev_dbg (hub_dev, "overcurrent change\n"); -- cgit v1.2.3-70-g09d2 From 393e5511a5f58e82b88589f1dd2464f6b661df06 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 18 Sep 2007 10:09:32 -0400 Subject: USB: unusual_devs update for Nokia 6131 This patch (as991) updates the unusual_devs entry for the Nokia 6131 phone. As reported by Juan Ignacio Cherrutti, there's new firmware available but it still has the same old transfer-size limit. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 94b1dd2aeb3..b0ff0295580 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -198,7 +198,7 @@ UNUSUAL_DEV( 0x0421, 0x044e, 0x0100, 0x0100, US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), /* Reported by Bardur Arantsson */ -UNUSUAL_DEV( 0x0421, 0x047c, 0x0370, 0x0370, +UNUSUAL_DEV( 0x0421, 0x047c, 0x0370, 0x0610, "Nokia", "6131", US_SC_DEVICE, US_PR_DEVICE, NULL, -- cgit v1.2.3-70-g09d2 From 7108f28465a0a37d5afc05c5ad788938423b74a7 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 20 Sep 2007 12:37:50 -0400 Subject: USB: don't propagate FREEZE or PRETHAW suspends This patch (as992) fixes a recently-added bug. During a FREEZE or PRETHAW suspend notification, non-root devices don't actually get suspended. So we shouldn't tell their parent hubs that they did. (This code path used to be skipped over, until the FREEZE/PRETHAW test got moved out of usb_suspend_both() into generic_suspend().) Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index ba5bbc7eedc..3f734240e0e 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1112,7 +1112,12 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) usb_hcd_flush_endpoint(udev, udev->ep_out[i]); usb_hcd_flush_endpoint(udev, udev->ep_in[i]); } - if (parent) + + /* If this is just a FREEZE or a PRETHAW, udev might + * not really be suspended. Only true suspends get + * propagated up the device tree. + */ + if (parent && udev->state == USB_STATE_SUSPENDED) usb_autosuspend_device(parent); } -- cgit v1.2.3-70-g09d2 From a691efa9888e71232dfb4088fb8a8304ffc7b0f9 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 21 Sep 2007 16:57:54 -0400 Subject: USB: remove USB_QUIRK_NO_AUTOSUSPEND This patch (as995) cleans up the remains of the former NO_AUTOSUSPEND quirk. Since autosuspend is disabled by default, we will let userspace worry about which devices can safely be suspended. Thus the lengthy series of quirk entries is no longer needed, and neither is the quirk ID. I suppose someone might eventually run across a hub that can't be suspended; let's ignore the possibility for now. The patch also cleans up the hasty way in which autosuspend gets disabled. Setting udev->autosuspend_delay to -1 wasn't quite right, because the value is always supposed to be a multiple of HZ. It's better to leave the delay value alone and set autosuspend_disabled, which is what the quirk routine used to do. Signed-off-by: Alan Stern Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/quirks.c | 81 +--------------------------------------------- include/linux/usb/quirks.h | 7 ++-- 2 files changed, 3 insertions(+), 85 deletions(-) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index ebf3dc20110..d42c561c75f 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -32,52 +32,6 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME }, /* HP 5300/5370C scanner */ { USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 }, - /* Hewlett-Packard PhotoSmart 720 / PhotoSmart 935 (storage) */ - { USB_DEVICE(0x03f0, 0x4002), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* SGS Thomson Microelectronics 4in1 card reader */ - { USB_DEVICE(0x0483, 0x0321), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* Acer Peripherals Inc. (now BenQ Corp.) Prisa 640BU */ - { USB_DEVICE(0x04a5, 0x207e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Benq S2W 3300U */ - { USB_DEVICE(0x04a5, 0x20b0), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Canon, Inc. CanoScan N1240U/LiDE30 */ - { USB_DEVICE(0x04a9, 0x220e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Canon, Inc. CanoScan N650U/N656U */ - { USB_DEVICE(0x04a9, 0x2206), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Canon, Inc. CanoScan 1220U */ - { USB_DEVICE(0x04a9, 0x2207), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Canon, Inc. CanoScan N670U/N676U/LiDE 20 */ - { USB_DEVICE(0x04a9, 0x220d), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* old Cannon scanner */ - { USB_DEVICE(0x04a9, 0x2220), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Seiko Epson Corp. Perfection 1200 */ - { USB_DEVICE(0x04b8, 0x0104), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Seiko Epson Corp. Perfection 660 */ - { USB_DEVICE(0x04b8, 0x0114), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Epson Perfection 1260 Photo */ - { USB_DEVICE(0x04b8, 0x011d), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Seiko Epson Corp - Perfection 1670 */ - { USB_DEVICE(0x04b8, 0x011f), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* EPSON Perfection 2480 */ - { USB_DEVICE(0x04b8, 0x0121), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Seiko Epson Corp.*/ - { USB_DEVICE(0x04b8, 0x0122), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Samsung ML-2010 printer */ - { USB_DEVICE(0x04e8, 0x326c), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Samsung ML-2510 Series printer */ - { USB_DEVICE(0x04e8, 0x327e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Elsa MicroLink 56k (V.250) */ - { USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Ultima Electronics Corp.*/ - { USB_DEVICE(0x05d8, 0x4005), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* Genesys USB-to-IDE */ - { USB_DEVICE(0x0503, 0x0702), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* USB Graphical LCD - EEH Datalink GmbH */ - { USB_DEVICE(0x060c, 0x04eb), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, /* INTEL VALUE SSD */ { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME }, @@ -85,44 +39,15 @@ static const struct usb_device_id usb_quirk_list[] = { /* M-Systems Flash Disk Pioneers */ { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME }, - /* Agfa Snapscan1212u */ - { USB_DEVICE(0x06bd, 0x2061), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Seagate RSS LLC */ - { USB_DEVICE(0x0bc2, 0x3000), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Umax [hex] Astra 3400U */ - { USB_DEVICE(0x1606, 0x0060), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Philips PSC805 audio device */ { USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME }, - /* Alcor multi-card reader */ - { USB_DEVICE(0x058f, 0x6366), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* Canon EOS 5D in PC Connection mode */ - { USB_DEVICE(0x04a9, 0x3101), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* RIM Blackberry */ - { USB_DEVICE(0x0fca, 0x0001), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - { USB_DEVICE(0x0fca, 0x0004), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - { USB_DEVICE(0x0fca, 0x0006), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* Apple iPhone */ - { USB_DEVICE(0x05ac, 0x1290), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* SKYMEDI USB_DRIVE */ { USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME }, { } /* terminating entry must be last */ }; -static void usb_autosuspend_quirk(struct usb_device *udev) -{ -#ifdef CONFIG_USB_SUSPEND - /* disable autosuspend, but allow the user to re-enable it via sysfs */ - udev->autosuspend_disabled = 1; -#endif -} - static const struct usb_device_id *find_id(struct usb_device *udev) { const struct usb_device_id *id = usb_quirk_list; @@ -149,13 +74,9 @@ void usb_detect_quirks(struct usb_device *udev) dev_dbg(&udev->dev, "USB quirks for this device: %x\n", udev->quirks); - /* do any special quirk handling here if needed */ - if (udev->quirks & USB_QUIRK_NO_AUTOSUSPEND) - usb_autosuspend_quirk(udev); - /* By default, disable autosuspend for all non-hubs */ #ifdef CONFIG_USB_SUSPEND if (udev->descriptor.bDeviceClass != USB_CLASS_HUB) - udev->autosuspend_delay = -1; + udev->autosuspend_disabled = 1; #endif } diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h index 8da374caf58..2692ec9389c 100644 --- a/include/linux/usb/quirks.h +++ b/include/linux/usb/quirks.h @@ -4,11 +4,8 @@ * belong here. */ -/* device must not be autosuspended */ -#define USB_QUIRK_NO_AUTOSUSPEND 0x00000001 - /* string descriptors must not be fetched using a 255-byte read */ -#define USB_QUIRK_STRING_FETCH_255 0x00000002 +#define USB_QUIRK_STRING_FETCH_255 0x00000001 /* device can't resume correctly so reset it instead */ -#define USB_QUIRK_RESET_RESUME 0x00000004 +#define USB_QUIRK_RESET_RESUME 0x00000002 -- cgit v1.2.3-70-g09d2 From 16eb345f4d9189b59bae576ae63cba7ca77817b2 Mon Sep 17 00:00:00 2001 From: Phil Dibowitz Date: Sat, 22 Sep 2007 20:58:12 -0700 Subject: USB: unusual_devs modification for Nikon D200 Upgrade the unusual_devs.h file to support the Nikon D200 Signed-off-by: Mike Pagano Signed-off-by: Phil Dibowitz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index b0ff0295580..5129b538be9 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -341,6 +341,13 @@ UNUSUAL_DEV( 0x04b0, 0x040d, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY), +/* Reported by Graber and Mike Pagano */ +UNUSUAL_DEV( 0x04b0, 0x040f, 0x0200, 0x0200, + "NIKON", + "NIKON DSC D200", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY), + /* Reported by Emil Larsson */ UNUSUAL_DEV( 0x04b0, 0x0411, 0x0100, 0x0101, "NIKON", -- cgit v1.2.3-70-g09d2 From 1f4f714f88955cfb61fba0cd43fe3b07e4212257 Mon Sep 17 00:00:00 2001 From: Edouard Lafargue Date: Tue, 25 Sep 2007 10:15:36 +0200 Subject: USB: cp2101.c: add additional device ID This patch adds an additional device ID to the cp2101 USB serial driver. This device is a Gemalto Prox-PU or CU contactless card reader (ISO14443-A/B and Mifare). The reader is a standard Gemalto serial proximity reader using the Gemalto Block Protocol (see reader's documentation) bundled with a built-in CP2102 for serial/USB conversion. Signed-off-by: Edouard Lafargue (edouard@lafargue.name) Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp2101.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 883625126d6..eb7df1835c1 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -53,6 +53,7 @@ static void cp2101_shutdown(struct usb_serial*); static int debug; static struct usb_device_id id_table [] = { + { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */ { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */ { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */ { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */ -- cgit v1.2.3-70-g09d2 From 4ac0718e83821db53451614e098399004694aa81 Mon Sep 17 00:00:00 2001 From: Simon Arlott Date: Tue, 25 Sep 2007 20:20:10 +0100 Subject: USB: cxacru: Use appropriate logging for errors When an error occurs, existing logging uses dbg() so the cause of a problem is hard to determine. Error conditions shouldn't only be properly reported with debugging enabled. A side effect of this change is that when an uninitialised device is started, a log message similar to the following is sent: cxacru 5-2:1.0: receive of cm 0x90 failed (-104) This is normal - the device did not respond so firmware will be loaded. Signed-off-by: Simon Arlott Acked-by: Duncan Sands Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/cxacru.c | 43 ++++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index a73e714288e..a51eeedc18d 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -482,7 +482,9 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm, int rbuflen = ((rsize - 1) / stride + 1) * CMD_PACKET_SIZE; if (wbuflen > PAGE_SIZE || rbuflen > PAGE_SIZE) { - dbg("too big transfer requested"); + if (printk_ratelimit()) + usb_err(instance->usbatm, "requested transfer size too large (%d, %d)\n", + wbuflen, rbuflen); ret = -ENOMEM; goto fail; } @@ -493,8 +495,9 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm, init_completion(&instance->rcv_done); ret = usb_submit_urb(instance->rcv_urb, GFP_KERNEL); if (ret < 0) { - dbg("submitting read urb for cm %#x failed", cm); - ret = ret; + if (printk_ratelimit()) + usb_err(instance->usbatm, "submit of read urb for cm %#x failed (%d)\n", + cm, ret); goto fail; } @@ -510,27 +513,29 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm, init_completion(&instance->snd_done); ret = usb_submit_urb(instance->snd_urb, GFP_KERNEL); if (ret < 0) { - dbg("submitting write urb for cm %#x failed", cm); - ret = ret; + if (printk_ratelimit()) + usb_err(instance->usbatm, "submit of write urb for cm %#x failed (%d)\n", + cm, ret); goto fail; } ret = cxacru_start_wait_urb(instance->snd_urb, &instance->snd_done, NULL); if (ret < 0) { - dbg("sending cm %#x failed", cm); - ret = ret; + if (printk_ratelimit()) + usb_err(instance->usbatm, "send of cm %#x failed (%d)\n", cm, ret); goto fail; } ret = cxacru_start_wait_urb(instance->rcv_urb, &instance->rcv_done, &actlen); if (ret < 0) { - dbg("receiving cm %#x failed", cm); - ret = ret; + if (printk_ratelimit()) + usb_err(instance->usbatm, "receive of cm %#x failed (%d)\n", cm, ret); goto fail; } if (actlen % CMD_PACKET_SIZE || !actlen) { - dbg("response is not a positive multiple of %d: %#x", - CMD_PACKET_SIZE, actlen); + if (printk_ratelimit()) + usb_err(instance->usbatm, "invalid response length to cm %#x: %d\n", + cm, actlen); ret = -EIO; goto fail; } @@ -538,12 +543,16 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm, /* check the return status and copy the data to the output buffer, if needed */ for (offb = offd = 0; offd < rsize && offb < actlen; offb += CMD_PACKET_SIZE) { if (rbuf[offb] != cm) { - dbg("wrong cm %#x in response", rbuf[offb]); + if (printk_ratelimit()) + usb_err(instance->usbatm, "wrong cm %#x in response to cm %#x\n", + rbuf[offb], cm); ret = -EIO; goto fail; } if (rbuf[offb + 1] != CM_STATUS_SUCCESS) { - dbg("response failed: %#x", rbuf[offb + 1]); + if (printk_ratelimit()) + usb_err(instance->usbatm, "response to cm %#x failed: %#x\n", + cm, rbuf[offb + 1]); ret = -EIO; goto fail; } @@ -582,14 +591,18 @@ static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_requ for (offb = 0; offb < len; ) { int l = le32_to_cpu(buf[offb++]); if (l > stride || l > (len - offb) / 2) { - dbg("wrong data length %#x in response", l); + if (printk_ratelimit()) + usb_err(instance->usbatm, "invalid data length from cm %#x: %d\n", + cm, l); ret = -EIO; goto cleanup; } while (l--) { offd = le32_to_cpu(buf[offb++]); if (offd >= size) { - dbg("wrong index %#x in response", offd); + if (printk_ratelimit()) + usb_err(instance->usbatm, "wrong index #%x in response to cm #%x\n", + offd, cm); ret = -EIO; goto cleanup; } -- cgit v1.2.3-70-g09d2 From 6ce76104781a10554129791dc62c3104424f6d48 Mon Sep 17 00:00:00 2001 From: Frank A Kingswood Date: Wed, 22 Aug 2007 20:48:58 +0100 Subject: USB: Driver for CH341 USB-serial adaptor This patch implements a USB serial port driver for the Winchiphead CH341 USB-RS232 Converter. This chip also implements an IEEE 1284 parallel port, I2C and SPI, but that is not supported by the driver. Signed-off-by: Frank A Kingswood Signed-off-by: Greg Kroah-Hartman --- Documentation/usb/usb-serial.txt | 11 ++ drivers/usb/serial/Kconfig | 10 ++ drivers/usb/serial/Makefile | 1 + drivers/usb/serial/ch341.c | 352 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 374 insertions(+) create mode 100644 drivers/usb/serial/ch341.c diff --git a/Documentation/usb/usb-serial.txt b/Documentation/usb/usb-serial.txt index 5b635ae8494..4e0b62b8566 100644 --- a/Documentation/usb/usb-serial.txt +++ b/Documentation/usb/usb-serial.txt @@ -428,6 +428,17 @@ Options supported: See http://www.uuhaus.de/linux/palmconnect.html for up-to-date information on this driver. +Winchiphead CH341 Driver + + This driver is for the Winchiphead CH341 USB-RS232 Converter. This chip + also implements an IEEE 1284 parallel port, I2C and SPI, but that is not + supported by the driver. The protocol was analyzed from the behaviour + of the Windows driver, no datasheet is available at present. + The manufacturer's website: http://www.winchiphead.com/. + For any questions or problems with this driver, please contact + frank@kingswood-consulting.co.uk. + + Generic Serial driver If your device is not one of the above listed devices, compatible with diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 43d6db696f9..99fefed7791 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -92,6 +92,16 @@ config USB_SERIAL_BELKIN To compile this driver as a module, choose M here: the module will be called belkin_sa. +config USB_SERIAL_CH341 + tristate "USB Winchiphead CH341 Single Port Serial Driver" + depends on USB_SERIAL + help + Say Y here if you want to use a Winchiphead CH341 single port + USB to serial adapter. + + To compile this driver as a module, choose M here: the + module will be called ch341. + config USB_SERIAL_WHITEHEAT tristate "USB ConnectTech WhiteHEAT Serial Driver" depends on USB_SERIAL diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 07a976eca6b..d6fb384e52b 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_USB_SERIAL_AIRCABLE) += aircable.o obj-$(CONFIG_USB_SERIAL_AIRPRIME) += airprime.o obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o +obj-$(CONFIG_USB_SERIAL_CH341) += ch341.o obj-$(CONFIG_USB_SERIAL_CP2101) += cp2101.o obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o obj-$(CONFIG_USB_SERIAL_CYPRESS_M8) += cypress_m8.o diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c new file mode 100644 index 00000000000..eb681069e24 --- /dev/null +++ b/drivers/usb/serial/ch341.c @@ -0,0 +1,352 @@ +/* + * Copyright 2007, Frank A Kingswood + * + * ch341.c implements a serial port driver for the Winchiphead CH341. + * + * The CH341 device can be used to implement an RS232 asynchronous + * serial port, an IEEE-1284 parallel printer port or a memory-like + * interface. In all cases the CH341 supports an I2C interface as well. + * This driver only supports the asynchronous serial interface. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_BAUD_RATE 2400 +#define DEFAULT_TIMEOUT 1000 + +static int debug; + +static struct usb_device_id id_table [] = { + { USB_DEVICE(0x4348, 0x5523) }, + { }, +}; +MODULE_DEVICE_TABLE(usb, id_table); + +struct ch341_private { + unsigned baud_rate; + u8 dtr; + u8 rts; +}; + +static int ch341_control_out(struct usb_device *dev, u8 request, + u16 value, u16 index) +{ + int r; + dbg("ch341_control_out(%02x,%02x,%04x,%04x)", USB_DIR_OUT|0x40, + (int)request, (int)value, (int)index); + + r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + value, index, NULL, 0, DEFAULT_TIMEOUT); + + return r; +} + +static int ch341_control_in(struct usb_device *dev, + u8 request, u16 value, u16 index, + char *buf, unsigned bufsize) +{ + int r; + dbg("ch341_control_in(%02x,%02x,%04x,%04x,%p,%u)", USB_DIR_IN|0x40, + (int)request, (int)value, (int)index, buf, (int)bufsize); + + r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + value, index, buf, bufsize, DEFAULT_TIMEOUT); + return r; +} + +int ch341_set_baudrate(struct usb_device *dev, struct ch341_private *priv) +{ + short a, b; + int r; + + dbg("ch341_set_baudrate(%d)", priv->baud_rate); + switch (priv->baud_rate) { + case 2400: + a = 0xd901; + b = 0x0038; + break; + case 4800: + a = 0x6402; + b = 0x001f; + break; + case 9600: + a = 0xb202; + b = 0x0013; + break; + case 19200: + a = 0xd902; + b = 0x000d; + break; + case 38400: + a = 0x6403; + b = 0x000a; + break; + case 115200: + a = 0xcc03; + b = 0x0008; + break; + default: + return -EINVAL; + } + + r = ch341_control_out(dev, 0x9a, 0x1312, a); + if (!r) + r = ch341_control_out(dev, 0x9a, 0x0f2c, b); + + return r; +} + +int ch341_set_handshake(struct usb_device *dev, struct ch341_private *priv) +{ + dbg("ch341_set_handshake(%d,%d)", priv->dtr, priv->rts); + return ch341_control_out(dev, 0xa4, + ~((priv->dtr?1<<5:0)|(priv->rts?1<<6:0)), 0); +} + +int ch341_get_status(struct usb_device *dev) +{ + char *buffer; + int r; + const unsigned size = 8; + + dbg("ch341_get_status()"); + + buffer = kmalloc(size, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + r = ch341_control_in(dev, 0x95, 0x0706, 0, buffer, size); + if ( r < 0) + goto out; + + /* Not having the datasheet for the CH341, we ignore the bytes returned + * from the device. Return error if the device did not respond in time. + */ + r = 0; + +out: kfree(buffer); + return r; +} + +/* -------------------------------------------------------------------------- */ + +int ch341_configure(struct usb_device *dev, struct ch341_private *priv) +{ + char *buffer; + int r; + const unsigned size = 8; + + dbg("ch341_configure()"); + + buffer = kmalloc(size, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + /* expect two bytes 0x27 0x00 */ + r = ch341_control_in(dev, 0x5f, 0, 0, buffer, size); + if (r < 0) + goto out; + + r = ch341_control_out(dev, 0xa1, 0, 0); + if (r < 0) + goto out; + + r = ch341_set_baudrate(dev, priv); + if (r < 0) + goto out; + + /* expect two bytes 0x56 0x00 */ + r = ch341_control_in(dev, 0x95, 0x2518, 0, buffer, size); + if (r < 0) + goto out; + + r = ch341_control_out(dev, 0x9a, 0x2518, 0x0050); + if (r < 0) + goto out; + + /* expect 0xff 0xee */ + r = ch341_get_status(dev); + if (r < 0) + goto out; + + r = ch341_control_out(dev, 0xa1, 0x501f, 0xd90a); + if (r < 0) + goto out; + + r = ch341_set_baudrate(dev, priv); + if (r < 0) + goto out; + + r = ch341_set_handshake(dev, priv); + if (r < 0) + goto out; + + /* expect 0x9f 0xee */ + r = ch341_get_status(dev); + +out: kfree(buffer); + return r; +} + +/* allocate private data */ +static int ch341_attach(struct usb_serial *serial) +{ + struct ch341_private *priv; + int r; + + dbg("ch341_attach()"); + + /* private data */ + priv = kzalloc(sizeof(struct ch341_private), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->baud_rate = DEFAULT_BAUD_RATE; + priv->dtr = 1; + priv->rts = 1; + + r = ch341_configure(serial->dev, priv); + if (r < 0) + goto error; + + usb_set_serial_port_data(serial->port[0], priv); + return 0; + +error: kfree(priv); + return r; +} + +/* open this device, set default parameters */ +static int ch341_open(struct usb_serial_port *port, struct file *filp) +{ + struct usb_serial *serial = port->serial; + struct ch341_private *priv = usb_get_serial_port_data(serial->port[0]); + int r; + + dbg("ch341_open()"); + + priv->baud_rate = DEFAULT_BAUD_RATE; + priv->dtr = 1; + priv->rts = 1; + + r = ch341_configure(serial->dev, priv); + if (r) + goto out; + + r = ch341_set_handshake(serial->dev, priv); + if (r) + goto out; + + r = ch341_set_baudrate(serial->dev, priv); + if (r) + goto out; + + r = usb_serial_generic_open(port, filp); + +out: return r; +} + +/* Old_termios contains the original termios settings and + * tty->termios contains the new setting to be used. + */ +static void ch341_set_termios(struct usb_serial_port *port, + struct ktermios *old_termios) +{ + struct ch341_private *priv = usb_get_serial_port_data(port); + struct tty_struct *tty = port->tty; + unsigned baud_rate; + + dbg("ch341_set_termios()"); + + if (!tty || !tty->termios) + return; + + baud_rate = tty_get_baud_rate(tty); + + switch (baud_rate) { + case 2400: + case 4800: + case 9600: + case 19200: + case 38400: + case 115200: + priv->baud_rate = baud_rate; + break; + default: + dbg("Rate %d not supported, using %d", + baud_rate, DEFAULT_BAUD_RATE); + priv->baud_rate = DEFAULT_BAUD_RATE; + } + + ch341_set_baudrate(port->serial->dev, priv); + + /* Unimplemented: + * (cflag & CSIZE) : data bits [5, 8] + * (cflag & PARENB) : parity {NONE, EVEN, ODD} + * (cflag & CSTOPB) : stop bits [1, 2] + */ +} + +static struct usb_driver ch341_driver = { + .name = "ch341", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table, + .no_dynamic_id = 1, +}; + +static struct usb_serial_driver ch341_device = { + .driver = { + .owner = THIS_MODULE, + .name = "ch341-uart", + }, + .id_table = id_table, + .usb_driver = &ch341_driver, + .num_interrupt_in = NUM_DONT_CARE, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_ports = 1, + .open = ch341_open, + .set_termios = ch341_set_termios, + .attach = ch341_attach, +}; + +static int __init ch341_init(void) +{ + int retval; + + retval = usb_serial_register(&ch341_device); + if (retval) + return retval; + retval = usb_register(&ch341_driver); + if (retval) + usb_serial_deregister(&ch341_device); + return retval; +} + +static void __exit ch341_exit(void) +{ + usb_deregister(&ch341_driver); + usb_serial_deregister(&ch341_device); +} + +module_init(ch341_init); +module_exit(ch341_exit); +MODULE_LICENSE("GPL"); + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + +/* EOF ch341.c */ -- cgit v1.2.3-70-g09d2 From 93b6497da99978742ffa9d9db6177397436278f5 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 9 Sep 2007 22:25:04 +0200 Subject: USB: usb/serial/ch341.c: make 4 functions static This patch makes four needlessly global functions static. Signed-off-by: Adrian Bunk Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ch341.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index eb681069e24..6b252ceb39a 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -66,7 +66,8 @@ static int ch341_control_in(struct usb_device *dev, return r; } -int ch341_set_baudrate(struct usb_device *dev, struct ch341_private *priv) +static int ch341_set_baudrate(struct usb_device *dev, + struct ch341_private *priv) { short a, b; int r; @@ -108,14 +109,15 @@ int ch341_set_baudrate(struct usb_device *dev, struct ch341_private *priv) return r; } -int ch341_set_handshake(struct usb_device *dev, struct ch341_private *priv) +static int ch341_set_handshake(struct usb_device *dev, + struct ch341_private *priv) { dbg("ch341_set_handshake(%d,%d)", priv->dtr, priv->rts); return ch341_control_out(dev, 0xa4, ~((priv->dtr?1<<5:0)|(priv->rts?1<<6:0)), 0); } -int ch341_get_status(struct usb_device *dev) +static int ch341_get_status(struct usb_device *dev) { char *buffer; int r; @@ -142,7 +144,7 @@ out: kfree(buffer); /* -------------------------------------------------------------------------- */ -int ch341_configure(struct usb_device *dev, struct ch341_private *priv) +static int ch341_configure(struct usb_device *dev, struct ch341_private *priv) { char *buffer; int r; -- cgit v1.2.3-70-g09d2 From e3a09051a16fcdb190ad0b7dc6064904c8118409 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 3 Oct 2007 18:53:13 +0900 Subject: USB: r8a66597-hcd: fix Class or Vendor Request Fixed the problem that does not work in the case of bRequest = 0x05 in Class or Vendor Request. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/r8a66597-hcd.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index fd00f1e33fb..0a699efe6c9 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -1034,6 +1034,15 @@ static void prepare_status_packet(struct r8a66597 *r8a66597, pipe_start(r8a66597, td->pipe); } +static int is_set_address(unsigned char *setup_packet) +{ + if (((setup_packet[0] & USB_TYPE_MASK) == USB_TYPE_STANDARD) && + setup_packet[1] == USB_REQ_SET_ADDRESS) + return 1; + else + return 0; +} + /* this function must be called with interrupt disabled */ static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td) { @@ -1041,7 +1050,7 @@ static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td) switch (td->type) { case USB_PID_SETUP: - if (td->urb->setup_packet[1] == USB_REQ_SET_ADDRESS) { + if (is_set_address(td->urb->setup_packet)) { td->set_address = 1; td->urb->setup_packet[2] = alloc_usb_address(r8a66597, td->urb); -- cgit v1.2.3-70-g09d2 From 05eac910b69209164b1d9357bf8877a7c81b2e4e Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 3 Oct 2007 18:53:28 +0900 Subject: USB: r8a66597-hcd: fix endian problem Fixed the problem that does not work in the big endian machine. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/r8a66597-hcd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 0a699efe6c9..64fba53c263 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -834,7 +834,7 @@ static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb, info.pipenum = get_empty_pipenum(r8a66597, ep); info.address = get_urb_to_r8a66597_addr(r8a66597, urb); info.epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - info.maxpacket = ep->wMaxPacketSize; + info.maxpacket = le16_to_cpu(ep->wMaxPacketSize); info.type = get_r8a66597_type(ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); info.bufnum = get_bufnum(info.pipenum); @@ -925,7 +925,7 @@ static void prepare_setup_packet(struct r8a66597 *r8a66597, r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1); for (i = 0; i < 4; i++) { - r8a66597_write(r8a66597, p[i], setup_addr); + r8a66597_write(r8a66597, cpu_to_le16(p[i]), setup_addr); setup_addr += 2; } r8a66597_write(r8a66597, SUREQ, DCPCTR); @@ -2027,7 +2027,7 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, case GetPortStatus: if (wIndex > R8A66597_MAX_ROOT_HUB) goto error; - *(u32 *)buf = rh->port; + *(u32 *)buf = cpu_to_le32(rh->port); break; case SetPortFeature: if (wIndex > R8A66597_MAX_ROOT_HUB) -- cgit v1.2.3-70-g09d2 From ca0677a29bddee35918bf3c0c55cc3badd69079e Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 5 Oct 2007 15:53:12 +0900 Subject: USB: r8a66597-hcd: fix driver removing Fixed the problem that accessed register of this controller after having called iounmap(). Signed-off-by: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/r8a66597-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 64fba53c263..ae8ec4474eb 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -2126,8 +2126,8 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev) struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597); del_timer_sync(&r8a66597->rh_timer); - iounmap((void *)r8a66597->reg); usb_remove_hcd(hcd); + iounmap((void *)r8a66597->reg); usb_put_hcd(hcd); return 0; } -- cgit v1.2.3-70-g09d2 From 9dcfbd97a695a3c28a867501127fa35ac49bc805 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 2 Oct 2007 14:40:46 -0700 Subject: USB: fix gregkh-usb-usb-sisusb2vga-convert-printk-to-dev_-macros drivers/usb/misc/sisusbvga/sisusb.c: In function 'sisusb_open': drivers/usb/misc/sisusbvga/sisusb.c:2444: warning: 'sisusb' is used uninitialized in this function I can tell that'll oops just by looking at it. How come this code assume a 7,000 column xterm? :( Cc: Felipe Balbi Cc: Thomas Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 033bdfe9b21..0790829a570 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -3323,15 +3323,7 @@ static int __init usb_sisusb_init(void) sisusb_init_concode(); #endif - if (!(retval = usb_register(&sisusb_driver))) { - - dev_info(&sisusb->sisusb_dev->dev, "Driver version %d.%d.%d\n", SISUSB_VERSION, - SISUSB_REVISION, SISUSB_PATCHLEVEL); - dev_info(&sisusb->sisusb_dev->dev, "sisusb: Copyright (C) 2005 Thomas Winischhofer\n"); - - } - - return retval; + return usb_register(&sisusb_driver); } static void __exit usb_sisusb_exit(void) -- cgit v1.2.3-70-g09d2 From 5395353e0c8272fe73ac914acd7e4add0da2bef0 Mon Sep 17 00:00:00 2001 From: Benedikt Spranger Date: Tue, 2 Oct 2007 14:40:48 -0700 Subject: usb-gadget-ether: prevent oops caused by error interrupt race Fix a longstanding race in the Ethernet gadget driver, which can cause an oops on device disconnect. The fix is just to make the TX path check whether its freelist is empty. That check is otherwise not necessary, since the queue is always stopped when that list empties (and restarted when request completion puts an entry back on that freelist). The race window starts when the network code decides to transmit a packet, and ends when hard_start_xmit() grabs the freelist lock. When disconnect() is called inside that window, it shuts down the TX queue and breaks the otherwise-solid assumption that packets are never sent through a TX queue that's stopped. Signed-off-by: Benedikt Spranger Signed-off-by: Thomas Gleixner Signed-off-by: David Brownell Signed-off-by: Andrew Morton Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ether.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index ff244f42723..9f4fd7e849a 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -1957,8 +1957,20 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) } spin_lock_irqsave(&dev->req_lock, flags); + /* + * this freelist can be empty if an interrupt triggered disconnect() + * and reconfigured the gadget (shutting down this queue) after the + * network stack decided to xmit but before we got the spinlock. + */ + if (list_empty(&dev->tx_reqs)) { + spin_unlock_irqrestore(&dev->req_lock, flags); + return 1; + } + req = container_of (dev->tx_reqs.next, struct usb_request, list); list_del (&req->list); + + /* temporarily stop TX queue when the freelist empties */ if (list_empty (&dev->tx_reqs)) netif_stop_queue (net); spin_unlock_irqrestore(&dev->req_lock, flags); -- cgit v1.2.3-70-g09d2 From a59048d46303c4146993c37f51ed97a760fc4c0a Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Tue, 2 Oct 2007 14:40:49 -0700 Subject: USB: drivers/usb/misc/sisusbvga/sisusb.c: kill two unused variables Kill two unused variables in drivers/usb/misc/sisusbvga/sisusb.c. Signed-off-by: WANG Cong Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 0790829a570..9244d067cec 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -3316,8 +3316,6 @@ static struct usb_driver sisusb_driver = { static int __init usb_sisusb_init(void) { - int retval; - struct sisusb_usb_data *sisusb; #ifdef INCL_SISUSB_CON sisusb_init_concode(); -- cgit v1.2.3-70-g09d2 From 437f375f262417b484f28007c3e8d21bd01d0e01 Mon Sep 17 00:00:00 2001 From: Vitaly Bordug Date: Thu, 27 Sep 2007 00:36:22 +0400 Subject: USB: serial gadget: Disable endpoints on unload After Serial gadget is being unloaded, neither serial itself, nor other gadget stuff can be loaded subsequently. Signed-off-by: Vitaly Bordug Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/serial.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index afdf71f76f7..a2a1ebc947d 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -1470,6 +1470,12 @@ static void /* __init_or_exit */ gs_unbind(struct usb_gadget *gadget) dev->dev_ctrl_req = NULL; } gs_free_ports(dev); + if (dev->dev_notify_ep) + usb_ep_disable(dev->dev_notify_ep); + if (dev->dev_in_ep) + usb_ep_disable(dev->dev_in_ep); + if (dev->dev_out_ep) + usb_ep_disable(dev->dev_out_ep); kfree(dev); set_gadget_data(gadget, NULL); } -- cgit v1.2.3-70-g09d2 From 4d59d8a11383ebf0e0260ee481a4e766959fd7d9 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Wed, 3 Oct 2007 14:56:03 -0700 Subject: USB: Export URB statistics for powertop powertop currently tracks interrupts generated by uhci, ehci, and ohci, but it has no way of telling which USB device to blame USB bus activity on. This patch exports the number of URBs that are submitted for a given device. Cat the file 'urbnum' in /sys/bus/usb/devices/.../ Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 2 ++ drivers/usb/core/sysfs.c | 11 +++++++++++ drivers/usb/core/usb.c | 1 + include/linux/usb.h | 1 + 4 files changed, 15 insertions(+) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 2c79aa6ca2b..3dd997df850 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1176,6 +1176,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) */ usb_get_urb(urb); atomic_inc(&urb->use_count); + atomic_inc(&urb->dev->urbnum); usbmon_urb_submit(&hcd->self, urb); /* NOTE requirements on root-hub callers (usbfs and the hub @@ -1197,6 +1198,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) urb->hcpriv = NULL; INIT_LIST_HEAD(&urb->urb_list); atomic_dec(&urb->use_count); + atomic_dec(&urb->dev->urbnum); if (urb->reject) wake_up(&usb_kill_urb_queue); usb_put_urb(urb); diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index e02590297d3..b04afd06e50 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -169,6 +169,16 @@ show_quirks(struct device *dev, struct device_attribute *attr, char *buf) } static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL); +static ssize_t +show_urbnum(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct usb_device *udev; + + udev = to_usb_device(dev); + return sprintf(buf, "%d\n", atomic_read(&udev->urbnum)); +} +static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL); + #if defined(CONFIG_USB_PERSIST) || defined(CONFIG_USB_SUSPEND) static const char power_group[] = "power"; @@ -458,6 +468,7 @@ static struct attribute *dev_attrs[] = { &dev_attr_bConfigurationValue.attr, &dev_attr_bmAttributes.attr, &dev_attr_bMaxPower.attr, + &dev_attr_urbnum.attr, /* device attributes */ &dev_attr_idVendor.attr, &dev_attr_idProduct.attr, diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 8121edbd149..c99938d5f78 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -266,6 +266,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) dev->dev.dma_mask = bus->controller->dma_mask; set_dev_node(&dev->dev, dev_to_node(bus->controller)); dev->state = USB_STATE_ATTACHED; + atomic_set(&dev->urbnum, 0); INIT_LIST_HEAD(&dev->ep0.urb_list); dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE; diff --git a/include/linux/usb.h b/include/linux/usb.h index e5b35e0dca2..c10935fdc03 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -415,6 +415,7 @@ struct usb_device { int pm_usage_cnt; /* usage counter for autosuspend */ u32 quirks; /* quirks of the whole device */ + atomic_t urbnum; /* number of URBs submitted for the whole device */ #ifdef CONFIG_PM struct delayed_work autosuspend; /* for delayed autosuspends */ -- cgit v1.2.3-70-g09d2 From 9454a57ab5922e5cd25321cae9d1a8cbeb3e2e85 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 4 Oct 2007 18:05:17 -0700 Subject: USB: move to Move to , reducing some of the clutter in the main include directory. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/amd5536udc.c | 2 +- drivers/usb/gadget/at91_udc.c | 2 +- drivers/usb/gadget/config.c | 2 +- drivers/usb/gadget/dummy_hcd.c | 2 +- drivers/usb/gadget/epautoconf.c | 2 +- drivers/usb/gadget/ether.c | 2 +- drivers/usb/gadget/file_storage.c | 2 +- drivers/usb/gadget/fsl_usb2_udc.c | 4 +- drivers/usb/gadget/gmidi.c | 2 +- drivers/usb/gadget/goku_udc.c | 2 +- drivers/usb/gadget/inode.c | 2 +- drivers/usb/gadget/lh7a40x_udc.h | 2 +- drivers/usb/gadget/m66592-udc.c | 2 +- drivers/usb/gadget/net2280.c | 2 +- drivers/usb/gadget/omap_udc.c | 2 +- drivers/usb/gadget/pxa2xx_udc.c | 2 +- drivers/usb/gadget/s3c2410_udc.c | 2 +- drivers/usb/gadget/serial.c | 2 +- drivers/usb/gadget/usbstring.c | 2 +- drivers/usb/gadget/zero.c | 2 +- include/linux/usb/gadget.h | 866 ++++++++++++++++++++++++++++++++++++++ include/linux/usb_gadget.h | 866 -------------------------------------- 22 files changed, 887 insertions(+), 887 deletions(-) create mode 100644 include/linux/usb/gadget.h delete mode 100644 include/linux/usb_gadget.h diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index bdd5f2284b3..1c804060252 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -69,7 +69,7 @@ /* gadget stack */ #include -#include +#include /* udc specific */ #include "amd5536udc.h" diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 63d7d656869..a6adf7e0f6f 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c index c6760aee1e5..a4e54b2743f 100644 --- a/drivers/usb/gadget/config.c +++ b/drivers/usb/gadget/config.c @@ -25,7 +25,7 @@ #include #include -#include +#include /** diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 6479a36d6f0..9db2482bdfa 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -46,7 +46,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 3aa46cfa66b..f9d07108bc3 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include "gadget_chips.h" diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 9f4fd7e849a..9e732bff9df 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -30,7 +30,7 @@ #include #include -#include +#include #include "gadget_chips.h" diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 0551140010e..73726c570a6 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -240,7 +240,7 @@ #include #include -#include +#include #include "gadget_chips.h" diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c index 89c768e2aed..9bb7f64a85c 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.c +++ b/drivers/usb/gadget/fsl_usb2_udc.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include #include @@ -1117,7 +1117,7 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on) return 0; } -/* defined in usb_gadget.h */ +/* defined in gadget.h */ static struct usb_gadget_ops fsl_gadget_ops = { .get_frame = fsl_get_frame, .wakeup = fsl_wakeup, diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index d2475755a20..0689189550b 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 349b8166f34..2ec9d196a8c 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 129eda5358f..47ef8bd58a0 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -37,7 +37,7 @@ #include #include -#include +#include /* diff --git a/drivers/usb/gadget/lh7a40x_udc.h b/drivers/usb/gadget/lh7a40x_udc.h index b3fe197e1ee..1ecfd6366b9 100644 --- a/drivers/usb/gadget/lh7a40x_udc.h +++ b/drivers/usb/gadget/lh7a40x_udc.h @@ -50,7 +50,7 @@ #include #include -#include +#include /* * Memory map diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 4b27d12f049..ebc5536aa27 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -27,7 +27,7 @@ #include #include -#include +#include #include "m66592-udc.h" diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index c3d364ecd4f..d5d473f8144 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -62,7 +62,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index bf2788dfb32..87c4f50dfb6 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 1407ad1c812..3e715082de3 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -54,7 +54,7 @@ #include #include -#include +#include #include diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index 0be80c635c4..e3e90f8a75e 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -42,7 +42,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index a2a1ebc947d..f5738eb8e76 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -25,7 +25,7 @@ #include #include -#include +#include #include "gadget_chips.h" diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c index 3459ea6c6c0..878e428a0ec 100644 --- a/drivers/usb/gadget/usbstring.c +++ b/drivers/usb/gadget/usbstring.c @@ -15,7 +15,7 @@ #include #include -#include +#include #include diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index ff540879ce3..fcde5d9c87d 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -55,7 +55,7 @@ #include #include -#include +#include #include "gadget_chips.h" diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h new file mode 100644 index 00000000000..46705e91573 --- /dev/null +++ b/include/linux/usb/gadget.h @@ -0,0 +1,866 @@ +/* + * + * + * We call the USB code inside a Linux-based peripheral device a "gadget" + * driver, except for the hardware-specific bus glue. One USB host can + * master many USB gadgets, but the gadgets are only slaved to one host. + * + * + * (C) Copyright 2002-2004 by David Brownell + * All Rights Reserved. + * + * This software is licensed under the GNU GPL version 2. + */ + +#ifndef __LINUX_USB_GADGET_H +#define __LINUX_USB_GADGET_H + +#ifdef __KERNEL__ + +struct usb_ep; + +/** + * struct usb_request - describes one i/o request + * @buf: Buffer used for data. Always provide this; some controllers + * only use PIO, or don't use DMA for some endpoints. + * @dma: DMA address corresponding to 'buf'. If you don't set this + * field, and the usb controller needs one, it is responsible + * for mapping and unmapping the buffer. + * @length: Length of that data + * @no_interrupt: If true, hints that no completion irq is needed. + * Helpful sometimes with deep request queues that are handled + * directly by DMA controllers. + * @zero: If true, when writing data, makes the last packet be "short" + * by adding a zero length packet as needed; + * @short_not_ok: When reading data, makes short packets be + * treated as errors (queue stops advancing till cleanup). + * @complete: Function called when request completes, so this request and + * its buffer may be re-used. + * Reads terminate with a short packet, or when the buffer fills, + * whichever comes first. When writes terminate, some data bytes + * will usually still be in flight (often in a hardware fifo). + * Errors (for reads or writes) stop the queue from advancing + * until the completion function returns, so that any transfers + * invalidated by the error may first be dequeued. + * @context: For use by the completion callback + * @list: For use by the gadget driver. + * @status: Reports completion code, zero or a negative errno. + * Normally, faults block the transfer queue from advancing until + * the completion callback returns. + * Code "-ESHUTDOWN" indicates completion caused by device disconnect, + * or when the driver disabled the endpoint. + * @actual: Reports bytes transferred to/from the buffer. For reads (OUT + * transfers) this may be less than the requested length. If the + * short_not_ok flag is set, short reads are treated as errors + * even when status otherwise indicates successful completion. + * Note that for writes (IN transfers) some data bytes may still + * reside in a device-side FIFO when the request is reported as + * complete. + * + * These are allocated/freed through the endpoint they're used with. The + * hardware's driver can add extra per-request data to the memory it returns, + * which often avoids separate memory allocations (potential failures), + * later when the request is queued. + * + * Request flags affect request handling, such as whether a zero length + * packet is written (the "zero" flag), whether a short read should be + * treated as an error (blocking request queue advance, the "short_not_ok" + * flag), or hinting that an interrupt is not required (the "no_interrupt" + * flag, for use with deep request queues). + * + * Bulk endpoints can use any size buffers, and can also be used for interrupt + * transfers. interrupt-only endpoints can be much less functional. + */ + // NOTE this is analagous to 'struct urb' on the host side, + // except that it's thinner and promotes more pre-allocation. + +struct usb_request { + void *buf; + unsigned length; + dma_addr_t dma; + + unsigned no_interrupt:1; + unsigned zero:1; + unsigned short_not_ok:1; + + void (*complete)(struct usb_ep *ep, + struct usb_request *req); + void *context; + struct list_head list; + + int status; + unsigned actual; +}; + +/*-------------------------------------------------------------------------*/ + +/* endpoint-specific parts of the api to the usb controller hardware. + * unlike the urb model, (de)multiplexing layers are not required. + * (so this api could slash overhead if used on the host side...) + * + * note that device side usb controllers commonly differ in how many + * endpoints they support, as well as their capabilities. + */ +struct usb_ep_ops { + int (*enable) (struct usb_ep *ep, + const struct usb_endpoint_descriptor *desc); + int (*disable) (struct usb_ep *ep); + + struct usb_request *(*alloc_request) (struct usb_ep *ep, + gfp_t gfp_flags); + void (*free_request) (struct usb_ep *ep, struct usb_request *req); + + int (*queue) (struct usb_ep *ep, struct usb_request *req, + gfp_t gfp_flags); + int (*dequeue) (struct usb_ep *ep, struct usb_request *req); + + int (*set_halt) (struct usb_ep *ep, int value); + int (*fifo_status) (struct usb_ep *ep); + void (*fifo_flush) (struct usb_ep *ep); +}; + +/** + * struct usb_ep - device side representation of USB endpoint + * @name:identifier for the endpoint, such as "ep-a" or "ep9in-bulk" + * @ops: Function pointers used to access hardware-specific operations. + * @ep_list:the gadget's ep_list holds all of its endpoints + * @maxpacket:The maximum packet size used on this endpoint. The initial + * value can sometimes be reduced (hardware allowing), according to + * the endpoint descriptor used to configure the endpoint. + * @driver_data:for use by the gadget driver. all other fields are + * read-only to gadget drivers. + * + * the bus controller driver lists all the general purpose endpoints in + * gadget->ep_list. the control endpoint (gadget->ep0) is not in that list, + * and is accessed only in response to a driver setup() callback. + */ +struct usb_ep { + void *driver_data; + + const char *name; + const struct usb_ep_ops *ops; + struct list_head ep_list; + unsigned maxpacket:16; +}; + +/*-------------------------------------------------------------------------*/ + +/** + * usb_ep_enable - configure endpoint, making it usable + * @ep:the endpoint being configured. may not be the endpoint named "ep0". + * drivers discover endpoints through the ep_list of a usb_gadget. + * @desc:descriptor for desired behavior. caller guarantees this pointer + * remains valid until the endpoint is disabled; the data byte order + * is little-endian (usb-standard). + * + * when configurations are set, or when interface settings change, the driver + * will enable or disable the relevant endpoints. while it is enabled, an + * endpoint may be used for i/o until the driver receives a disconnect() from + * the host or until the endpoint is disabled. + * + * the ep0 implementation (which calls this routine) must ensure that the + * hardware capabilities of each endpoint match the descriptor provided + * for it. for example, an endpoint named "ep2in-bulk" would be usable + * for interrupt transfers as well as bulk, but it likely couldn't be used + * for iso transfers or for endpoint 14. some endpoints are fully + * configurable, with more generic names like "ep-a". (remember that for + * USB, "in" means "towards the USB master".) + * + * returns zero, or a negative error code. + */ +static inline int +usb_ep_enable (struct usb_ep *ep, const struct usb_endpoint_descriptor *desc) +{ + return ep->ops->enable (ep, desc); +} + +/** + * usb_ep_disable - endpoint is no longer usable + * @ep:the endpoint being unconfigured. may not be the endpoint named "ep0". + * + * no other task may be using this endpoint when this is called. + * any pending and uncompleted requests will complete with status + * indicating disconnect (-ESHUTDOWN) before this call returns. + * gadget drivers must call usb_ep_enable() again before queueing + * requests to the endpoint. + * + * returns zero, or a negative error code. + */ +static inline int +usb_ep_disable (struct usb_ep *ep) +{ + return ep->ops->disable (ep); +} + +/** + * usb_ep_alloc_request - allocate a request object to use with this endpoint + * @ep:the endpoint to be used with with the request + * @gfp_flags:GFP_* flags to use + * + * Request objects must be allocated with this call, since they normally + * need controller-specific setup and may even need endpoint-specific + * resources such as allocation of DMA descriptors. + * Requests may be submitted with usb_ep_queue(), and receive a single + * completion callback. Free requests with usb_ep_free_request(), when + * they are no longer needed. + * + * Returns the request, or null if one could not be allocated. + */ +static inline struct usb_request * +usb_ep_alloc_request (struct usb_ep *ep, gfp_t gfp_flags) +{ + return ep->ops->alloc_request (ep, gfp_flags); +} + +/** + * usb_ep_free_request - frees a request object + * @ep:the endpoint associated with the request + * @req:the request being freed + * + * Reverses the effect of usb_ep_alloc_request(). + * Caller guarantees the request is not queued, and that it will + * no longer be requeued (or otherwise used). + */ +static inline void +usb_ep_free_request (struct usb_ep *ep, struct usb_request *req) +{ + ep->ops->free_request (ep, req); +} + +/** + * usb_ep_queue - queues (submits) an I/O request to an endpoint. + * @ep:the endpoint associated with the request + * @req:the request being submitted + * @gfp_flags: GFP_* flags to use in case the lower level driver couldn't + * pre-allocate all necessary memory with the request. + * + * This tells the device controller to perform the specified request through + * that endpoint (reading or writing a buffer). When the request completes, + * including being canceled by usb_ep_dequeue(), the request's completion + * routine is called to return the request to the driver. Any endpoint + * (except control endpoints like ep0) may have more than one transfer + * request queued; they complete in FIFO order. Once a gadget driver + * submits a request, that request may not be examined or modified until it + * is given back to that driver through the completion callback. + * + * Each request is turned into one or more packets. The controller driver + * never merges adjacent requests into the same packet. OUT transfers + * will sometimes use data that's already buffered in the hardware. + * Drivers can rely on the fact that the first byte of the request's buffer + * always corresponds to the first byte of some USB packet, for both + * IN and OUT transfers. + * + * Bulk endpoints can queue any amount of data; the transfer is packetized + * automatically. The last packet will be short if the request doesn't fill it + * out completely. Zero length packets (ZLPs) should be avoided in portable + * protocols since not all usb hardware can successfully handle zero length + * packets. (ZLPs may be explicitly written, and may be implicitly written if + * the request 'zero' flag is set.) Bulk endpoints may also be used + * for interrupt transfers; but the reverse is not true, and some endpoints + * won't support every interrupt transfer. (Such as 768 byte packets.) + * + * Interrupt-only endpoints are less functional than bulk endpoints, for + * example by not supporting queueing or not handling buffers that are + * larger than the endpoint's maxpacket size. They may also treat data + * toggle differently. + * + * Control endpoints ... after getting a setup() callback, the driver queues + * one response (even if it would be zero length). That enables the + * status ack, after transfering data as specified in the response. Setup + * functions may return negative error codes to generate protocol stalls. + * (Note that some USB device controllers disallow protocol stall responses + * in some cases.) When control responses are deferred (the response is + * written after the setup callback returns), then usb_ep_set_halt() may be + * used on ep0 to trigger protocol stalls. + * + * For periodic endpoints, like interrupt or isochronous ones, the usb host + * arranges to poll once per interval, and the gadget driver usually will + * have queued some data to transfer at that time. + * + * Returns zero, or a negative error code. Endpoints that are not enabled + * report errors; errors will also be + * reported when the usb peripheral is disconnected. + */ +static inline int +usb_ep_queue (struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags) +{ + return ep->ops->queue (ep, req, gfp_flags); +} + +/** + * usb_ep_dequeue - dequeues (cancels, unlinks) an I/O request from an endpoint + * @ep:the endpoint associated with the request + * @req:the request being canceled + * + * if the request is still active on the endpoint, it is dequeued and its + * completion routine is called (with status -ECONNRESET); else a negative + * error code is returned. + * + * note that some hardware can't clear out write fifos (to unlink the request + * at the head of the queue) except as part of disconnecting from usb. such + * restrictions prevent drivers from supporting configuration changes, + * even to configuration zero (a "chapter 9" requirement). + */ +static inline int usb_ep_dequeue (struct usb_ep *ep, struct usb_request *req) +{ + return ep->ops->dequeue (ep, req); +} + +/** + * usb_ep_set_halt - sets the endpoint halt feature. + * @ep: the non-isochronous endpoint being stalled + * + * Use this to stall an endpoint, perhaps as an error report. + * Except for control endpoints, + * the endpoint stays halted (will not stream any data) until the host + * clears this feature; drivers may need to empty the endpoint's request + * queue first, to make sure no inappropriate transfers happen. + * + * Note that while an endpoint CLEAR_FEATURE will be invisible to the + * gadget driver, a SET_INTERFACE will not be. To reset endpoints for the + * current altsetting, see usb_ep_clear_halt(). When switching altsettings, + * it's simplest to use usb_ep_enable() or usb_ep_disable() for the endpoints. + * + * Returns zero, or a negative error code. On success, this call sets + * underlying hardware state that blocks data transfers. + * Attempts to halt IN endpoints will fail (returning -EAGAIN) if any + * transfer requests are still queued, or if the controller hardware + * (usually a FIFO) still holds bytes that the host hasn't collected. + */ +static inline int +usb_ep_set_halt (struct usb_ep *ep) +{ + return ep->ops->set_halt (ep, 1); +} + +/** + * usb_ep_clear_halt - clears endpoint halt, and resets toggle + * @ep:the bulk or interrupt endpoint being reset + * + * Use this when responding to the standard usb "set interface" request, + * for endpoints that aren't reconfigured, after clearing any other state + * in the endpoint's i/o queue. + * + * Returns zero, or a negative error code. On success, this call clears + * the underlying hardware state reflecting endpoint halt and data toggle. + * Note that some hardware can't support this request (like pxa2xx_udc), + * and accordingly can't correctly implement interface altsettings. + */ +static inline int +usb_ep_clear_halt (struct usb_ep *ep) +{ + return ep->ops->set_halt (ep, 0); +} + +/** + * usb_ep_fifo_status - returns number of bytes in fifo, or error + * @ep: the endpoint whose fifo status is being checked. + * + * FIFO endpoints may have "unclaimed data" in them in certain cases, + * such as after aborted transfers. Hosts may not have collected all + * the IN data written by the gadget driver (and reported by a request + * completion). The gadget driver may not have collected all the data + * written OUT to it by the host. Drivers that need precise handling for + * fault reporting or recovery may need to use this call. + * + * This returns the number of such bytes in the fifo, or a negative + * errno if the endpoint doesn't use a FIFO or doesn't support such + * precise handling. + */ +static inline int +usb_ep_fifo_status (struct usb_ep *ep) +{ + if (ep->ops->fifo_status) + return ep->ops->fifo_status (ep); + else + return -EOPNOTSUPP; +} + +/** + * usb_ep_fifo_flush - flushes contents of a fifo + * @ep: the endpoint whose fifo is being flushed. + * + * This call may be used to flush the "unclaimed data" that may exist in + * an endpoint fifo after abnormal transaction terminations. The call + * must never be used except when endpoint is not being used for any + * protocol translation. + */ +static inline void +usb_ep_fifo_flush (struct usb_ep *ep) +{ + if (ep->ops->fifo_flush) + ep->ops->fifo_flush (ep); +} + + +/*-------------------------------------------------------------------------*/ + +struct usb_gadget; + +/* the rest of the api to the controller hardware: device operations, + * which don't involve endpoints (or i/o). + */ +struct usb_gadget_ops { + int (*get_frame)(struct usb_gadget *); + int (*wakeup)(struct usb_gadget *); + int (*set_selfpowered) (struct usb_gadget *, int is_selfpowered); + int (*vbus_session) (struct usb_gadget *, int is_active); + int (*vbus_draw) (struct usb_gadget *, unsigned mA); + int (*pullup) (struct usb_gadget *, int is_on); + int (*ioctl)(struct usb_gadget *, + unsigned code, unsigned long param); +}; + +/** + * struct usb_gadget - represents a usb slave device + * @ops: Function pointers used to access hardware-specific operations. + * @ep0: Endpoint zero, used when reading or writing responses to + * driver setup() requests + * @ep_list: List of other endpoints supported by the device. + * @speed: Speed of current connection to USB host. + * @is_dualspeed: True if the controller supports both high and full speed + * operation. If it does, the gadget driver must also support both. + * @is_otg: True if the USB device port uses a Mini-AB jack, so that the + * gadget driver must provide a USB OTG descriptor. + * @is_a_peripheral: False unless is_otg, the "A" end of a USB cable + * is in the Mini-AB jack, and HNP has been used to switch roles + * so that the "A" device currently acts as A-Peripheral, not A-Host. + * @a_hnp_support: OTG device feature flag, indicating that the A-Host + * supports HNP at this port. + * @a_alt_hnp_support: OTG device feature flag, indicating that the A-Host + * only supports HNP on a different root port. + * @b_hnp_enable: OTG device feature flag, indicating that the A-Host + * enabled HNP support. + * @name: Identifies the controller hardware type. Used in diagnostics + * and sometimes configuration. + * @dev: Driver model state for this abstract device. + * + * Gadgets have a mostly-portable "gadget driver" implementing device + * functions, handling all usb configurations and interfaces. Gadget + * drivers talk to hardware-specific code indirectly, through ops vectors. + * That insulates the gadget driver from hardware details, and packages + * the hardware endpoints through generic i/o queues. The "usb_gadget" + * and "usb_ep" interfaces provide that insulation from the hardware. + * + * Except for the driver data, all fields in this structure are + * read-only to the gadget driver. That driver data is part of the + * "driver model" infrastructure in 2.6 (and later) kernels, and for + * earlier systems is grouped in a similar structure that's not known + * to the rest of the kernel. + * + * Values of the three OTG device feature flags are updated before the + * setup() call corresponding to USB_REQ_SET_CONFIGURATION, and before + * driver suspend() calls. They are valid only when is_otg, and when the + * device is acting as a B-Peripheral (so is_a_peripheral is false). + */ +struct usb_gadget { + /* readonly to gadget driver */ + const struct usb_gadget_ops *ops; + struct usb_ep *ep0; + struct list_head ep_list; /* of usb_ep */ + enum usb_device_speed speed; + unsigned is_dualspeed:1; + unsigned is_otg:1; + unsigned is_a_peripheral:1; + unsigned b_hnp_enable:1; + unsigned a_hnp_support:1; + unsigned a_alt_hnp_support:1; + const char *name; + struct device dev; +}; + +static inline void set_gadget_data (struct usb_gadget *gadget, void *data) + { dev_set_drvdata (&gadget->dev, data); } +static inline void *get_gadget_data (struct usb_gadget *gadget) + { return dev_get_drvdata (&gadget->dev); } + +/* iterates the non-control endpoints; 'tmp' is a struct usb_ep pointer */ +#define gadget_for_each_ep(tmp,gadget) \ + list_for_each_entry(tmp, &(gadget)->ep_list, ep_list) + + +/** + * gadget_is_dualspeed - return true iff the hardware handles high speed + * @gadget: controller that might support both high and full speeds + */ +static inline int gadget_is_dualspeed(struct usb_gadget *g) +{ +#ifdef CONFIG_USB_GADGET_DUALSPEED + /* runtime test would check "g->is_dualspeed" ... that might be + * useful to work around hardware bugs, but is mostly pointless + */ + return 1; +#else + return 0; +#endif +} + +/** + * gadget_is_otg - return true iff the hardware is OTG-ready + * @gadget: controller that might have a Mini-AB connector + * + * This is a runtime test, since kernels with a USB-OTG stack sometimes + * run on boards which only have a Mini-B (or Mini-A) connector. + */ +static inline int gadget_is_otg(struct usb_gadget *g) +{ +#ifdef CONFIG_USB_OTG + return g->is_otg; +#else + return 0; +#endif +} + + +/** + * usb_gadget_frame_number - returns the current frame number + * @gadget: controller that reports the frame number + * + * Returns the usb frame number, normally eleven bits from a SOF packet, + * or negative errno if this device doesn't support this capability. + */ +static inline int usb_gadget_frame_number (struct usb_gadget *gadget) +{ + return gadget->ops->get_frame (gadget); +} + +/** + * usb_gadget_wakeup - tries to wake up the host connected to this gadget + * @gadget: controller used to wake up the host + * + * Returns zero on success, else negative error code if the hardware + * doesn't support such attempts, or its support has not been enabled + * by the usb host. Drivers must return device descriptors that report + * their ability to support this, or hosts won't enable it. + * + * This may also try to use SRP to wake the host and start enumeration, + * even if OTG isn't otherwise in use. OTG devices may also start + * remote wakeup even when hosts don't explicitly enable it. + */ +static inline int usb_gadget_wakeup (struct usb_gadget *gadget) +{ + if (!gadget->ops->wakeup) + return -EOPNOTSUPP; + return gadget->ops->wakeup (gadget); +} + +/** + * usb_gadget_set_selfpowered - sets the device selfpowered feature. + * @gadget:the device being declared as self-powered + * + * this affects the device status reported by the hardware driver + * to reflect that it now has a local power supply. + * + * returns zero on success, else negative errno. + */ +static inline int +usb_gadget_set_selfpowered (struct usb_gadget *gadget) +{ + if (!gadget->ops->set_selfpowered) + return -EOPNOTSUPP; + return gadget->ops->set_selfpowered (gadget, 1); +} + +/** + * usb_gadget_clear_selfpowered - clear the device selfpowered feature. + * @gadget:the device being declared as bus-powered + * + * this affects the device status reported by the hardware driver. + * some hardware may not support bus-powered operation, in which + * case this feature's value can never change. + * + * returns zero on success, else negative errno. + */ +static inline int +usb_gadget_clear_selfpowered (struct usb_gadget *gadget) +{ + if (!gadget->ops->set_selfpowered) + return -EOPNOTSUPP; + return gadget->ops->set_selfpowered (gadget, 0); +} + +/** + * usb_gadget_vbus_connect - Notify controller that VBUS is powered + * @gadget:The device which now has VBUS power. + * + * This call is used by a driver for an external transceiver (or GPIO) + * that detects a VBUS power session starting. Common responses include + * resuming the controller, activating the D+ (or D-) pullup to let the + * host detect that a USB device is attached, and starting to draw power + * (8mA or possibly more, especially after SET_CONFIGURATION). + * + * Returns zero on success, else negative errno. + */ +static inline int +usb_gadget_vbus_connect(struct usb_gadget *gadget) +{ + if (!gadget->ops->vbus_session) + return -EOPNOTSUPP; + return gadget->ops->vbus_session (gadget, 1); +} + +/** + * usb_gadget_vbus_draw - constrain controller's VBUS power usage + * @gadget:The device whose VBUS usage is being described + * @mA:How much current to draw, in milliAmperes. This should be twice + * the value listed in the configuration descriptor bMaxPower field. + * + * This call is used by gadget drivers during SET_CONFIGURATION calls, + * reporting how much power the device may consume. For example, this + * could affect how quickly batteries are recharged. + * + * Returns zero on success, else negative errno. + */ +static inline int +usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) +{ + if (!gadget->ops->vbus_draw) + return -EOPNOTSUPP; + return gadget->ops->vbus_draw (gadget, mA); +} + +/** + * usb_gadget_vbus_disconnect - notify controller about VBUS session end + * @gadget:the device whose VBUS supply is being described + * + * This call is used by a driver for an external transceiver (or GPIO) + * that detects a VBUS power session ending. Common responses include + * reversing everything done in usb_gadget_vbus_connect(). + * + * Returns zero on success, else negative errno. + */ +static inline int +usb_gadget_vbus_disconnect(struct usb_gadget *gadget) +{ + if (!gadget->ops->vbus_session) + return -EOPNOTSUPP; + return gadget->ops->vbus_session (gadget, 0); +} + +/** + * usb_gadget_connect - software-controlled connect to USB host + * @gadget:the peripheral being connected + * + * Enables the D+ (or potentially D-) pullup. The host will start + * enumerating this gadget when the pullup is active and a VBUS session + * is active (the link is powered). This pullup is always enabled unless + * usb_gadget_disconnect() has been used to disable it. + * + * Returns zero on success, else negative errno. + */ +static inline int +usb_gadget_connect (struct usb_gadget *gadget) +{ + if (!gadget->ops->pullup) + return -EOPNOTSUPP; + return gadget->ops->pullup (gadget, 1); +} + +/** + * usb_gadget_disconnect - software-controlled disconnect from USB host + * @gadget:the peripheral being disconnected + * + * Disables the D+ (or potentially D-) pullup, which the host may see + * as a disconnect (when a VBUS session is active). Not all systems + * support software pullup controls. + * + * This routine may be used during the gadget driver bind() call to prevent + * the peripheral from ever being visible to the USB host, unless later + * usb_gadget_connect() is called. For example, user mode components may + * need to be activated before the system can talk to hosts. + * + * Returns zero on success, else negative errno. + */ +static inline int +usb_gadget_disconnect (struct usb_gadget *gadget) +{ + if (!gadget->ops->pullup) + return -EOPNOTSUPP; + return gadget->ops->pullup (gadget, 0); +} + + + +/*-------------------------------------------------------------------------*/ + +/** + * struct usb_gadget_driver - driver for usb 'slave' devices + * @function: String describing the gadget's function + * @speed: Highest speed the driver handles. + * @bind: Invoked when the driver is bound to a gadget, usually + * after registering the driver. + * At that point, ep0 is fully initialized, and ep_list holds + * the currently-available endpoints. + * Called in a context that permits sleeping. + * @setup: Invoked for ep0 control requests that aren't handled by + * the hardware level driver. Most calls must be handled by + * the gadget driver, including descriptor and configuration + * management. The 16 bit members of the setup data are in + * USB byte order. Called in_interrupt; this may not sleep. Driver + * queues a response to ep0, or returns negative to stall. + * @disconnect: Invoked after all transfers have been stopped, + * when the host is disconnected. May be called in_interrupt; this + * may not sleep. Some devices can't detect disconnect, so this might + * not be called except as part of controller shutdown. + * @unbind: Invoked when the driver is unbound from a gadget, + * usually from rmmod (after a disconnect is reported). + * Called in a context that permits sleeping. + * @suspend: Invoked on USB suspend. May be called in_interrupt. + * @resume: Invoked on USB resume. May be called in_interrupt. + * @driver: Driver model state for this driver. + * + * Devices are disabled till a gadget driver successfully bind()s, which + * means the driver will handle setup() requests needed to enumerate (and + * meet "chapter 9" requirements) then do some useful work. + * + * If gadget->is_otg is true, the gadget driver must provide an OTG + * descriptor during enumeration, or else fail the bind() call. In such + * cases, no USB traffic may flow until both bind() returns without + * having called usb_gadget_disconnect(), and the USB host stack has + * initialized. + * + * Drivers use hardware-specific knowledge to configure the usb hardware. + * endpoint addressing is only one of several hardware characteristics that + * are in descriptors the ep0 implementation returns from setup() calls. + * + * Except for ep0 implementation, most driver code shouldn't need change to + * run on top of different usb controllers. It'll use endpoints set up by + * that ep0 implementation. + * + * The usb controller driver handles a few standard usb requests. Those + * include set_address, and feature flags for devices, interfaces, and + * endpoints (the get_status, set_feature, and clear_feature requests). + * + * Accordingly, the driver's setup() callback must always implement all + * get_descriptor requests, returning at least a device descriptor and + * a configuration descriptor. Drivers must make sure the endpoint + * descriptors match any hardware constraints. Some hardware also constrains + * other descriptors. (The pxa250 allows only configurations 1, 2, or 3). + * + * The driver's setup() callback must also implement set_configuration, + * and should also implement set_interface, get_configuration, and + * get_interface. Setting a configuration (or interface) is where + * endpoints should be activated or (config 0) shut down. + * + * (Note that only the default control endpoint is supported. Neither + * hosts nor devices generally support control traffic except to ep0.) + * + * Most devices will ignore USB suspend/resume operations, and so will + * not provide those callbacks. However, some may need to change modes + * when the host is not longer directing those activities. For example, + * local controls (buttons, dials, etc) may need to be re-enabled since + * the (remote) host can't do that any longer; or an error state might + * be cleared, to make the device behave identically whether or not + * power is maintained. + */ +struct usb_gadget_driver { + char *function; + enum usb_device_speed speed; + int (*bind)(struct usb_gadget *); + void (*unbind)(struct usb_gadget *); + int (*setup)(struct usb_gadget *, + const struct usb_ctrlrequest *); + void (*disconnect)(struct usb_gadget *); + void (*suspend)(struct usb_gadget *); + void (*resume)(struct usb_gadget *); + + // FIXME support safe rmmod + struct device_driver driver; +}; + + + +/*-------------------------------------------------------------------------*/ + +/* driver modules register and unregister, as usual. + * these calls must be made in a context that can sleep. + * + * these will usually be implemented directly by the hardware-dependent + * usb bus interface driver, which will only support a single driver. + */ + +/** + * usb_gadget_register_driver - register a gadget driver + * @driver:the driver being registered + * + * Call this in your gadget driver's module initialization function, + * to tell the underlying usb controller driver about your driver. + * The driver's bind() function will be called to bind it to a + * gadget before this registration call returns. It's expected that + * the bind() functions will be in init sections. + * This function must be called in a context that can sleep. + */ +int usb_gadget_register_driver (struct usb_gadget_driver *driver); + +/** + * usb_gadget_unregister_driver - unregister a gadget driver + * @driver:the driver being unregistered + * + * Call this in your gadget driver's module cleanup function, + * to tell the underlying usb controller that your driver is + * going away. If the controller is connected to a USB host, + * it will first disconnect(). The driver is also requested + * to unbind() and clean up any device state, before this procedure + * finally returns. It's expected that the unbind() functions + * will in in exit sections, so may not be linked in some kernels. + * This function must be called in a context that can sleep. + */ +int usb_gadget_unregister_driver (struct usb_gadget_driver *driver); + +/*-------------------------------------------------------------------------*/ + +/* utility to simplify dealing with string descriptors */ + +/** + * struct usb_string - wraps a C string and its USB id + * @id:the (nonzero) ID for this string + * @s:the string, in UTF-8 encoding + * + * If you're using usb_gadget_get_string(), use this to wrap a string + * together with its ID. + */ +struct usb_string { + u8 id; + const char *s; +}; + +/** + * struct usb_gadget_strings - a set of USB strings in a given language + * @language:identifies the strings' language (0x0409 for en-us) + * @strings:array of strings with their ids + * + * If you're using usb_gadget_get_string(), use this to wrap all the + * strings for a given language. + */ +struct usb_gadget_strings { + u16 language; /* 0x0409 for en-us */ + struct usb_string *strings; +}; + +/* put descriptor for string with that id into buf (buflen >= 256) */ +int usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf); + +/*-------------------------------------------------------------------------*/ + +/* utility to simplify managing config descriptors */ + +/* write vector of descriptors into buffer */ +int usb_descriptor_fillbuf(void *, unsigned, + const struct usb_descriptor_header **); + +/* build config descriptor from single descriptor vector */ +int usb_gadget_config_buf(const struct usb_config_descriptor *config, + void *buf, unsigned buflen, const struct usb_descriptor_header **desc); + +/*-------------------------------------------------------------------------*/ + +/* utility wrapping a simple endpoint selection policy */ + +extern struct usb_ep *usb_ep_autoconfig (struct usb_gadget *, + struct usb_endpoint_descriptor *) __devinit; + +extern void usb_ep_autoconfig_reset (struct usb_gadget *) __devinit; + +#endif /* __KERNEL__ */ + +#endif /* __LINUX_USB_GADGET_H */ diff --git a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h deleted file mode 100644 index 5ea611e48ec..00000000000 --- a/include/linux/usb_gadget.h +++ /dev/null @@ -1,866 +0,0 @@ -/* - * - * - * We call the USB code inside a Linux-based peripheral device a "gadget" - * driver, except for the hardware-specific bus glue. One USB host can - * master many USB gadgets, but the gadgets are only slaved to one host. - * - * - * (C) Copyright 2002-2004 by David Brownell - * All Rights Reserved. - * - * This software is licensed under the GNU GPL version 2. - */ - -#ifndef __LINUX_USB_GADGET_H -#define __LINUX_USB_GADGET_H - -#ifdef __KERNEL__ - -struct usb_ep; - -/** - * struct usb_request - describes one i/o request - * @buf: Buffer used for data. Always provide this; some controllers - * only use PIO, or don't use DMA for some endpoints. - * @dma: DMA address corresponding to 'buf'. If you don't set this - * field, and the usb controller needs one, it is responsible - * for mapping and unmapping the buffer. - * @length: Length of that data - * @no_interrupt: If true, hints that no completion irq is needed. - * Helpful sometimes with deep request queues that are handled - * directly by DMA controllers. - * @zero: If true, when writing data, makes the last packet be "short" - * by adding a zero length packet as needed; - * @short_not_ok: When reading data, makes short packets be - * treated as errors (queue stops advancing till cleanup). - * @complete: Function called when request completes, so this request and - * its buffer may be re-used. - * Reads terminate with a short packet, or when the buffer fills, - * whichever comes first. When writes terminate, some data bytes - * will usually still be in flight (often in a hardware fifo). - * Errors (for reads or writes) stop the queue from advancing - * until the completion function returns, so that any transfers - * invalidated by the error may first be dequeued. - * @context: For use by the completion callback - * @list: For use by the gadget driver. - * @status: Reports completion code, zero or a negative errno. - * Normally, faults block the transfer queue from advancing until - * the completion callback returns. - * Code "-ESHUTDOWN" indicates completion caused by device disconnect, - * or when the driver disabled the endpoint. - * @actual: Reports bytes transferred to/from the buffer. For reads (OUT - * transfers) this may be less than the requested length. If the - * short_not_ok flag is set, short reads are treated as errors - * even when status otherwise indicates successful completion. - * Note that for writes (IN transfers) some data bytes may still - * reside in a device-side FIFO when the request is reported as - * complete. - * - * These are allocated/freed through the endpoint they're used with. The - * hardware's driver can add extra per-request data to the memory it returns, - * which often avoids separate memory allocations (potential failures), - * later when the request is queued. - * - * Request flags affect request handling, such as whether a zero length - * packet is written (the "zero" flag), whether a short read should be - * treated as an error (blocking request queue advance, the "short_not_ok" - * flag), or hinting that an interrupt is not required (the "no_interrupt" - * flag, for use with deep request queues). - * - * Bulk endpoints can use any size buffers, and can also be used for interrupt - * transfers. interrupt-only endpoints can be much less functional. - */ - // NOTE this is analagous to 'struct urb' on the host side, - // except that it's thinner and promotes more pre-allocation. - -struct usb_request { - void *buf; - unsigned length; - dma_addr_t dma; - - unsigned no_interrupt:1; - unsigned zero:1; - unsigned short_not_ok:1; - - void (*complete)(struct usb_ep *ep, - struct usb_request *req); - void *context; - struct list_head list; - - int status; - unsigned actual; -}; - -/*-------------------------------------------------------------------------*/ - -/* endpoint-specific parts of the api to the usb controller hardware. - * unlike the urb model, (de)multiplexing layers are not required. - * (so this api could slash overhead if used on the host side...) - * - * note that device side usb controllers commonly differ in how many - * endpoints they support, as well as their capabilities. - */ -struct usb_ep_ops { - int (*enable) (struct usb_ep *ep, - const struct usb_endpoint_descriptor *desc); - int (*disable) (struct usb_ep *ep); - - struct usb_request *(*alloc_request) (struct usb_ep *ep, - gfp_t gfp_flags); - void (*free_request) (struct usb_ep *ep, struct usb_request *req); - - int (*queue) (struct usb_ep *ep, struct usb_request *req, - gfp_t gfp_flags); - int (*dequeue) (struct usb_ep *ep, struct usb_request *req); - - int (*set_halt) (struct usb_ep *ep, int value); - int (*fifo_status) (struct usb_ep *ep); - void (*fifo_flush) (struct usb_ep *ep); -}; - -/** - * struct usb_ep - device side representation of USB endpoint - * @name:identifier for the endpoint, such as "ep-a" or "ep9in-bulk" - * @ops: Function pointers used to access hardware-specific operations. - * @ep_list:the gadget's ep_list holds all of its endpoints - * @maxpacket:The maximum packet size used on this endpoint. The initial - * value can sometimes be reduced (hardware allowing), according to - * the endpoint descriptor used to configure the endpoint. - * @driver_data:for use by the gadget driver. all other fields are - * read-only to gadget drivers. - * - * the bus controller driver lists all the general purpose endpoints in - * gadget->ep_list. the control endpoint (gadget->ep0) is not in that list, - * and is accessed only in response to a driver setup() callback. - */ -struct usb_ep { - void *driver_data; - - const char *name; - const struct usb_ep_ops *ops; - struct list_head ep_list; - unsigned maxpacket:16; -}; - -/*-------------------------------------------------------------------------*/ - -/** - * usb_ep_enable - configure endpoint, making it usable - * @ep:the endpoint being configured. may not be the endpoint named "ep0". - * drivers discover endpoints through the ep_list of a usb_gadget. - * @desc:descriptor for desired behavior. caller guarantees this pointer - * remains valid until the endpoint is disabled; the data byte order - * is little-endian (usb-standard). - * - * when configurations are set, or when interface settings change, the driver - * will enable or disable the relevant endpoints. while it is enabled, an - * endpoint may be used for i/o until the driver receives a disconnect() from - * the host or until the endpoint is disabled. - * - * the ep0 implementation (which calls this routine) must ensure that the - * hardware capabilities of each endpoint match the descriptor provided - * for it. for example, an endpoint named "ep2in-bulk" would be usable - * for interrupt transfers as well as bulk, but it likely couldn't be used - * for iso transfers or for endpoint 14. some endpoints are fully - * configurable, with more generic names like "ep-a". (remember that for - * USB, "in" means "towards the USB master".) - * - * returns zero, or a negative error code. - */ -static inline int -usb_ep_enable (struct usb_ep *ep, const struct usb_endpoint_descriptor *desc) -{ - return ep->ops->enable (ep, desc); -} - -/** - * usb_ep_disable - endpoint is no longer usable - * @ep:the endpoint being unconfigured. may not be the endpoint named "ep0". - * - * no other task may be using this endpoint when this is called. - * any pending and uncompleted requests will complete with status - * indicating disconnect (-ESHUTDOWN) before this call returns. - * gadget drivers must call usb_ep_enable() again before queueing - * requests to the endpoint. - * - * returns zero, or a negative error code. - */ -static inline int -usb_ep_disable (struct usb_ep *ep) -{ - return ep->ops->disable (ep); -} - -/** - * usb_ep_alloc_request - allocate a request object to use with this endpoint - * @ep:the endpoint to be used with with the request - * @gfp_flags:GFP_* flags to use - * - * Request objects must be allocated with this call, since they normally - * need controller-specific setup and may even need endpoint-specific - * resources such as allocation of DMA descriptors. - * Requests may be submitted with usb_ep_queue(), and receive a single - * completion callback. Free requests with usb_ep_free_request(), when - * they are no longer needed. - * - * Returns the request, or null if one could not be allocated. - */ -static inline struct usb_request * -usb_ep_alloc_request (struct usb_ep *ep, gfp_t gfp_flags) -{ - return ep->ops->alloc_request (ep, gfp_flags); -} - -/** - * usb_ep_free_request - frees a request object - * @ep:the endpoint associated with the request - * @req:the request being freed - * - * Reverses the effect of usb_ep_alloc_request(). - * Caller guarantees the request is not queued, and that it will - * no longer be requeued (or otherwise used). - */ -static inline void -usb_ep_free_request (struct usb_ep *ep, struct usb_request *req) -{ - ep->ops->free_request (ep, req); -} - -/** - * usb_ep_queue - queues (submits) an I/O request to an endpoint. - * @ep:the endpoint associated with the request - * @req:the request being submitted - * @gfp_flags: GFP_* flags to use in case the lower level driver couldn't - * pre-allocate all necessary memory with the request. - * - * This tells the device controller to perform the specified request through - * that endpoint (reading or writing a buffer). When the request completes, - * including being canceled by usb_ep_dequeue(), the request's completion - * routine is called to return the request to the driver. Any endpoint - * (except control endpoints like ep0) may have more than one transfer - * request queued; they complete in FIFO order. Once a gadget driver - * submits a request, that request may not be examined or modified until it - * is given back to that driver through the completion callback. - * - * Each request is turned into one or more packets. The controller driver - * never merges adjacent requests into the same packet. OUT transfers - * will sometimes use data that's already buffered in the hardware. - * Drivers can rely on the fact that the first byte of the request's buffer - * always corresponds to the first byte of some USB packet, for both - * IN and OUT transfers. - * - * Bulk endpoints can queue any amount of data; the transfer is packetized - * automatically. The last packet will be short if the request doesn't fill it - * out completely. Zero length packets (ZLPs) should be avoided in portable - * protocols since not all usb hardware can successfully handle zero length - * packets. (ZLPs may be explicitly written, and may be implicitly written if - * the request 'zero' flag is set.) Bulk endpoints may also be used - * for interrupt transfers; but the reverse is not true, and some endpoints - * won't support every interrupt transfer. (Such as 768 byte packets.) - * - * Interrupt-only endpoints are less functional than bulk endpoints, for - * example by not supporting queueing or not handling buffers that are - * larger than the endpoint's maxpacket size. They may also treat data - * toggle differently. - * - * Control endpoints ... after getting a setup() callback, the driver queues - * one response (even if it would be zero length). That enables the - * status ack, after transfering data as specified in the response. Setup - * functions may return negative error codes to generate protocol stalls. - * (Note that some USB device controllers disallow protocol stall responses - * in some cases.) When control responses are deferred (the response is - * written after the setup callback returns), then usb_ep_set_halt() may be - * used on ep0 to trigger protocol stalls. - * - * For periodic endpoints, like interrupt or isochronous ones, the usb host - * arranges to poll once per interval, and the gadget driver usually will - * have queued some data to transfer at that time. - * - * Returns zero, or a negative error code. Endpoints that are not enabled - * report errors; errors will also be - * reported when the usb peripheral is disconnected. - */ -static inline int -usb_ep_queue (struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags) -{ - return ep->ops->queue (ep, req, gfp_flags); -} - -/** - * usb_ep_dequeue - dequeues (cancels, unlinks) an I/O request from an endpoint - * @ep:the endpoint associated with the request - * @req:the request being canceled - * - * if the request is still active on the endpoint, it is dequeued and its - * completion routine is called (with status -ECONNRESET); else a negative - * error code is returned. - * - * note that some hardware can't clear out write fifos (to unlink the request - * at the head of the queue) except as part of disconnecting from usb. such - * restrictions prevent drivers from supporting configuration changes, - * even to configuration zero (a "chapter 9" requirement). - */ -static inline int usb_ep_dequeue (struct usb_ep *ep, struct usb_request *req) -{ - return ep->ops->dequeue (ep, req); -} - -/** - * usb_ep_set_halt - sets the endpoint halt feature. - * @ep: the non-isochronous endpoint being stalled - * - * Use this to stall an endpoint, perhaps as an error report. - * Except for control endpoints, - * the endpoint stays halted (will not stream any data) until the host - * clears this feature; drivers may need to empty the endpoint's request - * queue first, to make sure no inappropriate transfers happen. - * - * Note that while an endpoint CLEAR_FEATURE will be invisible to the - * gadget driver, a SET_INTERFACE will not be. To reset endpoints for the - * current altsetting, see usb_ep_clear_halt(). When switching altsettings, - * it's simplest to use usb_ep_enable() or usb_ep_disable() for the endpoints. - * - * Returns zero, or a negative error code. On success, this call sets - * underlying hardware state that blocks data transfers. - * Attempts to halt IN endpoints will fail (returning -EAGAIN) if any - * transfer requests are still queued, or if the controller hardware - * (usually a FIFO) still holds bytes that the host hasn't collected. - */ -static inline int -usb_ep_set_halt (struct usb_ep *ep) -{ - return ep->ops->set_halt (ep, 1); -} - -/** - * usb_ep_clear_halt - clears endpoint halt, and resets toggle - * @ep:the bulk or interrupt endpoint being reset - * - * Use this when responding to the standard usb "set interface" request, - * for endpoints that aren't reconfigured, after clearing any other state - * in the endpoint's i/o queue. - * - * Returns zero, or a negative error code. On success, this call clears - * the underlying hardware state reflecting endpoint halt and data toggle. - * Note that some hardware can't support this request (like pxa2xx_udc), - * and accordingly can't correctly implement interface altsettings. - */ -static inline int -usb_ep_clear_halt (struct usb_ep *ep) -{ - return ep->ops->set_halt (ep, 0); -} - -/** - * usb_ep_fifo_status - returns number of bytes in fifo, or error - * @ep: the endpoint whose fifo status is being checked. - * - * FIFO endpoints may have "unclaimed data" in them in certain cases, - * such as after aborted transfers. Hosts may not have collected all - * the IN data written by the gadget driver (and reported by a request - * completion). The gadget driver may not have collected all the data - * written OUT to it by the host. Drivers that need precise handling for - * fault reporting or recovery may need to use this call. - * - * This returns the number of such bytes in the fifo, or a negative - * errno if the endpoint doesn't use a FIFO or doesn't support such - * precise handling. - */ -static inline int -usb_ep_fifo_status (struct usb_ep *ep) -{ - if (ep->ops->fifo_status) - return ep->ops->fifo_status (ep); - else - return -EOPNOTSUPP; -} - -/** - * usb_ep_fifo_flush - flushes contents of a fifo - * @ep: the endpoint whose fifo is being flushed. - * - * This call may be used to flush the "unclaimed data" that may exist in - * an endpoint fifo after abnormal transaction terminations. The call - * must never be used except when endpoint is not being used for any - * protocol translation. - */ -static inline void -usb_ep_fifo_flush (struct usb_ep *ep) -{ - if (ep->ops->fifo_flush) - ep->ops->fifo_flush (ep); -} - - -/*-------------------------------------------------------------------------*/ - -struct usb_gadget; - -/* the rest of the api to the controller hardware: device operations, - * which don't involve endpoints (or i/o). - */ -struct usb_gadget_ops { - int (*get_frame)(struct usb_gadget *); - int (*wakeup)(struct usb_gadget *); - int (*set_selfpowered) (struct usb_gadget *, int is_selfpowered); - int (*vbus_session) (struct usb_gadget *, int is_active); - int (*vbus_draw) (struct usb_gadget *, unsigned mA); - int (*pullup) (struct usb_gadget *, int is_on); - int (*ioctl)(struct usb_gadget *, - unsigned code, unsigned long param); -}; - -/** - * struct usb_gadget - represents a usb slave device - * @ops: Function pointers used to access hardware-specific operations. - * @ep0: Endpoint zero, used when reading or writing responses to - * driver setup() requests - * @ep_list: List of other endpoints supported by the device. - * @speed: Speed of current connection to USB host. - * @is_dualspeed: True if the controller supports both high and full speed - * operation. If it does, the gadget driver must also support both. - * @is_otg: True if the USB device port uses a Mini-AB jack, so that the - * gadget driver must provide a USB OTG descriptor. - * @is_a_peripheral: False unless is_otg, the "A" end of a USB cable - * is in the Mini-AB jack, and HNP has been used to switch roles - * so that the "A" device currently acts as A-Peripheral, not A-Host. - * @a_hnp_support: OTG device feature flag, indicating that the A-Host - * supports HNP at this port. - * @a_alt_hnp_support: OTG device feature flag, indicating that the A-Host - * only supports HNP on a different root port. - * @b_hnp_enable: OTG device feature flag, indicating that the A-Host - * enabled HNP support. - * @name: Identifies the controller hardware type. Used in diagnostics - * and sometimes configuration. - * @dev: Driver model state for this abstract device. - * - * Gadgets have a mostly-portable "gadget driver" implementing device - * functions, handling all usb configurations and interfaces. Gadget - * drivers talk to hardware-specific code indirectly, through ops vectors. - * That insulates the gadget driver from hardware details, and packages - * the hardware endpoints through generic i/o queues. The "usb_gadget" - * and "usb_ep" interfaces provide that insulation from the hardware. - * - * Except for the driver data, all fields in this structure are - * read-only to the gadget driver. That driver data is part of the - * "driver model" infrastructure in 2.6 (and later) kernels, and for - * earlier systems is grouped in a similar structure that's not known - * to the rest of the kernel. - * - * Values of the three OTG device feature flags are updated before the - * setup() call corresponding to USB_REQ_SET_CONFIGURATION, and before - * driver suspend() calls. They are valid only when is_otg, and when the - * device is acting as a B-Peripheral (so is_a_peripheral is false). - */ -struct usb_gadget { - /* readonly to gadget driver */ - const struct usb_gadget_ops *ops; - struct usb_ep *ep0; - struct list_head ep_list; /* of usb_ep */ - enum usb_device_speed speed; - unsigned is_dualspeed:1; - unsigned is_otg:1; - unsigned is_a_peripheral:1; - unsigned b_hnp_enable:1; - unsigned a_hnp_support:1; - unsigned a_alt_hnp_support:1; - const char *name; - struct device dev; -}; - -static inline void set_gadget_data (struct usb_gadget *gadget, void *data) - { dev_set_drvdata (&gadget->dev, data); } -static inline void *get_gadget_data (struct usb_gadget *gadget) - { return dev_get_drvdata (&gadget->dev); } - -/* iterates the non-control endpoints; 'tmp' is a struct usb_ep pointer */ -#define gadget_for_each_ep(tmp,gadget) \ - list_for_each_entry(tmp, &(gadget)->ep_list, ep_list) - - -/** - * gadget_is_dualspeed - return true iff the hardware handles high speed - * @gadget: controller that might support both high and full speeds - */ -static inline int gadget_is_dualspeed(struct usb_gadget *g) -{ -#ifdef CONFIG_USB_GADGET_DUALSPEED - /* runtime test would check "g->is_dualspeed" ... that might be - * useful to work around hardware bugs, but is mostly pointless - */ - return 1; -#else - return 0; -#endif -} - -/** - * gadget_is_otg - return true iff the hardware is OTG-ready - * @gadget: controller that might have a Mini-AB connector - * - * This is a runtime test, since kernels with a USB-OTG stack sometimes - * run on boards which only have a Mini-B (or Mini-A) connector. - */ -static inline int gadget_is_otg(struct usb_gadget *g) -{ -#ifdef CONFIG_USB_OTG - return g->is_otg; -#else - return 0; -#endif -} - - -/** - * usb_gadget_frame_number - returns the current frame number - * @gadget: controller that reports the frame number - * - * Returns the usb frame number, normally eleven bits from a SOF packet, - * or negative errno if this device doesn't support this capability. - */ -static inline int usb_gadget_frame_number (struct usb_gadget *gadget) -{ - return gadget->ops->get_frame (gadget); -} - -/** - * usb_gadget_wakeup - tries to wake up the host connected to this gadget - * @gadget: controller used to wake up the host - * - * Returns zero on success, else negative error code if the hardware - * doesn't support such attempts, or its support has not been enabled - * by the usb host. Drivers must return device descriptors that report - * their ability to support this, or hosts won't enable it. - * - * This may also try to use SRP to wake the host and start enumeration, - * even if OTG isn't otherwise in use. OTG devices may also start - * remote wakeup even when hosts don't explicitly enable it. - */ -static inline int usb_gadget_wakeup (struct usb_gadget *gadget) -{ - if (!gadget->ops->wakeup) - return -EOPNOTSUPP; - return gadget->ops->wakeup (gadget); -} - -/** - * usb_gadget_set_selfpowered - sets the device selfpowered feature. - * @gadget:the device being declared as self-powered - * - * this affects the device status reported by the hardware driver - * to reflect that it now has a local power supply. - * - * returns zero on success, else negative errno. - */ -static inline int -usb_gadget_set_selfpowered (struct usb_gadget *gadget) -{ - if (!gadget->ops->set_selfpowered) - return -EOPNOTSUPP; - return gadget->ops->set_selfpowered (gadget, 1); -} - -/** - * usb_gadget_clear_selfpowered - clear the device selfpowered feature. - * @gadget:the device being declared as bus-powered - * - * this affects the device status reported by the hardware driver. - * some hardware may not support bus-powered operation, in which - * case this feature's value can never change. - * - * returns zero on success, else negative errno. - */ -static inline int -usb_gadget_clear_selfpowered (struct usb_gadget *gadget) -{ - if (!gadget->ops->set_selfpowered) - return -EOPNOTSUPP; - return gadget->ops->set_selfpowered (gadget, 0); -} - -/** - * usb_gadget_vbus_connect - Notify controller that VBUS is powered - * @gadget:The device which now has VBUS power. - * - * This call is used by a driver for an external transceiver (or GPIO) - * that detects a VBUS power session starting. Common responses include - * resuming the controller, activating the D+ (or D-) pullup to let the - * host detect that a USB device is attached, and starting to draw power - * (8mA or possibly more, especially after SET_CONFIGURATION). - * - * Returns zero on success, else negative errno. - */ -static inline int -usb_gadget_vbus_connect(struct usb_gadget *gadget) -{ - if (!gadget->ops->vbus_session) - return -EOPNOTSUPP; - return gadget->ops->vbus_session (gadget, 1); -} - -/** - * usb_gadget_vbus_draw - constrain controller's VBUS power usage - * @gadget:The device whose VBUS usage is being described - * @mA:How much current to draw, in milliAmperes. This should be twice - * the value listed in the configuration descriptor bMaxPower field. - * - * This call is used by gadget drivers during SET_CONFIGURATION calls, - * reporting how much power the device may consume. For example, this - * could affect how quickly batteries are recharged. - * - * Returns zero on success, else negative errno. - */ -static inline int -usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) -{ - if (!gadget->ops->vbus_draw) - return -EOPNOTSUPP; - return gadget->ops->vbus_draw (gadget, mA); -} - -/** - * usb_gadget_vbus_disconnect - notify controller about VBUS session end - * @gadget:the device whose VBUS supply is being described - * - * This call is used by a driver for an external transceiver (or GPIO) - * that detects a VBUS power session ending. Common responses include - * reversing everything done in usb_gadget_vbus_connect(). - * - * Returns zero on success, else negative errno. - */ -static inline int -usb_gadget_vbus_disconnect(struct usb_gadget *gadget) -{ - if (!gadget->ops->vbus_session) - return -EOPNOTSUPP; - return gadget->ops->vbus_session (gadget, 0); -} - -/** - * usb_gadget_connect - software-controlled connect to USB host - * @gadget:the peripheral being connected - * - * Enables the D+ (or potentially D-) pullup. The host will start - * enumerating this gadget when the pullup is active and a VBUS session - * is active (the link is powered). This pullup is always enabled unless - * usb_gadget_disconnect() has been used to disable it. - * - * Returns zero on success, else negative errno. - */ -static inline int -usb_gadget_connect (struct usb_gadget *gadget) -{ - if (!gadget->ops->pullup) - return -EOPNOTSUPP; - return gadget->ops->pullup (gadget, 1); -} - -/** - * usb_gadget_disconnect - software-controlled disconnect from USB host - * @gadget:the peripheral being disconnected - * - * Disables the D+ (or potentially D-) pullup, which the host may see - * as a disconnect (when a VBUS session is active). Not all systems - * support software pullup controls. - * - * This routine may be used during the gadget driver bind() call to prevent - * the peripheral from ever being visible to the USB host, unless later - * usb_gadget_connect() is called. For example, user mode components may - * need to be activated before the system can talk to hosts. - * - * Returns zero on success, else negative errno. - */ -static inline int -usb_gadget_disconnect (struct usb_gadget *gadget) -{ - if (!gadget->ops->pullup) - return -EOPNOTSUPP; - return gadget->ops->pullup (gadget, 0); -} - - - -/*-------------------------------------------------------------------------*/ - -/** - * struct usb_gadget_driver - driver for usb 'slave' devices - * @function: String describing the gadget's function - * @speed: Highest speed the driver handles. - * @bind: Invoked when the driver is bound to a gadget, usually - * after registering the driver. - * At that point, ep0 is fully initialized, and ep_list holds - * the currently-available endpoints. - * Called in a context that permits sleeping. - * @setup: Invoked for ep0 control requests that aren't handled by - * the hardware level driver. Most calls must be handled by - * the gadget driver, including descriptor and configuration - * management. The 16 bit members of the setup data are in - * USB byte order. Called in_interrupt; this may not sleep. Driver - * queues a response to ep0, or returns negative to stall. - * @disconnect: Invoked after all transfers have been stopped, - * when the host is disconnected. May be called in_interrupt; this - * may not sleep. Some devices can't detect disconnect, so this might - * not be called except as part of controller shutdown. - * @unbind: Invoked when the driver is unbound from a gadget, - * usually from rmmod (after a disconnect is reported). - * Called in a context that permits sleeping. - * @suspend: Invoked on USB suspend. May be called in_interrupt. - * @resume: Invoked on USB resume. May be called in_interrupt. - * @driver: Driver model state for this driver. - * - * Devices are disabled till a gadget driver successfully bind()s, which - * means the driver will handle setup() requests needed to enumerate (and - * meet "chapter 9" requirements) then do some useful work. - * - * If gadget->is_otg is true, the gadget driver must provide an OTG - * descriptor during enumeration, or else fail the bind() call. In such - * cases, no USB traffic may flow until both bind() returns without - * having called usb_gadget_disconnect(), and the USB host stack has - * initialized. - * - * Drivers use hardware-specific knowledge to configure the usb hardware. - * endpoint addressing is only one of several hardware characteristics that - * are in descriptors the ep0 implementation returns from setup() calls. - * - * Except for ep0 implementation, most driver code shouldn't need change to - * run on top of different usb controllers. It'll use endpoints set up by - * that ep0 implementation. - * - * The usb controller driver handles a few standard usb requests. Those - * include set_address, and feature flags for devices, interfaces, and - * endpoints (the get_status, set_feature, and clear_feature requests). - * - * Accordingly, the driver's setup() callback must always implement all - * get_descriptor requests, returning at least a device descriptor and - * a configuration descriptor. Drivers must make sure the endpoint - * descriptors match any hardware constraints. Some hardware also constrains - * other descriptors. (The pxa250 allows only configurations 1, 2, or 3). - * - * The driver's setup() callback must also implement set_configuration, - * and should also implement set_interface, get_configuration, and - * get_interface. Setting a configuration (or interface) is where - * endpoints should be activated or (config 0) shut down. - * - * (Note that only the default control endpoint is supported. Neither - * hosts nor devices generally support control traffic except to ep0.) - * - * Most devices will ignore USB suspend/resume operations, and so will - * not provide those callbacks. However, some may need to change modes - * when the host is not longer directing those activities. For example, - * local controls (buttons, dials, etc) may need to be re-enabled since - * the (remote) host can't do that any longer; or an error state might - * be cleared, to make the device behave identically whether or not - * power is maintained. - */ -struct usb_gadget_driver { - char *function; - enum usb_device_speed speed; - int (*bind)(struct usb_gadget *); - void (*unbind)(struct usb_gadget *); - int (*setup)(struct usb_gadget *, - const struct usb_ctrlrequest *); - void (*disconnect)(struct usb_gadget *); - void (*suspend)(struct usb_gadget *); - void (*resume)(struct usb_gadget *); - - // FIXME support safe rmmod - struct device_driver driver; -}; - - - -/*-------------------------------------------------------------------------*/ - -/* driver modules register and unregister, as usual. - * these calls must be made in a context that can sleep. - * - * these will usually be implemented directly by the hardware-dependent - * usb bus interface driver, which will only support a single driver. - */ - -/** - * usb_gadget_register_driver - register a gadget driver - * @driver:the driver being registered - * - * Call this in your gadget driver's module initialization function, - * to tell the underlying usb controller driver about your driver. - * The driver's bind() function will be called to bind it to a - * gadget before this registration call returns. It's expected that - * the bind() functions will be in init sections. - * This function must be called in a context that can sleep. - */ -int usb_gadget_register_driver (struct usb_gadget_driver *driver); - -/** - * usb_gadget_unregister_driver - unregister a gadget driver - * @driver:the driver being unregistered - * - * Call this in your gadget driver's module cleanup function, - * to tell the underlying usb controller that your driver is - * going away. If the controller is connected to a USB host, - * it will first disconnect(). The driver is also requested - * to unbind() and clean up any device state, before this procedure - * finally returns. It's expected that the unbind() functions - * will in in exit sections, so may not be linked in some kernels. - * This function must be called in a context that can sleep. - */ -int usb_gadget_unregister_driver (struct usb_gadget_driver *driver); - -/*-------------------------------------------------------------------------*/ - -/* utility to simplify dealing with string descriptors */ - -/** - * struct usb_string - wraps a C string and its USB id - * @id:the (nonzero) ID for this string - * @s:the string, in UTF-8 encoding - * - * If you're using usb_gadget_get_string(), use this to wrap a string - * together with its ID. - */ -struct usb_string { - u8 id; - const char *s; -}; - -/** - * struct usb_gadget_strings - a set of USB strings in a given language - * @language:identifies the strings' language (0x0409 for en-us) - * @strings:array of strings with their ids - * - * If you're using usb_gadget_get_string(), use this to wrap all the - * strings for a given language. - */ -struct usb_gadget_strings { - u16 language; /* 0x0409 for en-us */ - struct usb_string *strings; -}; - -/* put descriptor for string with that id into buf (buflen >= 256) */ -int usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf); - -/*-------------------------------------------------------------------------*/ - -/* utility to simplify managing config descriptors */ - -/* write vector of descriptors into buffer */ -int usb_descriptor_fillbuf(void *, unsigned, - const struct usb_descriptor_header **); - -/* build config descriptor from single descriptor vector */ -int usb_gadget_config_buf(const struct usb_config_descriptor *config, - void *buf, unsigned buflen, const struct usb_descriptor_header **desc); - -/*-------------------------------------------------------------------------*/ - -/* utility wrapping a simple endpoint selection policy */ - -extern struct usb_ep *usb_ep_autoconfig (struct usb_gadget *, - struct usb_endpoint_descriptor *) __devinit; - -extern void usb_ep_autoconfig_reset (struct usb_gadget *) __devinit; - -#endif /* __KERNEL__ */ - -#endif /* __LINUX_USB_GADGET_H */ -- cgit v1.2.3-70-g09d2 From 27f5d75afaa1b65e4cc1e4ac8a2a5095d24f1576 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 4 Oct 2007 18:06:16 -0700 Subject: USB: re-remove Remove ... somehow this was recreated when the Blackfin arch was merged, instead of using which is the correct header. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- arch/blackfin/mach-bf537/boards/generic_board.c | 2 +- arch/blackfin/mach-bf537/boards/pnav10.c | 2 +- arch/blackfin/mach-bf537/boards/stamp.c | 2 +- include/linux/usb_sl811.h | 26 ------------------------- 4 files changed, 3 insertions(+), 29 deletions(-) delete mode 100644 include/linux/usb_sl811.h diff --git a/arch/blackfin/mach-bf537/boards/generic_board.c b/arch/blackfin/mach-bf537/boards/generic_board.c index 5e9d09eb857..6668c8e4a3f 100644 --- a/arch/blackfin/mach-bf537/boards/generic_board.c +++ b/arch/blackfin/mach-bf537/boards/generic_board.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/blackfin/mach-bf537/boards/pnav10.c b/arch/blackfin/mach-bf537/boards/pnav10.c index 20507e92a3a..f83a2544004 100644 --- a/arch/blackfin/mach-bf537/boards/pnav10.c +++ b/arch/blackfin/mach-bf537/boards/pnav10.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c index 47d7d4a0e73..f42ba3aa86d 100644 --- a/arch/blackfin/mach-bf537/boards/stamp.c +++ b/arch/blackfin/mach-bf537/boards/stamp.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/linux/usb_sl811.h b/include/linux/usb_sl811.h deleted file mode 100644 index 4f2d012d730..00000000000 --- a/include/linux/usb_sl811.h +++ /dev/null @@ -1,26 +0,0 @@ - -/* - * board initialization should put one of these into dev->platform_data - * and place the sl811hs onto platform_bus named "sl811-hcd". - */ - -struct sl811_platform_data { - unsigned can_wakeup:1; - - /* given port_power, msec/2 after power on till power good */ - u8 potpg; - - /* mA/2 power supplied on this port (max = default = 250) */ - u8 power; - - /* sl811 relies on an external source of VBUS current */ - void (*port_power)(struct device *dev, int is_on); - - /* pulse sl811 nRST (probably with a GPIO) */ - void (*reset)(struct device *dev); - - // some boards need something like these: - // int (*check_overcurrent)(struct device *dev); - // void (*clock_enable)(struct device *dev, int is_on); -}; - -- cgit v1.2.3-70-g09d2 From 3046c6db575019ba4ce6b9deac352d438ddf733d Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 5 Oct 2007 14:43:00 -0400 Subject: USB: unusual_devs entry for Nikon DSC D2Xs This patch (as996) adds an unusual_devs entry for the Nikon DSC D2Xs camera. Signed-off-by: Alan Stern Cc: Phil Dibowitz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 5129b538be9..edf92914674 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -362,6 +362,13 @@ UNUSUAL_DEV( 0x04b0, 0x0413, 0x0110, 0x0110, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY), +/* Reported by Paul Check */ +UNUSUAL_DEV( 0x04b0, 0x0415, 0x0100, 0x0100, + "NIKON", + "NIKON DSC D2Xs", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY), + /* BENQ DC5330 * Reported by Manuel Fombuena and * Frank Copeland */ -- cgit v1.2.3-70-g09d2 From d9c563626d9a136636385209d59d0c4f16c4a7ab Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 26 Sep 2007 23:34:18 +0100 Subject: USB: visor: termios bits Visor has a huge complex routine which displays termios bits for debug but doesn't do anything. Get the correct behaviour by removing it all Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/visor.c | 64 ---------------------------------------------- 1 file changed, 64 deletions(-) diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 30e08c0bcdc..7ee087fed91 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -46,7 +46,6 @@ static int visor_probe (struct usb_serial *serial, const struct usb_device_id static int visor_calc_num_ports(struct usb_serial *serial); static void visor_shutdown (struct usb_serial *serial); static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); -static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios); static void visor_write_bulk_callback (struct urb *urb); static void visor_read_bulk_callback (struct urb *urb); static void visor_read_int_callback (struct urb *urb); @@ -203,7 +202,6 @@ static struct usb_serial_driver handspring_device = { .calc_num_ports = visor_calc_num_ports, .shutdown = visor_shutdown, .ioctl = visor_ioctl, - .set_termios = visor_set_termios, .write = visor_write, .write_room = visor_write_room, .chars_in_buffer = visor_chars_in_buffer, @@ -234,7 +232,6 @@ static struct usb_serial_driver clie_5_device = { .calc_num_ports = visor_calc_num_ports, .shutdown = visor_shutdown, .ioctl = visor_ioctl, - .set_termios = visor_set_termios, .write = visor_write, .write_room = visor_write_room, .chars_in_buffer = visor_chars_in_buffer, @@ -262,7 +259,6 @@ static struct usb_serial_driver clie_3_5_device = { .unthrottle = visor_unthrottle, .attach = clie_3_5_startup, .ioctl = visor_ioctl, - .set_termios = visor_set_termios, .write = visor_write, .write_room = visor_write_room, .chars_in_buffer = visor_chars_in_buffer, @@ -936,66 +932,6 @@ static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsign return -ENOIOCTLCMD; } - -/* This function is all nice and good, but we don't change anything based on it :) */ -static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) -{ - unsigned int cflag; - - dbg("%s - port %d", __FUNCTION__, port->number); - - if ((!port->tty) || (!port->tty->termios)) { - dbg("%s - no tty structures", __FUNCTION__); - return; - } - - cflag = port->tty->termios->c_cflag; - - /* get the byte size */ - switch (cflag & CSIZE) { - case CS5: dbg("%s - data bits = 5", __FUNCTION__); break; - case CS6: dbg("%s - data bits = 6", __FUNCTION__); break; - case CS7: dbg("%s - data bits = 7", __FUNCTION__); break; - default: - case CS8: dbg("%s - data bits = 8", __FUNCTION__); break; - } - - /* determine the parity */ - if (cflag & PARENB) - if (cflag & PARODD) - dbg("%s - parity = odd", __FUNCTION__); - else - dbg("%s - parity = even", __FUNCTION__); - else - dbg("%s - parity = none", __FUNCTION__); - - /* figure out the stop bits requested */ - if (cflag & CSTOPB) - dbg("%s - stop bits = 2", __FUNCTION__); - else - dbg("%s - stop bits = 1", __FUNCTION__); - - - /* figure out the flow control settings */ - if (cflag & CRTSCTS) - dbg("%s - RTS/CTS is enabled", __FUNCTION__); - else - dbg("%s - RTS/CTS is disabled", __FUNCTION__); - - /* determine software flow control */ - if (I_IXOFF(port->tty)) - dbg("%s - XON/XOFF is enabled, XON = %2x, XOFF = %2x", - __FUNCTION__, START_CHAR(port->tty), STOP_CHAR(port->tty)); - else - dbg("%s - XON/XOFF is disabled", __FUNCTION__); - - /* get the baud rate wanted */ - dbg("%s - baud rate = %d", __FUNCTION__, tty_get_baud_rate(port->tty)); - - return; -} - - static int __init visor_init (void) { int i, retval; -- cgit v1.2.3-70-g09d2 From f621b8437d6ae502dde45797f56407e48c7a68b4 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 26 Sep 2007 23:22:36 +0100 Subject: USB: funsoft: Fix termios Funsoft has a bogus ioctl handler doing bogus termios handling in a bogus manner. Fortunately we can simply delete all the bogus bits and get the right default behaviour ! Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/funsoft.c | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c index 4092f6dc9ef..b5194dc7d3b 100644 --- a/drivers/usb/serial/funsoft.c +++ b/drivers/usb/serial/funsoft.c @@ -24,26 +24,6 @@ static struct usb_device_id id_table [] = { }; MODULE_DEVICE_TABLE(usb, id_table); -static int funsoft_ioctl(struct usb_serial_port *port, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct ktermios t; - - dbg("%s - port %d, cmd 0x%04x", __FUNCTION__, port->number, cmd); - - if (cmd == TCSETSF) { - if (user_termios_to_kernel_termios(&t, (struct termios __user *)arg)) - return -EFAULT; - - dbg("%s - iflag:%x oflag:%x cflag:%x lflag:%x", __FUNCTION__, - t.c_iflag, t.c_oflag, t.c_cflag, t.c_lflag); - - if (!(t.c_lflag & ICANON)) - return -EINVAL; - } - return -ENOIOCTLCMD; -} - static struct usb_driver funsoft_driver = { .name = "funsoft", .probe = usb_serial_probe, @@ -63,7 +43,6 @@ static struct usb_serial_driver funsoft_device = { .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, .num_ports = 1, - .ioctl = funsoft_ioctl, }; static int __init funsoft_init(void) -- cgit v1.2.3-70-g09d2 From 4f45426cfd6170311e116442ccd8ce0e31979237 Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Tue, 9 Oct 2007 15:00:05 -0700 Subject: USB: add runtime frame_no quirk for big-endian OHCI Add OHCI big endian frame_no quirk. The frame_no value stored in the HCCA is a 16 bit field at a specific offset, but since not all CPUs can do 16-bit memory accesses it's used as a 32 bit field. And that's why big-endian OHCI must shift 16 bits ... unless the spec is not followed. Currently there's one MPC52xx platform that doesn't need the shift. This patch adds a new "big endian frame_no" quirk to control that at runtime. Signed-off-by: Valentine Barshak Acked-by: Dale Farnsworth Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-ppc-of.c | 5 ++++- drivers/usb/host/ohci-ppc-soc.c | 5 +++++ drivers/usb/host/ohci.h | 13 ++++++------- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c index c43b66acd4d..0a742692015 100644 --- a/drivers/usb/host/ohci-ppc-of.c +++ b/drivers/usb/host/ohci-ppc-of.c @@ -134,8 +134,11 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match) } ohci = hcd_to_ohci(hcd); - if (is_bigendian) + if (is_bigendian) { ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC; + if (of_device_is_compatible(dn, "mpc5200-ohci")) + ohci->flags |= OHCI_QUIRK_FRAME_NO; + } ohci_hcd_init(ohci); diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c index 1a2e1777ca6..f95be1896b0 100644 --- a/drivers/usb/host/ohci-ppc-soc.c +++ b/drivers/usb/host/ohci-ppc-soc.c @@ -73,6 +73,11 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver, ohci = hcd_to_ohci(hcd); ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC; + +#ifdef CONFIG_PPC_MPC52xx + /* MPC52xx doesn't need frame_no shift */ + ohci->flags |= OHCI_QUIRK_FRAME_NO; +#endif ohci_hcd_init(ohci); retval = usb_add_hcd(hcd, irq, IRQF_DISABLED); diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index dd4d5b4dcb6..47c5c66a282 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -398,6 +398,7 @@ struct ohci_hcd { #define OHCI_QUIRK_BE_MMIO 0x10 /* BE registers */ #define OHCI_QUIRK_ZFMICRO 0x20 /* Compaq ZFMicro chipset*/ #define OHCI_QUIRK_NEC 0x40 /* lost interrupts */ +#define OHCI_QUIRK_FRAME_NO 0x80 /* no big endian frame_no shift */ // there are also chip quirks/bugs in init logic struct work_struct nec_work; /* Worker for NEC quirk */ @@ -633,15 +634,12 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x) /* HCCA frame number is 16 bits, but is accessed as 32 bits since not all * hardware handles 16 bit reads. That creates a different confusion on * some big-endian SOC implementations. Same thing happens with PSW access. - * - * FIXME: Deal with that as a runtime quirk when STB03xxx is ported over - * to arch/powerpc */ -#ifdef CONFIG_STB03xxx -#define OHCI_BE_FRAME_NO_SHIFT 16 +#ifdef CONFIG_PPC_MPC52xx +#define big_endian_frame_no_quirk(ohci) (ohci->flags & OHCI_QUIRK_FRAME_NO) #else -#define OHCI_BE_FRAME_NO_SHIFT 0 +#define big_endian_frame_no_quirk(ohci) 0 #endif static inline u16 ohci_frame_no(const struct ohci_hcd *ohci) @@ -649,7 +647,8 @@ static inline u16 ohci_frame_no(const struct ohci_hcd *ohci) u32 tmp; if (big_endian_desc(ohci)) { tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no); - tmp >>= OHCI_BE_FRAME_NO_SHIFT; + if (!big_endian_frame_no_quirk(ohci)) + tmp >>= 16; } else tmp = le32_to_cpup((__force __le32 *)&ohci->hcca->frame_no); -- cgit v1.2.3-70-g09d2 From b24896c6b7ddb37ab20ba0bbfd0ed36a38923f67 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 9 Oct 2007 22:04:16 -0700 Subject: USB: ehci build fixes on au1xxx, ppc-soc Cleanup: references to two PM routines (and HCD entry points) that no longer exist are swapped with their replacements. Evidently au1xxx and ppc-soc EHCI support doesn't get compiled with power management very much, or these build bugs would have been patched long ago. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-au1xxx.c | 6 ++---- drivers/usb/host/ehci-ppc-soc.c | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c index b1d19268cb2..766ef68a0b4 100644 --- a/drivers/usb/host/ehci-au1xxx.c +++ b/drivers/usb/host/ehci-au1xxx.c @@ -220,10 +220,8 @@ static const struct hc_driver ehci_au1xxx_hc_driver = { */ .hub_status_data = ehci_hub_status_data, .hub_control = ehci_hub_control, -#ifdef CONFIG_PM - .hub_suspend = ehci_hub_suspend, - .hub_resume = ehci_hub_resume, -#endif + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ehci-ppc-soc.c b/drivers/usb/host/ehci-ppc-soc.c index 4f99b0eb27b..452d4b1bc85 100644 --- a/drivers/usb/host/ehci-ppc-soc.c +++ b/drivers/usb/host/ehci-ppc-soc.c @@ -160,10 +160,8 @@ static const struct hc_driver ehci_ppc_soc_hc_driver = { */ .hub_status_data = ehci_hub_status_data, .hub_control = ehci_hub_control, -#ifdef CONFIG_PM - .hub_suspend = ehci_hub_suspend, - .hub_resume = ehci_hub_resume, -#endif + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, }; static int ehci_hcd_ppc_soc_drv_probe(struct platform_device *pdev) -- cgit v1.2.3-70-g09d2 From c604e851486eabcbeb73e984279d436ce121fd5d Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 9 Oct 2007 23:47:17 -0700 Subject: USB: ohci SSB bus glue This adds SSB bus glue for the USB OHCI HCD. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/Kconfig | 13 +++ drivers/usb/host/ohci-hcd.c | 21 +++- drivers/usb/host/ohci-ssb.c | 247 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 280 insertions(+), 1 deletion(-) create mode 100644 drivers/usb/host/ohci-ssb.c diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 565d6ef4c4c..c978d622fa8 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -154,6 +154,19 @@ config USB_OHCI_HCD_PCI Enables support for PCI-bus plug-in USB controller cards. If unsure, say Y. +config USB_OHCI_HCD_SSB + bool "OHCI support for Broadcom SSB OHCI core" + depends on USB_OHCI_HCD && SSB && EXPERIMENTAL + default n + ---help--- + Support for the Sonics Silicon Backplane (SSB) attached + Broadcom USB OHCI core. + + This device is present in some embedded devices with + Broadcom based SSB bus. + + If unsure, say N. + config USB_OHCI_BIG_ENDIAN_DESC bool depends on USB_OHCI_HCD diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index f7c6ced2bc0..240c7f50754 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -1033,11 +1033,17 @@ MODULE_LICENSE ("GPL"); #define PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver #endif +#ifdef CONFIG_USB_OHCI_HCD_SSB +#include "ohci-ssb.c" +#define SSB_OHCI_DRIVER ssb_ohci_driver +#endif + #if !defined(PCI_DRIVER) && \ !defined(PLATFORM_DRIVER) && \ !defined(OF_PLATFORM_DRIVER) && \ !defined(SA1111_DRIVER) && \ - !defined(PS3_SYSTEM_BUS_DRIVER) + !defined(PS3_SYSTEM_BUS_DRIVER) && \ + !defined(SSB_OHCI_DRIVER) #error "missing bus glue for ohci-hcd" #endif @@ -1082,10 +1088,20 @@ static int __init ohci_hcd_mod_init(void) goto error_pci; #endif +#ifdef SSB_OHCI_DRIVER + retval = ssb_driver_register(&SSB_OHCI_DRIVER); + if (retval) + goto error_ssb; +#endif + return retval; /* Error path */ +#ifdef SSB_OHCI_DRIVER + error_ssb: +#endif #ifdef PCI_DRIVER + pci_unregister_driver(&PCI_DRIVER); error_pci: #endif #ifdef SA1111_DRIVER @@ -1110,6 +1126,9 @@ module_init(ohci_hcd_mod_init); static void __exit ohci_hcd_mod_exit(void) { +#ifdef SSB_OHCI_DRIVER + ssb_driver_unregister(&SSB_OHCI_DRIVER); +#endif #ifdef PCI_DRIVER pci_unregister_driver(&PCI_DRIVER); #endif diff --git a/drivers/usb/host/ohci-ssb.c b/drivers/usb/host/ohci-ssb.c new file mode 100644 index 00000000000..bc3e785d8c0 --- /dev/null +++ b/drivers/usb/host/ohci-ssb.c @@ -0,0 +1,247 @@ +/* + * Sonics Silicon Backplane + * Broadcom USB-core OHCI driver + * + * Copyright 2007 Michael Buesch + * + * Derived from the OHCI-PCI driver + * Copyright 1999 Roman Weissgaerber + * Copyright 2000-2002 David Brownell + * Copyright 1999 Linus Torvalds + * Copyright 1999 Gregory P. Smith + * + * Derived from the USBcore related parts of Broadcom-SB + * Copyright 2005 Broadcom Corporation + * + * Licensed under the GNU/GPL. See COPYING for details. + */ +#include + + +#define SSB_OHCI_TMSLOW_HOSTMODE (1 << 29) + +struct ssb_ohci_device { + struct ohci_hcd ohci; /* _must_ be at the beginning. */ + + u32 enable_flags; +}; + +static inline +struct ssb_ohci_device *hcd_to_ssb_ohci(struct usb_hcd *hcd) +{ + return (struct ssb_ohci_device *)(hcd->hcd_priv); +} + + +static int ssb_ohci_reset(struct usb_hcd *hcd) +{ + struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); + struct ohci_hcd *ohci = &ohcidev->ohci; + int err; + + ohci_hcd_init(ohci); + err = ohci_init(ohci); + + return err; +} + +static int ssb_ohci_start(struct usb_hcd *hcd) +{ + struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); + struct ohci_hcd *ohci = &ohcidev->ohci; + int err; + + err = ohci_run(ohci); + if (err < 0) { + ohci_err(ohci, "can't start\n"); + ohci_stop(hcd); + } + + return err; +} + +#ifdef CONFIG_PM +static int ssb_ohci_hcd_suspend(struct usb_hcd *hcd, pm_message_t message) +{ + struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); + struct ohci_hcd *ohci = &ohcidev->ohci; + unsigned long flags; + + spin_lock_irqsave(&ohci->lock, flags); + + ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); + ohci_readl(ohci, &ohci->regs->intrdisable); /* commit write */ + + /* make sure snapshot being resumed re-enumerates everything */ + if (message.event == PM_EVENT_PRETHAW) + ohci_usb_reset(ohci); + + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + + spin_unlock_irqrestore(&ohci->lock, flags); + return 0; +} + +static int ssb_ohci_hcd_resume(struct usb_hcd *hcd) +{ + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + usb_hcd_resume_root_hub(hcd); + return 0; +} +#endif /* CONFIG_PM */ + +static const struct hc_driver ssb_ohci_hc_driver = { + .description = "ssb-usb-ohci", + .product_desc = "SSB OHCI Controller", + .hcd_priv_size = sizeof(struct ssb_ohci_device), + + .irq = ohci_irq, + .flags = HCD_MEMORY | HCD_USB11, + + .reset = ssb_ohci_reset, + .start = ssb_ohci_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, + +#ifdef CONFIG_PM + .suspend = ssb_ohci_hcd_suspend, + .resume = ssb_ohci_hcd_resume, +#endif + + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + .get_frame_number = ohci_get_frame, + + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, + .hub_irq_enable = ohci_rhsc_enable, + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, + + .start_port_reset = ohci_start_port_reset, +}; + +static void ssb_ohci_detach(struct ssb_device *dev) +{ + struct usb_hcd *hcd = ssb_get_drvdata(dev); + + usb_remove_hcd(hcd); + iounmap(hcd->regs); + usb_put_hcd(hcd); + ssb_device_disable(dev, 0); +} + +static int ssb_ohci_attach(struct ssb_device *dev) +{ + struct ssb_ohci_device *ohcidev; + struct usb_hcd *hcd; + int err = -ENOMEM; + u32 tmp, flags = 0; + + if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) + flags |= SSB_OHCI_TMSLOW_HOSTMODE; + + ssb_device_enable(dev, flags); + + hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev, + dev->dev->bus_id); + if (!hcd) + goto err_dev_disable; + ohcidev = hcd_to_ssb_ohci(hcd); + ohcidev->enable_flags = flags; + + tmp = ssb_read32(dev, SSB_ADMATCH0); + hcd->rsrc_start = ssb_admatch_base(tmp); + hcd->rsrc_len = ssb_admatch_size(tmp); + hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); + if (!hcd->regs) + goto err_put_hcd; + err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED); + if (err) + goto err_iounmap; + + ssb_set_drvdata(dev, hcd); + + return err; + +err_iounmap: + iounmap(hcd->regs); +err_put_hcd: + usb_put_hcd(hcd); +err_dev_disable: + ssb_device_disable(dev, flags); + return err; +} + +static int ssb_ohci_probe(struct ssb_device *dev, + const struct ssb_device_id *id) +{ + int err; + u16 chipid_top; + + /* USBcores are only connected on embedded devices. */ + chipid_top = (dev->bus->chip_id & 0xFF00); + if (chipid_top != 0x4700 && chipid_top != 0x5300) + return -ENODEV; + + /* TODO: Probably need checks here; is the core connected? */ + + if (usb_disabled()) + return -ENODEV; + + /* We currently always attach SSB_DEV_USB11_HOSTDEV + * as HOST OHCI. If we want to attach it as Client device, + * we must branch here and call into the (yet to + * be written) Client mode driver. Same for remove(). */ + + err = ssb_ohci_attach(dev); + + return err; +} + +static void ssb_ohci_remove(struct ssb_device *dev) +{ + ssb_ohci_detach(dev); +} + +#ifdef CONFIG_PM + +static int ssb_ohci_suspend(struct ssb_device *dev, pm_message_t state) +{ + ssb_device_disable(dev, 0); + + return 0; +} + +static int ssb_ohci_resume(struct ssb_device *dev) +{ + struct usb_hcd *hcd = ssb_get_drvdata(dev); + struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); + + ssb_device_enable(dev, ohcidev->enable_flags); + + return 0; +} + +#else /* !CONFIG_PM */ +#define ssb_ohci_suspend NULL +#define ssb_ohci_resume NULL +#endif /* CONFIG_PM */ + +static const struct ssb_device_id ssb_ohci_table[] = { + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV), + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV), + SSB_DEVTABLE_END +}; +MODULE_DEVICE_TABLE(ssb, ssb_ohci_table); + +static struct ssb_driver ssb_ohci_driver = { + .name = KBUILD_MODNAME, + .id_table = ssb_ohci_table, + .probe = ssb_ohci_probe, + .remove = ssb_ohci_remove, + .suspend = ssb_ohci_suspend, + .resume = ssb_ohci_resume, +}; -- cgit v1.2.3-70-g09d2 From 914a3f3b375493eb44ad652a431939258cf34f71 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Wed, 10 Oct 2007 02:29:43 -0700 Subject: USB: add atmel_usba_udc driver This is a driver for the Atmel USBA UDC which can be found integrated on AT32AP700x AVR32 processors. For hardware documentation, please see the AT32AP7000 data sheet: http://www.atmel.com/dyn/resources/prod_documents/doc32003.pdf This is a dual speed controller (connects at high or full speed). The driver supports up to 7 control, bulk, interrupt and isochronous endpoints with some constraints. Bulk, interrupt and isochronous transfers are driven by DMA. Signed-off-by: Haavard Skinnemoen Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 7 + drivers/usb/gadget/Kconfig | 26 +- drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/atmel_usba_udc.c | 2038 +++++++++++++++++++++++++++++++++++ drivers/usb/gadget/atmel_usba_udc.h | 350 ++++++ 5 files changed, 2421 insertions(+), 1 deletion(-) create mode 100644 drivers/usb/gadget/atmel_usba_udc.c create mode 100644 drivers/usb/gadget/atmel_usba_udc.h diff --git a/MAINTAINERS b/MAINTAINERS index c4eca56ed5b..60e649ff6fd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -677,6 +677,13 @@ P: Haavard Skinnemoen M: hskinnemoen@atmel.com S: Supported +ATMEL USBA UDC DRIVER +P: Haavard Skinnemoen +M: hskinnemoen@atmel.com +L: kernel@avr32linux.org +W: http://avr32linux.org/twiki/bin/view/Main/AtmelUsbDeviceDriver +S: Supported + ATMEL WIRELESS DRIVER P: Simon Kelley M: simon@thekelleys.org.uk diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 767aed5b4be..f81d08d6538 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -67,6 +67,17 @@ config USB_GADGET_DEBUG_FILES driver on a new board. Enable these files by choosing "Y" here. If in doubt, or to conserve kernel memory, say "N". +config USB_GADGET_DEBUG_FS + boolean "Debugging information files in debugfs" + depends on USB_GADGET && DEBUG_FS + help + Some of the drivers in the "gadget" framework can expose + debugging information in files under /sys/kernel/debug/. + The information in these files may help when you're + troubleshooting or bringing up a driver on a new board. + Enable these files by choosing "Y" here. If in doubt, or + to conserve kernel memory, say "N". + config USB_GADGET_SELECTED boolean @@ -103,6 +114,20 @@ config USB_AMD5536UDC default USB_GADGET select USB_GADGET_SELECTED +config USB_GADGET_ATMEL_USBA + boolean "Atmel USBA" + select USB_GADGET_DUALSPEED + depends on AVR32 + help + USBA is the integrated high-speed USB Device controller on + the AT32AP700x processors from Atmel. + +config USB_ATMEL_USBA + tristate + depends on USB_GADGET_ATMEL_USBA + default USB_GADGET + select USB_GADGET_SELECTED + config USB_GADGET_FSL_USB2 boolean "Freescale Highspeed USB DR Peripheral Controller" depends on MPC834x || PPC_MPC831x @@ -228,7 +253,6 @@ config USB_LH7A40X default USB_GADGET select USB_GADGET_SELECTED - config USB_GADGET_OMAP boolean "OMAP USB Device Controller" depends on ARCH_OMAP diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 1bc0f03550c..904e57bf611 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_USB_OMAP) += omap_udc.o obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o obj-$(CONFIG_USB_AT91) += at91_udc.o +obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o obj-$(CONFIG_USB_M66592) += m66592-udc.o diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c new file mode 100644 index 00000000000..2bb28a58393 --- /dev/null +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -0,0 +1,2038 @@ +/* + * Driver for the Atmel USBA high speed USB device controller + * + * Copyright (C) 2005-2007 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "atmel_usba_udc.h" + + +static struct usba_udc the_udc; + +#ifdef CONFIG_USB_GADGET_DEBUG_FS +#include +#include + +static int queue_dbg_open(struct inode *inode, struct file *file) +{ + struct usba_ep *ep = inode->i_private; + struct usba_request *req, *req_copy; + struct list_head *queue_data; + + queue_data = kmalloc(sizeof(*queue_data), GFP_KERNEL); + if (!queue_data) + return -ENOMEM; + INIT_LIST_HEAD(queue_data); + + spin_lock_irq(&ep->udc->lock); + list_for_each_entry(req, &ep->queue, queue) { + req_copy = kmalloc(sizeof(*req_copy), GFP_ATOMIC); + if (!req_copy) + goto fail; + memcpy(req_copy, req, sizeof(*req_copy)); + list_add_tail(&req_copy->queue, queue_data); + } + spin_unlock_irq(&ep->udc->lock); + + file->private_data = queue_data; + return 0; + +fail: + spin_unlock_irq(&ep->udc->lock); + list_for_each_entry_safe(req, req_copy, queue_data, queue) { + list_del(&req->queue); + kfree(req); + } + kfree(queue_data); + return -ENOMEM; +} + +/* + * bbbbbbbb llllllll IZS sssss nnnn FDL\n\0 + * + * b: buffer address + * l: buffer length + * I/i: interrupt/no interrupt + * Z/z: zero/no zero + * S/s: short ok/short not ok + * s: status + * n: nr_packets + * F/f: submitted/not submitted to FIFO + * D/d: using/not using DMA + * L/l: last transaction/not last transaction + */ +static ssize_t queue_dbg_read(struct file *file, char __user *buf, + size_t nbytes, loff_t *ppos) +{ + struct list_head *queue = file->private_data; + struct usba_request *req, *tmp_req; + size_t len, remaining, actual = 0; + char tmpbuf[38]; + + if (!access_ok(VERIFY_WRITE, buf, nbytes)) + return -EFAULT; + + mutex_lock(&file->f_dentry->d_inode->i_mutex); + list_for_each_entry_safe(req, tmp_req, queue, queue) { + len = snprintf(tmpbuf, sizeof(tmpbuf), + "%8p %08x %c%c%c %5d %c%c%c\n", + req->req.buf, req->req.length, + req->req.no_interrupt ? 'i' : 'I', + req->req.zero ? 'Z' : 'z', + req->req.short_not_ok ? 's' : 'S', + req->req.status, + req->submitted ? 'F' : 'f', + req->using_dma ? 'D' : 'd', + req->last_transaction ? 'L' : 'l'); + len = min(len, sizeof(tmpbuf)); + if (len > nbytes) + break; + + list_del(&req->queue); + kfree(req); + + remaining = __copy_to_user(buf, tmpbuf, len); + actual += len - remaining; + if (remaining) + break; + + nbytes -= len; + buf += len; + } + mutex_unlock(&file->f_dentry->d_inode->i_mutex); + + return actual; +} + +static int queue_dbg_release(struct inode *inode, struct file *file) +{ + struct list_head *queue_data = file->private_data; + struct usba_request *req, *tmp_req; + + list_for_each_entry_safe(req, tmp_req, queue_data, queue) { + list_del(&req->queue); + kfree(req); + } + kfree(queue_data); + return 0; +} + +static int regs_dbg_open(struct inode *inode, struct file *file) +{ + struct usba_udc *udc; + unsigned int i; + u32 *data; + int ret = -ENOMEM; + + mutex_lock(&inode->i_mutex); + udc = inode->i_private; + data = kmalloc(inode->i_size, GFP_KERNEL); + if (!data) + goto out; + + spin_lock_irq(&udc->lock); + for (i = 0; i < inode->i_size / 4; i++) + data[i] = __raw_readl(udc->regs + i * 4); + spin_unlock_irq(&udc->lock); + + file->private_data = data; + ret = 0; + +out: + mutex_unlock(&inode->i_mutex); + + return ret; +} + +static ssize_t regs_dbg_read(struct file *file, char __user *buf, + size_t nbytes, loff_t *ppos) +{ + struct inode *inode = file->f_dentry->d_inode; + int ret; + + mutex_lock(&inode->i_mutex); + ret = simple_read_from_buffer(buf, nbytes, ppos, + file->private_data, + file->f_dentry->d_inode->i_size); + mutex_unlock(&inode->i_mutex); + + return ret; +} + +static int regs_dbg_release(struct inode *inode, struct file *file) +{ + kfree(file->private_data); + return 0; +} + +const struct file_operations queue_dbg_fops = { + .owner = THIS_MODULE, + .open = queue_dbg_open, + .llseek = no_llseek, + .read = queue_dbg_read, + .release = queue_dbg_release, +}; + +const struct file_operations regs_dbg_fops = { + .owner = THIS_MODULE, + .open = regs_dbg_open, + .llseek = generic_file_llseek, + .read = regs_dbg_read, + .release = regs_dbg_release, +}; + +static void usba_ep_init_debugfs(struct usba_udc *udc, + struct usba_ep *ep) +{ + struct dentry *ep_root; + + ep_root = debugfs_create_dir(ep->ep.name, udc->debugfs_root); + if (!ep_root) + goto err_root; + ep->debugfs_dir = ep_root; + + ep->debugfs_queue = debugfs_create_file("queue", 0400, ep_root, + ep, &queue_dbg_fops); + if (!ep->debugfs_queue) + goto err_queue; + + if (ep->can_dma) { + ep->debugfs_dma_status + = debugfs_create_u32("dma_status", 0400, ep_root, + &ep->last_dma_status); + if (!ep->debugfs_dma_status) + goto err_dma_status; + } + if (ep_is_control(ep)) { + ep->debugfs_state + = debugfs_create_u32("state", 0400, ep_root, + &ep->state); + if (!ep->debugfs_state) + goto err_state; + } + + return; + +err_state: + if (ep->can_dma) + debugfs_remove(ep->debugfs_dma_status); +err_dma_status: + debugfs_remove(ep->debugfs_queue); +err_queue: + debugfs_remove(ep_root); +err_root: + dev_err(&ep->udc->pdev->dev, + "failed to create debugfs directory for %s\n", ep->ep.name); +} + +static void usba_ep_cleanup_debugfs(struct usba_ep *ep) +{ + debugfs_remove(ep->debugfs_queue); + debugfs_remove(ep->debugfs_dma_status); + debugfs_remove(ep->debugfs_state); + debugfs_remove(ep->debugfs_dir); + ep->debugfs_dma_status = NULL; + ep->debugfs_dir = NULL; +} + +static void usba_init_debugfs(struct usba_udc *udc) +{ + struct dentry *root, *regs; + struct resource *regs_resource; + + root = debugfs_create_dir(udc->gadget.name, NULL); + if (IS_ERR(root) || !root) + goto err_root; + udc->debugfs_root = root; + + regs = debugfs_create_file("regs", 0400, root, udc, ®s_dbg_fops); + if (!regs) + goto err_regs; + + regs_resource = platform_get_resource(udc->pdev, IORESOURCE_MEM, + CTRL_IOMEM_ID); + regs->d_inode->i_size = regs_resource->end - regs_resource->start + 1; + udc->debugfs_regs = regs; + + usba_ep_init_debugfs(udc, to_usba_ep(udc->gadget.ep0)); + + return; + +err_regs: + debugfs_remove(root); +err_root: + udc->debugfs_root = NULL; + dev_err(&udc->pdev->dev, "debugfs is not available\n"); +} + +static void usba_cleanup_debugfs(struct usba_udc *udc) +{ + usba_ep_cleanup_debugfs(to_usba_ep(udc->gadget.ep0)); + debugfs_remove(udc->debugfs_regs); + debugfs_remove(udc->debugfs_root); + udc->debugfs_regs = NULL; + udc->debugfs_root = NULL; +} +#else +static inline void usba_ep_init_debugfs(struct usba_udc *udc, + struct usba_ep *ep) +{ + +} + +static inline void usba_ep_cleanup_debugfs(struct usba_ep *ep) +{ + +} + +static inline void usba_init_debugfs(struct usba_udc *udc) +{ + +} + +static inline void usba_cleanup_debugfs(struct usba_udc *udc) +{ + +} +#endif + +static int vbus_is_present(struct usba_udc *udc) +{ + if (udc->vbus_pin != -1) + return gpio_get_value(udc->vbus_pin); + + /* No Vbus detection: Assume always present */ + return 1; +} + +static void copy_to_fifo(void __iomem *fifo, const void *buf, int len) +{ + unsigned long tmp; + + DBG(DBG_FIFO, "copy to FIFO (len %d):\n", len); + for (; len > 0; len -= 4, buf += 4, fifo += 4) { + tmp = *(unsigned long *)buf; + if (len >= 4) { + DBG(DBG_FIFO, " -> %08lx\n", tmp); + __raw_writel(tmp, fifo); + } else { + do { + DBG(DBG_FIFO, " -> %02lx\n", tmp >> 24); + __raw_writeb(tmp >> 24, fifo); + fifo++; + tmp <<= 8; + } while (--len); + break; + } + } +} + +static void copy_from_fifo(void *buf, void __iomem *fifo, int len) +{ + union { + unsigned long *w; + unsigned char *b; + } p; + unsigned long tmp; + + DBG(DBG_FIFO, "copy from FIFO (len %d):\n", len); + for (p.w = buf; len > 0; len -= 4, p.w++, fifo += 4) { + if (len >= 4) { + tmp = __raw_readl(fifo); + *p.w = tmp; + DBG(DBG_FIFO, " -> %08lx\n", tmp); + } else { + do { + tmp = __raw_readb(fifo); + *p.b = tmp; + DBG(DBG_FIFO, " -> %02lx\n", tmp); + fifo++, p.b++; + } while (--len); + } + } +} + +static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req) +{ + unsigned int transaction_len; + + transaction_len = req->req.length - req->req.actual; + req->last_transaction = 1; + if (transaction_len > ep->ep.maxpacket) { + transaction_len = ep->ep.maxpacket; + req->last_transaction = 0; + } else if (transaction_len == ep->ep.maxpacket && req->req.zero) + req->last_transaction = 0; + + DBG(DBG_QUEUE, "%s: submit_transaction, req %p (length %d)%s\n", + ep->ep.name, req, transaction_len, + req->last_transaction ? ", done" : ""); + + copy_to_fifo(ep->fifo, req->req.buf + req->req.actual, transaction_len); + usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); + req->req.actual += transaction_len; +} + +static void submit_request(struct usba_ep *ep, struct usba_request *req) +{ + DBG(DBG_QUEUE, "%s: submit_request: req %p (length %d)\n", + ep->ep.name, req, req->req.length); + + req->req.actual = 0; + req->submitted = 1; + + if (req->using_dma) { + if (req->req.length == 0) { + usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY); + return; + } + + if (req->req.zero) + usba_ep_writel(ep, CTL_ENB, USBA_SHORT_PACKET); + else + usba_ep_writel(ep, CTL_DIS, USBA_SHORT_PACKET); + + usba_dma_writel(ep, ADDRESS, req->req.dma); + usba_dma_writel(ep, CONTROL, req->ctrl); + } else { + next_fifo_transaction(ep, req); + if (req->last_transaction) { + usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY); + usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE); + } else { + usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); + usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY); + } + } +} + +static void submit_next_request(struct usba_ep *ep) +{ + struct usba_request *req; + + if (list_empty(&ep->queue)) { + usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY | USBA_RX_BK_RDY); + return; + } + + req = list_entry(ep->queue.next, struct usba_request, queue); + if (!req->submitted) + submit_request(ep, req); +} + +static void send_status(struct usba_udc *udc, struct usba_ep *ep) +{ + ep->state = STATUS_STAGE_IN; + usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); + usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE); +} + +static void receive_data(struct usba_ep *ep) +{ + struct usba_udc *udc = ep->udc; + struct usba_request *req; + unsigned long status; + unsigned int bytecount, nr_busy; + int is_complete = 0; + + status = usba_ep_readl(ep, STA); + nr_busy = USBA_BFEXT(BUSY_BANKS, status); + + DBG(DBG_QUEUE, "receive data: nr_busy=%u\n", nr_busy); + + while (nr_busy > 0) { + if (list_empty(&ep->queue)) { + usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); + break; + } + req = list_entry(ep->queue.next, + struct usba_request, queue); + + bytecount = USBA_BFEXT(BYTE_COUNT, status); + + if (status & (1 << 31)) + is_complete = 1; + if (req->req.actual + bytecount >= req->req.length) { + is_complete = 1; + bytecount = req->req.length - req->req.actual; + } + + copy_from_fifo(req->req.buf + req->req.actual, + ep->fifo, bytecount); + req->req.actual += bytecount; + + usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); + + if (is_complete) { + DBG(DBG_QUEUE, "%s: request done\n", ep->ep.name); + req->req.status = 0; + list_del_init(&req->queue); + usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); + spin_unlock(&udc->lock); + req->req.complete(&ep->ep, &req->req); + spin_lock(&udc->lock); + } + + status = usba_ep_readl(ep, STA); + nr_busy = USBA_BFEXT(BUSY_BANKS, status); + + if (is_complete && ep_is_control(ep)) { + send_status(udc, ep); + break; + } + } +} + +static void +request_complete(struct usba_ep *ep, struct usba_request *req, int status) +{ + struct usba_udc *udc = ep->udc; + + WARN_ON(!list_empty(&req->queue)); + + if (req->req.status == -EINPROGRESS) + req->req.status = status; + + if (req->mapped) { + dma_unmap_single( + &udc->pdev->dev, req->req.dma, req->req.length, + ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + req->req.dma = DMA_ADDR_INVALID; + req->mapped = 0; + } + + DBG(DBG_GADGET | DBG_REQ, + "%s: req %p complete: status %d, actual %u\n", + ep->ep.name, req, req->req.status, req->req.actual); + + spin_unlock(&udc->lock); + req->req.complete(&ep->ep, &req->req); + spin_lock(&udc->lock); +} + +static void +request_complete_list(struct usba_ep *ep, struct list_head *list, int status) +{ + struct usba_request *req, *tmp_req; + + list_for_each_entry_safe(req, tmp_req, list, queue) { + list_del_init(&req->queue); + request_complete(ep, req, status); + } +} + +static int +usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) +{ + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + unsigned long flags, ept_cfg, maxpacket; + unsigned int nr_trans; + + DBG(DBG_GADGET, "%s: ep_enable: desc=%p\n", ep->ep.name, desc); + + maxpacket = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff; + + if (((desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) != ep->index) + || ep->index == 0 + || desc->bDescriptorType != USB_DT_ENDPOINT + || maxpacket == 0 + || maxpacket > ep->fifo_size) { + DBG(DBG_ERR, "ep_enable: Invalid argument"); + return -EINVAL; + } + + ep->is_isoc = 0; + ep->is_in = 0; + + if (maxpacket <= 8) + ept_cfg = USBA_BF(EPT_SIZE, USBA_EPT_SIZE_8); + else + /* LSB is bit 1, not 0 */ + ept_cfg = USBA_BF(EPT_SIZE, fls(maxpacket - 1) - 3); + + DBG(DBG_HW, "%s: EPT_SIZE = %lu (maxpacket = %lu)\n", + ep->ep.name, ept_cfg, maxpacket); + + if ((desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { + ep->is_in = 1; + ept_cfg |= USBA_EPT_DIR_IN; + } + + switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_CONTROL: + ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL); + ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE); + break; + case USB_ENDPOINT_XFER_ISOC: + if (!ep->can_isoc) { + DBG(DBG_ERR, "ep_enable: %s is not isoc capable\n", + ep->ep.name); + return -EINVAL; + } + + /* + * Bits 11:12 specify number of _additional_ + * transactions per microframe. + */ + nr_trans = ((le16_to_cpu(desc->wMaxPacketSize) >> 11) & 3) + 1; + if (nr_trans > 3) + return -EINVAL; + + ep->is_isoc = 1; + ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_ISO); + + /* + * Do triple-buffering on high-bandwidth iso endpoints. + */ + if (nr_trans > 1 && ep->nr_banks == 3) + ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_TRIPLE); + else + ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE); + ept_cfg |= USBA_BF(NB_TRANS, nr_trans); + break; + case USB_ENDPOINT_XFER_BULK: + ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK); + ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE); + break; + case USB_ENDPOINT_XFER_INT: + ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_INT); + ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE); + break; + } + + spin_lock_irqsave(&ep->udc->lock, flags); + + if (ep->desc) { + spin_unlock_irqrestore(&ep->udc->lock, flags); + DBG(DBG_ERR, "ep%d already enabled\n", ep->index); + return -EBUSY; + } + + ep->desc = desc; + ep->ep.maxpacket = maxpacket; + + usba_ep_writel(ep, CFG, ept_cfg); + usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE); + + if (ep->can_dma) { + u32 ctrl; + + usba_writel(udc, INT_ENB, + (usba_readl(udc, INT_ENB) + | USBA_BF(EPT_INT, 1 << ep->index) + | USBA_BF(DMA_INT, 1 << ep->index))); + ctrl = USBA_AUTO_VALID | USBA_INTDIS_DMA; + usba_ep_writel(ep, CTL_ENB, ctrl); + } else { + usba_writel(udc, INT_ENB, + (usba_readl(udc, INT_ENB) + | USBA_BF(EPT_INT, 1 << ep->index))); + } + + spin_unlock_irqrestore(&udc->lock, flags); + + DBG(DBG_HW, "EPT_CFG%d after init: %#08lx\n", ep->index, + (unsigned long)usba_ep_readl(ep, CFG)); + DBG(DBG_HW, "INT_ENB after init: %#08lx\n", + (unsigned long)usba_readl(udc, INT_ENB)); + + return 0; +} + +static int usba_ep_disable(struct usb_ep *_ep) +{ + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + LIST_HEAD(req_list); + unsigned long flags; + + DBG(DBG_GADGET, "ep_disable: %s\n", ep->ep.name); + + spin_lock_irqsave(&udc->lock, flags); + + if (!ep->desc) { + spin_unlock_irqrestore(&udc->lock, flags); + DBG(DBG_ERR, "ep_disable: %s not enabled\n", ep->ep.name); + return -EINVAL; + } + ep->desc = NULL; + + list_splice_init(&ep->queue, &req_list); + if (ep->can_dma) { + usba_dma_writel(ep, CONTROL, 0); + usba_dma_writel(ep, ADDRESS, 0); + usba_dma_readl(ep, STATUS); + } + usba_ep_writel(ep, CTL_DIS, USBA_EPT_ENABLE); + usba_writel(udc, INT_ENB, + usba_readl(udc, INT_ENB) + & ~USBA_BF(EPT_INT, 1 << ep->index)); + + request_complete_list(ep, &req_list, -ESHUTDOWN); + + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static struct usb_request * +usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) +{ + struct usba_request *req; + + DBG(DBG_GADGET, "ep_alloc_request: %p, 0x%x\n", _ep, gfp_flags); + + req = kzalloc(sizeof(*req), gfp_flags); + if (!req) + return NULL; + + INIT_LIST_HEAD(&req->queue); + req->req.dma = DMA_ADDR_INVALID; + + return &req->req; +} + +static void +usba_ep_free_request(struct usb_ep *_ep, struct usb_request *_req) +{ + struct usba_request *req = to_usba_req(_req); + + DBG(DBG_GADGET, "ep_free_request: %p, %p\n", _ep, _req); + + kfree(req); +} + +static int queue_dma(struct usba_udc *udc, struct usba_ep *ep, + struct usba_request *req, gfp_t gfp_flags) +{ + unsigned long flags; + int ret; + + DBG(DBG_DMA, "%s: req l/%u d/%08x %c%c%c\n", + ep->ep.name, req->req.length, req->req.dma, + req->req.zero ? 'Z' : 'z', + req->req.short_not_ok ? 'S' : 's', + req->req.no_interrupt ? 'I' : 'i'); + + if (req->req.length > 0x10000) { + /* Lengths from 0 to 65536 (inclusive) are supported */ + DBG(DBG_ERR, "invalid request length %u\n", req->req.length); + return -EINVAL; + } + + req->using_dma = 1; + + if (req->req.dma == DMA_ADDR_INVALID) { + req->req.dma = dma_map_single( + &udc->pdev->dev, req->req.buf, req->req.length, + ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + req->mapped = 1; + } else { + dma_sync_single_for_device( + &udc->pdev->dev, req->req.dma, req->req.length, + ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + req->mapped = 0; + } + + req->ctrl = USBA_BF(DMA_BUF_LEN, req->req.length) + | USBA_DMA_CH_EN | USBA_DMA_END_BUF_IE + | USBA_DMA_END_TR_EN | USBA_DMA_END_TR_IE; + + if (ep->is_in) + req->ctrl |= USBA_DMA_END_BUF_EN; + + /* + * Add this request to the queue and submit for DMA if + * possible. Check if we're still alive first -- we may have + * received a reset since last time we checked. + */ + ret = -ESHUTDOWN; + spin_lock_irqsave(&udc->lock, flags); + if (ep->desc) { + if (list_empty(&ep->queue)) + submit_request(ep, req); + + list_add_tail(&req->queue, &ep->queue); + ret = 0; + } + spin_unlock_irqrestore(&udc->lock, flags); + + return ret; +} + +static int +usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) +{ + struct usba_request *req = to_usba_req(_req); + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + unsigned long flags; + int ret; + + DBG(DBG_GADGET | DBG_QUEUE | DBG_REQ, "%s: queue req %p, len %u\n", + ep->ep.name, req, _req->length); + + if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN || !ep->desc) + return -ESHUTDOWN; + + req->submitted = 0; + req->using_dma = 0; + req->last_transaction = 0; + + _req->status = -EINPROGRESS; + _req->actual = 0; + + if (ep->can_dma) + return queue_dma(udc, ep, req, gfp_flags); + + /* May have received a reset since last time we checked */ + ret = -ESHUTDOWN; + spin_lock_irqsave(&udc->lock, flags); + if (ep->desc) { + list_add_tail(&req->queue, &ep->queue); + + if (ep->is_in || (ep_is_control(ep) + && (ep->state == DATA_STAGE_IN + || ep->state == STATUS_STAGE_IN))) + usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY); + else + usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY); + ret = 0; + } + spin_unlock_irqrestore(&udc->lock, flags); + + return ret; +} + +static void +usba_update_req(struct usba_ep *ep, struct usba_request *req, u32 status) +{ + req->req.actual = req->req.length - USBA_BFEXT(DMA_BUF_LEN, status); +} + +static int stop_dma(struct usba_ep *ep, u32 *pstatus) +{ + unsigned int timeout; + u32 status; + + /* + * Stop the DMA controller. When writing both CH_EN + * and LINK to 0, the other bits are not affected. + */ + usba_dma_writel(ep, CONTROL, 0); + + /* Wait for the FIFO to empty */ + for (timeout = 40; timeout; --timeout) { + status = usba_dma_readl(ep, STATUS); + if (!(status & USBA_DMA_CH_EN)) + break; + udelay(1); + } + + if (pstatus) + *pstatus = status; + + if (timeout == 0) { + dev_err(&ep->udc->pdev->dev, + "%s: timed out waiting for DMA FIFO to empty\n", + ep->ep.name); + return -ETIMEDOUT; + } + + return 0; +} + +static int usba_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + struct usba_request *req = to_usba_req(_req); + unsigned long flags; + u32 status; + + DBG(DBG_GADGET | DBG_QUEUE, "ep_dequeue: %s, req %p\n", + ep->ep.name, req); + + spin_lock_irqsave(&udc->lock, flags); + + if (req->using_dma) { + /* + * If this request is currently being transferred, + * stop the DMA controller and reset the FIFO. + */ + if (ep->queue.next == &req->queue) { + status = usba_dma_readl(ep, STATUS); + if (status & USBA_DMA_CH_EN) + stop_dma(ep, &status); + +#ifdef CONFIG_USB_GADGET_DEBUG_FS + ep->last_dma_status = status; +#endif + + usba_writel(udc, EPT_RST, 1 << ep->index); + + usba_update_req(ep, req, status); + } + } + + /* + * Errors should stop the queue from advancing until the + * completion function returns. + */ + list_del_init(&req->queue); + + request_complete(ep, req, -ECONNRESET); + + /* Process the next request if any */ + submit_next_request(ep); + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static int usba_ep_set_halt(struct usb_ep *_ep, int value) +{ + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + unsigned long flags; + int ret = 0; + + DBG(DBG_GADGET, "endpoint %s: %s HALT\n", ep->ep.name, + value ? "set" : "clear"); + + if (!ep->desc) { + DBG(DBG_ERR, "Attempted to halt uninitialized ep %s\n", + ep->ep.name); + return -ENODEV; + } + if (ep->is_isoc) { + DBG(DBG_ERR, "Attempted to halt isochronous ep %s\n", + ep->ep.name); + return -ENOTTY; + } + + spin_lock_irqsave(&udc->lock, flags); + + /* + * We can't halt IN endpoints while there are still data to be + * transferred + */ + if (!list_empty(&ep->queue) + || ((value && ep->is_in && (usba_ep_readl(ep, STA) + & USBA_BF(BUSY_BANKS, -1L))))) { + ret = -EAGAIN; + } else { + if (value) + usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL); + else + usba_ep_writel(ep, CLR_STA, + USBA_FORCE_STALL | USBA_TOGGLE_CLR); + usba_ep_readl(ep, STA); + } + + spin_unlock_irqrestore(&udc->lock, flags); + + return ret; +} + +static int usba_ep_fifo_status(struct usb_ep *_ep) +{ + struct usba_ep *ep = to_usba_ep(_ep); + + return USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA)); +} + +static void usba_ep_fifo_flush(struct usb_ep *_ep) +{ + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + + usba_writel(udc, EPT_RST, 1 << ep->index); +} + +static const struct usb_ep_ops usba_ep_ops = { + .enable = usba_ep_enable, + .disable = usba_ep_disable, + .alloc_request = usba_ep_alloc_request, + .free_request = usba_ep_free_request, + .queue = usba_ep_queue, + .dequeue = usba_ep_dequeue, + .set_halt = usba_ep_set_halt, + .fifo_status = usba_ep_fifo_status, + .fifo_flush = usba_ep_fifo_flush, +}; + +static int usba_udc_get_frame(struct usb_gadget *gadget) +{ + struct usba_udc *udc = to_usba_udc(gadget); + + return USBA_BFEXT(FRAME_NUMBER, usba_readl(udc, FNUM)); +} + +static const struct usb_gadget_ops usba_udc_ops = { + .get_frame = usba_udc_get_frame, +}; + +#define EP(nam, idx, maxpkt, maxbk, dma, isoc) \ +{ \ + .ep = { \ + .ops = &usba_ep_ops, \ + .name = nam, \ + .maxpacket = maxpkt, \ + }, \ + .udc = &the_udc, \ + .queue = LIST_HEAD_INIT(usba_ep[idx].queue), \ + .fifo_size = maxpkt, \ + .nr_banks = maxbk, \ + .index = idx, \ + .can_dma = dma, \ + .can_isoc = isoc, \ +} + +static struct usba_ep usba_ep[] = { + EP("ep0", 0, 64, 1, 0, 0), + EP("ep1in-bulk", 1, 512, 2, 1, 1), + EP("ep2out-bulk", 2, 512, 2, 1, 1), + EP("ep3in-int", 3, 64, 3, 1, 0), + EP("ep4out-int", 4, 64, 3, 1, 0), + EP("ep5in-iso", 5, 1024, 3, 1, 1), + EP("ep6out-iso", 6, 1024, 3, 1, 1), +}; +#undef EP + +static struct usb_endpoint_descriptor usba_ep0_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0, + .bmAttributes = USB_ENDPOINT_XFER_CONTROL, + .wMaxPacketSize = __constant_cpu_to_le16(64), + /* FIXME: I have no idea what to put here */ + .bInterval = 1, +}; + +static void nop_release(struct device *dev) +{ + +} + +static struct usba_udc the_udc = { + .gadget = { + .ops = &usba_udc_ops, + .ep0 = &usba_ep[0].ep, + .ep_list = LIST_HEAD_INIT(the_udc.gadget.ep_list), + .is_dualspeed = 1, + .name = "atmel_usba_udc", + .dev = { + .bus_id = "gadget", + .release = nop_release, + }, + }, + + .lock = SPIN_LOCK_UNLOCKED, +}; + +/* + * Called with interrupts disabled and udc->lock held. + */ +static void reset_all_endpoints(struct usba_udc *udc) +{ + struct usba_ep *ep; + struct usba_request *req, *tmp_req; + + usba_writel(udc, EPT_RST, ~0UL); + + ep = to_usba_ep(udc->gadget.ep0); + list_for_each_entry_safe(req, tmp_req, &ep->queue, queue) { + list_del_init(&req->queue); + request_complete(ep, req, -ECONNRESET); + } + + list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { + if (ep->desc) + usba_ep_disable(&ep->ep); + } +} + +static struct usba_ep *get_ep_by_addr(struct usba_udc *udc, u16 wIndex) +{ + struct usba_ep *ep; + + if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0) + return to_usba_ep(udc->gadget.ep0); + + list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) { + u8 bEndpointAddress; + + if (!ep->desc) + continue; + bEndpointAddress = ep->desc->bEndpointAddress; + if ((wIndex ^ bEndpointAddress) & USB_DIR_IN) + continue; + if ((bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) + == (wIndex & USB_ENDPOINT_NUMBER_MASK)) + return ep; + } + + return NULL; +} + +/* Called with interrupts disabled and udc->lock held */ +static inline void set_protocol_stall(struct usba_udc *udc, struct usba_ep *ep) +{ + usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL); + ep->state = WAIT_FOR_SETUP; +} + +static inline int is_stalled(struct usba_udc *udc, struct usba_ep *ep) +{ + if (usba_ep_readl(ep, STA) & USBA_FORCE_STALL) + return 1; + return 0; +} + +static inline void set_address(struct usba_udc *udc, unsigned int addr) +{ + u32 regval; + + DBG(DBG_BUS, "setting address %u...\n", addr); + regval = usba_readl(udc, CTRL); + regval = USBA_BFINS(DEV_ADDR, addr, regval); + usba_writel(udc, CTRL, regval); +} + +static int do_test_mode(struct usba_udc *udc) +{ + static const char test_packet_buffer[] = { + /* JKJKJKJK * 9 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* JJKKJJKK * 8 */ + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + /* JJKKJJKK * 8 */ + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, + /* JJJJJJJKKKKKKK * 8 */ + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + /* JJJJJJJK * 8 */ + 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, + /* {JKKKKKKK * 10}, JK */ + 0xFC, 0x7E, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0x7E + }; + struct usba_ep *ep; + struct device *dev = &udc->pdev->dev; + int test_mode; + + test_mode = udc->test_mode; + + /* Start from a clean slate */ + reset_all_endpoints(udc); + + switch (test_mode) { + case 0x0100: + /* Test_J */ + usba_writel(udc, TST, USBA_TST_J_MODE); + dev_info(dev, "Entering Test_J mode...\n"); + break; + case 0x0200: + /* Test_K */ + usba_writel(udc, TST, USBA_TST_K_MODE); + dev_info(dev, "Entering Test_K mode...\n"); + break; + case 0x0300: + /* + * Test_SE0_NAK: Force high-speed mode and set up ep0 + * for Bulk IN transfers + */ + ep = &usba_ep[0]; + usba_writel(udc, TST, + USBA_BF(SPEED_CFG, USBA_SPEED_CFG_FORCE_HIGH)); + usba_ep_writel(ep, CFG, + USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64) + | USBA_EPT_DIR_IN + | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK) + | USBA_BF(BK_NUMBER, 1)); + if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) { + set_protocol_stall(udc, ep); + dev_err(dev, "Test_SE0_NAK: ep0 not mapped\n"); + } else { + usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE); + dev_info(dev, "Entering Test_SE0_NAK mode...\n"); + } + break; + case 0x0400: + /* Test_Packet */ + ep = &usba_ep[0]; + usba_ep_writel(ep, CFG, + USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64) + | USBA_EPT_DIR_IN + | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK) + | USBA_BF(BK_NUMBER, 1)); + if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) { + set_protocol_stall(udc, ep); + dev_err(dev, "Test_Packet: ep0 not mapped\n"); + } else { + usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE); + usba_writel(udc, TST, USBA_TST_PKT_MODE); + copy_to_fifo(ep->fifo, test_packet_buffer, + sizeof(test_packet_buffer)); + usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); + dev_info(dev, "Entering Test_Packet mode...\n"); + } + break; + default: + dev_err(dev, "Invalid test mode: 0x%04x\n", test_mode); + return -EINVAL; + } + + return 0; +} + +/* Avoid overly long expressions */ +static inline bool feature_is_dev_remote_wakeup(struct usb_ctrlrequest *crq) +{ + if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_REMOTE_WAKEUP)) + return true; + return false; +} + +static inline bool feature_is_dev_test_mode(struct usb_ctrlrequest *crq) +{ + if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_TEST_MODE)) + return true; + return false; +} + +static inline bool feature_is_ep_halt(struct usb_ctrlrequest *crq) +{ + if (crq->wValue == __constant_cpu_to_le16(USB_ENDPOINT_HALT)) + return true; + return false; +} + +static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep, + struct usb_ctrlrequest *crq) +{ + int retval = 0;; + + switch (crq->bRequest) { + case USB_REQ_GET_STATUS: { + u16 status; + + if (crq->bRequestType == (USB_DIR_IN | USB_RECIP_DEVICE)) { + /* Self-powered, no remote wakeup */ + status = __constant_cpu_to_le16(1 << 0); + } else if (crq->bRequestType + == (USB_DIR_IN | USB_RECIP_INTERFACE)) { + status = __constant_cpu_to_le16(0); + } else if (crq->bRequestType + == (USB_DIR_IN | USB_RECIP_ENDPOINT)) { + struct usba_ep *target; + + target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex)); + if (!target) + goto stall; + + status = 0; + if (is_stalled(udc, target)) + status |= __constant_cpu_to_le16(1); + } else + goto delegate; + + /* Write directly to the FIFO. No queueing is done. */ + if (crq->wLength != __constant_cpu_to_le16(sizeof(status))) + goto stall; + ep->state = DATA_STAGE_IN; + __raw_writew(status, ep->fifo); + usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); + break; + } + + case USB_REQ_CLEAR_FEATURE: { + if (crq->bRequestType == USB_RECIP_DEVICE) { + if (feature_is_dev_remote_wakeup(crq)) { + /* TODO: Handle REMOTE_WAKEUP */ + } else { + /* Can't CLEAR_FEATURE TEST_MODE */ + goto stall; + } + } else if (crq->bRequestType == USB_RECIP_ENDPOINT) { + struct usba_ep *target; + + if (crq->wLength != __constant_cpu_to_le16(0) + || !feature_is_ep_halt(crq)) + goto stall; + target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex)); + if (!target) + goto stall; + + usba_ep_writel(target, CLR_STA, USBA_FORCE_STALL); + if (target->index != 0) + usba_ep_writel(target, CLR_STA, + USBA_TOGGLE_CLR); + } else { + goto delegate; + } + + send_status(udc, ep); + break; + } + + case USB_REQ_SET_FEATURE: { + if (crq->bRequestType == USB_RECIP_DEVICE) { + if (feature_is_dev_test_mode(crq)) { + send_status(udc, ep); + ep->state = STATUS_STAGE_TEST; + udc->test_mode = le16_to_cpu(crq->wIndex); + return 0; + } else if (feature_is_dev_remote_wakeup(crq)) { + /* TODO: Handle REMOTE_WAKEUP */ + } else { + goto stall; + } + } else if (crq->bRequestType == USB_RECIP_ENDPOINT) { + struct usba_ep *target; + + if (crq->wLength != __constant_cpu_to_le16(0) + || !feature_is_ep_halt(crq)) + goto stall; + + target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex)); + if (!target) + goto stall; + + usba_ep_writel(target, SET_STA, USBA_FORCE_STALL); + } else + goto delegate; + + send_status(udc, ep); + break; + } + + case USB_REQ_SET_ADDRESS: + if (crq->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE)) + goto delegate; + + set_address(udc, le16_to_cpu(crq->wValue)); + send_status(udc, ep); + ep->state = STATUS_STAGE_ADDR; + break; + + default: +delegate: + spin_unlock(&udc->lock); + retval = udc->driver->setup(&udc->gadget, crq); + spin_lock(&udc->lock); + } + + return retval; + +stall: + printk(KERN_ERR + "udc: %s: Invalid setup request: %02x.%02x v%04x i%04x l%d, " + "halting endpoint...\n", + ep->ep.name, crq->bRequestType, crq->bRequest, + le16_to_cpu(crq->wValue), le16_to_cpu(crq->wIndex), + le16_to_cpu(crq->wLength)); + set_protocol_stall(udc, ep); + return -1; +} + +static void usba_control_irq(struct usba_udc *udc, struct usba_ep *ep) +{ + struct usba_request *req; + u32 epstatus; + u32 epctrl; + +restart: + epstatus = usba_ep_readl(ep, STA); + epctrl = usba_ep_readl(ep, CTL); + + DBG(DBG_INT, "%s [%d]: s/%08x c/%08x\n", + ep->ep.name, ep->state, epstatus, epctrl); + + req = NULL; + if (!list_empty(&ep->queue)) + req = list_entry(ep->queue.next, + struct usba_request, queue); + + if ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) { + if (req->submitted) + next_fifo_transaction(ep, req); + else + submit_request(ep, req); + + if (req->last_transaction) { + usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY); + usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE); + } + goto restart; + } + if ((epstatus & epctrl) & USBA_TX_COMPLETE) { + usba_ep_writel(ep, CLR_STA, USBA_TX_COMPLETE); + + switch (ep->state) { + case DATA_STAGE_IN: + usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY); + usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); + ep->state = STATUS_STAGE_OUT; + break; + case STATUS_STAGE_ADDR: + /* Activate our new address */ + usba_writel(udc, CTRL, (usba_readl(udc, CTRL) + | USBA_FADDR_EN)); + usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); + ep->state = WAIT_FOR_SETUP; + break; + case STATUS_STAGE_IN: + if (req) { + list_del_init(&req->queue); + request_complete(ep, req, 0); + submit_next_request(ep); + } + usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); + ep->state = WAIT_FOR_SETUP; + break; + case STATUS_STAGE_TEST: + usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); + ep->state = WAIT_FOR_SETUP; + if (do_test_mode(udc)) + set_protocol_stall(udc, ep); + break; + default: + printk(KERN_ERR + "udc: %s: TXCOMP: Invalid endpoint state %d, " + "halting endpoint...\n", + ep->ep.name, ep->state); + set_protocol_stall(udc, ep); + break; + } + + goto restart; + } + if ((epstatus & epctrl) & USBA_RX_BK_RDY) { + switch (ep->state) { + case STATUS_STAGE_OUT: + usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); + usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); + + if (req) { + list_del_init(&req->queue); + request_complete(ep, req, 0); + } + ep->state = WAIT_FOR_SETUP; + break; + + case DATA_STAGE_OUT: + receive_data(ep); + break; + + default: + usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); + usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); + printk(KERN_ERR + "udc: %s: RXRDY: Invalid endpoint state %d, " + "halting endpoint...\n", + ep->ep.name, ep->state); + set_protocol_stall(udc, ep); + break; + } + + goto restart; + } + if (epstatus & USBA_RX_SETUP) { + union { + struct usb_ctrlrequest crq; + unsigned long data[2]; + } crq; + unsigned int pkt_len; + int ret; + + if (ep->state != WAIT_FOR_SETUP) { + /* + * Didn't expect a SETUP packet at this + * point. Clean up any pending requests (which + * may be successful). + */ + int status = -EPROTO; + + /* + * RXRDY and TXCOMP are dropped when SETUP + * packets arrive. Just pretend we received + * the status packet. + */ + if (ep->state == STATUS_STAGE_OUT + || ep->state == STATUS_STAGE_IN) { + usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); + status = 0; + } + + if (req) { + list_del_init(&req->queue); + request_complete(ep, req, status); + } + } + + pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA)); + DBG(DBG_HW, "Packet length: %u\n", pkt_len); + if (pkt_len != sizeof(crq)) { + printk(KERN_WARNING "udc: Invalid packet length %u " + "(expected %lu)\n", pkt_len, sizeof(crq)); + set_protocol_stall(udc, ep); + return; + } + + DBG(DBG_FIFO, "Copying ctrl request from 0x%p:\n", ep->fifo); + copy_from_fifo(crq.data, ep->fifo, sizeof(crq)); + + /* Free up one bank in the FIFO so that we can + * generate or receive a reply right away. */ + usba_ep_writel(ep, CLR_STA, USBA_RX_SETUP); + + /* printk(KERN_DEBUG "setup: %d: %02x.%02x\n", + ep->state, crq.crq.bRequestType, + crq.crq.bRequest); */ + + if (crq.crq.bRequestType & USB_DIR_IN) { + /* + * The USB 2.0 spec states that "if wLength is + * zero, there is no data transfer phase." + * However, testusb #14 seems to actually + * expect a data phase even if wLength = 0... + */ + ep->state = DATA_STAGE_IN; + } else { + if (crq.crq.wLength != __constant_cpu_to_le16(0)) + ep->state = DATA_STAGE_OUT; + else + ep->state = STATUS_STAGE_IN; + } + + ret = -1; + if (ep->index == 0) + ret = handle_ep0_setup(udc, ep, &crq.crq); + else { + spin_unlock(&udc->lock); + ret = udc->driver->setup(&udc->gadget, &crq.crq); + spin_lock(&udc->lock); + } + + DBG(DBG_BUS, "req %02x.%02x, length %d, state %d, ret %d\n", + crq.crq.bRequestType, crq.crq.bRequest, + le16_to_cpu(crq.crq.wLength), ep->state, ret); + + if (ret < 0) { + /* Let the host know that we failed */ + set_protocol_stall(udc, ep); + } + } +} + +static void usba_ep_irq(struct usba_udc *udc, struct usba_ep *ep) +{ + struct usba_request *req; + u32 epstatus; + u32 epctrl; + + epstatus = usba_ep_readl(ep, STA); + epctrl = usba_ep_readl(ep, CTL); + + DBG(DBG_INT, "%s: interrupt, status: 0x%08x\n", ep->ep.name, epstatus); + + while ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) { + DBG(DBG_BUS, "%s: TX PK ready\n", ep->ep.name); + + if (list_empty(&ep->queue)) { + dev_warn(&udc->pdev->dev, "ep_irq: queue empty\n"); + usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY); + return; + } + + req = list_entry(ep->queue.next, struct usba_request, queue); + + if (req->using_dma) { + /* Send a zero-length packet */ + usba_ep_writel(ep, SET_STA, + USBA_TX_PK_RDY); + usba_ep_writel(ep, CTL_DIS, + USBA_TX_PK_RDY); + list_del_init(&req->queue); + submit_next_request(ep); + request_complete(ep, req, 0); + } else { + if (req->submitted) + next_fifo_transaction(ep, req); + else + submit_request(ep, req); + + if (req->last_transaction) { + list_del_init(&req->queue); + submit_next_request(ep); + request_complete(ep, req, 0); + } + } + + epstatus = usba_ep_readl(ep, STA); + epctrl = usba_ep_readl(ep, CTL); + } + if ((epstatus & epctrl) & USBA_RX_BK_RDY) { + DBG(DBG_BUS, "%s: RX data ready\n", ep->ep.name); + receive_data(ep); + usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); + } +} + +static void usba_dma_irq(struct usba_udc *udc, struct usba_ep *ep) +{ + struct usba_request *req; + u32 status, control, pending; + + status = usba_dma_readl(ep, STATUS); + control = usba_dma_readl(ep, CONTROL); +#ifdef CONFIG_USB_GADGET_DEBUG_FS + ep->last_dma_status = status; +#endif + pending = status & control; + DBG(DBG_INT | DBG_DMA, "dma irq, s/%#08x, c/%#08x\n", status, control); + + if (status & USBA_DMA_CH_EN) { + dev_err(&udc->pdev->dev, + "DMA_CH_EN is set after transfer is finished!\n"); + dev_err(&udc->pdev->dev, + "status=%#08x, pending=%#08x, control=%#08x\n", + status, pending, control); + + /* + * try to pretend nothing happened. We might have to + * do something here... + */ + } + + if (list_empty(&ep->queue)) + /* Might happen if a reset comes along at the right moment */ + return; + + if (pending & (USBA_DMA_END_TR_ST | USBA_DMA_END_BUF_ST)) { + req = list_entry(ep->queue.next, struct usba_request, queue); + usba_update_req(ep, req, status); + + list_del_init(&req->queue); + submit_next_request(ep); + request_complete(ep, req, 0); + } +} + +static irqreturn_t usba_udc_irq(int irq, void *devid) +{ + struct usba_udc *udc = devid; + u32 status; + u32 dma_status; + u32 ep_status; + + spin_lock(&udc->lock); + + status = usba_readl(udc, INT_STA); + DBG(DBG_INT, "irq, status=%#08x\n", status); + + if (status & USBA_DET_SUSPEND) { + usba_writel(udc, INT_CLR, USBA_DET_SUSPEND); + DBG(DBG_BUS, "Suspend detected\n"); + if (udc->gadget.speed != USB_SPEED_UNKNOWN + && udc->driver && udc->driver->suspend) { + spin_unlock(&udc->lock); + udc->driver->suspend(&udc->gadget); + spin_lock(&udc->lock); + } + } + + if (status & USBA_WAKE_UP) { + usba_writel(udc, INT_CLR, USBA_WAKE_UP); + DBG(DBG_BUS, "Wake Up CPU detected\n"); + } + + if (status & USBA_END_OF_RESUME) { + usba_writel(udc, INT_CLR, USBA_END_OF_RESUME); + DBG(DBG_BUS, "Resume detected\n"); + if (udc->gadget.speed != USB_SPEED_UNKNOWN + && udc->driver && udc->driver->resume) { + spin_unlock(&udc->lock); + udc->driver->resume(&udc->gadget); + spin_lock(&udc->lock); + } + } + + dma_status = USBA_BFEXT(DMA_INT, status); + if (dma_status) { + int i; + + for (i = 1; i < USBA_NR_ENDPOINTS; i++) + if (dma_status & (1 << i)) + usba_dma_irq(udc, &usba_ep[i]); + } + + ep_status = USBA_BFEXT(EPT_INT, status); + if (ep_status) { + int i; + + for (i = 0; i < USBA_NR_ENDPOINTS; i++) + if (ep_status & (1 << i)) { + if (ep_is_control(&usba_ep[i])) + usba_control_irq(udc, &usba_ep[i]); + else + usba_ep_irq(udc, &usba_ep[i]); + } + } + + if (status & USBA_END_OF_RESET) { + struct usba_ep *ep0; + + usba_writel(udc, INT_CLR, USBA_END_OF_RESET); + reset_all_endpoints(udc); + + if (status & USBA_HIGH_SPEED) { + DBG(DBG_BUS, "High-speed bus reset detected\n"); + udc->gadget.speed = USB_SPEED_HIGH; + } else { + DBG(DBG_BUS, "Full-speed bus reset detected\n"); + udc->gadget.speed = USB_SPEED_FULL; + } + + ep0 = &usba_ep[0]; + ep0->desc = &usba_ep0_desc; + ep0->state = WAIT_FOR_SETUP; + usba_ep_writel(ep0, CFG, + (USBA_BF(EPT_SIZE, EP0_EPT_SIZE) + | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL) + | USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE))); + usba_ep_writel(ep0, CTL_ENB, + USBA_EPT_ENABLE | USBA_RX_SETUP); + usba_writel(udc, INT_ENB, + (usba_readl(udc, INT_ENB) + | USBA_BF(EPT_INT, 1) + | USBA_DET_SUSPEND + | USBA_END_OF_RESUME)); + + if (!(usba_ep_readl(ep0, CFG) & USBA_EPT_MAPPED)) + dev_warn(&udc->pdev->dev, + "WARNING: EP0 configuration is invalid!\n"); + } + + spin_unlock(&udc->lock); + + return IRQ_HANDLED; +} + +static irqreturn_t usba_vbus_irq(int irq, void *devid) +{ + struct usba_udc *udc = devid; + int vbus; + + /* debounce */ + udelay(10); + + spin_lock(&udc->lock); + + /* May happen if Vbus pin toggles during probe() */ + if (!udc->driver) + goto out; + + vbus = gpio_get_value(udc->vbus_pin); + if (vbus != udc->vbus_prev) { + if (vbus) { + usba_writel(udc, CTRL, USBA_EN_USBA); + usba_writel(udc, INT_ENB, USBA_END_OF_RESET); + } else { + udc->gadget.speed = USB_SPEED_UNKNOWN; + reset_all_endpoints(udc); + usba_writel(udc, CTRL, 0); + spin_unlock(&udc->lock); + udc->driver->disconnect(&udc->gadget); + spin_lock(&udc->lock); + } + udc->vbus_prev = vbus; + } + +out: + spin_unlock(&udc->lock); + + return IRQ_HANDLED; +} + +int usb_gadget_register_driver(struct usb_gadget_driver *driver) +{ + struct usba_udc *udc = &the_udc; + unsigned long flags; + int ret; + + if (!udc->pdev) + return -ENODEV; + + spin_lock_irqsave(&udc->lock, flags); + if (udc->driver) { + spin_unlock_irqrestore(&udc->lock, flags); + return -EBUSY; + } + + udc->driver = driver; + udc->gadget.dev.driver = &driver->driver; + spin_unlock_irqrestore(&udc->lock, flags); + + clk_enable(udc->pclk); + clk_enable(udc->hclk); + + ret = driver->bind(&udc->gadget); + if (ret) { + DBG(DBG_ERR, "Could not bind to driver %s: error %d\n", + driver->driver.name, ret); + goto err_driver_bind; + } + + DBG(DBG_GADGET, "registered driver `%s'\n", driver->driver.name); + + udc->vbus_prev = 0; + if (udc->vbus_pin != -1) + enable_irq(gpio_to_irq(udc->vbus_pin)); + + /* If Vbus is present, enable the controller and wait for reset */ + spin_lock_irqsave(&udc->lock, flags); + if (vbus_is_present(udc) && udc->vbus_prev == 0) { + usba_writel(udc, CTRL, USBA_EN_USBA); + usba_writel(udc, INT_ENB, USBA_END_OF_RESET); + } + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; + +err_driver_bind: + udc->driver = NULL; + udc->gadget.dev.driver = NULL; + return ret; +} +EXPORT_SYMBOL(usb_gadget_register_driver); + +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ + struct usba_udc *udc = &the_udc; + unsigned long flags; + + if (!udc->pdev) + return -ENODEV; + if (driver != udc->driver) + return -EINVAL; + + if (udc->vbus_pin != -1) + disable_irq(gpio_to_irq(udc->vbus_pin)); + + spin_lock_irqsave(&udc->lock, flags); + udc->gadget.speed = USB_SPEED_UNKNOWN; + reset_all_endpoints(udc); + spin_unlock_irqrestore(&udc->lock, flags); + + /* This will also disable the DP pullup */ + usba_writel(udc, CTRL, 0); + + driver->unbind(&udc->gadget); + udc->gadget.dev.driver = NULL; + udc->driver = NULL; + + clk_disable(udc->hclk); + clk_disable(udc->pclk); + + DBG(DBG_GADGET, "unregistered driver `%s'\n", driver->driver.name); + + return 0; +} +EXPORT_SYMBOL(usb_gadget_unregister_driver); + +static int __init usba_udc_probe(struct platform_device *pdev) +{ + struct usba_platform_data *pdata = pdev->dev.platform_data; + struct resource *regs, *fifo; + struct clk *pclk, *hclk; + struct usba_udc *udc = &the_udc; + int irq, ret, i; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, CTRL_IOMEM_ID); + fifo = platform_get_resource(pdev, IORESOURCE_MEM, FIFO_IOMEM_ID); + if (!regs || !fifo) + return -ENXIO; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + pclk = clk_get(&pdev->dev, "pclk"); + if (IS_ERR(pclk)) + return PTR_ERR(pclk); + hclk = clk_get(&pdev->dev, "hclk"); + if (IS_ERR(hclk)) { + ret = PTR_ERR(hclk); + goto err_get_hclk; + } + + udc->pdev = pdev; + udc->pclk = pclk; + udc->hclk = hclk; + udc->vbus_pin = -1; + + ret = -ENOMEM; + udc->regs = ioremap(regs->start, regs->end - regs->start + 1); + if (!udc->regs) { + dev_err(&pdev->dev, "Unable to map I/O memory, aborting.\n"); + goto err_map_regs; + } + dev_info(&pdev->dev, "MMIO registers at 0x%08lx mapped at %p\n", + (unsigned long)regs->start, udc->regs); + udc->fifo = ioremap(fifo->start, fifo->end - fifo->start + 1); + if (!udc->fifo) { + dev_err(&pdev->dev, "Unable to map FIFO, aborting.\n"); + goto err_map_fifo; + } + dev_info(&pdev->dev, "FIFO at 0x%08lx mapped at %p\n", + (unsigned long)fifo->start, udc->fifo); + + device_initialize(&udc->gadget.dev); + udc->gadget.dev.parent = &pdev->dev; + udc->gadget.dev.dma_mask = pdev->dev.dma_mask; + + platform_set_drvdata(pdev, udc); + + /* Make sure we start from a clean slate */ + clk_enable(pclk); + usba_writel(udc, CTRL, 0); + clk_disable(pclk); + + INIT_LIST_HEAD(&usba_ep[0].ep.ep_list); + usba_ep[0].ep_regs = udc->regs + USBA_EPT_BASE(0); + usba_ep[0].dma_regs = udc->regs + USBA_DMA_BASE(0); + usba_ep[0].fifo = udc->fifo + USBA_FIFO_BASE(0); + for (i = 1; i < ARRAY_SIZE(usba_ep); i++) { + struct usba_ep *ep = &usba_ep[i]; + + ep->ep_regs = udc->regs + USBA_EPT_BASE(i); + ep->dma_regs = udc->regs + USBA_DMA_BASE(i); + ep->fifo = udc->fifo + USBA_FIFO_BASE(i); + + list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); + } + + ret = request_irq(irq, usba_udc_irq, 0, "atmel_usba_udc", udc); + if (ret) { + dev_err(&pdev->dev, "Cannot request irq %d (error %d)\n", + irq, ret); + goto err_request_irq; + } + udc->irq = irq; + + ret = device_add(&udc->gadget.dev); + if (ret) { + dev_dbg(&pdev->dev, "Could not add gadget: %d\n", ret); + goto err_device_add; + } + + if (pdata && pdata->vbus_pin != GPIO_PIN_NONE) { + if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) { + udc->vbus_pin = pdata->vbus_pin; + + ret = request_irq(gpio_to_irq(udc->vbus_pin), + usba_vbus_irq, 0, + "atmel_usba_udc", udc); + if (ret) { + gpio_free(udc->vbus_pin); + udc->vbus_pin = -1; + dev_warn(&udc->pdev->dev, + "failed to request vbus irq; " + "assuming always on\n"); + } else { + disable_irq(gpio_to_irq(udc->vbus_pin)); + } + } + } + + usba_init_debugfs(udc); + for (i = 1; i < ARRAY_SIZE(usba_ep); i++) + usba_ep_init_debugfs(udc, &usba_ep[i]); + + return 0; + +err_device_add: + free_irq(irq, udc); +err_request_irq: + iounmap(udc->fifo); +err_map_fifo: + iounmap(udc->regs); +err_map_regs: + clk_put(hclk); +err_get_hclk: + clk_put(pclk); + + platform_set_drvdata(pdev, NULL); + + return ret; +} + +static int __exit usba_udc_remove(struct platform_device *pdev) +{ + struct usba_udc *udc; + int i; + + udc = platform_get_drvdata(pdev); + + for (i = 1; i < ARRAY_SIZE(usba_ep); i++) + usba_ep_cleanup_debugfs(&usba_ep[i]); + usba_cleanup_debugfs(udc); + + if (udc->vbus_pin != -1) + gpio_free(udc->vbus_pin); + + free_irq(udc->irq, udc); + iounmap(udc->fifo); + iounmap(udc->regs); + clk_put(udc->hclk); + clk_put(udc->pclk); + + device_unregister(&udc->gadget.dev); + + return 0; +} + +static struct platform_driver udc_driver = { + .remove = __exit_p(usba_udc_remove), + .driver = { + .name = "atmel_usba_udc", + }, +}; + +static int __init udc_init(void) +{ + return platform_driver_probe(&udc_driver, usba_udc_probe); +} +module_init(udc_init); + +static void __exit udc_exit(void) +{ + platform_driver_unregister(&udc_driver); +} +module_exit(udc_exit); + +MODULE_DESCRIPTION("Atmel USBA UDC driver"); +MODULE_AUTHOR("Haavard Skinnemoen "); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h new file mode 100644 index 00000000000..f4f0f8bf812 --- /dev/null +++ b/drivers/usb/gadget/atmel_usba_udc.h @@ -0,0 +1,350 @@ +/* + * Driver for the Atmel USBA high speed USB device controller + * + * Copyright (C) 2005-2007 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __LINUX_USB_GADGET_USBA_UDC_H__ +#define __LINUX_USB_GADGET_USBA_UDC_H__ + +/* USB register offsets */ +#define USBA_CTRL 0x0000 +#define USBA_FNUM 0x0004 +#define USBA_INT_ENB 0x0010 +#define USBA_INT_STA 0x0014 +#define USBA_INT_CLR 0x0018 +#define USBA_EPT_RST 0x001c +#define USBA_TST 0x00e0 + +/* USB endpoint register offsets */ +#define USBA_EPT_CFG 0x0000 +#define USBA_EPT_CTL_ENB 0x0004 +#define USBA_EPT_CTL_DIS 0x0008 +#define USBA_EPT_CTL 0x000c +#define USBA_EPT_SET_STA 0x0014 +#define USBA_EPT_CLR_STA 0x0018 +#define USBA_EPT_STA 0x001c + +/* USB DMA register offsets */ +#define USBA_DMA_NXT_DSC 0x0000 +#define USBA_DMA_ADDRESS 0x0004 +#define USBA_DMA_CONTROL 0x0008 +#define USBA_DMA_STATUS 0x000c + +/* Bitfields in CTRL */ +#define USBA_DEV_ADDR_OFFSET 0 +#define USBA_DEV_ADDR_SIZE 7 +#define USBA_FADDR_EN (1 << 7) +#define USBA_EN_USBA (1 << 8) +#define USBA_DETACH (1 << 9) +#define USBA_REMOTE_WAKE_UP (1 << 10) + +/* Bitfields in FNUM */ +#define USBA_MICRO_FRAME_NUM_OFFSET 0 +#define USBA_MICRO_FRAME_NUM_SIZE 3 +#define USBA_FRAME_NUMBER_OFFSET 3 +#define USBA_FRAME_NUMBER_SIZE 11 +#define USBA_FRAME_NUM_ERROR (1 << 31) + +/* Bitfields in INT_ENB/INT_STA/INT_CLR */ +#define USBA_HIGH_SPEED (1 << 0) +#define USBA_DET_SUSPEND (1 << 1) +#define USBA_MICRO_SOF (1 << 2) +#define USBA_SOF (1 << 3) +#define USBA_END_OF_RESET (1 << 4) +#define USBA_WAKE_UP (1 << 5) +#define USBA_END_OF_RESUME (1 << 6) +#define USBA_UPSTREAM_RESUME (1 << 7) +#define USBA_EPT_INT_OFFSET 8 +#define USBA_EPT_INT_SIZE 16 +#define USBA_DMA_INT_OFFSET 24 +#define USBA_DMA_INT_SIZE 8 + +/* Bitfields in EPT_RST */ +#define USBA_RST_OFFSET 0 +#define USBA_RST_SIZE 16 + +/* Bitfields in USBA_TST */ +#define USBA_SPEED_CFG_OFFSET 0 +#define USBA_SPEED_CFG_SIZE 2 +#define USBA_TST_J_MODE (1 << 2) +#define USBA_TST_K_MODE (1 << 3) +#define USBA_TST_PKT_MODE (1 << 4) +#define USBA_OPMODE2 (1 << 5) + +/* Bitfields in EPT_CFG */ +#define USBA_EPT_SIZE_OFFSET 0 +#define USBA_EPT_SIZE_SIZE 3 +#define USBA_EPT_DIR_IN (1 << 3) +#define USBA_EPT_TYPE_OFFSET 4 +#define USBA_EPT_TYPE_SIZE 2 +#define USBA_BK_NUMBER_OFFSET 6 +#define USBA_BK_NUMBER_SIZE 2 +#define USBA_NB_TRANS_OFFSET 8 +#define USBA_NB_TRANS_SIZE 2 +#define USBA_EPT_MAPPED (1 << 31) + +/* Bitfields in EPT_CTL/EPT_CTL_ENB/EPT_CTL_DIS */ +#define USBA_EPT_ENABLE (1 << 0) +#define USBA_AUTO_VALID (1 << 1) +#define USBA_INTDIS_DMA (1 << 3) +#define USBA_NYET_DIS (1 << 4) +#define USBA_DATAX_RX (1 << 6) +#define USBA_MDATA_RX (1 << 7) +/* Bits 8-15 and 31 enable interrupts for respective bits in EPT_STA */ +#define USBA_BUSY_BANK_IE (1 << 18) + +/* Bitfields in EPT_SET_STA/EPT_CLR_STA/EPT_STA */ +#define USBA_FORCE_STALL (1 << 5) +#define USBA_TOGGLE_CLR (1 << 6) +#define USBA_TOGGLE_SEQ_OFFSET 6 +#define USBA_TOGGLE_SEQ_SIZE 2 +#define USBA_ERR_OVFLW (1 << 8) +#define USBA_RX_BK_RDY (1 << 9) +#define USBA_KILL_BANK (1 << 9) +#define USBA_TX_COMPLETE (1 << 10) +#define USBA_TX_PK_RDY (1 << 11) +#define USBA_ISO_ERR_TRANS (1 << 11) +#define USBA_RX_SETUP (1 << 12) +#define USBA_ISO_ERR_FLOW (1 << 12) +#define USBA_STALL_SENT (1 << 13) +#define USBA_ISO_ERR_CRC (1 << 13) +#define USBA_ISO_ERR_NBTRANS (1 << 13) +#define USBA_NAK_IN (1 << 14) +#define USBA_ISO_ERR_FLUSH (1 << 14) +#define USBA_NAK_OUT (1 << 15) +#define USBA_CURRENT_BANK_OFFSET 16 +#define USBA_CURRENT_BANK_SIZE 2 +#define USBA_BUSY_BANKS_OFFSET 18 +#define USBA_BUSY_BANKS_SIZE 2 +#define USBA_BYTE_COUNT_OFFSET 20 +#define USBA_BYTE_COUNT_SIZE 11 +#define USBA_SHORT_PACKET (1 << 31) + +/* Bitfields in DMA_CONTROL */ +#define USBA_DMA_CH_EN (1 << 0) +#define USBA_DMA_LINK (1 << 1) +#define USBA_DMA_END_TR_EN (1 << 2) +#define USBA_DMA_END_BUF_EN (1 << 3) +#define USBA_DMA_END_TR_IE (1 << 4) +#define USBA_DMA_END_BUF_IE (1 << 5) +#define USBA_DMA_DESC_LOAD_IE (1 << 6) +#define USBA_DMA_BURST_LOCK (1 << 7) +#define USBA_DMA_BUF_LEN_OFFSET 16 +#define USBA_DMA_BUF_LEN_SIZE 16 + +/* Bitfields in DMA_STATUS */ +#define USBA_DMA_CH_ACTIVE (1 << 1) +#define USBA_DMA_END_TR_ST (1 << 4) +#define USBA_DMA_END_BUF_ST (1 << 5) +#define USBA_DMA_DESC_LOAD_ST (1 << 6) + +/* Constants for SPEED_CFG */ +#define USBA_SPEED_CFG_NORMAL 0 +#define USBA_SPEED_CFG_FORCE_HIGH 2 +#define USBA_SPEED_CFG_FORCE_FULL 3 + +/* Constants for EPT_SIZE */ +#define USBA_EPT_SIZE_8 0 +#define USBA_EPT_SIZE_16 1 +#define USBA_EPT_SIZE_32 2 +#define USBA_EPT_SIZE_64 3 +#define USBA_EPT_SIZE_128 4 +#define USBA_EPT_SIZE_256 5 +#define USBA_EPT_SIZE_512 6 +#define USBA_EPT_SIZE_1024 7 + +/* Constants for EPT_TYPE */ +#define USBA_EPT_TYPE_CONTROL 0 +#define USBA_EPT_TYPE_ISO 1 +#define USBA_EPT_TYPE_BULK 2 +#define USBA_EPT_TYPE_INT 3 + +/* Constants for BK_NUMBER */ +#define USBA_BK_NUMBER_ZERO 0 +#define USBA_BK_NUMBER_ONE 1 +#define USBA_BK_NUMBER_DOUBLE 2 +#define USBA_BK_NUMBER_TRIPLE 3 + +/* Bit manipulation macros */ +#define USBA_BF(name, value) \ + (((value) & ((1 << USBA_##name##_SIZE) - 1)) \ + << USBA_##name##_OFFSET) +#define USBA_BFEXT(name, value) \ + (((value) >> USBA_##name##_OFFSET) \ + & ((1 << USBA_##name##_SIZE) - 1)) +#define USBA_BFINS(name, value, old) \ + (((old) & ~(((1 << USBA_##name##_SIZE) - 1) \ + << USBA_##name##_OFFSET)) \ + | USBA_BF(name, value)) + +/* Register access macros */ +#define usba_readl(udc, reg) \ + __raw_readl((udc)->regs + USBA_##reg) +#define usba_writel(udc, reg, value) \ + __raw_writel((value), (udc)->regs + USBA_##reg) +#define usba_ep_readl(ep, reg) \ + __raw_readl((ep)->ep_regs + USBA_EPT_##reg) +#define usba_ep_writel(ep, reg, value) \ + __raw_writel((value), (ep)->ep_regs + USBA_EPT_##reg) +#define usba_dma_readl(ep, reg) \ + __raw_readl((ep)->dma_regs + USBA_DMA_##reg) +#define usba_dma_writel(ep, reg, value) \ + __raw_writel((value), (ep)->dma_regs + USBA_DMA_##reg) + +/* Calculate base address for a given endpoint or DMA controller */ +#define USBA_EPT_BASE(x) (0x100 + (x) * 0x20) +#define USBA_DMA_BASE(x) (0x300 + (x) * 0x10) +#define USBA_FIFO_BASE(x) ((x) << 16) + +/* Synth parameters */ +#define USBA_NR_ENDPOINTS 7 + +#define EP0_FIFO_SIZE 64 +#define EP0_EPT_SIZE USBA_EPT_SIZE_64 +#define EP0_NR_BANKS 1 + +/* + * REVISIT: Try to eliminate this value. Can we rely on req->mapped to + * provide this information? + */ +#define DMA_ADDR_INVALID (~(dma_addr_t)0) + +#define FIFO_IOMEM_ID 0 +#define CTRL_IOMEM_ID 1 + +#ifdef DEBUG +#define DBG_ERR 0x0001 /* report all error returns */ +#define DBG_HW 0x0002 /* debug hardware initialization */ +#define DBG_GADGET 0x0004 /* calls to/from gadget driver */ +#define DBG_INT 0x0008 /* interrupts */ +#define DBG_BUS 0x0010 /* report changes in bus state */ +#define DBG_QUEUE 0x0020 /* debug request queue processing */ +#define DBG_FIFO 0x0040 /* debug FIFO contents */ +#define DBG_DMA 0x0080 /* debug DMA handling */ +#define DBG_REQ 0x0100 /* print out queued request length */ +#define DBG_ALL 0xffff +#define DBG_NONE 0x0000 + +#define DEBUG_LEVEL (DBG_ERR) +#define DBG(level, fmt, ...) \ + do { \ + if ((level) & DEBUG_LEVEL) \ + printk(KERN_DEBUG "udc: " fmt, ## __VA_ARGS__); \ + } while (0) +#else +#define DBG(level, fmt...) +#endif + +enum usba_ctrl_state { + WAIT_FOR_SETUP, + DATA_STAGE_IN, + DATA_STAGE_OUT, + STATUS_STAGE_IN, + STATUS_STAGE_OUT, + STATUS_STAGE_ADDR, + STATUS_STAGE_TEST, +}; +/* + EP_STATE_IDLE, + EP_STATE_SETUP, + EP_STATE_IN_DATA, + EP_STATE_OUT_DATA, + EP_STATE_SET_ADDR_STATUS, + EP_STATE_RX_STATUS, + EP_STATE_TX_STATUS, + EP_STATE_HALT, +*/ + +struct usba_dma_desc { + dma_addr_t next; + dma_addr_t addr; + u32 ctrl; +}; + +struct usba_ep { + int state; + void __iomem *ep_regs; + void __iomem *dma_regs; + void __iomem *fifo; + struct usb_ep ep; + struct usba_udc *udc; + + struct list_head queue; + const struct usb_endpoint_descriptor *desc; + + u16 fifo_size; + u8 nr_banks; + u8 index; + unsigned int can_dma:1; + unsigned int can_isoc:1; + unsigned int is_isoc:1; + unsigned int is_in:1; + +#ifdef CONFIG_USB_GADGET_DEBUG_FS + u32 last_dma_status; + struct dentry *debugfs_dir; + struct dentry *debugfs_queue; + struct dentry *debugfs_dma_status; + struct dentry *debugfs_state; +#endif +}; + +struct usba_request { + struct usb_request req; + struct list_head queue; + + u32 ctrl; + + unsigned int submitted:1; + unsigned int last_transaction:1; + unsigned int using_dma:1; + unsigned int mapped:1; +}; + +struct usba_udc { + /* Protect hw registers from concurrent modifications */ + spinlock_t lock; + + void __iomem *regs; + void __iomem *fifo; + + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + struct platform_device *pdev; + int irq; + int vbus_pin; + struct clk *pclk; + struct clk *hclk; + + int test_mode; + int vbus_prev; + +#ifdef CONFIG_USB_GADGET_DEBUG_FS + struct dentry *debugfs_root; + struct dentry *debugfs_regs; +#endif +}; + +static inline struct usba_ep *to_usba_ep(struct usb_ep *ep) +{ + return container_of(ep, struct usba_ep, ep); +} + +static inline struct usba_request *to_usba_req(struct usb_request *req) +{ + return container_of(req, struct usba_request, req); +} + +static inline struct usba_udc *to_usba_udc(struct usb_gadget *gadget) +{ + return container_of(gadget, struct usba_udc, gadget); +} + +#define ep_is_control(ep) ((ep)->index == 0) +#define ep_is_idle(ep) ((ep)->state == EP_STATE_IDLE) + +#endif /* __LINUX_USB_GADGET_USBA_UDC_H */ -- cgit v1.2.3-70-g09d2 From eecfb911a03a48ef5f7114246343128bd01c1b5f Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Thu, 11 Oct 2007 00:37:50 +0900 Subject: USB: Adding support for SHARP WS011SH to ipaq.c This patch supports for SHARP WS011SH[0] to ipaq.c [0]: http://www.willcom-inc.com/ja/lineup/ws/011sh/index.html (Sorry , Japanese only.) Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ipaq.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index c1a6484f652..e836ad07fdb 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -256,6 +256,7 @@ static struct usb_device_id ipaq_id_table [] = { { USB_DEVICE(0x04DD, 0x9121) }, /* SHARP WS004SH USB Modem */ { USB_DEVICE(0x04DD, 0x9123) }, /* SHARP WS007SH USB Modem */ { USB_DEVICE(0x04DD, 0x9151) }, /* SHARP S01SH USB Modem */ + { USB_DEVICE(0x04DD, 0x91AC) }, /* SHARP WS011SH USB Modem */ { USB_DEVICE(0x04E8, 0x5F00) }, /* Samsung NEXiO USB Sync */ { USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */ { USB_DEVICE(0x04E8, 0x5F02) }, /* Samsung NEXiO USB Sync */ -- cgit v1.2.3-70-g09d2 From 17f060224fb9f435c6f9306b7b61419d038def13 Mon Sep 17 00:00:00 2001 From: Richard Sharpe Date: Wed, 10 Oct 2007 10:56:28 -0700 Subject: USB: allow usbstorage to have LUNS greater than 2Tb Attached is a very small patch (several comment lines) and a one-line coded change) that allows for USB storage devices that are larger than 2TB. At the company where I work we need such support, and one of my co-workers, Jane Liu, pointed out that SCSI low-layer drivers need to specify what size CDBs they accept. After looking through the code it became obvious that the current USB Storage code accepted the default of 12-byte CDBs, so I changed it to accept 16-byte CDBs. This allows our device to work. Signed-off-by: Richard Sharpe Signed-off-by: Matthew Dharm Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/usb.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 59181667066..3451e8d03ab 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -960,6 +960,10 @@ static int storage_probe(struct usb_interface *intf, return -ENOMEM; } + /* + * Allow 16-byte CDBs and thus > 2TB + */ + host->max_cmd_len = 16; us = host_to_us(host); memset(us, 0, sizeof(struct us_data)); mutex_init(&(us->dev_mutex)); -- cgit v1.2.3-70-g09d2 From 32fe01985aa2cb2562f6fc171e526e279abe10db Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 10 Oct 2007 16:27:07 -0400 Subject: USB: mutual exclusion for EHCI init and port resets This patch (as999) fixes a problem that sometimes shows up when host controller driver modules are loaded in the wrong order. If ehci-hcd happens to initialize an EHCI controller while the companion OHCI or UHCI controller is in the middle of a port reset, the reset can fail and the companion may get very confused. The patch adds an rw-semaphore and uses it to keep EHCI initialization and port resets mutually exclusive. Signed-off-by: Alan Stern Acked-by: David Brownell Cc: David Miller Cc: Dely L Sy Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.h | 8 +++++++- drivers/usb/core/hub.c | 15 ++++++++++++++- drivers/usb/host/ehci-hcd.c | 8 ++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 1396141274f..98e24194a4a 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -19,6 +19,8 @@ #ifdef __KERNEL__ +#include + /* This file contains declarations of usbcore internals that are mostly * used or exposed by Host Controller Drivers. */ @@ -470,5 +472,9 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb, : (in_interrupt () ? "in_interrupt" : "can sleep")) -#endif /* __KERNEL__ */ +/* This rwsem is for use only by the hub driver and ehci-hcd. + * Nobody else should touch it. + */ +extern struct rw_semaphore ehci_cf_port_reset_rwsem; +#endif /* __KERNEL__ */ diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 481dca641ea..d20cb545a6e 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -125,6 +125,12 @@ MODULE_PARM_DESC(use_both_schemes, "try the other device initialization scheme if the " "first one fails"); +/* Mutual exclusion for EHCI CF initialization. This interferes with + * port reset on some companion controllers. + */ +DECLARE_RWSEM(ehci_cf_port_reset_rwsem); +EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem); + static inline char *portspeed(int portstatus) { @@ -1581,6 +1587,11 @@ static int hub_port_reset(struct usb_hub *hub, int port1, { int i, status; + /* Block EHCI CF initialization during the port reset. + * Some companion controllers don't like it when they mix. + */ + down_read(&ehci_cf_port_reset_rwsem); + /* Reset the port */ for (i = 0; i < PORT_RESET_TRIES; i++) { status = set_port_feature(hub->hdev, @@ -1612,7 +1623,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1, usb_set_device_state(udev, status ? USB_STATE_NOTATTACHED : USB_STATE_DEFAULT); - return status; + goto done; } dev_dbg (hub->intfdev, @@ -1625,6 +1636,8 @@ static int hub_port_reset(struct usb_hub *hub, int port1, "Cannot enable port %i. Maybe the USB cable is bad?\n", port1); + done: + up_read(&ehci_cf_port_reset_rwsem); return status; } diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index db00492588b..c1514442883 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -570,10 +570,18 @@ static int ehci_run (struct usb_hcd *hcd) * are explicitly handed to companion controller(s), so no TT is * involved with the root hub. (Except where one is integrated, * and there's no companion controller unless maybe for USB OTG.) + * + * Turning on the CF flag will transfer ownership of all ports + * from the companions to the EHCI controller. If any of the + * companions are in the middle of a port reset at the time, it + * could cause trouble. Write-locking ehci_cf_port_reset_rwsem + * guarantees that no resets are in progress. */ + down_write(&ehci_cf_port_reset_rwsem); hcd->state = HC_STATE_RUNNING; ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ + up_write(&ehci_cf_port_reset_rwsem); temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase)); ehci_info (ehci, -- cgit v1.2.3-70-g09d2 From 271f9e68f3450ac8d1ff3bda36581f1ec0d0cc1f Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 10 Oct 2007 16:30:12 -0400 Subject: USB: skip autosuspended devices during system resume System suspends and hibernation are supposed to be as transparent as possible. By this reasoning, if a USB device is already autosuspended before the system sleep begins then it should remain autosuspended after the system wakes up. This patch (as1001) adds a skip_sys_resume flag to the usb_device structure and uses it to avoid waking up devices which were suspended when a system sleep began. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 27 ++++++++++++++++++++------- include/linux/usb.h | 1 + 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 3f734240e0e..8c1eac27f2d 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1540,9 +1540,21 @@ int usb_external_resume_device(struct usb_device *udev) static int usb_suspend(struct device *dev, pm_message_t message) { + struct usb_device *udev; + if (!is_usb_device(dev)) /* Ignore PM for interfaces */ return 0; - return usb_external_suspend_device(to_usb_device(dev), message); + udev = to_usb_device(dev); + + /* If udev is already suspended, we can skip this suspend and + * we should also skip the upcoming system resume. */ + if (udev->state == USB_STATE_SUSPENDED) { + udev->skip_sys_resume = 1; + return 0; + } + + udev->skip_sys_resume = 0; + return usb_external_suspend_device(udev, message); } static int usb_resume(struct device *dev) @@ -1553,13 +1565,14 @@ static int usb_resume(struct device *dev) return 0; udev = to_usb_device(dev); - /* If autoresume is disabled then we also want to prevent resume - * during system wakeup. However, a "persistent-device" reset-resume - * after power loss counts as a wakeup event. So allow a - * reset-resume to occur if remote wakeup is enabled. */ - if (udev->autoresume_disabled) { + /* If udev->skip_sys_resume is set then udev was already suspended + * when the system suspend started, so we don't want to resume + * udev during this system wakeup. However a reset-resume counts + * as a wakeup event, so allow a reset-resume to occur if remote + * wakeup is enabled. */ + if (udev->skip_sys_resume) { if (!(udev->reset_resume && udev->do_remote_wakeup)) - return -EPERM; + return -EHOSTUNREACH; } return usb_external_resume_device(udev); } diff --git a/include/linux/usb.h b/include/linux/usb.h index c10935fdc03..c5c8f169d3c 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -430,6 +430,7 @@ struct usb_device { unsigned persist_enabled:1; /* USB_PERSIST enabled for this dev */ unsigned autosuspend_disabled:1; /* autosuspend and autoresume */ unsigned autoresume_disabled:1; /* disabled by the user */ + unsigned skip_sys_resume:1; /* skip the next system resume */ #endif }; #define to_usb_device(d) container_of(d, struct usb_device, dev) -- cgit v1.2.3-70-g09d2 From cd38c1e1ae5273c28a12baacaf17c1faa062661f Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 10 Oct 2007 16:24:56 -0400 Subject: USB: documentation for USB power management This patch (as998) adds documentation on how USB power management works and how to use it. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- Documentation/usb/power-management.txt | 517 +++++++++++++++++++++++++++++++++ 1 file changed, 517 insertions(+) create mode 100644 Documentation/usb/power-management.txt diff --git a/Documentation/usb/power-management.txt b/Documentation/usb/power-management.txt new file mode 100644 index 00000000000..97842deec47 --- /dev/null +++ b/Documentation/usb/power-management.txt @@ -0,0 +1,517 @@ + Power Management for USB + + Alan Stern + + October 5, 2007 + + + + What is Power Management? + ------------------------- + +Power Management (PM) is the practice of saving energy by suspending +parts of a computer system when they aren't being used. While a +component is "suspended" it is in a nonfunctional low-power state; it +might even be turned off completely. A suspended component can be +"resumed" (returned to a functional full-power state) when the kernel +needs to use it. (There also are forms of PM in which components are +placed in a less functional but still usable state instead of being +suspended; an example would be reducing the CPU's clock rate. This +document will not discuss those other forms.) + +When the parts being suspended include the CPU and most of the rest of +the system, we speak of it as a "system suspend". When a particular +device is turned off while the system as a whole remains running, we +call it a "dynamic suspend" (also known as a "runtime suspend" or +"selective suspend"). This document concentrates mostly on how +dynamic PM is implemented in the USB subsystem, although system PM is +covered to some extent (see Documentation/power/*.txt for more +information about system PM). + +Note: Dynamic PM support for USB is present only if the kernel was +built with CONFIG_USB_SUSPEND enabled. System PM support is present +only if the kernel was built with CONFIG_SUSPEND or CONFIG_HIBERNATION +enabled. + + + What is Remote Wakeup? + ---------------------- + +When a device has been suspended, it generally doesn't resume until +the computer tells it to. Likewise, if the entire computer has been +suspended, it generally doesn't resume until the user tells it to, say +by pressing a power button or opening the cover. + +However some devices have the capability of resuming by themselves, or +asking the kernel to resume them, or even telling the entire computer +to resume. This capability goes by several names such as "Wake On +LAN"; we will refer to it generically as "remote wakeup". When a +device is enabled for remote wakeup and it is suspended, it may resume +itself (or send a request to be resumed) in response to some external +event. Examples include a suspended keyboard resuming when a key is +pressed, or a suspended USB hub resuming when a device is plugged in. + + + When is a USB device idle? + -------------------------- + +A device is idle whenever the kernel thinks it's not busy doing +anything important and thus is a candidate for being suspended. The +exact definition depends on the device's driver; drivers are allowed +to declare that a device isn't idle even when there's no actual +communication taking place. (For example, a hub isn't considered idle +unless all the devices plugged into that hub are already suspended.) +In addition, a device isn't considered idle so long as a program keeps +its usbfs file open, whether or not any I/O is going on. + +If a USB device has no driver, its usbfs file isn't open, and it isn't +being accessed through sysfs, then it definitely is idle. + + + Forms of dynamic PM + ------------------- + +Dynamic suspends can occur in two ways: manual and automatic. +"Manual" means that the user has told the kernel to suspend a device, +whereas "automatic" means that the kernel has decided all by itself to +suspend a device. Automatic suspend is called "autosuspend" for +short. In general, a device won't be autosuspended unless it has been +idle for some minimum period of time, the so-called idle-delay time. + +Of course, nothing the kernel does on its own initiative should +prevent the computer or its devices from working properly. If a +device has been autosuspended and a program tries to use it, the +kernel will automatically resume the device (autoresume). For the +same reason, an autosuspended device will usually have remote wakeup +enabled, if the device supports remote wakeup. + +It is worth mentioning that many USB drivers don't support +autosuspend. In fact, at the time of this writing (Linux 2.6.23) the +only drivers which do support it are the hub driver, kaweth, asix, +usblp, usblcd, and usb-skeleton (which doesn't count). If a +non-supporting driver is bound to a device, the device won't be +autosuspended. In effect, the kernel pretends the device is never +idle. + +We can categorize power management events in two broad classes: +external and internal. External events are those triggered by some +agent outside the USB stack: system suspend/resume (triggered by +userspace), manual dynamic suspend/resume (also triggered by +userspace), and remote wakeup (triggered by the device). Internal +events are those triggered within the USB stack: autosuspend and +autoresume. + + + The user interface for dynamic PM + --------------------------------- + +The user interface for controlling dynamic PM is located in the power/ +subdirectory of each USB device's sysfs directory, that is, in +/sys/bus/usb/devices/.../power/ where "..." is the device's ID. The +relevant attribute files are: wakeup, level, and autosuspend. + + power/wakeup + + This file is empty if the device does not support + remote wakeup. Otherwise the file contains either the + word "enabled" or the word "disabled", and you can + write those words to the file. The setting determines + whether or not remote wakeup will be enabled when the + device is next suspended. (If the setting is changed + while the device is suspended, the change won't take + effect until the following suspend.) + + power/level + + This file contains one of three words: "on", "auto", + or "suspend". You can write those words to the file + to change the device's setting. + + "on" means that the device should be resumed and + autosuspend is not allowed. (Of course, system + suspends are still allowed.) + + "auto" is the normal state in which the kernel is + allowed to autosuspend and autoresume the device. + + "suspend" means that the device should remain + suspended, and autoresume is not allowed. (But remote + wakeup may still be allowed, since it is controlled + separately by the power/wakeup attribute.) + + power/autosuspend + + This file contains an integer value, which is the + number of seconds the device should remain idle before + the kernel will autosuspend it (the idle-delay time). + The default is 2. 0 means to autosuspend as soon as + the device becomes idle, and -1 means never to + autosuspend. You can write a number to the file to + change the autosuspend idle-delay time. + +Writing "-1" to power/autosuspend and writing "on" to power/level do +essentially the same thing -- they both prevent the device from being +autosuspended. Yes, this is a redundancy in the API. + +(In 2.6.21 writing "0" to power/autosuspend would prevent the device +from being autosuspended; the behavior was changed in 2.6.22. The +power/autosuspend attribute did not exist prior to 2.6.21, and the +power/level attribute did not exist prior to 2.6.22.) + + + Changing the default idle-delay time + ------------------------------------ + +The default autosuspend idle-delay time is controlled by a module +parameter in usbcore. You can specify the value when usbcore is +loaded. For example, to set it to 5 seconds instead of 2 you would +do: + + modprobe usbcore autosuspend=5 + +Equivalently, you could add to /etc/modprobe.conf a line saying: + + options usbcore autosuspend=5 + +Some distributions load the usbcore module very early during the boot +process, by means of a program or script running from an initramfs +image. To alter the parameter value you would have to rebuild that +image. + +If usbcore is compiled into the kernel rather than built as a loadable +module, you can add + + usbcore.autosuspend=5 + +to the kernel's boot command line. + +Finally, the parameter value can be changed while the system is +running. If you do: + + echo 5 >/sys/module/usbcore/parameters/autosuspend + +then each new USB device will have its autosuspend idle-delay +initialized to 5. (The idle-delay values for already existing devices +will not be affected.) + +Setting the initial default idle-delay to -1 will prevent any +autosuspend of any USB device. This is a simple alternative to +disabling CONFIG_USB_SUSPEND and rebuilding the kernel, and it has the +added benefit of allowing you to enable autosuspend for selected +devices. + + + Warnings + -------- + +The USB specification states that all USB devices must support power +management. Nevertheless, the sad fact is that many devices do not +support it very well. You can suspend them all right, but when you +try to resume them they disconnect themselves from the USB bus or +they stop working entirely. This seems to be especially prevalent +among printers and scanners, but plenty of other types of device have +the same deficiency. + +For this reason, by default the kernel disables autosuspend (the +power/level attribute is initialized to "on") for all devices other +than hubs. Hubs, at least, appear to be reasonably well-behaved in +this regard. + +(In 2.6.21 and 2.6.22 this wasn't the case. Autosuspend was enabled +by default for almost all USB devices. A number of people experienced +problems as a result.) + +This means that non-hub devices won't be autosuspended unless the user +or a program explicitly enables it. As of this writing there aren't +any widespread programs which will do this; we hope that in the near +future device managers such as HAL will take on this added +responsibility. In the meantime you can always carry out the +necessary operations by hand or add them to a udev script. You can +also change the idle-delay time; 2 seconds is not the best choice for +every device. + +Sometimes it turns out that even when a device does work okay with +autosuspend there are still problems. For example, there are +experimental patches adding autosuspend support to the usbhid driver, +which manages keyboards and mice, among other things. Tests with a +number of keyboards showed that typing on a suspended keyboard, while +causing the keyboard to do a remote wakeup all right, would +nonetheless frequently result in lost keystrokes. Tests with mice +showed that some of them would issue a remote-wakeup request in +response to button presses but not to motion, and some in response to +neither. + +The kernel will not prevent you from enabling autosuspend on devices +that can't handle it. It is even possible in theory to damage a +device by suspending it at the wrong time -- for example, suspending a +USB hard disk might cause it to spin down without parking the heads. +(Highly unlikely, but possible.) Take care. + + + The driver interface for Power Management + ----------------------------------------- + +The requirements for a USB driver to support external power management +are pretty modest; the driver need only define + + .suspend + .resume + .reset_resume + +methods in its usb_driver structure, and the reset_resume method is +optional. The methods' jobs are quite simple: + + The suspend method is called to warn the driver that the + device is going to be suspended. If the driver returns a + negative error code, the suspend will be aborted. Normally + the driver will return 0, in which case it must cancel all + outstanding URBs (usb_kill_urb()) and not submit any more. + + The resume method is called to tell the driver that the + device has been resumed and the driver can return to normal + operation. URBs may once more be submitted. + + The reset_resume method is called to tell the driver that + the device has been resumed and it also has been reset. + The driver should redo any necessary device initialization, + since the device has probably lost most or all of its state + (although the interfaces will be in the same altsettings as + before the suspend). + +The reset_resume method is used by the USB Persist facility (see +Documentation/usb/persist.txt) and it can also be used under certain +circumstances when CONFIG_USB_PERSIST is not enabled. Currently, if a +device is reset during a resume and the driver does not have a +reset_resume method, the driver won't receive any notification about +the resume. Later kernels will call the driver's disconnect method; +2.6.23 doesn't do this. + +USB drivers are bound to interfaces, so their suspend and resume +methods get called when the interfaces are suspended or resumed. In +principle one might want to suspend some interfaces on a device (i.e., +force the drivers for those interface to stop all activity) without +suspending the other interfaces. The USB core doesn't allow this; all +interfaces are suspended when the device itself is suspended and all +interfaces are resumed when the device is resumed. It isn't possible +to suspend or resume some but not all of a device's interfaces. The +closest you can come is to unbind the interfaces' drivers. + + + The driver interface for autosuspend and autoresume + --------------------------------------------------- + +To support autosuspend and autoresume, a driver should implement all +three of the methods listed above. In addition, a driver indicates +that it supports autosuspend by setting the .supports_autosuspend flag +in its usb_driver structure. It is then responsible for informing the +USB core whenever one of its interfaces becomes busy or idle. The +driver does so by calling these three functions: + + int usb_autopm_get_interface(struct usb_interface *intf); + void usb_autopm_put_interface(struct usb_interface *intf); + int usb_autopm_set_interface(struct usb_interface *intf); + +The functions work by maintaining a counter in the usb_interface +structure. When intf->pm_usage_count is > 0 then the interface is +deemed to be busy, and the kernel will not autosuspend the interface's +device. When intf->pm_usage_count is <= 0 then the interface is +considered to be idle, and the kernel may autosuspend the device. + +(There is a similar pm_usage_count field in struct usb_device, +associated with the device itself rather than any of its interfaces. +This field is used only by the USB core.) + +The driver owns intf->pm_usage_count; it can modify the value however +and whenever it likes. A nice aspect of the usb_autopm_* routines is +that the changes they make are protected by the usb_device structure's +PM mutex (udev->pm_mutex); however drivers may change pm_usage_count +without holding the mutex. + + usb_autopm_get_interface() increments pm_usage_count and + attempts an autoresume if the new value is > 0 and the + device is suspended. + + usb_autopm_put_interface() decrements pm_usage_count and + attempts an autosuspend if the new value is <= 0 and the + device isn't suspended. + + usb_autopm_set_interface() leaves pm_usage_count alone. + It attempts an autoresume if the value is > 0 and the device + is suspended, and it attempts an autosuspend if the value is + <= 0 and the device isn't suspended. + +There also are a couple of utility routines drivers can use: + + usb_autopm_enable() sets pm_usage_cnt to 1 and then calls + usb_autopm_set_interface(), which will attempt an autoresume. + + usb_autopm_disable() sets pm_usage_cnt to 0 and then calls + usb_autopm_set_interface(), which will attempt an autosuspend. + +The conventional usage pattern is that a driver calls +usb_autopm_get_interface() in its open routine and +usb_autopm_put_interface() in its close or release routine. But +other patterns are possible. + +The autosuspend attempts mentioned above will often fail for one +reason or another. For example, the power/level attribute might be +set to "on", or another interface in the same device might not be +idle. This is perfectly normal. If the reason for failure was that +the device hasn't been idle for long enough, a delayed workqueue +routine is automatically set up to carry out the operation when the +autosuspend idle-delay has expired. + +Autoresume attempts also can fail. This will happen if power/level is +set to "suspend" or if the device doesn't manage to resume properly. +Unlike autosuspend, there's no delay for an autoresume. + + + Other parts of the driver interface + ----------------------------------- + +Sometimes a driver needs to make sure that remote wakeup is enabled +during autosuspend. For example, there's not much point +autosuspending a keyboard if the user can't cause the keyboard to do a +remote wakeup by typing on it. If the driver sets +intf->needs_remote_wakeup to 1, the kernel won't autosuspend the +device if remote wakeup isn't available or has been disabled through +the power/wakeup attribute. (If the device is already autosuspended, +though, setting this flag won't cause the kernel to autoresume it. +Normally a driver would set this flag in its probe method, at which +time the device is guaranteed not to be autosuspended.) + +The usb_autopm_* routines have to run in a sleepable process context; +they must not be called from an interrupt handler or while holding a +spinlock. In fact, the entire autosuspend mechanism is not well geared +toward interrupt-driven operation. However there is one thing a +driver can do in an interrupt handler: + + usb_mark_last_busy(struct usb_device *udev); + +This sets udev->last_busy to the current time. udev->last_busy is the +field used for idle-delay calculations; updating it will cause any +pending autosuspend to be moved back. The usb_autopm_* routines will +also set the last_busy field to the current time. + +Calling urb_mark_last_busy() from within an URB completion handler is +subject to races: The kernel may have just finished deciding the +device has been idle for long enough but not yet gotten around to +calling the driver's suspend method. The driver would have to be +responsible for synchronizing its suspend method with its URB +completion handler and causing the autosuspend to fail with -EBUSY if +an URB had completed too recently. + +External suspend calls should never be allowed to fail in this way, +only autosuspend calls. The driver can tell them apart by checking +udev->auto_pm; this flag will be set to 1 for internal PM events +(autosuspend or autoresume) and 0 for external PM events. + +Many of the ingredients in the autosuspend framework are oriented +towards interfaces: The usb_interface structure contains the +pm_usage_cnt field, and the usb_autopm_* routines take an interface +pointer as their argument. But somewhat confusingly, a few of the +pieces (usb_mark_last_busy() and udev->auto_pm) use the usb_device +structure instead. Drivers need to keep this straight; they can call +interface_to_usbdev() to find the device structure for a given +interface. + + + Locking requirements + -------------------- + +All three suspend/resume methods are always called while holding the +usb_device's PM mutex. For external events -- but not necessarily for +autosuspend or autoresume -- the device semaphore (udev->dev.sem) will +also be held. This implies that external suspend/resume events are +mutually exclusive with calls to probe, disconnect, pre_reset, and +post_reset; the USB core guarantees that this is true of internal +suspend/resume events as well. + +If a driver wants to block all suspend/resume calls during some +critical section, it can simply acquire udev->pm_mutex. +Alternatively, if the critical section might call some of the +usb_autopm_* routines, the driver can avoid deadlock by doing: + + down(&udev->dev.sem); + rc = usb_autopm_get_interface(intf); + +and at the end of the critical section: + + if (!rc) + usb_autopm_put_interface(intf); + up(&udev->dev.sem); + +Holding the device semaphore will block all external PM calls, and the +usb_autopm_get_interface() will prevent any internal PM calls, even if +it fails. (Exercise: Why?) + +The rules for locking order are: + + Never acquire any device semaphore while holding any PM mutex. + + Never acquire udev->pm_mutex while holding the PM mutex for + a device that isn't a descendant of udev. + +In other words, PM mutexes should only be acquired going up the device +tree, and they should be acquired only after locking all the device +semaphores you need to hold. These rules don't matter to drivers very +much; they usually affect just the USB core. + +Still, drivers do need to be careful. For example, many drivers use a +private mutex to synchronize their normal I/O activities with their +disconnect method. Now if the driver supports autosuspend then it +must call usb_autopm_put_interface() from somewhere -- maybe from its +close method. It should make the call while holding the private mutex, +since a driver shouldn't call any of the usb_autopm_* functions for an +interface from which it has been unbound. + +But the usb_autpm_* routines always acquire the device's PM mutex, and +consequently the locking order has to be: private mutex first, PM +mutex second. Since the suspend method is always called with the PM +mutex held, it mustn't try to acquire the private mutex. It has to +synchronize with the driver's I/O activities in some other way. + + + Interaction between dynamic PM and system PM + -------------------------------------------- + +Dynamic power management and system power management can interact in +a couple of ways. + +Firstly, a device may already be manually suspended or autosuspended +when a system suspend occurs. Since system suspends are supposed to +be as transparent as possible, the device should remain suspended +following the system resume. The 2.6.23 kernel obeys this principle +for manually suspended devices but not for autosuspended devices; they +do get resumed when the system wakes up. (Presumably they will be +autosuspended again after their idle-delay time expires.) In later +kernels this behavior will be fixed. + +(There is an exception. If a device would undergo a reset-resume +instead of a normal resume, and the device is enabled for remote +wakeup, then the reset-resume takes place even if the device was +already suspended when the system suspend began. The justification is +that a reset-resume is a kind of remote-wakeup event. Or to put it +another way, a device which needs a reset won't be able to generate +normal remote-wakeup signals, so it ought to be resumed immediately.) + +Secondly, a dynamic power-management event may occur as a system +suspend is underway. The window for this is short, since system +suspends don't take long (a few seconds usually), but it can happen. +For example, a suspended device may send a remote-wakeup signal while +the system is suspending. The remote wakeup may succeed, which would +cause the system suspend to abort. If the remote wakeup doesn't +succeed, it may still remain active and thus cause the system to +resume as soon as the system suspend is complete. Or the remote +wakeup may fail and get lost. Which outcome occurs depends on timing +and on the hardware and firmware design. + +More interestingly, a device might undergo a manual resume or +autoresume during system suspend. With current kernels this shouldn't +happen, because manual resumes must be initiated by userspace and +autoresumes happen in response to I/O requests, but all user processes +and I/O should be quiescent during a system suspend -- thanks to the +freezer. However there are plans to do away with the freezer, which +would mean these things would become possible. If and when this comes +about, the USB core will carefully arrange matters so that either type +of resume will block until the entire system has resumed. -- cgit v1.2.3-70-g09d2 From 063a2da8f01806906f7d7b1a1424b9afddebc443 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 10 Oct 2007 16:24:06 -0400 Subject: USB: serial core should respect driver requirements This patch (as997) fixes a bug in the USB serial core. The core needs to pay attention to drivers' requirements regarding the number and type of endpoints a device has. At the same time, the patch changes the NUM_DONT_CARE constant (which is stored in a single-byte field) from -1 to a safer, unsigned value. It also improves the kerneldoc for several fields in the usb_serial_driver structure. Finally, the patch replaces a list_for_each() with list_for_each_entry(). Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/usb-serial.c | 31 ++++++++++++++++++++++--------- include/linux/usb/serial.h | 20 +++++++++++++------- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 26e015c39a3..4b1bd7def4a 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -662,16 +662,14 @@ exit: static struct usb_serial_driver *search_serial_device(struct usb_interface *iface) { - struct list_head *p; const struct usb_device_id *id; - struct usb_serial_driver *t; + struct usb_serial_driver *drv; /* Check if the usb id matches a known device */ - list_for_each(p, &usb_serial_driver_list) { - t = list_entry(p, struct usb_serial_driver, driver_list); - id = get_iface_id(t, iface); + list_for_each_entry(drv, &usb_serial_driver_list, driver_list) { + id = get_iface_id(drv, iface); if (id) - return t; + return drv; } return NULL; @@ -811,9 +809,6 @@ int usb_serial_probe(struct usb_interface *interface, /* END HORRIBLE HACK FOR PL2303 */ #endif - /* found all that we need */ - dev_info(&interface->dev, "%s converter detected\n", type->description); - #ifdef CONFIG_USB_SERIAL_GENERIC if (type == &usb_serial_generic_device) { num_ports = num_bulk_out; @@ -847,6 +842,24 @@ int usb_serial_probe(struct usb_interface *interface, serial->num_interrupt_in = num_interrupt_in; serial->num_interrupt_out = num_interrupt_out; + /* check that the device meets the driver's requirements */ + if ((type->num_interrupt_in != NUM_DONT_CARE && + type->num_interrupt_in != num_interrupt_in) + || (type->num_interrupt_out != NUM_DONT_CARE && + type->num_interrupt_out != num_interrupt_out) + || (type->num_bulk_in != NUM_DONT_CARE && + type->num_bulk_in != num_bulk_in) + || (type->num_bulk_out != NUM_DONT_CARE && + type->num_bulk_out != num_bulk_out)) { + dbg("wrong number of endpoints"); + kfree(serial); + return -EIO; + } + + /* found all that we need */ + dev_info(&interface->dev, "%s converter detected\n", + type->description); + /* create our ports, we need as many as the max endpoints */ /* we don't use num_ports here cauz some devices have more endpoint pairs than ports */ max_endpoints = max(num_bulk_in, num_bulk_out); diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index e8b8928232c..488ce128885 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -141,7 +141,7 @@ struct usb_serial { }; #define to_usb_serial(d) container_of(d, struct usb_serial, kref) -#define NUM_DONT_CARE (-1) +#define NUM_DONT_CARE 99 /* get and set the serial private data pointer helper functions */ static inline void *usb_get_serial_data (struct usb_serial *serial) @@ -160,12 +160,18 @@ static inline void usb_set_serial_data (struct usb_serial *serial, void *data) * in the syslog messages when a device is inserted or removed. * @id_table: pointer to a list of usb_device_id structures that define all * of the devices this structure can support. - * @num_interrupt_in: the number of interrupt in endpoints this device will - * have. - * @num_interrupt_out: the number of interrupt out endpoints this device will - * have. - * @num_bulk_in: the number of bulk in endpoints this device will have. - * @num_bulk_out: the number of bulk out endpoints this device will have. + * @num_interrupt_in: If a device doesn't have this many interrupt-in + * endpoints, it won't be sent to the driver's attach() method. + * (But it might still be sent to the probe() method.) + * @num_interrupt_out: If a device doesn't have this many interrupt-out + * endpoints, it won't be sent to the driver's attach() method. + * (But it might still be sent to the probe() method.) + * @num_bulk_in: If a device doesn't have this many bulk-in + * endpoints, it won't be sent to the driver's attach() method. + * (But it might still be sent to the probe() method.) + * @num_bulk_out: If a device doesn't have this many bulk-out + * endpoints, it won't be sent to the driver's attach() method. + * (But it might still be sent to the probe() method.) * @num_ports: the number of different ports this device will have. * @calc_num_ports: pointer to a function to determine how many ports this * device has dynamically. It will be called after the probe() -- cgit v1.2.3-70-g09d2 From d466a9190ff1ceddfee50686e61d63590fc820d9 Mon Sep 17 00:00:00 2001 From: Ortwin Glück Date: Thu, 11 Oct 2007 17:29:43 +0200 Subject: USB: Nikon D40X unusual_devs entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not surprisingly the Nikon D40X DSC needs the same quirks as the D40, but it has a separate ID. See http://bugs.gentoo.org/show_bug.cgi?id=191431 From: Ortwin Glück Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index edf92914674..9b656ec427d 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -369,6 +369,13 @@ UNUSUAL_DEV( 0x04b0, 0x0415, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY), +/* Reported by Shan Destromp (shansan@gmail.com) */ +UNUSUAL_DEV( 0x04b0, 0x0417, 0x0100, 0x0100, + "NIKON", + "NIKON DSC D40X", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY), + /* BENQ DC5330 * Reported by Manuel Fombuena and * Frank Copeland */ -- cgit v1.2.3-70-g09d2 From 58ed7b94d98245fbad54a0af7ea3317ab1dd6876 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Thu, 11 Oct 2007 13:40:30 -0700 Subject: atmel_usba_udc: Keep track of the device status Keep track of the device status (as returned by the GET_STATUS request) and allow it to be manipulated by set_selfpowered() as well as SET_FEATURE/CLEAR_FEATURE (for remote wakeup) Implement the wakeup() op, which refuses to do anything if the DEVICE_REMOTE_WAKEUP feature wasn't set by the host. Now this driver passes USBCV (at least, with gadget zero). Fix one more locking bug; lockdep is every developer's friend. Signed-off-by: Haavard Skinnemoen Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/atmel_usba_udc.c | 57 +++++++++++++++++++++++++++++++------ drivers/usb/gadget/atmel_usba_udc.h | 4 ++- 2 files changed, 51 insertions(+), 10 deletions(-) diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 2bb28a58393..4fb5ff46957 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -989,8 +989,44 @@ static int usba_udc_get_frame(struct usb_gadget *gadget) return USBA_BFEXT(FRAME_NUMBER, usba_readl(udc, FNUM)); } +static int usba_udc_wakeup(struct usb_gadget *gadget) +{ + struct usba_udc *udc = to_usba_udc(gadget); + unsigned long flags; + u32 ctrl; + int ret = -EINVAL; + + spin_lock_irqsave(&udc->lock, flags); + if (udc->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) { + ctrl = usba_readl(udc, CTRL); + usba_writel(udc, CTRL, ctrl | USBA_REMOTE_WAKE_UP); + ret = 0; + } + spin_unlock_irqrestore(&udc->lock, flags); + + return ret; +} + +static int +usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered) +{ + struct usba_udc *udc = to_usba_udc(gadget); + unsigned long flags; + + spin_lock_irqsave(&udc->lock, flags); + if (is_selfpowered) + udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED; + else + udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED); + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + static const struct usb_gadget_ops usba_udc_ops = { - .get_frame = usba_udc_get_frame, + .get_frame = usba_udc_get_frame, + .wakeup = usba_udc_wakeup, + .set_selfpowered = usba_udc_set_selfpowered, }; #define EP(nam, idx, maxpkt, maxbk, dma, isoc) \ @@ -1068,8 +1104,11 @@ static void reset_all_endpoints(struct usba_udc *udc) } list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { - if (ep->desc) + if (ep->desc) { + spin_unlock(&udc->lock); usba_ep_disable(&ep->ep); + spin_lock(&udc->lock); + } } } @@ -1238,8 +1277,7 @@ static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep, u16 status; if (crq->bRequestType == (USB_DIR_IN | USB_RECIP_DEVICE)) { - /* Self-powered, no remote wakeup */ - status = __constant_cpu_to_le16(1 << 0); + status = cpu_to_le16(udc->devstatus); } else if (crq->bRequestType == (USB_DIR_IN | USB_RECIP_INTERFACE)) { status = __constant_cpu_to_le16(0); @@ -1268,12 +1306,12 @@ static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep, case USB_REQ_CLEAR_FEATURE: { if (crq->bRequestType == USB_RECIP_DEVICE) { - if (feature_is_dev_remote_wakeup(crq)) { - /* TODO: Handle REMOTE_WAKEUP */ - } else { + if (feature_is_dev_remote_wakeup(crq)) + udc->devstatus + &= ~(1 << USB_DEVICE_REMOTE_WAKEUP); + else /* Can't CLEAR_FEATURE TEST_MODE */ goto stall; - } } else if (crq->bRequestType == USB_RECIP_ENDPOINT) { struct usba_ep *target; @@ -1304,7 +1342,7 @@ static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep, udc->test_mode = le16_to_cpu(crq->wIndex); return 0; } else if (feature_is_dev_remote_wakeup(crq)) { - /* TODO: Handle REMOTE_WAKEUP */ + udc->devstatus |= 1 << USB_DEVICE_REMOTE_WAKEUP; } else { goto stall; } @@ -1791,6 +1829,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) return -EBUSY; } + udc->devstatus = 1 << USB_DEVICE_SELF_POWERED; udc->driver = driver; udc->gadget.dev.driver = &driver->driver; spin_unlock_irqrestore(&udc->lock, flags); diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h index f4f0f8bf812..a68304e31a6 100644 --- a/drivers/usb/gadget/atmel_usba_udc.h +++ b/drivers/usb/gadget/atmel_usba_udc.h @@ -320,7 +320,9 @@ struct usba_udc { struct clk *pclk; struct clk *hclk; - int test_mode; + u16 devstatus; + + u16 test_mode; int vbus_prev; #ifdef CONFIG_USB_GADGET_DEBUG_FS -- cgit v1.2.3-70-g09d2 From d1aa3e6aa8edfeb864af7c930523d9e588b28bea Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 11 Oct 2007 16:47:36 -0400 Subject: USB: fix race in autosuspend reschedule This patch (as1002) fixes a small race which can occur when a driver expects usbcore to reschedule an autosuspend request. If the request arrives too late, it won't be rescheduled. The patch adds an extra argument to autosuspend_check(), indicating that a reschedule is needed no matter how much time has elapsed. It also tries to avoid letting asynchronous changes to the value of jiffies cause a delay to become negative, by caching a local copy of the current time. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 8c1eac27f2d..c27bc080d84 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -950,11 +950,11 @@ done: #ifdef CONFIG_USB_SUSPEND /* Internal routine to check whether we may autosuspend a device. */ -static int autosuspend_check(struct usb_device *udev) +static int autosuspend_check(struct usb_device *udev, int reschedule) { int i; struct usb_interface *intf; - unsigned long suspend_time; + unsigned long suspend_time, j; /* For autosuspend, fail fast if anything is in use or autosuspend * is disabled. Also fail if any interfaces require remote wakeup @@ -996,20 +996,20 @@ static int autosuspend_check(struct usb_device *udev) } /* If everything is okay but the device hasn't been idle for long - * enough, queue a delayed autosuspend request. + * enough, queue a delayed autosuspend request. If the device + * _has_ been idle for long enough and the reschedule flag is set, + * likewise queue a delayed (1 second) autosuspend request. */ - if (time_after(suspend_time, jiffies)) { + j = jiffies; + if (time_before(j, suspend_time)) + reschedule = 1; + else + suspend_time = j + HZ; + if (reschedule) { if (!timer_pending(&udev->autosuspend.timer)) { - - /* The value of jiffies may change between the - * time_after() comparison above and the subtraction - * below. That's okay; the system behaves sanely - * when a timer is registered for the present moment - * or for the past. - */ queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, - round_jiffies_relative(suspend_time - jiffies)); - } + round_jiffies_relative(suspend_time - j)); + } return -EAGAIN; } return 0; @@ -1017,7 +1017,7 @@ static int autosuspend_check(struct usb_device *udev) #else -static inline int autosuspend_check(struct usb_device *udev) +static inline int autosuspend_check(struct usb_device *udev, int reschedule) { return 0; } @@ -1074,7 +1074,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) udev->do_remote_wakeup = device_may_wakeup(&udev->dev); if (udev->auto_pm) { - status = autosuspend_check(udev); + status = autosuspend_check(udev, 0); if (status < 0) goto done; } @@ -1100,7 +1100,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) /* Try another autosuspend when the interfaces aren't busy */ if (udev->auto_pm) - autosuspend_check(udev); + autosuspend_check(udev, status == -EBUSY); /* If the suspend succeeded then prevent any more URB submissions, * flush any outstanding URBs, and propagate the suspend up the tree. -- cgit v1.2.3-70-g09d2