diff options
Diffstat (limited to 'drivers')
46 files changed, 5344 insertions, 1079 deletions
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index 1bc884051e0..02c52f8d5db 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -456,7 +456,7 @@ static int cxacru_start_wait_urb(struct urb *urb, struct completion *done, int* actual_length) { struct timer_list timer; - int status; + int status = urb->status; init_timer(&timer); timer.expires = jiffies + msecs_to_jiffies(CMD_TIMEOUT); @@ -464,7 +464,6 @@ static int cxacru_start_wait_urb(struct urb *urb, struct completion *done, timer.function = cxacru_timeout_kill; add_timer(&timer); wait_for_completion(done); - status = urb->status; del_timer_sync(&timer); if (actual_length) diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 638b8009b3b..eb0615abff6 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -612,7 +612,8 @@ static void speedtch_handle_int(struct urb *int_urb) struct speedtch_instance_data *instance = int_urb->context; struct usbatm_data *usbatm = instance->usbatm; unsigned int count = int_urb->actual_length; - int ret = int_urb->status; + int status = int_urb->status; + int ret; /* The magic interrupt for "up state" */ static const unsigned char up_int[6] = { 0xa1, 0x00, 0x01, 0x00, 0x00, 0x00 }; @@ -621,8 +622,8 @@ static void speedtch_handle_int(struct urb *int_urb) atm_dbg(usbatm, "%s entered\n", __func__); - if (ret < 0) { - atm_dbg(usbatm, "%s: nonzero urb status %d!\n", __func__, ret); + if (status < 0) { + atm_dbg(usbatm, "%s: nonzero urb status %d!\n", __func__, status); goto fail; } diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 8f046659b4e..a1a1c9d467e 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -1308,11 +1308,13 @@ static void uea_intr(struct urb *urb) { struct uea_softc *sc = urb->context; struct intr_pkt *intr = urb->transfer_buffer; + int status = urb->status; + uea_enters(INS_TO_USBDEV(sc)); - if (unlikely(urb->status < 0)) { + if (unlikely(status < 0)) { uea_err(INS_TO_USBDEV(sc), "uea_intr() failed with %d\n", - urb->status); + status); return; } diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index 11e9b15ca45..e717f5b1cae 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -257,9 +257,10 @@ static void usbatm_complete(struct urb *urb) { struct usbatm_channel *channel = urb->context; unsigned long flags; + int status = urb->status; vdbg("%s: urb 0x%p, status %d, actual_length %d", - __func__, urb, urb->status, urb->actual_length); + __func__, urb, status, urb->actual_length); /* usually in_interrupt(), but not always */ spin_lock_irqsave(&channel->lock, flags); @@ -269,16 +270,16 @@ static void usbatm_complete(struct urb *urb) spin_unlock_irqrestore(&channel->lock, flags); - if (unlikely(urb->status) && + if (unlikely(status) && (!(channel->usbatm->flags & UDSL_IGNORE_EILSEQ) || - urb->status != -EILSEQ )) + status != -EILSEQ )) { - if (urb->status == -ESHUTDOWN) + if (status == -ESHUTDOWN) return; if (printk_ratelimit()) atm_warn(channel->usbatm, "%s: urb 0x%p failed (%d)!\n", - __func__, urb, urb->status); + __func__, urb, status); /* throttle processing in case of an error */ mod_timer(&channel->delay, jiffies + msecs_to_jiffies(THROTTLE_MSECS)); } else diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index cd51520c7e7..fe940e0536e 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -257,9 +257,10 @@ static void acm_ctrl_irq(struct urb *urb) struct usb_cdc_notification *dr = urb->transfer_buffer; unsigned char *data; int newctrl; - int status; + int retval; + int status = urb->status; - switch (urb->status) { + switch (status) { case 0: /* success */ break; @@ -267,10 +268,10 @@ static void acm_ctrl_irq(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); + dbg("%s - urb shutting down with status: %d", __FUNCTION__, status); return; default: - dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); + dbg("%s - nonzero urb status received: %d", __FUNCTION__, status); goto exit; } @@ -311,10 +312,10 @@ static void acm_ctrl_irq(struct urb *urb) break; } exit: - status = usb_submit_urb (urb, GFP_ATOMIC); - if (status) + retval = usb_submit_urb (urb, GFP_ATOMIC); + if (retval) err ("%s - usb_submit_urb failed with result %d", - __FUNCTION__, status); + __FUNCTION__, retval); } /* data interface returns incoming bytes, or we got unthrottled */ @@ -324,7 +325,8 @@ static void acm_read_bulk(struct urb *urb) struct acm_ru *rcv = urb->context; struct acm *acm = rcv->instance; int status = urb->status; - dbg("Entering acm_read_bulk with status %d", urb->status); + + dbg("Entering acm_read_bulk with status %d", status); if (!ACM_READY(acm)) return; diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 9a1478972bf..5192cd9356d 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -289,16 +289,17 @@ static int proto_bias = -1; static void usblp_bulk_read(struct urb *urb) { struct usblp *usblp = urb->context; + int status = urb->status; if (usblp->present && usblp->used) { - if (urb->status) + if (status) printk(KERN_WARNING "usblp%d: " "nonzero read bulk status received: %d\n", - usblp->minor, urb->status); + usblp->minor, status); } spin_lock(&usblp->lock); - if (urb->status < 0) - usblp->rstatus = urb->status; + if (status < 0) + usblp->rstatus = status; else usblp->rstatus = urb->actual_length; usblp->rcomplete = 1; @@ -311,16 +312,17 @@ static void usblp_bulk_read(struct urb *urb) static void usblp_bulk_write(struct urb *urb) { struct usblp *usblp = urb->context; + int status = urb->status; if (usblp->present && usblp->used) { - if (urb->status) + if (status) printk(KERN_WARNING "usblp%d: " "nonzero write bulk status received: %d\n", - usblp->minor, urb->status); + usblp->minor, status); } spin_lock(&usblp->lock); - if (urb->status < 0) - usblp->wstatus = urb->status; + if (status < 0) + usblp->wstatus = status; else usblp->wstatus = urb->actual_length; usblp->wcomplete = 1; @@ -741,10 +743,11 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t */ rv = usblp_wwait(usblp, !!(file->f_flags&O_NONBLOCK)); if (rv < 0) { - /* - * If interrupted, we simply leave the URB to dangle, - * so the ->release will call usb_kill_urb(). - */ + if (rv == -EAGAIN) { + /* Presume that it's going to complete well. */ + writecount += transfer_length; + } + /* Leave URB dangling, to be cleaned on close. */ goto collect_error; } diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 963520fbef9..42ef1d5f6c8 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -99,12 +99,17 @@ EXPORT_SYMBOL_GPL (usb_bus_list_lock); /* used for controlling access to virtual root hubs */ static DEFINE_SPINLOCK(hcd_root_hub_lock); -/* used when updating hcd data */ -static DEFINE_SPINLOCK(hcd_data_lock); +/* used when updating an endpoint's URB list */ +static DEFINE_SPINLOCK(hcd_urb_list_lock); /* wait queue for synchronous unlinks */ DECLARE_WAIT_QUEUE_HEAD(usb_kill_urb_queue); +static inline int is_root_hub(struct usb_device *udev) +{ + return (udev->parent == NULL); +} + /*-------------------------------------------------------------------------*/ /* @@ -906,14 +911,13 @@ EXPORT_SYMBOL (usb_calc_bus_time); static void urb_unlink(struct usb_hcd *hcd, struct urb *urb) { unsigned long flags; - int at_root_hub = (urb->dev == hcd->self.root_hub); /* clear all state linking urb to this dev (and hcd) */ - spin_lock_irqsave (&hcd_data_lock, flags); + spin_lock_irqsave(&hcd_urb_list_lock, flags); list_del_init (&urb->urb_list); - spin_unlock_irqrestore (&hcd_data_lock, flags); + spin_unlock_irqrestore(&hcd_urb_list_lock, flags); - if (hcd->self.uses_dma && !at_root_hub) { + if (hcd->self.uses_dma && !is_root_hub(urb->dev)) { if (usb_pipecontrol (urb->pipe) && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) dma_unmap_single (hcd->self.controller, urb->setup_dma, @@ -955,7 +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_data_lock, 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)) @@ -972,7 +976,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) status = -ESHUTDOWN; break; } - spin_unlock_irqrestore (&hcd_data_lock, flags); + spin_unlock_irqrestore(&hcd_urb_list_lock, flags); if (status) { INIT_LIST_HEAD (&urb->urb_list); usbmon_urb_submit_error(&hcd->self, urb, status); @@ -986,7 +990,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) urb = usb_get_urb (urb); atomic_inc (&urb->use_count); - if (urb->dev == hcd->self.root_hub) { + 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 @@ -1033,18 +1037,6 @@ done: /*-------------------------------------------------------------------------*/ -/* called in any context */ -int usb_hcd_get_frame_number (struct usb_device *udev) -{ - struct usb_hcd *hcd = bus_to_hcd(udev->bus); - - if (!HC_IS_RUNNING (hcd->state)) - return -ESHUTDOWN; - return hcd->driver->get_frame_number (hcd); -} - -/*-------------------------------------------------------------------------*/ - /* this makes the hcd giveback() the urb more quickly, by kicking it * off hardware queues (which may take a while) and returning it as * soon as practical. we've already set up the urb's return status, @@ -1055,7 +1047,7 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb) { int value; - if (urb->dev == hcd->self.root_hub) + if (is_root_hub(urb->dev)) value = usb_rh_urb_dequeue (hcd, urb); else { @@ -1103,11 +1095,11 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) * 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_data_lock) in case some other CPU is now + * (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_data_lock); + spin_lock(&hcd_urb_list_lock); sys = &urb->dev->dev; hcd = bus_to_hcd(urb->dev->bus); @@ -1139,17 +1131,16 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) * finish unlinking the initial failed usb_set_address() * or device descriptor fetch. */ - if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) - && hcd->self.root_hub != urb->dev) { + 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"); + "Controller is probably using the wrong IRQ.\n"); set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); } urb->status = status; - spin_unlock (&hcd_data_lock); + spin_unlock(&hcd_urb_list_lock); spin_unlock_irqrestore (&urb->lock, flags); retval = unlink1 (hcd, urb); @@ -1158,7 +1149,7 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) return retval; done: - spin_unlock (&hcd_data_lock); + 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); @@ -1167,6 +1158,35 @@ done: /*-------------------------------------------------------------------------*/ +/** + * 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. + * Context: in_interrupt() + * + * This hands the URB from HCD to its USB device driver, using its + * completion function. The HCD has freed all per-urb resources + * (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. + */ +void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) +{ + urb_unlink(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); + if (unlikely (urb->reject)) + wake_up (&usb_kill_urb_queue); + usb_put_urb (urb); +} +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 @@ -1186,7 +1206,7 @@ void usb_hcd_endpoint_disable (struct usb_device *udev, /* ep is already gone from udev->ep_{in,out}[]; no more submits */ rescan: - spin_lock (&hcd_data_lock); + spin_lock(&hcd_urb_list_lock); list_for_each_entry (urb, &ep->urb_list, urb_list) { int tmp; @@ -1194,7 +1214,7 @@ rescan: if (urb->status != -EINPROGRESS) continue; usb_get_urb (urb); - spin_unlock (&hcd_data_lock); + spin_unlock(&hcd_urb_list_lock); spin_lock (&urb->lock); tmp = urb->status; @@ -1223,7 +1243,7 @@ rescan: /* list contents may have changed */ goto rescan; } - spin_unlock (&hcd_data_lock); + spin_unlock(&hcd_urb_list_lock); local_irq_enable (); /* synchronize with the hardware, so old configuration state @@ -1240,7 +1260,7 @@ rescan: * endpoint_disable methods. */ while (!list_empty (&ep->urb_list)) { - spin_lock_irq (&hcd_data_lock); + spin_lock_irq(&hcd_urb_list_lock); /* The list may have changed while we acquired the spinlock */ urb = NULL; @@ -1249,7 +1269,7 @@ rescan: urb_list); usb_get_urb (urb); } - spin_unlock_irq (&hcd_data_lock); + spin_unlock_irq(&hcd_urb_list_lock); if (urb) { usb_kill_urb (urb); @@ -1260,6 +1280,18 @@ rescan: /*-------------------------------------------------------------------------*/ +/* called in any context */ +int usb_hcd_get_frame_number (struct usb_device *udev) +{ + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + + if (!HC_IS_RUNNING (hcd->state)) + return -ESHUTDOWN; + return hcd->driver->get_frame_number (hcd); +} + +/*-------------------------------------------------------------------------*/ + #ifdef CONFIG_PM int hcd_bus_suspend(struct usb_device *rhdev) @@ -1395,35 +1427,6 @@ EXPORT_SYMBOL (usb_bus_start_enum); /*-------------------------------------------------------------------------*/ /** - * 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. - * Context: in_interrupt() - * - * This hands the URB from HCD to its USB device driver, using its - * completion function. The HCD has freed all per-urb resources - * (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. - */ -void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) -{ - urb_unlink(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); - if (unlikely (urb->reject)) - wake_up (&usb_kill_urb_queue); - usb_put_urb (urb); -} -EXPORT_SYMBOL (usb_hcd_giveback_urb); - -/*-------------------------------------------------------------------------*/ - -/** * usb_hcd_irq - hook IRQs to HCD framework (bus glue) * @irq: the IRQ being raised * @__hcd: pointer to the HCD whose IRQ is being signaled diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index fd74c50b180..e341a1da517 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1335,6 +1335,10 @@ int usb_new_device(struct usb_device *udev) udev->dev.devt = MKDEV(USB_DEVICE_MAJOR, (((udev->bus->busnum-1) * 128) + (udev->devnum-1))); + /* Increment the parent's count of unsuspended children */ + if (udev->parent) + usb_autoresume_device(udev->parent); + /* Register the device. The device driver is responsible * for adding the device files to sysfs and for configuring * the device. @@ -1342,13 +1346,11 @@ 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; } - /* Increment the parent's count of unsuspended children */ - if (udev->parent) - usb_autoresume_device(udev->parent); - exit: return err; diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 530e854961c..25f63f1096b 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -34,13 +34,14 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length) { struct completion done; unsigned long expire; - int status; + int retval; + int status = urb->status; init_completion(&done); urb->context = &done; urb->actual_length = 0; - status = usb_submit_urb(urb, GFP_NOIO); - if (unlikely(status)) + retval = usb_submit_urb(urb, GFP_NOIO); + if (unlikely(retval)) goto out; expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT; @@ -55,15 +56,15 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length) urb->transfer_buffer_length); usb_kill_urb(urb); - status = urb->status == -ENOENT ? -ETIMEDOUT : urb->status; + retval = status == -ENOENT ? -ETIMEDOUT : status; } else - status = urb->status; + retval = status; out: if (actual_length) *actual_length = urb->actual_length; usb_free_urb(urb); - return status; + return retval; } /*-------------------------------------------------------------------*/ @@ -250,6 +251,7 @@ static void sg_clean (struct usb_sg_request *io) static void sg_complete (struct urb *urb) { struct usb_sg_request *io = urb->context; + int status = urb->status; spin_lock (&io->lock); @@ -265,21 +267,21 @@ static void sg_complete (struct urb *urb) */ if (io->status && (io->status != -ECONNRESET - || urb->status != -ECONNRESET) + || status != -ECONNRESET) && urb->actual_length) { 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", - urb->status, io->status); + status, io->status); // BUG (); } - if (io->status == 0 && urb->status && urb->status != -ECONNRESET) { - int i, found, status; + if (io->status == 0 && status && status != -ECONNRESET) { + int i, found, retval; - io->status = urb->status; + io->status = status; /* the previous urbs, and this one, completed already. * unlink pending urbs so they won't rx/tx bad data. @@ -290,13 +292,13 @@ static void sg_complete (struct urb *urb) if (!io->urbs [i] || !io->urbs [i]->dev) continue; if (found) { - status = usb_unlink_urb (io->urbs [i]); - if (status != -EINPROGRESS - && status != -ENODEV - && status != -EBUSY) + retval = usb_unlink_urb (io->urbs [i]); + if (retval != -EINPROGRESS && + retval != -ENODEV && + retval != -EBUSY) dev_err (&io->dev->dev, "%s, unlink --> %d\n", - __FUNCTION__, status); + __FUNCTION__, retval); } else if (urb == io->urbs [i]) found = 1; } diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index d47ae89154a..2ab222be8fd 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -441,6 +441,54 @@ static struct attribute_group dev_attr_grp = { .attrs = dev_attrs, }; +/* Binary descriptors */ + +static ssize_t +read_descriptors(struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct usb_device *udev = to_usb_device( + container_of(kobj, struct device, kobj)); + size_t nleft = count; + size_t srclen, n; + + usb_lock_device(udev); + + /* The binary attribute begins with the device descriptor */ + srclen = sizeof(struct usb_device_descriptor); + if (off < srclen) { + n = min_t(size_t, nleft, srclen - off); + memcpy(buf, off + (char *) &udev->descriptor, n); + nleft -= n; + buf += n; + off = 0; + } else { + off -= srclen; + } + + /* Then follows the raw descriptor entry for the current + * configuration (config plus subsidiary descriptors). + */ + if (udev->actconfig) { + int cfgno = udev->actconfig - udev->config; + + srclen = __le16_to_cpu(udev->actconfig->desc.wTotalLength); + if (off < srclen) { + n = min_t(size_t, nleft, srclen - off); + memcpy(buf, off + udev->rawdescriptors[cfgno], n); + nleft -= n; + } + } + usb_unlock_device(udev); + return count - nleft; +} + +static struct bin_attribute dev_bin_attr_descriptors = { + .attr = {.name = "descriptors", .mode = 0444}, + .read = read_descriptors, + .size = 18 + 65535, /* dev descr + max-size raw descriptor */ +}; + int usb_create_sysfs_dev_files(struct usb_device *udev) { struct device *dev = &udev->dev; @@ -450,6 +498,10 @@ int usb_create_sysfs_dev_files(struct usb_device *udev) if (retval) return retval; + retval = device_create_bin_file(dev, &dev_bin_attr_descriptors); + if (retval) + goto error; + retval = add_persist_attributes(dev); if (retval) goto error; @@ -492,6 +544,7 @@ void usb_remove_sysfs_dev_files(struct usb_device *udev) device_remove_file(dev, &dev_attr_serial); remove_power_attributes(dev); remove_persist_attributes(dev); + device_remove_bin_file(dev, &dev_bin_attr_descriptors); sysfs_remove_group(&dev->kobj, &dev_attr_grp); } diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 52ec44b828f..be630228461 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -440,55 +440,57 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) * @urb: pointer to urb describing a previously submitted request, * may be NULL * - * This routine cancels an in-progress request. URBs complete only - * once per submission, and may be canceled only once per submission. - * Successful cancellation means the requests's completion handler will - * be called with a status code indicating that the request has been - * canceled (rather than any other code) and will quickly be removed - * from host controller data structures. - * - * This request is always asynchronous. - * Success is indicated by returning -EINPROGRESS, - * at which time the URB will normally have been unlinked but not yet - * given back to the device driver. When it is called, the completion - * function will see urb->status == -ECONNRESET. Failure is indicated - * by any other return value. Unlinking will fail when the URB is not - * currently "linked" (i.e., it was never submitted, or it was unlinked - * before, or the hardware is already finished with it), even if the - * completion handler has not yet run. + * This routine cancels an in-progress request. URBs complete only once + * per submission, and may be canceled only once per submission. + * Successful cancellation means termination of @urb will be expedited + * and the completion handler will be called with a status code + * indicating that the request has been canceled (rather than any other + * code). + * + * This request is always asynchronous. Success is indicated by + * returning -EINPROGRESS, at which time the URB will probably not yet + * have been given back to the device driver. When it is eventually + * called, the completion function will see @urb->status == -ECONNRESET. + * Failure is indicated by usb_unlink_urb() returning any other value. + * Unlinking will fail when @urb is not currently "linked" (i.e., it was + * never submitted, or it was unlinked before, or the hardware is already + * finished with it), even if the completion handler has not yet run. * * Unlinking and Endpoint Queues: * + * [The behaviors and guarantees described below do not apply to virtual + * root hubs but only to endpoint queues for physical USB devices.] + * * Host Controller Drivers (HCDs) place all the URBs for a particular * endpoint in a queue. Normally the queue advances as the controller * hardware processes each request. But when an URB terminates with an - * error its queue stops, at least until that URB's completion routine - * returns. It is guaranteed that the queue will not restart until all - * its unlinked URBs have been fully retired, with their completion - * routines run, even if that's not until some time after the original - * completion handler returns. Normally the same behavior and guarantees - * apply when an URB terminates because it was unlinked; however if an - * URB is unlinked before the hardware has started to execute it, then - * its queue is not guaranteed to stop until all the preceding URBs have - * completed. - * - * This means that USB device drivers can safely build deep queues for - * large or complex transfers, and clean them up reliably after any sort - * of aborted transfer by unlinking all pending URBs at the first fault. - * - * Note that an URB terminating early because a short packet was received - * will count as an error if and only if the URB_SHORT_NOT_OK flag is set. - * Also, that all unlinks performed in any URB completion handler must - * be asynchronous. - * - * Queues for isochronous endpoints are treated differently, because they - * advance at fixed rates. Such queues do not stop when an URB is unlinked. - * An unlinked URB may leave a gap in the stream of packets. It is undefined - * whether such gaps can be filled in. - * - * When a control URB terminates with an error, it is likely that the - * status stage of the transfer will not take place, even if it is merely - * a soft error resulting from a short-packet with URB_SHORT_NOT_OK set. + * error its queue generally stops (see below), at least until that URB's + * completion routine returns. It is guaranteed that a stopped queue + * will not restart until all its unlinked URBs have been fully retired, + * with their completion routines run, even if that's not until some time + * after the original completion handler returns. The same behavior and + * guarantee apply when an URB terminates because it was unlinked. + * + * Bulk and interrupt endpoint queues are guaranteed to stop whenever an + * URB terminates with any sort of error, including -ECONNRESET, -ENOENT, + * and -EREMOTEIO. Control endpoint queues behave the same way except + * that they are not guaranteed to stop for -EREMOTEIO errors. Queues + * for isochronous endpoints are treated differently, because they must + * advance at fixed rates. Such queues do not stop when an URB + * encounters an error or is unlinked. An unlinked isochronous URB may + * leave a gap in the stream of packets; it is undefined whether such + * gaps can be filled in. + * + * Note that early termination of an URB because a short packet was + * received will generate a -EREMOTEIO error if and only if the + * URB_SHORT_NOT_OK flag is set. By setting this flag, USB device + * drivers can build deep queues for large or complex bulk transfers + * and clean them up reliably after any sort of aborted transfer by + * unlinking all pending URBs at the first fault. + * + * When a control URB terminates with an error other than -EREMOTEIO, it + * is quite likely that the status stage of the transfer will not take + * place. */ int usb_unlink_urb(struct urb *urb) { diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 45e01e28945..767aed5b4be 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -82,6 +82,27 @@ choice Many controller drivers are platform-specific; these often need board-specific hooks. +config USB_GADGET_AMD5536UDC + boolean "AMD5536 UDC" + depends on PCI + select USB_GADGET_DUALSPEED + help + The AMD5536 UDC is part of the AMD Geode CS5536, an x86 southbridge. + It is a USB Highspeed DMA capable USB device controller. Beside ep0 + it provides 4 IN and 4 OUT endpoints (bulk or interrupt type). + The UDC port supports OTG operation, and may be used as a host port + if it's not being used to implement peripheral or OTG roles. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "amd5536udc" and force all + gadget drivers to also be dynamically linked. + +config USB_AMD5536UDC + tristate + depends on USB_GADGET_AMD5536UDC + default USB_GADGET + select USB_GADGET_SELECTED + config USB_GADGET_FSL_USB2 boolean "Freescale Highspeed USB DR Peripheral Controller" depends on MPC834x || PPC_MPC831x @@ -156,6 +177,24 @@ config USB_PXA2XX_SMALL default y if USB_ETH default y if USB_G_SERIAL +config USB_GADGET_M66592 + boolean "Renesas M66592 USB Peripheral Controller" + select USB_GADGET_DUALSPEED + help + M66592 is a discrete USB peripheral controller chip that + supports both full and high speed USB 2.0 data transfers. + It has seven configurable endpoints, and endpoint zero. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "m66592_udc" and force all + gadget drivers to also be dynamically linked. + +config USB_M66592 + tristate + depends on USB_GADGET_M66592 + default USB_GADGET + select USB_GADGET_SELECTED + config USB_GADGET_GOKU boolean "Toshiba TC86C001 'Goku-S'" depends on PCI @@ -261,24 +300,6 @@ config USB_AT91 depends on USB_GADGET_AT91 default USB_GADGET -config USB_GADGET_M66592 - boolean "M66592 driver" - select USB_GADGET_DUALSPEED - help - M66592 is a USB 2.0 peripheral controller. - - It has seven configurable endpoints, and endpoint zero. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "m66592_udc" and force all - gadget drivers to also be dynamically linked. - -config USB_M66592 - tristate - depends on USB_GADGET_M66592 - default USB_GADGET - select USB_GADGET_SELECTED - config USB_GADGET_DUMMY_HCD boolean "Dummy HCD (DEVELOPMENT)" depends on (USB=y || (USB=m && USB_GADGET=m)) && EXPERIMENTAL diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 8ae76f73863..1bc0f03550c 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -7,6 +7,7 @@ endif obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o obj-$(CONFIG_USB_NET2280) += net2280.o +obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc.o obj-$(CONFIG_USB_PXA2XX) += pxa2xx_udc.o obj-$(CONFIG_USB_GOKU) += goku_udc.o obj-$(CONFIG_USB_OMAP) += omap_udc.o diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c new file mode 100644 index 00000000000..714156ca8fe --- /dev/null +++ b/drivers/usb/gadget/amd5536udc.c @@ -0,0 +1,3454 @@ +/* + * amd5536.c -- AMD 5536 UDC high/full speed USB device controller + * + * Copyright (C) 2005-2007 AMD (http://www.amd.com) + * Author: Thomas Dahlmann + * + * 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. + * + * 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. + * + * 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 + */ + +/* + * The AMD5536 UDC is part of the x86 southbridge AMD Geode CS5536. + * It is a USB Highspeed DMA capable USB device controller. Beside ep0 it + * provides 4 IN and 4 OUT endpoints (bulk or interrupt type). + * + * Make sure that UDC is assigned to port 4 by BIOS settings (port can also + * be used as host port) and UOC bits PAD_EN and APU are set (should be done + * by BIOS init). + * + * UDC DMA requires 32-bit aligned buffers so DMA with gadget ether does not + * work without updating NET_IP_ALIGN. Or PIO mode (module param "use_dma=0") + * can be used with gadget ether. + */ + +/* debug control */ +/* #define UDC_VERBOSE */ + +/* Driver strings */ +#define UDC_MOD_DESCRIPTION "AMD 5536 UDC - USB Device Controller" +#define UDC_DRIVER_VERSION_STRING "01.00.0206 - $Revision: #3 $" + +/* system */ +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/version.h> +#include <linux/delay.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/smp_lock.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/timer.h> +#include <linux/list.h> +#include <linux/interrupt.h> +#include <linux/ioctl.h> +#include <linux/fs.h> +#include <linux/dmapool.h> +#include <linux/moduleparam.h> +#include <linux/device.h> +#include <linux/io.h> +#include <linux/irq.h> + +#include <asm/byteorder.h> +#include <asm/system.h> +#include <asm/unaligned.h> + +/* gadget stack */ +#include <linux/usb/ch9.h> +#include <linux/usb_gadget.h> + +/* udc specific */ +#include "amd5536udc.h" + + +static void udc_tasklet_disconnect(unsigned long); +static void empty_req_queue(struct udc_ep *); +static int udc_probe(struct udc *dev); +static void udc_basic_init(struct udc *dev); +static void udc_setup_endpoints(struct udc *dev); +static void udc_soft_reset(struct udc *dev); +static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep); +static void udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq); +static int udc_free_dma_chain(struct udc *dev, struct udc_request *req); +static int udc_create_dma_chain(struct udc_ep *ep, struct udc_request *req, + unsigned long buf_len, gfp_t gfp_flags); +static int udc_remote_wakeup(struct udc *dev); +static int udc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id); +static void udc_pci_remove(struct pci_dev *pdev); + +/* description */ +static const char mod_desc[] = UDC_MOD_DESCRIPTION; +static const char name[] = "amd5536udc"; + +/* structure to hold endpoint function pointers */ +static const struct usb_ep_ops udc_ep_ops; + +/* received setup data */ +static union udc_setup_data setup_data; + +/* pointer to device object */ +static struct udc *udc; + +/* irq spin lock for soft reset */ +static DEFINE_SPINLOCK(udc_irq_spinlock); +/* stall spin lock */ +static DEFINE_SPINLOCK(udc_stall_spinlock); + +/* +* slave mode: pending bytes in rx fifo after nyet, +* used if EPIN irq came but no req was available +*/ +static unsigned int udc_rxfifo_pending; + +/* count soft resets after suspend to avoid loop */ +static int soft_reset_occured; +static int soft_reset_after_usbreset_occured; + +/* timer */ +static struct timer_list udc_timer; +static int stop_timer; + +/* set_rde -- Is used to control enabling of RX DMA. Problem is + * that UDC has only one bit (RDE) to enable/disable RX DMA for + * all OUT endpoints. So we have to handle race conditions like + * when OUT data reaches the fifo but no request was queued yet. + * This cannot be solved by letting the RX DMA disabled until a + * request gets queued because there may be other OUT packets + * in the FIFO (important for not blocking control traffic). + * The value of set_rde controls the correspondig timer. + * + * set_rde -1 == not used, means it is alloed to be set to 0 or 1 + * set_rde 0 == do not touch RDE, do no start the RDE timer + * set_rde 1 == timer function will look whether FIFO has data + * set_rde 2 == set by timer function to enable RX DMA on next call + */ +static int set_rde = -1; + +static DECLARE_COMPLETION(on_exit); +static struct timer_list udc_pollstall_timer; +static int stop_pollstall_timer; +static DECLARE_COMPLETION(on_pollstall_exit); + +/* tasklet for usb disconnect */ +static DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect, + (unsigned long) &udc); + + +/* endpoint names used for print */ +static const char ep0_string[] = "ep0in"; +static const char *ep_string[] = { + ep0_string, + "ep1in-int", "ep2in-bulk", "ep3in-bulk", "ep4in-bulk", "ep5in-bulk", + "ep6in-bulk", "ep7in-bulk", "ep8in-bulk", "ep9in-bulk", "ep10in-bulk", + "ep11in-bulk", "ep12in-bulk", "ep13in-bulk", "ep14in-bulk", + "ep15in-bulk", "ep0out", "ep1out-bulk", "ep2out-bulk", "ep3out-bulk", + "ep4out-bulk", "ep5out-bulk", "ep6out-bulk", "ep7out-bulk", + "ep8out-bulk", "ep9out-bulk", "ep10out-bulk", "ep11out-bulk", + "ep12out-bulk", "ep13out-bulk", "ep14out-bulk", "ep15out-bulk" +}; + +/* DMA usage flag */ +static int use_dma = 1; +/* packet per buffer dma */ +static int use_dma_ppb = 1; +/* with per descr. update */ +static int use_dma_ppb_du; +/* buffer fill mode */ +static int use_dma_bufferfill_mode; +/* full speed only mode */ +static int use_fullspeed; +/* tx buffer size for high speed */ +static unsigned long hs_tx_buf = UDC_EPIN_BUFF_SIZE; + +/* module parameters */ +module_param(use_dma, bool, S_IRUGO); +MODULE_PARM_DESC(use_dma, "true for DMA"); +module_param(use_dma_ppb, bool, S_IRUGO); +MODULE_PARM_DESC(use_dma_ppb, "true for DMA in packet per buffer mode"); +module_param(use_dma_ppb_du, bool, S_IRUGO); +MODULE_PARM_DESC(use_dma_ppb_du, + "true for DMA in packet per buffer mode with descriptor update"); +module_param(use_fullspeed, bool, S_IRUGO); +MODULE_PARM_DESC(use_fullspeed, "true for fullspeed only"); + +/*---------------------------------------------------------------------------*/ +/* Prints UDC device registers and endpoint irq registers */ +static void print_regs(struct udc *dev) +{ + DBG(dev, "------- Device registers -------\n"); + DBG(dev, "dev config = %08x\n", readl(&dev->regs->cfg)); + DBG(dev, "dev control = %08x\n", readl(&dev->regs->ctl)); + DBG(dev, "dev status = %08x\n", readl(&dev->regs->sts)); + DBG(dev, "\n"); + DBG(dev, "dev int's = %08x\n", readl(&dev->regs->irqsts)); + DBG(dev, "dev intmask = %08x\n", readl(&dev->regs->irqmsk)); + DBG(dev, "\n"); + DBG(dev, "dev ep int's = %08x\n", readl(&dev->regs->ep_irqsts)); + DBG(dev, "dev ep intmask = %08x\n", readl(&dev->regs->ep_irqmsk)); + DBG(dev, "\n"); + DBG(dev, "USE DMA = %d\n", use_dma); + if (use_dma && use_dma_ppb && !use_dma_ppb_du) { + DBG(dev, "DMA mode = PPBNDU (packet per buffer " + "WITHOUT desc. update)\n"); + dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBNDU"); + } else if (use_dma && use_dma_ppb_du && use_dma_ppb_du) { + DBG(dev, "DMA mode = PPBDU (packet per buffer " + "WITH desc. update)\n"); + dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBDU"); + } + if (use_dma && use_dma_bufferfill_mode) { + DBG(dev, "DMA mode = BF (buffer fill mode)\n"); + dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "BF"); + } + if (!use_dma) { + dev_info(&dev->pdev->dev, "FIFO mode\n"); + } + DBG(dev, "-------------------------------------------------------\n"); +} + +/* Masks unused interrupts */ +static int udc_mask_unused_interrupts(struct udc *dev) +{ + u32 tmp; + + /* mask all dev interrupts */ + tmp = AMD_BIT(UDC_DEVINT_SVC) | + AMD_BIT(UDC_DEVINT_ENUM) | + AMD_BIT(UDC_DEVINT_US) | + AMD_BIT(UDC_DEVINT_UR) | + AMD_BIT(UDC_DEVINT_ES) | + AMD_BIT(UDC_DEVINT_SI) | + AMD_BIT(UDC_DEVINT_SOF)| + AMD_BIT(UDC_DEVINT_SC); + writel(tmp, &dev->regs->irqmsk); + + /* mask all ep interrupts */ + writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqmsk); + + return 0; +} + +/* Enables endpoint 0 interrupts */ +static int udc_enable_ep0_interrupts(struct udc *dev) +{ + u32 tmp; + + DBG(dev, "udc_enable_ep0_interrupts()\n"); + + /* read irq mask */ + tmp = readl(&dev->regs->ep_irqmsk); + /* enable ep0 irq's */ + tmp &= AMD_UNMASK_BIT(UDC_EPINT_IN_EP0) + & AMD_UNMASK_BIT(UDC_EPINT_OUT_EP0); + writel(tmp, &dev->regs->ep_irqmsk); + + return 0; +} + +/* Enables device interrupts for SET_INTF and SET_CONFIG */ +static int udc_enable_dev_setup_interrupts(struct udc *dev) +{ + u32 tmp; + + DBG(dev, "enable device interrupts for setup data\n"); + + /* read irq mask */ + tmp = readl(&dev->regs->irqmsk); + + /* enable SET_INTERFACE, SET_CONFIG and other needed irq's */ + tmp &= AMD_UNMASK_BIT(UDC_DEVINT_SI) + & AMD_UNMASK_BIT(UDC_DEVINT_SC) + & AMD_UNMASK_BIT(UDC_DEVINT_UR) + & AMD_UNMASK_BIT(UDC_DEVINT_SVC) + & AMD_UNMASK_BIT(UDC_DEVINT_ENUM); + writel(tmp, &dev->regs->irqmsk); + + return 0; +} + +/* Calculates fifo start of endpoint based on preceeding endpoints */ +static int udc_set_txfifo_addr(struct udc_ep *ep) +{ + struct udc *dev; + u32 tmp; + int i; + + if (!ep || !(ep->in)) + return -EINVAL; + + dev = ep->dev; + ep->txfifo = dev->txfifo; + + /* traverse ep's */ + for (i = 0; i < ep->num; i++) { + if (dev->ep[i].regs) { + /* read fifo size */ + tmp = readl(&dev->ep[i].regs->bufin_framenum); + tmp = AMD_GETBITS(tmp, UDC_EPIN_BUFF_SIZE); + ep->txfifo += tmp; + } + } + return 0; +} + +/* CNAK pending field: bit0 = ep0in, bit16 = ep0out */ +static u32 cnak_pending; + +static void UDC_QUEUE_CNAK(struct udc_ep *ep, unsigned num) +{ + if (readl(&ep->regs->ctl) & AMD_BIT(UDC_EPCTL_NAK)) { + DBG(ep->dev, "NAK could not be cleared for ep%d\n", num); + cnak_pending |= 1 << (num); + ep->naking = 1; + } else + cnak_pending = cnak_pending & (~(1 << (num))); +} + + +/* Enables endpoint, is called by gadget driver */ +static int +udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc) +{ + struct udc_ep *ep; + struct udc *dev; + u32 tmp; + unsigned long iflags; + u8 udc_csr_epix; + + if (!usbep + || usbep->name == ep0_string + || !desc + || desc->bDescriptorType != USB_DT_ENDPOINT) + return -EINVAL; + + ep = container_of(usbep, struct udc_ep, ep); + dev = ep->dev; + + DBG(dev, "udc_ep_enable() ep %d\n", ep->num); + + if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) + return -ESHUTDOWN; + + spin_lock_irqsave(&dev->lock, iflags); + ep->desc = desc; + + ep->halted = 0; + + /* set traffic type */ + tmp = readl(&dev->ep[ep->num].regs->ctl); + tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_EPCTL_ET); + writel(tmp, &dev->ep[ep->num].regs->ctl); + + /* set max packet size */ + tmp = readl(&dev->ep[ep->num].regs->bufout_maxpkt); + tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_EP_MAX_PKT_SIZE); + ep->ep.maxpacket = desc->wMaxPacketSize; + writel(tmp, &dev->ep[ep->num].regs->bufout_maxpkt); + + /* IN ep */ + if (ep->in) { + + /* ep ix in UDC CSR register space */ + udc_csr_epix = ep->num; + + /* set buffer size (tx fifo entries) */ + tmp = readl(&dev->ep[ep->num].regs->bufin_framenum); + /* double buffering: fifo size = 2 x max packet size */ + tmp = AMD_ADDBITS( + tmp, + desc->wMaxPacketSize * UDC_EPIN_BUFF_SIZE_MULT + / UDC_DWORD_BYTES, + UDC_EPIN_BUFF_SIZE); + writel(tmp, &dev->ep[ep->num].regs->bufin_framenum); + + /* calc. tx fifo base addr */ + udc_set_txfifo_addr(ep); + + /* flush fifo */ + tmp = readl(&ep->regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_F); + writel(tmp, &ep->regs->ctl); + + /* OUT ep */ + } else { + /* ep ix in UDC CSR register space */ + udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS; + + /* set max packet size UDC CSR */ + tmp = readl(&dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]); + tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, + UDC_CSR_NE_MAX_PKT); + writel(tmp, &dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]); + + if (use_dma && !ep->in) { + /* alloc and init BNA dummy request */ + ep->bna_dummy_req = udc_alloc_bna_dummy(ep); + ep->bna_occurred = 0; + } + + if (ep->num != UDC_EP0OUT_IX) + dev->data_ep_enabled = 1; + } + + /* set ep values */ + tmp = readl(&dev->csr->ne[udc_csr_epix]); + /* max packet */ + tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_CSR_NE_MAX_PKT); + /* ep number */ + tmp = AMD_ADDBITS(tmp, desc->bEndpointAddress, UDC_CSR_NE_NUM); + /* ep direction */ + tmp = AMD_ADDBITS(tmp, ep->in, UDC_CSR_NE_DIR); + /* ep type */ + tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_CSR_NE_TYPE); + /* ep config */ + tmp = AMD_ADDBITS(tmp, ep->dev->cur_config, UDC_CSR_NE_CFG); + /* ep interface */ + tmp = AMD_ADDBITS(tmp, ep->dev->cur_intf, UDC_CSR_NE_INTF); + /* ep alt */ + tmp = AMD_ADDBITS(tmp, ep->dev->cur_alt, UDC_CSR_NE_ALT); + /* write reg */ + writel(tmp, &dev->csr->ne[udc_csr_epix]); + + /* enable ep irq */ + tmp = readl(&dev->regs->ep_irqmsk); + tmp &= AMD_UNMASK_BIT(ep->num); + writel(tmp, &dev->regs->ep_irqmsk); + + /* + * clear NAK by writing CNAK + * avoid BNA for OUT DMA, don't clear NAK until DMA desc. written + */ + if (!use_dma || ep->in) { + tmp = readl(&ep->regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_CNAK); + writel(tmp, &ep->regs->ctl); + ep->naking = 0; + UDC_QUEUE_CNAK(ep, ep->num); + } + tmp = desc->bEndpointAddress; + DBG(dev, "%s enabled\n", usbep->name); + + spin_unlock_irqrestore(&dev->lock, iflags); + return 0; +} + +/* Resets endpoint */ +static void ep_init(struct udc_regs __iomem *regs, struct udc_ep *ep) +{ + u32 tmp; + + VDBG(ep->dev, "ep-%d reset\n", ep->num); + ep->desc = NULL; + ep->ep.ops = &udc_ep_ops; + INIT_LIST_HEAD(&ep->queue); + + ep->ep.maxpacket = (u16) ~0; + /* set NAK */ + tmp = readl(&ep->regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_SNAK); + writel(tmp, &ep->regs->ctl); + ep->naking = 1; + + /* disable interrupt */ + tmp = readl(®s->ep_irqmsk); + tmp |= AMD_BIT(ep->num); + writel(tmp, ®s->ep_irqmsk); + + if (ep->in) { + /* unset P and IN bit of potential former DMA */ + tmp = readl(&ep->regs->ctl); + tmp &= AMD_UNMASK_BIT(UDC_EPCTL_P); + writel(tmp, &ep->regs->ctl); + + tmp = readl(&ep->regs->sts); + tmp |= AMD_BIT(UDC_EPSTS_IN); + writel(tmp, &ep->regs->sts); + + /* flush the fifo */ + tmp = readl(&ep->regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_F); + writel(tmp, &ep->regs->ctl); + + } + /* reset desc pointer */ + writel(0, &ep->regs->desptr); +} + +/* Disables endpoint, is called by gadget driver */ +static int udc_ep_disable(struct usb_ep *usbep) +{ + struct udc_ep *ep = NULL; + unsigned long iflags; + + if (!usbep) + return -EINVAL; + + ep = container_of(usbep, struct udc_ep, ep); + if (usbep->name == ep0_string || !ep->desc) + return -EINVAL; + + DBG(ep->dev, "Disable ep-%d\n", ep->num); + + spin_lock_irqsave(&ep->dev->lock, iflags); + udc_free_request(&ep->ep, &ep->bna_dummy_req->req); + empty_req_queue(ep); + ep_init(ep->dev->regs, ep); + spin_unlock_irqrestore(&ep->dev->lock, iflags); + + return 0; +} + +/* Allocates request packet, called by gadget driver */ +static struct usb_request * +udc_alloc_request(struct usb_ep *usbep, gfp_t gfp) +{ + struct udc_request *req; + struct udc_data_dma *dma_desc; + struct udc_ep *ep; + + if (!usbep) + return NULL; + + ep = container_of(usbep, struct udc_ep, ep); + + VDBG(ep->dev, "udc_alloc_req(): ep%d\n", ep->num); + req = kzalloc(sizeof(struct udc_request), gfp); + if (!req) + return NULL; + + req->req.dma = DMA_DONT_USE; + INIT_LIST_HEAD(&req->queue); + + if (ep->dma) { + /* ep0 in requests are allocated from data pool here */ + dma_desc = pci_pool_alloc(ep->dev->data_requests, gfp, + &req->td_phys); + if (!dma_desc) { + kfree(req); + return NULL; + } + + VDBG(ep->dev, "udc_alloc_req: req = %p dma_desc = %p, " + "td_phys = %lx\n", + req, dma_desc, + (unsigned long)req->td_phys); + /* prevent from using desc. - set HOST BUSY */ + dma_desc->status = AMD_ADDBITS(dma_desc->status, + UDC_DMA_STP_STS_BS_HOST_BUSY, + UDC_DMA_STP_STS_BS); + dma_desc->bufptr = __constant_cpu_to_le32(DMA_DONT_USE); + req->td_data = dma_desc; + req->td_data_last = NULL; + req->chain_len = 1; + } + + return &req->req; +} + +/* Frees request packet, called by gadget driver */ +static void +udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq) +{ + struct udc_ep *ep; + struct udc_request *req; + + if (!usbep || !usbreq) + return; + + ep = container_of(usbep, struct udc_ep, ep); + req = container_of(usbreq, struct udc_request, req); + VDBG(ep->dev, "free_req req=%p\n", req); + BUG_ON(!list_empty(&req->queue)); + if (req->td_data) { + VDBG(ep->dev, "req->td_data=%p\n", req->td_data); + + /* free dma chain if created */ + if (req->chain_len > 1) { + udc_free_dma_chain(ep->dev, req); + } + + pci_pool_free(ep->dev->data_requests, req->td_data, + req->td_phys); + } + kfree(req); +} + +/* Init BNA dummy descriptor for HOST BUSY and pointing to itself */ +static void udc_init_bna_dummy(struct udc_request *req) +{ + if (req) { + /* set last bit */ + req->td_data->status |= AMD_BIT(UDC_DMA_IN_STS_L); + /* set next pointer to itself */ + req->td_data->next = req->td_phys; + /* set HOST BUSY */ + req->td_data->status + = AMD_ADDBITS(req->td_data->status, + UDC_DMA_STP_STS_BS_DMA_DONE, + UDC_DMA_STP_STS_BS); +#ifdef UDC_VERBOSE + pr_debug("bna desc = %p, sts = %08x\n", + req->td_data, req->td_data->status); +#endif + } +} + +/* Allocate BNA dummy descriptor */ +static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep) +{ + struct udc_request *req = NULL; + struct usb_request *_req = NULL; + + /* alloc the dummy request */ + _req = udc_alloc_request(&ep->ep, GFP_ATOMIC); + if (_req) { + req = container_of(_req, struct udc_request, req); + ep->bna_dummy_req = req; + udc_init_bna_dummy(req); + } + return req; +} + +/* Write data to TX fifo for IN packets */ +static void +udc_txfifo_write(struct udc_ep *ep, struct usb_request *req) +{ + u8 *req_buf; + u32 *buf; + int i, j; + unsigned bytes = 0; + unsigned remaining = 0; + + if (!req || !ep) + return; + + req_buf = req->buf + req->actual; + prefetch(req_buf); + remaining = req->length - req->actual; + + buf = (u32 *) req_buf; + + bytes = ep->ep.maxpacket; + if (bytes > remaining) + bytes = remaining; + + /* dwords first */ + for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) { + writel(*(buf + i), ep->txfifo); + } + + /* remaining bytes must be written by byte access */ + for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) { + writeb((u8)(*(buf + i) >> (j << UDC_BITS_PER_BYTE_SHIFT)), + ep->txfifo); + } + + /* dummy write confirm */ + writel(0, &ep->regs->confirm); +} + +/* Read dwords from RX fifo for OUT transfers */ +static int udc_rxfifo_read_dwords(struct udc *dev, u32 *buf, int dwords) +{ + int i; + + VDBG(dev, "udc_read_dwords(): %d dwords\n", dwords); + + for (i = 0; i < dwords; i++) { + *(buf + i) = readl(dev->rxfifo); + } + return 0; +} + +/* Read bytes from RX fifo for OUT transfers */ +static int udc_rxfifo_read_bytes(struct udc *dev, u8 *buf, int bytes) +{ + int i, j; + u32 tmp; + + VDBG(dev, "udc_read_bytes(): %d bytes\n", bytes); + + /* dwords first */ + for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) { + *((u32 *)(buf + (i<<2))) = readl(dev->rxfifo); + } + + /* remaining bytes must be read by byte access */ + if (bytes % UDC_DWORD_BYTES) { + tmp = readl(dev->rxfifo); + for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) { + *(buf + (i<<2) + j) = (u8)(tmp & UDC_BYTE_MASK); + tmp = tmp >> UDC_BITS_PER_BYTE; + } + } + + return 0; +} + +/* Read data from RX fifo for OUT transfers */ +static int +udc_rxfifo_read(struct udc_ep *ep, struct udc_request *req) +{ + u8 *buf; + unsigned buf_space; + unsigned bytes = 0; + unsigned finished = 0; + + /* received number bytes */ + bytes = readl(&ep->regs->sts); + bytes = AMD_GETBITS(bytes, UDC_EPSTS_RX_PKT_SIZE); + + buf_space = req->req.length - req->req.actual; + buf = req->req.buf + req->req.actual; + if (bytes > buf_space) { + if ((buf_space % ep->ep.maxpacket) != 0) { + DBG(ep->dev, + "%s: rx %d bytes, rx-buf space = %d bytesn\n", + ep->ep.name, bytes, buf_space); + req->req.status = -EOVERFLOW; + } + bytes = buf_space; + } + req->req.actual += bytes; + + /* last packet ? */ + if (((bytes % ep->ep.maxpacket) != 0) || (!bytes) + || ((req->req.actual == req->req.length) && !req->req.zero)) + finished = 1; + + /* read rx fifo bytes */ + VDBG(ep->dev, "ep %s: rxfifo read %d bytes\n", ep->ep.name, bytes); + udc_rxfifo_read_bytes(ep->dev, buf, bytes); + + return finished; +} + +/* create/re-init a DMA descriptor or a DMA descriptor chain */ +static int prep_dma(struct udc_ep *ep, struct udc_request *req, gfp_t gfp) +{ + int retval = 0; + u32 tmp; + + VDBG(ep->dev, "prep_dma\n"); + VDBG(ep->dev, "prep_dma ep%d req->td_data=%p\n", + ep->num, req->td_data); + + /* set buffer pointer */ + req->td_data->bufptr = req->req.dma; + + /* set last bit */ + req->td_data->status |= AMD_BIT(UDC_DMA_IN_STS_L); + + /* build/re-init dma chain if maxpkt scatter mode, not for EP0 */ + if (use_dma_ppb) { + + retval = udc_create_dma_chain(ep, req, ep->ep.maxpacket, gfp); + if (retval != 0) { + if (retval == -ENOMEM) + DBG(ep->dev, "Out of DMA memory\n"); + return retval; + } + if (ep->in) { + if (req->req.length == ep->ep.maxpacket) { + /* write tx bytes */ + req->td_data->status = + AMD_ADDBITS(req->td_data->status, + ep->ep.maxpacket, + UDC_DMA_IN_STS_TXBYTES); + + } + } + + } + + if (ep->in) { + VDBG(ep->dev, "IN: use_dma_ppb=%d req->req.len=%d " + "maxpacket=%d ep%d\n", + use_dma_ppb, req->req.length, + ep->ep.maxpacket, ep->num); + /* + * if bytes < max packet then tx bytes must + * be written in packet per buffer mode + */ + if (!use_dma_ppb || req->req.length < ep->ep.maxpacket + || ep->num == UDC_EP0OUT_IX + || ep->num == UDC_EP0IN_IX) { + /* write tx bytes */ + req->td_data->status = + AMD_ADDBITS(req->td_data->status, + req->req.length, + UDC_DMA_IN_STS_TXBYTES); + /* reset frame num */ + req->td_data->status = + AMD_ADDBITS(req->td_data->status, + 0, + UDC_DMA_IN_STS_FRAMENUM); + } + /* set HOST BUSY */ + req->td_data->status = + AMD_ADDBITS(req->td_data->status, + UDC_DMA_STP_STS_BS_HOST_BUSY, + UDC_DMA_STP_STS_BS); + } else { + VDBG(ep->dev, "OUT set host ready\n"); + /* set HOST READY */ + req->td_data->status = + AMD_ADDBITS(req->td_data->status, + UDC_DMA_STP_STS_BS_HOST_READY, + UDC_DMA_STP_STS_BS); + + + /* clear NAK by writing CNAK */ + if (ep->naking) { + tmp = readl(&ep->regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_CNAK); + writel(tmp, &ep->regs->ctl); + ep->naking = 0; + UDC_QUEUE_CNAK(ep, ep->num); + } + + } + + return retval; +} + +/* Completes request packet ... caller MUST hold lock */ +static void +complete_req(struct udc_ep *ep, struct udc_request *req, int sts) +__releases(ep->dev->lock) +__acquires(ep->dev->lock) +{ + struct udc *dev; + unsigned halted; + + VDBG(ep->dev, "complete_req(): ep%d\n", ep->num); + + dev = ep->dev; + /* unmap DMA */ + if (req->dma_mapping) { + if (ep->in) + pci_unmap_single(dev->pdev, + req->req.dma, + req->req.length, + PCI_DMA_TODEVICE); + else + pci_unmap_single(dev->pdev, + req->req.dma, + req->req.length, + PCI_DMA_FROMDEVICE); + req->dma_mapping = 0; + req->req.dma = DMA_DONT_USE; + } + + halted = ep->halted; + ep->halted = 1; + + /* set new status if pending */ + if (req->req.status == -EINPROGRESS) + req->req.status = sts; + + /* remove from ep queue */ + list_del_init(&req->queue); + + VDBG(ep->dev, "req %p => complete %d bytes at %s with sts %d\n", + &req->req, req->req.length, ep->ep.name, sts); + + spin_unlock(&dev->lock); + req->req.complete(&ep->ep, &req->req); + spin_lock(&dev->lock); + ep->halted = halted; +} + +/* frees pci pool descriptors of a DMA chain */ +static int udc_free_dma_chain(struct udc *dev, struct udc_request *req) +{ + + int ret_val = 0; + struct udc_data_dma *td; + struct udc_data_dma *td_last = NULL; + unsigned int i; + + DBG(dev, "free chain req = %p\n", req); + + /* do not free first desc., will be done by free for request */ + td_last = req->td_data; + td = phys_to_virt(td_last->next); + + for (i = 1; i < req->chain_len; i++) { + + pci_pool_free(dev->data_requests, td, + (dma_addr_t) td_last->next); + td_last = td; + td = phys_to_virt(td_last->next); + } + + return ret_val; +} + +/* Iterates to the end of a DMA chain and returns last descriptor */ +static struct udc_data_dma *udc_get_last_dma_desc(struct udc_request *req) +{ + struct udc_data_dma *td; + + td = req->td_data; + while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) { + td = phys_to_virt(td->next); + } + + return td; + +} + +/* Iterates to the end of a DMA chain and counts bytes received */ +static u32 udc_get_ppbdu_rxbytes(struct udc_request *req) +{ + struct udc_data_dma *td; + u32 count; + + td = req->td_data; + /* received number bytes */ + count = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_RXBYTES); + + while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) { + td = phys_to_virt(td->next); + /* received number bytes */ + if (td) { + count += AMD_GETBITS(td->status, + UDC_DMA_OUT_STS_RXBYTES); + } + } + + return count; + +} + +/* Creates or re-inits a DMA chain */ +static int udc_create_dma_chain( + struct udc_ep *ep, + struct udc_request *req, + unsigned long buf_len, gfp_t gfp_flags +) +{ + unsigned long bytes = req->req.length; + unsigned int i; + dma_addr_t dma_addr; + struct udc_data_dma *td = NULL; + struct udc_data_dma *last = NULL; + unsigned long txbytes; + unsigned create_new_chain = 0; + unsigned len; + + VDBG(ep->dev, "udc_create_dma_chain: bytes=%ld buf_len=%ld\n", + bytes, buf_len); + dma_addr = DMA_DONT_USE; + + /* unset L bit in first desc for OUT */ + if (!ep->in) { + req->td_data->status &= AMD_CLEAR_BIT(UDC_DMA_IN_STS_L); + } + + /* alloc only new desc's if not already available */ + len = req->req.length / ep->ep.maxpacket; + if (req->req.length % ep->ep.maxpacket) { + len++; + } + + if (len > req->chain_len) { + /* shorter chain already allocated before */ + if (req->chain_len > 1) { + udc_free_dma_chain(ep->dev, req); + } + req->chain_len = len; + create_new_chain = 1; + } + + td = req->td_data; + /* gen. required number of descriptors and buffers */ + for (i = buf_len; i < bytes; i += buf_len) { + /* create or determine next desc. */ + if (create_new_chain) { + + td = pci_pool_alloc(ep->dev->data_requests, + gfp_flags, &dma_addr); + if (!td) + return -ENOMEM; + + td->status = 0; + } else if (i == buf_len) { + /* first td */ + td = (struct udc_data_dma *) phys_to_virt( + req->td_data->next); + td->status = 0; + } else { + td = (struct udc_data_dma *) phys_to_virt(last->next); + td->status = 0; + } + + + if (td) + td->bufptr = req->req.dma + i; /* assign buffer */ + else + break; + + /* short packet ? */ + if ((bytes - i) >= buf_len) { + txbytes = buf_len; + } else { + /* short packet */ + txbytes = bytes - i; + } + + /* link td and assign tx bytes */ + if (i == buf_len) { + if (create_new_chain) { + req->td_data->next = dma_addr; + } else { + /* req->td_data->next = virt_to_phys(td); */ + } + /* write tx bytes */ + if (ep->in) { + /* first desc */ + req->td_data->status = + AMD_ADDBITS(req->td_data->status, + ep->ep.maxpacket, + UDC_DMA_IN_STS_TXBYTES); + /* second desc */ + td->status = AMD_ADDBITS(td->status, + txbytes, + UDC_DMA_IN_STS_TXBYTES); + } + } else { + if (create_new_chain) { + last->next = dma_addr; + } else { + /* last->next = virt_to_phys(td); */ + } + if (ep->in) { + /* write tx bytes */ + td->status = AMD_ADDBITS(td->status, + txbytes, + UDC_DMA_IN_STS_TXBYTES); + } + } + last = td; + } + /* set last bit */ + if (td) { + td->status |= AMD_BIT(UDC_DMA_IN_STS_L); + /* last desc. points to itself */ + req->td_data_last = td; + } + + return 0; +} + +/* Enabling RX DMA */ +static void udc_set_rde(struct udc *dev) +{ + u32 tmp; + + VDBG(dev, "udc_set_rde()\n"); + /* stop RDE timer */ + if (timer_pending(&udc_timer)) { + set_rde = 0; + mod_timer(&udc_timer, jiffies - 1); + } + /* set RDE */ + tmp = readl(&dev->regs->ctl); + tmp |= AMD_BIT(UDC_DEVCTL_RDE); + writel(tmp, &dev->regs->ctl); +} + +/* Queues a request packet, called by gadget driver */ +static int +udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp) +{ + int retval = 0; + u8 open_rxfifo = 0; + unsigned long iflags; + struct udc_ep *ep; + struct udc_request *req; + struct udc *dev; + u32 tmp; + + /* check the inputs */ + req = container_of(usbreq, struct udc_request, req); + + if (!usbep || !usbreq || !usbreq->complete || !usbreq->buf + || !list_empty(&req->queue)) + return -EINVAL; + + ep = container_of(usbep, struct udc_ep, ep); + if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX)) + return -EINVAL; + + VDBG(ep->dev, "udc_queue(): ep%d-in=%d\n", ep->num, ep->in); + dev = ep->dev; + + if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) + return -ESHUTDOWN; + + /* map dma (usually done before) */ + if (ep->dma && usbreq->length != 0 + && (usbreq->dma == DMA_DONT_USE || usbreq->dma == 0)) { + VDBG(dev, "DMA map req %p\n", req); + if (ep->in) + usbreq->dma = pci_map_single(dev->pdev, + usbreq->buf, + usbreq->length, + PCI_DMA_TODEVICE); + else + usbreq->dma = pci_map_single(dev->pdev, + usbreq->buf, + usbreq->length, + PCI_DMA_FROMDEVICE); + req->dma_mapping = 1; + } + + VDBG(dev, "%s queue req %p, len %d req->td_data=%p buf %p\n", + usbep->name, usbreq, usbreq->length, + req->td_data, usbreq->buf); + + spin_lock_irqsave(&dev->lock, iflags); + usbreq->actual = 0; + usbreq->status = -EINPROGRESS; + req->dma_done = 0; + + /* on empty queue just do first transfer */ + if (list_empty(&ep->queue)) { + /* zlp */ + if (usbreq->length == 0) { + /* IN zlp's are handled by hardware */ + complete_req(ep, req, 0); + VDBG(dev, "%s: zlp\n", ep->ep.name); + /* + * if set_config or set_intf is waiting for ack by zlp + * then set CSR_DONE + */ + if (dev->set_cfg_not_acked) { + tmp = readl(&dev->regs->ctl); + tmp |= AMD_BIT(UDC_DEVCTL_CSR_DONE); + writel(tmp, &dev->regs->ctl); + dev->set_cfg_not_acked = 0; + } + /* setup command is ACK'ed now by zlp */ + if (dev->waiting_zlp_ack_ep0in) { + /* clear NAK by writing CNAK in EP0_IN */ + tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_CNAK); + writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl); + dev->ep[UDC_EP0IN_IX].naking = 0; + UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], + UDC_EP0IN_IX); + dev->waiting_zlp_ack_ep0in = 0; + } + goto finished; + } + if (ep->dma) { + retval = prep_dma(ep, req, gfp); + if (retval != 0) + goto finished; + /* write desc pointer to enable DMA */ + if (ep->in) { + /* set HOST READY */ + req->td_data->status = + AMD_ADDBITS(req->td_data->status, + UDC_DMA_IN_STS_BS_HOST_READY, + UDC_DMA_IN_STS_BS); + } + + /* disabled rx dma while descriptor update */ + if (!ep->in) { + /* stop RDE timer */ + if (timer_pending(&udc_timer)) { + set_rde = 0; + mod_timer(&udc_timer, jiffies - 1); + } + /* clear RDE */ + tmp = readl(&dev->regs->ctl); + tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE); + writel(tmp, &dev->regs->ctl); + open_rxfifo = 1; + + /* + * if BNA occurred then let BNA dummy desc. + * point to current desc. + */ + if (ep->bna_occurred) { + VDBG(dev, "copy to BNA dummy desc.\n"); + memcpy(ep->bna_dummy_req->td_data, + req->td_data, + sizeof(struct udc_data_dma)); + } + } + /* write desc pointer */ + writel(req->td_phys, &ep->regs->desptr); + + /* clear NAK by writing CNAK */ + if (ep->naking) { + tmp = readl(&ep->regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_CNAK); + writel(tmp, &ep->regs->ctl); + ep->naking = 0; + UDC_QUEUE_CNAK(ep, ep->num); + } + + if (ep->in) { + /* enable ep irq */ + tmp = readl(&dev->regs->ep_irqmsk); + tmp &= AMD_UNMASK_BIT(ep->num); + writel(tmp, &dev->regs->ep_irqmsk); + } + } + + } else if (ep->dma) { + + /* + * prep_dma not used for OUT ep's, this is not possible + * for PPB modes, because of chain creation reasons + */ + if (ep->in) { + retval = prep_dma(ep, req, gfp); + if (retval != 0) + goto finished; + } + } + VDBG(dev, "list_add\n"); + /* add request to ep queue */ + if (req) { + + list_add_tail(&req->queue, &ep->queue); + + /* open rxfifo if out data queued */ + if (open_rxfifo) { + /* enable DMA */ + req->dma_going = 1; + udc_set_rde(dev); + if (ep->num != UDC_EP0OUT_IX) + dev->data_ep_queued = 1; + } + /* stop OUT naking */ + if (!ep->in) { + if (!use_dma && udc_rxfifo_pending) { + DBG(dev, "udc_queue(): pending bytes in" + "rxfifo after nyet\n"); + /* + * read pending bytes afer nyet: + * referring to isr + */ + if (udc_rxfifo_read(ep, req)) { + /* finish */ + complete_req(ep, req, 0); + } + udc_rxfifo_pending = 0; + + } + } + } + +finished: + spin_unlock_irqrestore(&dev->lock, iflags); + return retval; +} + +/* Empty request queue of an endpoint; caller holds spinlock */ +static void empty_req_queue(struct udc_ep *ep) +{ + struct udc_request *req; + + ep->halted = 1; + while (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, + struct udc_request, + queue); + complete_req(ep, req, -ESHUTDOWN); + } +} + +/* Dequeues a request packet, called by gadget driver */ +static int udc_dequeue(struct usb_ep *usbep, struct usb_request *usbreq) +{ + struct udc_ep *ep; + struct udc_request *req; + unsigned halted; + unsigned long iflags; + + ep = container_of(usbep, struct udc_ep, ep); + if (!usbep || !usbreq || (!ep->desc && (ep->num != 0 + && ep->num != UDC_EP0OUT_IX))) + return -EINVAL; + + req = container_of(usbreq, struct udc_request, req); + + spin_lock_irqsave(&ep->dev->lock, iflags); + halted = ep->halted; + ep->halted = 1; + /* request in processing or next one */ + if (ep->queue.next == &req->queue) { + if (ep->dma && req->dma_going) { + if (ep->in) + ep->cancel_transfer = 1; + else { + u32 tmp; + u32 dma_sts; + /* stop potential receive DMA */ + tmp = readl(&udc->regs->ctl); + writel(tmp & AMD_UNMASK_BIT(UDC_DEVCTL_RDE), + &udc->regs->ctl); + /* + * Cancel transfer later in ISR + * if descriptor was touched. + */ + dma_sts = AMD_GETBITS(req->td_data->status, + UDC_DMA_OUT_STS_BS); + if (dma_sts != UDC_DMA_OUT_STS_BS_HOST_READY) + ep->cancel_transfer = 1; + else { + udc_init_bna_dummy(ep->req); + writel(ep->bna_dummy_req->td_phys, + &ep->regs->desptr); + } + writel(tmp, &udc->regs->ctl); + } + } + } + complete_req(ep, req, -ECONNRESET); + ep->halted = halted; + + spin_unlock_irqrestore(&ep->dev->lock, iflags); + return 0; +} + +/* Halt or clear halt of endpoint */ +static int +udc_set_halt(struct usb_ep *usbep, int halt) +{ + struct udc_ep *ep; + u32 tmp; + unsigned long iflags; + int retval = 0; + + if (!usbep) + return -EINVAL; + + pr_debug("set_halt %s: halt=%d\n", usbep->name, halt); + + ep = container_of(usbep, struct udc_ep, ep); + if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX)) + return -EINVAL; + if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) + return -ESHUTDOWN; + + spin_lock_irqsave(&udc_stall_spinlock, iflags); + /* halt or clear halt */ + if (halt) { + if (ep->num == 0) + ep->dev->stall_ep0in = 1; + else { + /* + * set STALL + * rxfifo empty not taken into acount + */ + tmp = readl(&ep->regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_S); + writel(tmp, &ep->regs->ctl); + ep->halted = 1; + + /* setup poll timer */ + if (!timer_pending(&udc_pollstall_timer)) { + udc_pollstall_timer.expires = jiffies + + HZ * UDC_POLLSTALL_TIMER_USECONDS + / (1000 * 1000); + if (!stop_pollstall_timer) { + DBG(ep->dev, "start polltimer\n"); + add_timer(&udc_pollstall_timer); + } + } + } + } else { + /* ep is halted by set_halt() before */ + if (ep->halted) { + tmp = readl(&ep->regs->ctl); + /* clear stall bit */ + tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S); + /* clear NAK by writing CNAK */ + tmp |= AMD_BIT(UDC_EPCTL_CNAK); + writel(tmp, &ep->regs->ctl); + ep->halted = 0; + UDC_QUEUE_CNAK(ep, ep->num); + } + } + spin_unlock_irqrestore(&udc_stall_spinlock, iflags); + return retval; +} + +/* gadget interface */ +static const struct usb_ep_ops udc_ep_ops = { + .enable = udc_ep_enable, + .disable = udc_ep_disable, + + .alloc_request = udc_alloc_request, + .free_request = udc_free_request, + + .queue = udc_queue, + .dequeue = udc_dequeue, + + .set_halt = udc_set_halt, + /* fifo ops not implemented */ +}; + +/*-------------------------------------------------------------------------*/ + +/* Get frame counter (not implemented) */ +static int udc_get_frame(struct usb_gadget *gadget) +{ + return -EOPNOTSUPP; +} + +/* Remote wakeup gadget interface */ +static int udc_wakeup(struct usb_gadget *gadget) +{ + struct udc *dev; + + if (!gadget) + return -EINVAL; + dev = container_of(gadget, struct udc, gadget); + udc_remote_wakeup(dev); + + return 0; +} + +/* gadget operations */ +static const struct usb_gadget_ops udc_ops = { + .wakeup = udc_wakeup, + .get_frame = udc_get_frame, +}; + +/* Setups endpoint parameters, adds endpoints to linked list */ +static void make_ep_lists(struct udc *dev) +{ + /* make gadget ep lists */ + INIT_LIST_HEAD(&dev->gadget.ep_list); + list_add_tail(&dev->ep[UDC_EPIN_STATUS_IX].ep.ep_list, + &dev->gadget.ep_list); + list_add_tail(&dev->ep[UDC_EPIN_IX].ep.ep_list, + &dev->gadget.ep_list); + list_add_tail(&dev->ep[UDC_EPOUT_IX].ep.ep_list, + &dev->gadget.ep_list); + + /* fifo config */ + dev->ep[UDC_EPIN_STATUS_IX].fifo_depth = UDC_EPIN_SMALLINT_BUFF_SIZE; + if (dev->gadget.speed == USB_SPEED_FULL) + dev->ep[UDC_EPIN_IX].fifo_depth = UDC_FS_EPIN_BUFF_SIZE; + else if (dev->gadget.speed == USB_SPEED_HIGH) + dev->ep[UDC_EPIN_IX].fifo_depth = hs_tx_buf; + dev->ep[UDC_EPOUT_IX].fifo_depth = UDC_RXFIFO_SIZE; +} + +/* init registers at driver load time */ +static int startup_registers(struct udc *dev) +{ + u32 tmp; + + /* init controller by soft reset */ + udc_soft_reset(dev); + + /* mask not needed interrupts */ + udc_mask_unused_interrupts(dev); + + /* put into initial config */ + udc_basic_init(dev); + /* link up all endpoints */ + udc_setup_endpoints(dev); + + /* program speed */ + tmp = readl(&dev->regs->cfg); + if (use_fullspeed) { + tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD); + } else { + tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_HS, UDC_DEVCFG_SPD); + } + writel(tmp, &dev->regs->cfg); + + return 0; +} + +/* Inits UDC context */ +static void udc_basic_init(struct udc *dev) +{ + u32 tmp; + + DBG(dev, "udc_basic_init()\n"); + + dev->gadget.speed = USB_SPEED_UNKNOWN; + + /* stop RDE timer */ + if (timer_pending(&udc_timer)) { + set_rde = 0; + mod_timer(&udc_timer, jiffies - 1); + } + /* stop poll stall timer */ + if (timer_pending(&udc_pollstall_timer)) { + mod_timer(&udc_pollstall_timer, jiffies - 1); + } + /* disable DMA */ + tmp = readl(&dev->regs->ctl); + tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE); + tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_TDE); + writel(tmp, &dev->regs->ctl); + + /* enable dynamic CSR programming */ + tmp = readl(&dev->regs->cfg); + tmp |= AMD_BIT(UDC_DEVCFG_CSR_PRG); + /* set self powered */ + tmp |= AMD_BIT(UDC_DEVCFG_SP); + /* set remote wakeupable */ + tmp |= AMD_BIT(UDC_DEVCFG_RWKP); + writel(tmp, &dev->regs->cfg); + + make_ep_lists(dev); + + dev->data_ep_enabled = 0; + dev->data_ep_queued = 0; +} + +/* Sets initial endpoint parameters */ +static void udc_setup_endpoints(struct udc *dev) +{ + struct udc_ep *ep; + u32 tmp; + u32 reg; + + DBG(dev, "udc_setup_endpoints()\n"); + + /* read enum speed */ + tmp = readl(&dev->regs->sts); + tmp = AMD_GETBITS(tmp, UDC_DEVSTS_ENUM_SPEED); + if (tmp == UDC_DEVSTS_ENUM_SPEED_HIGH) { + dev->gadget.speed = USB_SPEED_HIGH; + } else if (tmp == UDC_DEVSTS_ENUM_SPEED_FULL) { + dev->gadget.speed = USB_SPEED_FULL; + } + + /* set basic ep parameters */ + for (tmp = 0; tmp < UDC_EP_NUM; tmp++) { + ep = &dev->ep[tmp]; + ep->dev = dev; + ep->ep.name = ep_string[tmp]; + ep->num = tmp; + /* txfifo size is calculated at enable time */ + ep->txfifo = dev->txfifo; + + /* fifo size */ + if (tmp < UDC_EPIN_NUM) { + ep->fifo_depth = UDC_TXFIFO_SIZE; + ep->in = 1; + } else { + ep->fifo_depth = UDC_RXFIFO_SIZE; + ep->in = 0; + + } + ep->regs = &dev->ep_regs[tmp]; + /* + * ep will be reset only if ep was not enabled before to avoid + * disabling ep interrupts when ENUM interrupt occurs but ep is + * not enabled by gadget driver + */ + if (!ep->desc) { + ep_init(dev->regs, ep); + } + + if (use_dma) { + /* + * ep->dma is not really used, just to indicate that + * DMA is active: remove this + * dma regs = dev control regs + */ + ep->dma = &dev->regs->ctl; + + /* nak OUT endpoints until enable - not for ep0 */ + if (tmp != UDC_EP0IN_IX && tmp != UDC_EP0OUT_IX + && tmp > UDC_EPIN_NUM) { + /* set NAK */ + reg = readl(&dev->ep[tmp].regs->ctl); + reg |= AMD_BIT(UDC_EPCTL_SNAK); + writel(reg, &dev->ep[tmp].regs->ctl); + dev->ep[tmp].naking = 1; + + } + } + } + /* EP0 max packet */ + if (dev->gadget.speed == USB_SPEED_FULL) { + dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_FS_EP0IN_MAX_PKT_SIZE; + dev->ep[UDC_EP0OUT_IX].ep.maxpacket = + UDC_FS_EP0OUT_MAX_PKT_SIZE; + } else if (dev->gadget.speed == USB_SPEED_HIGH) { + dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE; + dev->ep[UDC_EP0OUT_IX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE; + } + + /* + * with suspend bug workaround, ep0 params for gadget driver + * are set at gadget driver bind() call + */ + dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep; + dev->ep[UDC_EP0IN_IX].halted = 0; + INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); + + /* init cfg/alt/int */ + dev->cur_config = 0; + dev->cur_intf = 0; + dev->cur_alt = 0; +} + +/* Bringup after Connect event, initial bringup to be ready for ep0 events */ +static void usb_connect(struct udc *dev) +{ + + dev_info(&dev->pdev->dev, "USB Connect\n"); + + dev->connected = 1; + + /* put into initial config */ + udc_basic_init(dev); + + /* enable device setup interrupts */ + udc_enable_dev_setup_interrupts(dev); +} + +/* + * Calls gadget with disconnect event and resets the UDC and makes + * initial bringup to be ready for ep0 events + */ +static void usb_disconnect(struct udc *dev) +{ + + dev_info(&dev->pdev->dev, "USB Disconnect\n"); + + dev->connected = 0; + + /* mask interrupts */ + udc_mask_unused_interrupts(dev); + + /* REVISIT there doesn't seem to be a point to having this + * talk to a tasklet ... do it directly, we already hold + * the spinlock needed to process the disconnect. + */ + + tasklet_schedule(&disconnect_tasklet); +} + +/* Tasklet for disconnect to be outside of interrupt context */ +static void udc_tasklet_disconnect(unsigned long par) +{ + struct udc *dev = (struct udc *)(*((struct udc **) par)); + u32 tmp; + + DBG(dev, "Tasklet disconnect\n"); + spin_lock_irq(&dev->lock); + + if (dev->driver) { + spin_unlock(&dev->lock); + dev->driver->disconnect(&dev->gadget); + spin_lock(&dev->lock); + + /* empty queues */ + for (tmp = 0; tmp < UDC_EP_NUM; tmp++) { + empty_req_queue(&dev->ep[tmp]); + } + + } + + /* disable ep0 */ + ep_init(dev->regs, + &dev->ep[UDC_EP0IN_IX]); + + + if (!soft_reset_occured) { + /* init controller by soft reset */ + udc_soft_reset(dev); + soft_reset_occured++; + } + + /* re-enable dev interrupts */ + udc_enable_dev_setup_interrupts(dev); + /* back to full speed ? */ + if (use_fullspeed) { + tmp = readl(&dev->regs->cfg); + tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD); + writel(tmp, &dev->regs->cfg); + } + + spin_unlock_irq(&dev->lock); +} + +/* Reset the UDC core */ +static void udc_soft_reset(struct udc *dev) +{ + unsigned long flags; + + DBG(dev, "Soft reset\n"); + /* + * reset possible waiting interrupts, because int. + * status is lost after soft reset, + * ep int. status reset + */ + writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqsts); + /* device int. status reset */ + writel(UDC_DEV_MSK_DISABLE, &dev->regs->irqsts); + + spin_lock_irqsave(&udc_irq_spinlock, flags); + writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg); + readl(&dev->regs->cfg); + spin_unlock_irqrestore(&udc_irq_spinlock, flags); + +} + +/* RDE timer callback to set RDE bit */ +static void udc_timer_function(unsigned long v) +{ + u32 tmp; + + spin_lock_irq(&udc_irq_spinlock); + + if (set_rde > 0) { + /* + * open the fifo if fifo was filled on last timer call + * conditionally + */ + if (set_rde > 1) { + /* set RDE to receive setup data */ + tmp = readl(&udc->regs->ctl); + tmp |= AMD_BIT(UDC_DEVCTL_RDE); + writel(tmp, &udc->regs->ctl); + set_rde = -1; + } else if (readl(&udc->regs->sts) + & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) { + /* + * if fifo empty setup polling, do not just + * open the fifo + */ + udc_timer.expires = jiffies + HZ/UDC_RDE_TIMER_DIV; + if (!stop_timer) { + add_timer(&udc_timer); + } + } else { + /* + * fifo contains data now, setup timer for opening + * the fifo when timer expires to be able to receive + * setup packets, when data packets gets queued by + * gadget layer then timer will forced to expire with + * set_rde=0 (RDE is set in udc_queue()) + */ + set_rde++; + /* debug: lhadmot_timer_start = 221070 */ + udc_timer.expires = jiffies + HZ*UDC_RDE_TIMER_SECONDS; + if (!stop_timer) { + add_timer(&udc_timer); + } + } + + } else + set_rde = -1; /* RDE was set by udc_queue() */ + spin_unlock_irq(&udc_irq_spinlock); + if (stop_timer) + complete(&on_exit); + +} + +/* Handle halt state, used in stall poll timer */ +static void udc_handle_halt_state(struct udc_ep *ep) +{ + u32 tmp; + /* set stall as long not halted */ + if (ep->halted == 1) { + tmp = readl(&ep->regs->ctl); + /* STALL cleared ? */ + if (!(tmp & AMD_BIT(UDC_EPCTL_S))) { + /* + * FIXME: MSC spec requires that stall remains + * even on receivng of CLEAR_FEATURE HALT. So + * we would set STALL again here to be compliant. + * But with current mass storage drivers this does + * not work (would produce endless host retries). + * So we clear halt on CLEAR_FEATURE. + * + DBG(ep->dev, "ep %d: set STALL again\n", ep->num); + tmp |= AMD_BIT(UDC_EPCTL_S); + writel(tmp, &ep->regs->ctl);*/ + + /* clear NAK by writing CNAK */ + tmp |= AMD_BIT(UDC_EPCTL_CNAK); + writel(tmp, &ep->regs->ctl); + ep->halted = 0; + UDC_QUEUE_CNAK(ep, ep->num); + } + } +} + +/* Stall timer callback to poll S bit and set it again after */ +static void udc_pollstall_timer_function(unsigned long v) +{ + struct udc_ep *ep; + int halted = 0; + + spin_lock_irq(&udc_stall_spinlock); + /* + * only one IN and OUT endpoints are handled + * IN poll stall + */ + ep = &udc->ep[UDC_EPIN_IX]; + udc_handle_halt_state(ep); + if (ep->halted) + halted = 1; + /* OUT poll stall */ + ep = &udc->ep[UDC_EPOUT_IX]; + udc_handle_halt_state(ep); + if (ep->halted) + halted = 1; + + /* setup timer again when still halted */ + if (!stop_pollstall_timer && halted) { + udc_pollstall_timer.expires = jiffies + + HZ * UDC_POLLSTALL_TIMER_USECONDS + / (1000 * 1000); + add_timer(&udc_pollstall_timer); + } + spin_unlock_irq(&udc_stall_spinlock); + + if (stop_pollstall_timer) + complete(&on_pollstall_exit); +} + +/* Inits endpoint 0 so that SETUP packets are processed */ +static void activate_control_endpoints(struct udc *dev) +{ + u32 tmp; + + DBG(dev, "activate_control_endpoints\n"); + + /* flush fifo */ + tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_F); + writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl); + + /* set ep0 directions */ + dev->ep[UDC_EP0IN_IX].in = 1; + dev->ep[UDC_EP0OUT_IX].in = 0; + + /* set buffer size (tx fifo entries) of EP0_IN */ + tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufin_framenum); + if (dev->gadget.speed == USB_SPEED_FULL) + tmp = AMD_ADDBITS(tmp, UDC_FS_EPIN0_BUFF_SIZE, + UDC_EPIN_BUFF_SIZE); + else if (dev->gadget.speed == USB_SPEED_HIGH) + tmp = AMD_ADDBITS(tmp, UDC_EPIN0_BUFF_SIZE, + UDC_EPIN_BUFF_SIZE); + writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufin_framenum); + + /* set max packet size of EP0_IN */ + tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt); + if (dev->gadget.speed == USB_SPEED_FULL) + tmp = AMD_ADDBITS(tmp, UDC_FS_EP0IN_MAX_PKT_SIZE, + UDC_EP_MAX_PKT_SIZE); + else if (dev->gadget.speed == USB_SPEED_HIGH) + tmp = AMD_ADDBITS(tmp, UDC_EP0IN_MAX_PKT_SIZE, + UDC_EP_MAX_PKT_SIZE); + writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt); + + /* set max packet size of EP0_OUT */ + tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt); + if (dev->gadget.speed == USB_SPEED_FULL) + tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE, + UDC_EP_MAX_PKT_SIZE); + else if (dev->gadget.speed == USB_SPEED_HIGH) + tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE, + UDC_EP_MAX_PKT_SIZE); + writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt); + + /* set max packet size of EP0 in UDC CSR */ + tmp = readl(&dev->csr->ne[0]); + if (dev->gadget.speed == USB_SPEED_FULL) + tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE, + UDC_CSR_NE_MAX_PKT); + else if (dev->gadget.speed == USB_SPEED_HIGH) + tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE, + UDC_CSR_NE_MAX_PKT); + writel(tmp, &dev->csr->ne[0]); + + if (use_dma) { + dev->ep[UDC_EP0OUT_IX].td->status |= + AMD_BIT(UDC_DMA_OUT_STS_L); + /* write dma desc address */ + writel(dev->ep[UDC_EP0OUT_IX].td_stp_dma, + &dev->ep[UDC_EP0OUT_IX].regs->subptr); + writel(dev->ep[UDC_EP0OUT_IX].td_phys, + &dev->ep[UDC_EP0OUT_IX].regs->desptr); + /* stop RDE timer */ + if (timer_pending(&udc_timer)) { + set_rde = 0; + mod_timer(&udc_timer, jiffies - 1); + } + /* stop pollstall timer */ + if (timer_pending(&udc_pollstall_timer)) { + mod_timer(&udc_pollstall_timer, jiffies - 1); + } + /* enable DMA */ + tmp = readl(&dev->regs->ctl); + tmp |= AMD_BIT(UDC_DEVCTL_MODE) + | AMD_BIT(UDC_DEVCTL_RDE) + | AMD_BIT(UDC_DEVCTL_TDE); + if (use_dma_bufferfill_mode) { + tmp |= AMD_BIT(UDC_DEVCTL_BF); + } else if (use_dma_ppb_du) { + tmp |= AMD_BIT(UDC_DEVCTL_DU); + } + writel(tmp, &dev->regs->ctl); + } + + /* clear NAK by writing CNAK for EP0IN */ + tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_CNAK); + writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl); + dev->ep[UDC_EP0IN_IX].naking = 0; + UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX); + + /* clear NAK by writing CNAK for EP0OUT */ + tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_CNAK); + writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl); + dev->ep[UDC_EP0OUT_IX].naking = 0; + UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX); +} + +/* Make endpoint 0 ready for control traffic */ +static int setup_ep0(struct udc *dev) +{ + activate_control_endpoints(dev); + /* enable ep0 interrupts */ + udc_enable_ep0_interrupts(dev); + /* enable device setup interrupts */ + udc_enable_dev_setup_interrupts(dev); + + return 0; +} + +/* Called by gadget driver to register itself */ +int usb_gadget_register_driver(struct usb_gadget_driver *driver) +{ + struct udc *dev = udc; + int retval; + u32 tmp; + + if (!driver || !driver->bind || !driver->setup + || driver->speed != USB_SPEED_HIGH) + return -EINVAL; + if (!dev) + return -ENODEV; + if (dev->driver) + return -EBUSY; + + driver->driver.bus = NULL; + dev->driver = driver; + dev->gadget.dev.driver = &driver->driver; + + retval = driver->bind(&dev->gadget); + + /* Some gadget drivers use both ep0 directions. + * NOTE: to gadget driver, ep0 is just one endpoint... + */ + dev->ep[UDC_EP0OUT_IX].ep.driver_data = + dev->ep[UDC_EP0IN_IX].ep.driver_data; + + if (retval) { + DBG(dev, "binding to %s returning %d\n", + driver->driver.name, retval); + dev->driver = NULL; + dev->gadget.dev.driver = NULL; + return retval; + } + + /* get ready for ep0 traffic */ + setup_ep0(dev); + + /* clear SD */ + tmp = readl(&dev->regs->ctl); + tmp = tmp & AMD_CLEAR_BIT(UDC_DEVCTL_SD); + writel(tmp, &dev->regs->ctl); + + usb_connect(dev); + + return 0; +} +EXPORT_SYMBOL(usb_gadget_register_driver); + +/* shutdown requests and disconnect from gadget */ +static void +shutdown(struct udc *dev, struct usb_gadget_driver *driver) +__releases(dev->lock) +__acquires(dev->lock) +{ + int tmp; + + /* empty queues and init hardware */ + udc_basic_init(dev); + for (tmp = 0; tmp < UDC_EP_NUM; tmp++) { + empty_req_queue(&dev->ep[tmp]); + } + + if (dev->gadget.speed != USB_SPEED_UNKNOWN) { + spin_unlock(&dev->lock); + driver->disconnect(&dev->gadget); + spin_lock(&dev->lock); + } + /* init */ + udc_setup_endpoints(dev); +} + +/* Called by gadget driver to unregister itself */ +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ + struct udc *dev = udc; + unsigned long flags; + u32 tmp; + + if (!dev) + return -ENODEV; + if (!driver || driver != dev->driver || !driver->unbind) + return -EINVAL; + + spin_lock_irqsave(&dev->lock, flags); + udc_mask_unused_interrupts(dev); + shutdown(dev, driver); + spin_unlock_irqrestore(&dev->lock, flags); + + driver->unbind(&dev->gadget); + dev->driver = NULL; + + /* set SD */ + tmp = readl(&dev->regs->ctl); + tmp |= AMD_BIT(UDC_DEVCTL_SD); + writel(tmp, &dev->regs->ctl); + + + DBG(dev, "%s: unregistered\n", driver->driver.name); + + return 0; +} +EXPORT_SYMBOL(usb_gadget_unregister_driver); + + +/* Clear pending NAK bits */ +static void udc_process_cnak_queue(struct udc *dev) +{ + u32 tmp; + u32 reg; + + /* check epin's */ + DBG(dev, "CNAK pending queue processing\n"); + for (tmp = 0; tmp < UDC_EPIN_NUM_USED; tmp++) { + if (cnak_pending & (1 << tmp)) { + DBG(dev, "CNAK pending for ep%d\n", tmp); + /* clear NAK by writing CNAK */ + reg = readl(&dev->ep[tmp].regs->ctl); + reg |= AMD_BIT(UDC_EPCTL_CNAK); + writel(reg, &dev->ep[tmp].regs->ctl); + dev->ep[tmp].naking = 0; + UDC_QUEUE_CNAK(&dev->ep[tmp], dev->ep[tmp].num); + } + } + /* ... and ep0out */ + if (cnak_pending & (1 << UDC_EP0OUT_IX)) { + DBG(dev, "CNAK pending for ep%d\n", UDC_EP0OUT_IX); + /* clear NAK by writing CNAK */ + reg = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl); + reg |= AMD_BIT(UDC_EPCTL_CNAK); + writel(reg, &dev->ep[UDC_EP0OUT_IX].regs->ctl); + dev->ep[UDC_EP0OUT_IX].naking = 0; + UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], + dev->ep[UDC_EP0OUT_IX].num); + } +} + +/* Enabling RX DMA after setup packet */ +static void udc_ep0_set_rde(struct udc *dev) +{ + if (use_dma) { + /* + * only enable RXDMA when no data endpoint enabled + * or data is queued + */ + if (!dev->data_ep_enabled || dev->data_ep_queued) { + udc_set_rde(dev); + } else { + /* + * setup timer for enabling RDE (to not enable + * RXFIFO DMA for data endpoints to early) + */ + if (set_rde != 0 && !timer_pending(&udc_timer)) { + udc_timer.expires = + jiffies + HZ/UDC_RDE_TIMER_DIV; + set_rde = 1; + if (!stop_timer) { + add_timer(&udc_timer); + } + } + } + } +} + + +/* Interrupt handler for data OUT traffic */ +static irqreturn_t udc_data_out_isr(struct udc *dev, int ep_ix) +{ + irqreturn_t ret_val = IRQ_NONE; + u32 tmp; + struct udc_ep *ep; + struct udc_request *req; + unsigned int count; + struct udc_data_dma *td = NULL; + unsigned dma_done; + + VDBG(dev, "ep%d irq\n", ep_ix); + ep = &dev->ep[ep_ix]; + + tmp = readl(&ep->regs->sts); + if (use_dma) { + /* BNA event ? */ + if (tmp & AMD_BIT(UDC_EPSTS_BNA)) { + DBG(dev, "BNA ep%dout occured - DESPTR = %x \n", + ep->num, readl(&ep->regs->desptr)); + /* clear BNA */ + writel(tmp | AMD_BIT(UDC_EPSTS_BNA), &ep->regs->sts); + if (!ep->cancel_transfer) + ep->bna_occurred = 1; + else + ep->cancel_transfer = 0; + ret_val = IRQ_HANDLED; + goto finished; + } + } + /* HE event ? */ + if (tmp & AMD_BIT(UDC_EPSTS_HE)) { + dev_err(&dev->pdev->dev, "HE ep%dout occured\n", ep->num); + + /* clear HE */ + writel(tmp | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts); + ret_val = IRQ_HANDLED; + goto finished; + } + + if (!list_empty(&ep->queue)) { + + /* next request */ + req = list_entry(ep->queue.next, + struct udc_request, queue); + } else { + req = NULL; + udc_rxfifo_pending = 1; + } + VDBG(dev, "req = %p\n", req); + /* fifo mode */ + if (!use_dma) { + + /* read fifo */ + if (req && udc_rxfifo_read(ep, req)) { + ret_val = IRQ_HANDLED; + + /* finish */ + complete_req(ep, req, 0); + /* next request */ + if (!list_empty(&ep->queue) && !ep->halted) { + req = list_entry(ep->queue.next, + struct udc_request, queue); + } else + req = NULL; + } + + /* DMA */ + } else if (!ep->cancel_transfer && req != NULL) { + ret_val = IRQ_HANDLED; + + /* check for DMA done */ + if (!use_dma_ppb) { + dma_done = AMD_GETBITS(req->td_data->status, + UDC_DMA_OUT_STS_BS); + /* packet per buffer mode - rx bytes */ + } else { + /* + * if BNA occurred then recover desc. from + * BNA dummy desc. + */ + if (ep->bna_occurred) { + VDBG(dev, "Recover desc. from BNA dummy\n"); + memcpy(req->td_data, ep->bna_dummy_req->td_data, + sizeof(struct udc_data_dma)); + ep->bna_occurred = 0; + udc_init_bna_dummy(ep->req); + } + td = udc_get_last_dma_desc(req); + dma_done = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_BS); + } + if (dma_done == UDC_DMA_OUT_STS_BS_DMA_DONE) { + /* buffer fill mode - rx bytes */ + if (!use_dma_ppb) { + /* received number bytes */ + count = AMD_GETBITS(req->td_data->status, + UDC_DMA_OUT_STS_RXBYTES); + VDBG(dev, "rx bytes=%u\n", count); + /* packet per buffer mode - rx bytes */ + } else { + VDBG(dev, "req->td_data=%p\n", req->td_data); + VDBG(dev, "last desc = %p\n", td); + /* received number bytes */ + if (use_dma_ppb_du) { + /* every desc. counts bytes */ + count = udc_get_ppbdu_rxbytes(req); + } else { + /* last desc. counts bytes */ + count = AMD_GETBITS(td->status, + UDC_DMA_OUT_STS_RXBYTES); + if (!count && req->req.length + == UDC_DMA_MAXPACKET) { + /* + * on 64k packets the RXBYTES + * field is zero + */ + count = UDC_DMA_MAXPACKET; + } + } + VDBG(dev, "last desc rx bytes=%u\n", count); + } + + tmp = req->req.length - req->req.actual; + if (count > tmp) { + if ((tmp % ep->ep.maxpacket) != 0) { + DBG(dev, "%s: rx %db, space=%db\n", + ep->ep.name, count, tmp); + req->req.status = -EOVERFLOW; + } + count = tmp; + } + req->req.actual += count; + req->dma_going = 0; + /* complete request */ + complete_req(ep, req, 0); + + /* next request */ + if (!list_empty(&ep->queue) && !ep->halted) { + req = list_entry(ep->queue.next, + struct udc_request, + queue); + /* + * DMA may be already started by udc_queue() + * called by gadget drivers completion + * routine. This happens when queue + * holds one request only. + */ + if (req->dma_going == 0) { + /* next dma */ + if (prep_dma(ep, req, GFP_ATOMIC) != 0) + goto finished; + /* write desc pointer */ + writel(req->td_phys, + &ep->regs->desptr); + req->dma_going = 1; + /* enable DMA */ + udc_set_rde(dev); + } + } else { + /* + * implant BNA dummy descriptor to allow + * RXFIFO opening by RDE + */ + if (ep->bna_dummy_req) { + /* write desc pointer */ + writel(ep->bna_dummy_req->td_phys, + &ep->regs->desptr); + ep->bna_occurred = 0; + } + + /* + * schedule timer for setting RDE if queue + * remains empty to allow ep0 packets pass + * through + */ + if (set_rde != 0 + && !timer_pending(&udc_timer)) { + udc_timer.expires = + jiffies + + HZ*UDC_RDE_TIMER_SECONDS; + set_rde = 1; + if (!stop_timer) { + add_timer(&udc_timer); + } + } + if (ep->num != UDC_EP0OUT_IX) + dev->data_ep_queued = 0; + } + + } else { + /* + * RX DMA must be reenabled for each desc in PPBDU mode + * and must be enabled for PPBNDU mode in case of BNA + */ + udc_set_rde(dev); + } + + } else if (ep->cancel_transfer) { + ret_val = IRQ_HANDLED; + ep->cancel_transfer = 0; + } + + /* check pending CNAKS */ + if (cnak_pending) { + /* CNAk processing when rxfifo empty only */ + if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) { + udc_process_cnak_queue(dev); + } + } + + /* clear OUT bits in ep status */ + writel(UDC_EPSTS_OUT_CLEAR, &ep->regs->sts); +finished: + return ret_val; +} + +/* Interrupt handler for data IN traffic */ +static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix) +{ + irqreturn_t ret_val = IRQ_NONE; + u32 tmp; + u32 epsts; + struct udc_ep *ep; + struct udc_request *req; + struct udc_data_dma *td; + unsigned dma_done; + unsigned len; + + ep = &dev->ep[ep_ix]; + + epsts = readl(&ep->regs->sts); + if (use_dma) { + /* BNA ? */ + if (epsts & AMD_BIT(UDC_EPSTS_BNA)) { + dev_err(&dev->pdev->dev, + "BNA ep%din occured - DESPTR = %08lx \n", + ep->num, + (unsigned long) readl(&ep->regs->desptr)); + + /* clear BNA */ + writel(epsts, &ep->regs->sts); + ret_val = IRQ_HANDLED; + goto finished; + } + } + /* HE event ? */ + if (epsts & AMD_BIT(UDC_EPSTS_HE)) { + dev_err(&dev->pdev->dev, + "HE ep%dn occured - DESPTR = %08lx \n", + ep->num, (unsigned long) readl(&ep->regs->desptr)); + + /* clear HE */ + writel(epsts | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts); + ret_val = IRQ_HANDLED; + goto finished; + } + + /* DMA completion */ + if (epsts & AMD_BIT(UDC_EPSTS_TDC)) { + VDBG(dev, "TDC set- completion\n"); + ret_val = IRQ_HANDLED; + if (!ep->cancel_transfer && !list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, + struct udc_request, queue); + if (req) { + /* + * length bytes transfered + * check dma done of last desc. in PPBDU mode + */ + if (use_dma_ppb_du) { + td = udc_get_last_dma_desc(req); + if (td) { + dma_done = + AMD_GETBITS(td->status, + UDC_DMA_IN_STS_BS); + /* don't care DMA done */ + req->req.actual = + req->req.length; + } + } else { + /* assume all bytes transferred */ + req->req.actual = req->req.length; + } + + if (req->req.actual == req->req.length) { + /* complete req */ + complete_req(ep, req, 0); + req->dma_going = 0; + /* further request available ? */ + if (list_empty(&ep->queue)) { + /* disable interrupt */ + tmp = readl( + &dev->regs->ep_irqmsk); + tmp |= AMD_BIT(ep->num); + writel(tmp, + &dev->regs->ep_irqmsk); + } + + } + } + } + ep->cancel_transfer = 0; + + } + /* + * status reg has IN bit set and TDC not set (if TDC was handled, + * IN must not be handled (UDC defect) ? + */ + if ((epsts & AMD_BIT(UDC_EPSTS_IN)) + && !(epsts & AMD_BIT(UDC_EPSTS_TDC))) { + ret_val = IRQ_HANDLED; + if (!list_empty(&ep->queue)) { + /* next request */ + req = list_entry(ep->queue.next, + struct udc_request, queue); + /* FIFO mode */ + if (!use_dma) { + /* write fifo */ + udc_txfifo_write(ep, &req->req); + len = req->req.length - req->req.actual; + if (len > ep->ep.maxpacket) + len = ep->ep.maxpacket; + req->req.actual += len; + if (req->req.actual == req->req.length + || (len != ep->ep.maxpacket)) { + /* complete req */ + complete_req(ep, req, 0); + } + /* DMA */ + } else if (req && !req->dma_going) { + VDBG(dev, "IN DMA : req=%p req->td_data=%p\n", + req, req->td_data); + if (req->td_data) { + + req->dma_going = 1; + + /* + * unset L bit of first desc. + * for chain + */ + if (use_dma_ppb && req->req.length > + ep->ep.maxpacket) { + req->td_data->status &= + AMD_CLEAR_BIT( + UDC_DMA_IN_STS_L); + } + + /* write desc pointer */ + writel(req->td_phys, &ep->regs->desptr); + + /* set HOST READY */ + req->td_data->status = + AMD_ADDBITS( + req->td_data->status, + UDC_DMA_IN_STS_BS_HOST_READY, + UDC_DMA_IN_STS_BS); + + /* set poll demand bit */ + tmp = readl(&ep->regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_P); + writel(tmp, &ep->regs->ctl); + } + } + + } + } + /* clear status bits */ + writel(epsts, &ep->regs->sts); + +finished: + return ret_val; + +} + +/* Interrupt handler for Control OUT traffic */ +static irqreturn_t udc_control_out_isr(struct udc *dev) +__releases(dev->lock) +__acquires(dev->lock) +{ + irqreturn_t ret_val = IRQ_NONE; + u32 tmp; + int setup_supported; + u32 count; + int set = 0; + struct udc_ep *ep; + struct udc_ep *ep_tmp; + + ep = &dev->ep[UDC_EP0OUT_IX]; + + /* clear irq */ + writel(AMD_BIT(UDC_EPINT_OUT_EP0), &dev->regs->ep_irqsts); + + tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts); + /* check BNA and clear if set */ + if (tmp & AMD_BIT(UDC_EPSTS_BNA)) { + VDBG(dev, "ep0: BNA set\n"); + writel(AMD_BIT(UDC_EPSTS_BNA), + &dev->ep[UDC_EP0OUT_IX].regs->sts); + ep->bna_occurred = 1; + ret_val = IRQ_HANDLED; + goto finished; + } + + /* type of data: SETUP or DATA 0 bytes */ + tmp = AMD_GETBITS(tmp, UDC_EPSTS_OUT); + VDBG(dev, "data_typ = %x\n", tmp); + + /* setup data */ + if (tmp == UDC_EPSTS_OUT_SETUP) { + ret_val = IRQ_HANDLED; + + ep->dev->stall_ep0in = 0; + dev->waiting_zlp_ack_ep0in = 0; + + /* set NAK for EP0_IN */ + tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_SNAK); + writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl); + dev->ep[UDC_EP0IN_IX].naking = 1; + /* get setup data */ + if (use_dma) { + + /* clear OUT bits in ep status */ + writel(UDC_EPSTS_OUT_CLEAR, + &dev->ep[UDC_EP0OUT_IX].regs->sts); + + setup_data.data[0] = + dev->ep[UDC_EP0OUT_IX].td_stp->data12; + setup_data.data[1] = + dev->ep[UDC_EP0OUT_IX].td_stp->data34; + /* set HOST READY */ + dev->ep[UDC_EP0OUT_IX].td_stp->status = + UDC_DMA_STP_STS_BS_HOST_READY; + } else { + /* read fifo */ + udc_rxfifo_read_dwords(dev, setup_data.data, 2); + } + + /* determine direction of control data */ + if ((setup_data.request.bRequestType & USB_DIR_IN) != 0) { + dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep; + /* enable RDE */ + udc_ep0_set_rde(dev); + set = 0; + } else { + dev->gadget.ep0 = &dev->ep[UDC_EP0OUT_IX].ep; + /* + * implant BNA dummy descriptor to allow RXFIFO opening + * by RDE + */ + if (ep->bna_dummy_req) { + /* write desc pointer */ + writel(ep->bna_dummy_req->td_phys, + &dev->ep[UDC_EP0OUT_IX].regs->desptr); + ep->bna_occurred = 0; + } + + set = 1; + dev->ep[UDC_EP0OUT_IX].naking = 1; + /* + * setup timer for enabling RDE (to not enable + * RXFIFO DMA for data to early) + */ + set_rde = 1; + if (!timer_pending(&udc_timer)) { + udc_timer.expires = jiffies + + HZ/UDC_RDE_TIMER_DIV; + if (!stop_timer) { + add_timer(&udc_timer); + } + } + } + + /* + * mass storage reset must be processed here because + * next packet may be a CLEAR_FEATURE HALT which would not + * clear the stall bit when no STALL handshake was received + * before (autostall can cause this) + */ + if (setup_data.data[0] == UDC_MSCRES_DWORD0 + && setup_data.data[1] == UDC_MSCRES_DWORD1) { + DBG(dev, "MSC Reset\n"); + /* + * clear stall bits + * only one IN and OUT endpoints are handled + */ + ep_tmp = &udc->ep[UDC_EPIN_IX]; + udc_set_halt(&ep_tmp->ep, 0); + ep_tmp = &udc->ep[UDC_EPOUT_IX]; + udc_set_halt(&ep_tmp->ep, 0); + } + + /* call gadget with setup data received */ + spin_unlock(&dev->lock); + setup_supported = dev->driver->setup(&dev->gadget, + &setup_data.request); + spin_lock(&dev->lock); + + tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl); + /* ep0 in returns data (not zlp) on IN phase */ + if (setup_supported >= 0 && setup_supported < + UDC_EP0IN_MAXPACKET) { + /* clear NAK by writing CNAK in EP0_IN */ + tmp |= AMD_BIT(UDC_EPCTL_CNAK); + writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl); + dev->ep[UDC_EP0IN_IX].naking = 0; + UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX); + + /* if unsupported request then stall */ + } else if (setup_supported < 0) { + tmp |= AMD_BIT(UDC_EPCTL_S); + writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl); + } else + dev->waiting_zlp_ack_ep0in = 1; + + + /* clear NAK by writing CNAK in EP0_OUT */ + if (!set) { + tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_CNAK); + writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl); + dev->ep[UDC_EP0OUT_IX].naking = 0; + UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX); + } + + if (!use_dma) { + /* clear OUT bits in ep status */ + writel(UDC_EPSTS_OUT_CLEAR, + &dev->ep[UDC_EP0OUT_IX].regs->sts); + } + + /* data packet 0 bytes */ + } else if (tmp == UDC_EPSTS_OUT_DATA) { + /* clear OUT bits in ep status */ + writel(UDC_EPSTS_OUT_CLEAR, &dev->ep[UDC_EP0OUT_IX].regs->sts); + + /* get setup data: only 0 packet */ + if (use_dma) { + /* no req if 0 packet, just reactivate */ + if (list_empty(&dev->ep[UDC_EP0OUT_IX].queue)) { + VDBG(dev, "ZLP\n"); + + /* set HOST READY */ + dev->ep[UDC_EP0OUT_IX].td->status = + AMD_ADDBITS( + dev->ep[UDC_EP0OUT_IX].td->status, + UDC_DMA_OUT_STS_BS_HOST_READY, + UDC_DMA_OUT_STS_BS); + /* enable RDE */ + udc_ep0_set_rde(dev); + ret_val = IRQ_HANDLED; + + } else { + /* control write */ + ret_val |= udc_data_out_isr(dev, UDC_EP0OUT_IX); + /* re-program desc. pointer for possible ZLPs */ + writel(dev->ep[UDC_EP0OUT_IX].td_phys, + &dev->ep[UDC_EP0OUT_IX].regs->desptr); + /* enable RDE */ + udc_ep0_set_rde(dev); + } + } else { + + /* received number bytes */ + count = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts); + count = AMD_GETBITS(count, UDC_EPSTS_RX_PKT_SIZE); + /* out data for fifo mode not working */ + count = 0; + + /* 0 packet or real data ? */ + if (count != 0) { + ret_val |= udc_data_out_isr(dev, UDC_EP0OUT_IX); + } else { + /* dummy read confirm */ + readl(&dev->ep[UDC_EP0OUT_IX].regs->confirm); + ret_val = IRQ_HANDLED; + } + } + } + + /* check pending CNAKS */ + if (cnak_pending) { + /* CNAk processing when rxfifo empty only */ + if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) { + udc_process_cnak_queue(dev); + } + } + +finished: + return ret_val; +} + +/* Interrupt handler for Control IN traffic */ +static irqreturn_t udc_control_in_isr(struct udc *dev) +{ + irqreturn_t ret_val = IRQ_NONE; + u32 tmp; + struct udc_ep *ep; + struct udc_request *req; + unsigned len; + + ep = &dev->ep[UDC_EP0IN_IX]; + + /* clear irq */ + writel(AMD_BIT(UDC_EPINT_IN_EP0), &dev->regs->ep_irqsts); + + tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->sts); + /* DMA completion */ + if (tmp & AMD_BIT(UDC_EPSTS_TDC)) { + VDBG(dev, "isr: TDC clear \n"); + ret_val = IRQ_HANDLED; + + /* clear TDC bit */ + writel(AMD_BIT(UDC_EPSTS_TDC), + &dev->ep[UDC_EP0IN_IX].regs->sts); + + /* status reg has IN bit set ? */ + } else if (tmp & AMD_BIT(UDC_EPSTS_IN)) { + ret_val = IRQ_HANDLED; + + if (ep->dma) { + /* clear IN bit */ + writel(AMD_BIT(UDC_EPSTS_IN), + &dev->ep[UDC_EP0IN_IX].regs->sts); + } + if (dev->stall_ep0in) { + DBG(dev, "stall ep0in\n"); + /* halt ep0in */ + tmp = readl(&ep->regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_S); + writel(tmp, &ep->regs->ctl); + } else { + if (!list_empty(&ep->queue)) { + /* next request */ + req = list_entry(ep->queue.next, + struct udc_request, queue); + + if (ep->dma) { + /* write desc pointer */ + writel(req->td_phys, &ep->regs->desptr); + /* set HOST READY */ + req->td_data->status = + AMD_ADDBITS( + req->td_data->status, + UDC_DMA_STP_STS_BS_HOST_READY, + UDC_DMA_STP_STS_BS); + + /* set poll demand bit */ + tmp = + readl(&dev->ep[UDC_EP0IN_IX].regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_P); + writel(tmp, + &dev->ep[UDC_EP0IN_IX].regs->ctl); + + /* all bytes will be transferred */ + req->req.actual = req->req.length; + + /* complete req */ + complete_req(ep, req, 0); + + } else { + /* write fifo */ + udc_txfifo_write(ep, &req->req); + + /* lengh bytes transfered */ + len = req->req.length - req->req.actual; + if (len > ep->ep.maxpacket) + len = ep->ep.maxpacket; + + req->req.actual += len; + if (req->req.actual == req->req.length + || (len != ep->ep.maxpacket)) { + /* complete req */ + complete_req(ep, req, 0); + } + } + + } + } + ep->halted = 0; + dev->stall_ep0in = 0; + if (!ep->dma) { + /* clear IN bit */ + writel(AMD_BIT(UDC_EPSTS_IN), + &dev->ep[UDC_EP0IN_IX].regs->sts); + } + } + + return ret_val; +} + + +/* Interrupt handler for global device events */ +static irqreturn_t udc_dev_isr(struct udc *dev, u32 dev_irq) +__releases(dev->lock) +__acquires(dev->lock) +{ + irqreturn_t ret_val = IRQ_NONE; + u32 tmp; + u32 cfg; + struct udc_ep *ep; + u16 i; + u8 udc_csr_epix; + + /* SET_CONFIG irq ? */ + if (dev_irq & AMD_BIT(UDC_DEVINT_SC)) { + ret_val = IRQ_HANDLED; + + /* read config value */ + tmp = readl(&dev->regs->sts); + cfg = AMD_GETBITS(tmp, UDC_DEVSTS_CFG); + DBG(dev, "SET_CONFIG interrupt: config=%d\n", cfg); + dev->cur_config = cfg; + dev->set_cfg_not_acked = 1; + + /* make usb request for gadget driver */ + memset(&setup_data, 0 , sizeof(union udc_setup_data)); + setup_data.request.bRequest = USB_REQ_SET_CONFIGURATION; + setup_data.request.wValue = dev->cur_config; + + /* programm the NE registers */ + for (i = 0; i < UDC_EP_NUM; i++) { + ep = &dev->ep[i]; + if (ep->in) { + + /* ep ix in UDC CSR register space */ + udc_csr_epix = ep->num; + + + /* OUT ep */ + } else { + /* ep ix in UDC CSR register space */ + udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS; + } + + tmp = readl(&dev->csr->ne[udc_csr_epix]); + /* ep cfg */ + tmp = AMD_ADDBITS(tmp, ep->dev->cur_config, + UDC_CSR_NE_CFG); + /* write reg */ + writel(tmp, &dev->csr->ne[udc_csr_epix]); + + /* clear stall bits */ + ep->halted = 0; + tmp = readl(&ep->regs->ctl); + tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S); + writel(tmp, &ep->regs->ctl); + } + /* call gadget zero with setup data received */ + spin_unlock(&dev->lock); + tmp = dev->driver->setup(&dev->gadget, &setup_data.request); + spin_lock(&dev->lock); + + } /* SET_INTERFACE ? */ + if (dev_irq & AMD_BIT(UDC_DEVINT_SI)) { + ret_val = IRQ_HANDLED; + + dev->set_cfg_not_acked = 1; + /* read interface and alt setting values */ + tmp = readl(&dev->regs->sts); + dev->cur_alt = AMD_GETBITS(tmp, UDC_DEVSTS_ALT); + dev->cur_intf = AMD_GETBITS(tmp, UDC_DEVSTS_INTF); + + /* make usb request for gadget driver */ + memset(&setup_data, 0 , sizeof(union udc_setup_data)); + setup_data.request.bRequest = USB_REQ_SET_INTERFACE; + setup_data.request.bRequestType = USB_RECIP_INTERFACE; + setup_data.request.wValue = dev->cur_alt; + setup_data.request.wIndex = dev->cur_intf; + + DBG(dev, "SET_INTERFACE interrupt: alt=%d intf=%d\n", + dev->cur_alt, dev->cur_intf); + + /* programm the NE registers */ + for (i = 0; i < UDC_EP_NUM; i++) { + ep = &dev->ep[i]; + if (ep->in) { + + /* ep ix in UDC CSR register space */ + udc_csr_epix = ep->num; + + + /* OUT ep */ + } else { + /* ep ix in UDC CSR register space */ + udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS; + } + + /* UDC CSR reg */ + /* set ep values */ + tmp = readl(&dev->csr->ne[udc_csr_epix]); + /* ep interface */ + tmp = AMD_ADDBITS(tmp, ep->dev->cur_intf, + UDC_CSR_NE_INTF); + /* tmp = AMD_ADDBITS(tmp, 2, UDC_CSR_NE_INTF); */ + /* ep alt */ + tmp = AMD_ADDBITS(tmp, ep->dev->cur_alt, + UDC_CSR_NE_ALT); + /* write reg */ + writel(tmp, &dev->csr->ne[udc_csr_epix]); + + /* clear stall bits */ + ep->halted = 0; + tmp = readl(&ep->regs->ctl); + tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S); + writel(tmp, &ep->regs->ctl); + } + + /* call gadget zero with setup data received */ + spin_unlock(&dev->lock); + tmp = dev->driver->setup(&dev->gadget, &setup_data.request); + spin_lock(&dev->lock); + + } /* USB reset */ + if (dev_irq & AMD_BIT(UDC_DEVINT_UR)) { + DBG(dev, "USB Reset interrupt\n"); + ret_val = IRQ_HANDLED; + + /* allow soft reset when suspend occurs */ + soft_reset_occured = 0; + + dev->waiting_zlp_ack_ep0in = 0; + dev->set_cfg_not_acked = 0; + + /* mask not needed interrupts */ + udc_mask_unused_interrupts(dev); + + /* call gadget to resume and reset configs etc. */ + spin_unlock(&dev->lock); + if (dev->sys_suspended && dev->driver->resume) { + dev->driver->resume(&dev->gadget); + dev->sys_suspended = 0; + } + dev->driver->disconnect(&dev->gadget); + spin_lock(&dev->lock); + + /* disable ep0 to empty req queue */ + empty_req_queue(&dev->ep[UDC_EP0IN_IX]); + ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]); + + /* soft reset when rxfifo not empty */ + tmp = readl(&dev->regs->sts); + if (!(tmp & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) + && !soft_reset_after_usbreset_occured) { + udc_soft_reset(dev); + soft_reset_after_usbreset_occured++; + } + + /* + * DMA reset to kill potential old DMA hw hang, + * POLL bit is already reset by ep_init() through + * disconnect() + */ + DBG(dev, "DMA machine reset\n"); + tmp = readl(&dev->regs->cfg); + writel(tmp | AMD_BIT(UDC_DEVCFG_DMARST), &dev->regs->cfg); + writel(tmp, &dev->regs->cfg); + + /* put into initial config */ + udc_basic_init(dev); + + /* enable device setup interrupts */ + udc_enable_dev_setup_interrupts(dev); + + /* enable suspend interrupt */ + tmp = readl(&dev->regs->irqmsk); + tmp &= AMD_UNMASK_BIT(UDC_DEVINT_US); + writel(tmp, &dev->regs->irqmsk); + + } /* USB suspend */ + if (dev_irq & AMD_BIT(UDC_DEVINT_US)) { + DBG(dev, "USB Suspend interrupt\n"); + ret_val = IRQ_HANDLED; + if (dev->driver->suspend) { + spin_unlock(&dev->lock); + dev->sys_suspended = 1; + dev->driver->suspend(&dev->gadget); + spin_lock(&dev->lock); + } + } /* new speed ? */ + if (dev_irq & AMD_BIT(UDC_DEVINT_ENUM)) { + DBG(dev, "ENUM interrupt\n"); + ret_val = IRQ_HANDLED; + soft_reset_after_usbreset_occured = 0; + + /* disable ep0 to empty req queue */ + empty_req_queue(&dev->ep[UDC_EP0IN_IX]); + ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]); + + /* link up all endpoints */ + udc_setup_endpoints(dev); + if (dev->gadget.speed == USB_SPEED_HIGH) { + dev_info(&dev->pdev->dev, "Connect: speed = %s\n", + "high"); + } else if (dev->gadget.speed == USB_SPEED_FULL) { + dev_info(&dev->pdev->dev, "Connect: speed = %s\n", + "full"); + } + + /* init ep 0 */ + activate_control_endpoints(dev); + + /* enable ep0 interrupts */ + udc_enable_ep0_interrupts(dev); + } + /* session valid change interrupt */ + if (dev_irq & AMD_BIT(UDC_DEVINT_SVC)) { + DBG(dev, "USB SVC interrupt\n"); + ret_val = IRQ_HANDLED; + + /* check that session is not valid to detect disconnect */ + tmp = readl(&dev->regs->sts); + if (!(tmp & AMD_BIT(UDC_DEVSTS_SESSVLD))) { + /* disable suspend interrupt */ + tmp = readl(&dev->regs->irqmsk); + tmp |= AMD_BIT(UDC_DEVINT_US); + writel(tmp, &dev->regs->irqmsk); + DBG(dev, "USB Disconnect (session valid low)\n"); + /* cleanup on disconnect */ + usb_disconnect(udc); + } + + } + + return ret_val; +} + +/* Interrupt Service Routine, see Linux Kernel Doc for parameters */ +static irqreturn_t udc_irq(int irq, void *pdev) +{ + struct udc *dev = pdev; + u32 reg; + u16 i; + u32 ep_irq; + irqreturn_t ret_val = IRQ_NONE; + + spin_lock(&dev->lock); + + /* check for ep irq */ + reg = readl(&dev->regs->ep_irqsts); + if (reg) { + if (reg & AMD_BIT(UDC_EPINT_OUT_EP0)) + ret_val |= udc_control_out_isr(dev); + if (reg & AMD_BIT(UDC_EPINT_IN_EP0)) + ret_val |= udc_control_in_isr(dev); + + /* + * data endpoint + * iterate ep's + */ + for (i = 1; i < UDC_EP_NUM; i++) { + ep_irq = 1 << i; + if (!(reg & ep_irq) || i == UDC_EPINT_OUT_EP0) + continue; + + /* clear irq status */ + writel(ep_irq, &dev->regs->ep_irqsts); + + /* irq for out ep ? */ + if (i > UDC_EPIN_NUM) + ret_val |= udc_data_out_isr(dev, i); + else + ret_val |= udc_data_in_isr(dev, i); + } + + } + + + /* check for dev irq */ + reg = readl(&dev->regs->irqsts); + if (reg) { + /* clear irq */ + writel(reg, &dev->regs->irqsts); + ret_val |= udc_dev_isr(dev, reg); + } + + + spin_unlock(&dev->lock); + return ret_val; +} + +/* Tears down device */ +static void gadget_release(struct device *pdev) +{ + struct amd5536udc *dev = dev_get_drvdata(pdev); + kfree(dev); +} + +/* Cleanup on device remove */ +static void udc_remove(struct udc *dev) +{ + /* remove timer */ + stop_timer++; + if (timer_pending(&udc_timer)) + wait_for_completion(&on_exit); + if (udc_timer.data) + del_timer_sync(&udc_timer); + /* remove pollstall timer */ + stop_pollstall_timer++; + if (timer_pending(&udc_pollstall_timer)) + wait_for_completion(&on_pollstall_exit); + if (udc_pollstall_timer.data) + del_timer_sync(&udc_pollstall_timer); + udc = NULL; +} + +/* Reset all pci context */ +static void udc_pci_remove(struct pci_dev *pdev) +{ + struct udc *dev; + + dev = pci_get_drvdata(pdev); + + /* gadget driver must not be registered */ + BUG_ON(dev->driver != NULL); + + /* dma pool cleanup */ + if (dev->data_requests) + pci_pool_destroy(dev->data_requests); + + if (dev->stp_requests) { + /* cleanup DMA desc's for ep0in */ + pci_pool_free(dev->stp_requests, + dev->ep[UDC_EP0OUT_IX].td_stp, + dev->ep[UDC_EP0OUT_IX].td_stp_dma); + pci_pool_free(dev->stp_requests, + dev->ep[UDC_EP0OUT_IX].td, + dev->ep[UDC_EP0OUT_IX].td_phys); + + pci_pool_destroy(dev->stp_requests); + } + + /* reset controller */ + writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg); + if (dev->irq_registered) + free_irq(pdev->irq, dev); + if (dev->regs) + iounmap(dev->regs); + if (dev->mem_region) + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (dev->active) + pci_disable_device(pdev); + + device_unregister(&dev->gadget.dev); + pci_set_drvdata(pdev, NULL); + + udc_remove(dev); +} + +/* create dma pools on init */ +static int init_dma_pools(struct udc *dev) +{ + struct udc_stp_dma *td_stp; + struct udc_data_dma *td_data; + int retval; + + /* consistent DMA mode setting ? */ + if (use_dma_ppb) { + use_dma_bufferfill_mode = 0; + } else { + use_dma_ppb_du = 0; + use_dma_bufferfill_mode = 1; + } + + /* DMA setup */ + dev->data_requests = dma_pool_create("data_requests", NULL, + sizeof(struct udc_data_dma), 0, 0); + if (!dev->data_requests) { + DBG(dev, "can't get request data pool\n"); + retval = -ENOMEM; + goto finished; + } + + /* EP0 in dma regs = dev control regs */ + dev->ep[UDC_EP0IN_IX].dma = &dev->regs->ctl; + + /* dma desc for setup data */ + dev->stp_requests = dma_pool_create("setup requests", NULL, + sizeof(struct udc_stp_dma), 0, 0); + if (!dev->stp_requests) { + DBG(dev, "can't get stp request pool\n"); + retval = -ENOMEM; + goto finished; + } + /* setup */ + td_stp = dma_pool_alloc(dev->stp_requests, GFP_KERNEL, + &dev->ep[UDC_EP0OUT_IX].td_stp_dma); + if (td_stp == NULL) { + retval = -ENOMEM; + goto finished; + } + dev->ep[UDC_EP0OUT_IX].td_stp = td_stp; + + /* data: 0 packets !? */ + td_data = dma_pool_alloc(dev->stp_requests, GFP_KERNEL, + &dev->ep[UDC_EP0OUT_IX].td_phys); + if (td_data == NULL) { + retval = -ENOMEM; + goto finished; + } + dev->ep[UDC_EP0OUT_IX].td = td_data; + return 0; + +finished: + return retval; +} + +/* Called by pci bus driver to init pci context */ +static int udc_pci_probe( + struct pci_dev *pdev, + const struct pci_device_id *id +) +{ + struct udc *dev; + unsigned long resource; + unsigned long len; + int retval = 0; + + /* one udc only */ + if (udc) { + dev_dbg(&pdev->dev, "already probed\n"); + return -EBUSY; + } + + /* init */ + dev = kzalloc(sizeof(struct udc), GFP_KERNEL); + if (!dev) { + retval = -ENOMEM; + goto finished; + } + memset(dev, 0, sizeof(struct udc)); + + /* pci setup */ + if (pci_enable_device(pdev) < 0) { + retval = -ENODEV; + goto finished; + } + dev->active = 1; + + /* PCI resource allocation */ + resource = pci_resource_start(pdev, 0); + len = pci_resource_len(pdev, 0); + + if (!request_mem_region(resource, len, name)) { + dev_dbg(&pdev->dev, "pci device used already\n"); + retval = -EBUSY; + goto finished; + } + dev->mem_region = 1; + + dev->virt_addr = ioremap_nocache(resource, len); + if (dev->virt_addr == NULL) { + dev_dbg(&pdev->dev, "start address cannot be mapped\n"); + retval = -EFAULT; + goto finished; + } + + if (!pdev->irq) { + dev_err(&dev->pdev->dev, "irq not set\n"); + retval = -ENODEV; + goto finished; + } + + if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) { + dev_dbg(&dev->pdev->dev, "request_irq(%d) fail\n", pdev->irq); + retval = -EBUSY; + goto finished; + } + dev->irq_registered = 1; + + pci_set_drvdata(pdev, dev); + + /* chip revision */ + dev->chiprev = 0; + + 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); + if (retval != 0) + goto finished; + } + + dev->phys_addr = resource; + dev->irq = pdev->irq; + dev->pdev = pdev; + dev->gadget.dev.parent = &pdev->dev; + dev->gadget.dev.dma_mask = pdev->dev.dma_mask; + + /* general probing */ + if (udc_probe(dev) == 0) + return 0; + +finished: + if (dev) + udc_pci_remove(pdev); + return retval; +} + +/* general probe */ +static int udc_probe(struct udc *dev) +{ + char tmp[128]; + u32 reg; + int retval; + + /* mark timer as not initialized */ + udc_timer.data = 0; + udc_pollstall_timer.data = 0; + + /* device struct setup */ + spin_lock_init(&dev->lock); + dev->gadget.ops = &udc_ops; + + strcpy(dev->gadget.dev.bus_id, "gadget"); + dev->gadget.dev.release = gadget_release; + dev->gadget.name = name; + dev->gadget.name = name; + dev->gadget.is_dualspeed = 1; + + /* udc csr registers base */ + dev->csr = dev->virt_addr + UDC_CSR_ADDR; + /* dev registers base */ + dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR; + /* ep registers base */ + dev->ep_regs = dev->virt_addr + UDC_EPREGS_ADDR; + /* fifo's base */ + dev->rxfifo = (u32 __iomem *)(dev->virt_addr + UDC_RXFIFO_ADDR); + dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR); + + /* init registers, interrupts, ... */ + startup_registers(dev); + + dev_info(&dev->pdev->dev, "%s\n", mod_desc); + + snprintf(tmp, sizeof tmp, "%d", dev->irq); + dev_info(&dev->pdev->dev, + "irq %s, pci mem %08lx, chip rev %02x(Geode5536 %s)\n", + tmp, dev->phys_addr, dev->chiprev, + (dev->chiprev == UDC_HSA0_REV) ? "A0" : "B1"); + strcpy(tmp, UDC_DRIVER_VERSION_STRING); + if (dev->chiprev == UDC_HSA0_REV) { + dev_err(&dev->pdev->dev, "chip revision is A0; too old\n"); + retval = -ENODEV; + goto finished; + } + dev_info(&dev->pdev->dev, + "driver version: %s(for Geode5536 B1)\n", tmp); + udc = dev; + + retval = device_register(&dev->gadget.dev); + if (retval) + goto finished; + + /* timer init */ + init_timer(&udc_timer); + udc_timer.function = udc_timer_function; + udc_timer.data = 1; + /* timer pollstall init */ + init_timer(&udc_pollstall_timer); + udc_pollstall_timer.function = udc_pollstall_timer_function; + udc_pollstall_timer.data = 1; + + /* set SD */ + reg = readl(&dev->regs->ctl); + reg |= AMD_BIT(UDC_DEVCTL_SD); + writel(reg, &dev->regs->ctl); + + /* print dev register info */ + print_regs(dev); + + return 0; + +finished: + return retval; +} + +/* Initiates a remote wakeup */ +static int udc_remote_wakeup(struct udc *dev) +{ + unsigned long flags; + u32 tmp; + + DBG(dev, "UDC initiates remote wakeup\n"); + + spin_lock_irqsave(&dev->lock, flags); + + tmp = readl(&dev->regs->ctl); + tmp |= AMD_BIT(UDC_DEVCTL_RES); + writel(tmp, &dev->regs->ctl); + tmp &= AMD_CLEAR_BIT(UDC_DEVCTL_RES); + writel(tmp, &dev->regs->ctl); + + spin_unlock_irqrestore(&dev->lock, flags); + return 0; +} + +/* PCI device parameters */ +static const struct pci_device_id pci_id[] = { + { + PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x2096), + .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe, + .class_mask = 0xffffffff, + }, + {}, +}; +MODULE_DEVICE_TABLE(pci, pci_id); + +/* PCI functions */ +static struct pci_driver udc_pci_driver = { + .name = (char *) name, + .id_table = pci_id, + .probe = udc_pci_probe, + .remove = udc_pci_remove, +}; + +/* Inits driver */ +static int __init init(void) +{ + return pci_register_driver(&udc_pci_driver); +} +module_init(init); + +/* Cleans driver */ +static void __exit cleanup(void) +{ + pci_unregister_driver(&udc_pci_driver); +} +module_exit(cleanup); + +MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION); +MODULE_AUTHOR("Thomas Dahlmann"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/usb/gadget/amd5536udc.h b/drivers/usb/gadget/amd5536udc.h new file mode 100644 index 00000000000..4bbabbbfc93 --- /dev/null +++ b/drivers/usb/gadget/amd5536udc.h @@ -0,0 +1,626 @@ +/* + * amd5536.h -- header for AMD 5536 UDC high/full speed USB device controller + * + * Copyright (C) 2007 AMD (http://www.amd.com) + * Author: Thomas Dahlmann + * + * 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. + * + * 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. + * + * 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 + */ + +#ifndef AMD5536UDC_H +#define AMD5536UDC_H + +/* various constants */ +#define UDC_RDE_TIMER_SECONDS 1 +#define UDC_RDE_TIMER_DIV 10 +#define UDC_POLLSTALL_TIMER_USECONDS 500 + +/* Hs AMD5536 chip rev. */ +#define UDC_HSA0_REV 1 +#define UDC_HSB1_REV 2 + +/* + * SETUP usb commands + * needed, because some SETUP's are handled in hw, but must be passed to + * gadget driver above + * SET_CONFIG + */ +#define UDC_SETCONFIG_DWORD0 0x00000900 +#define UDC_SETCONFIG_DWORD0_VALUE_MASK 0xffff0000 +#define UDC_SETCONFIG_DWORD0_VALUE_OFS 16 + +#define UDC_SETCONFIG_DWORD1 0x00000000 + +/* SET_INTERFACE */ +#define UDC_SETINTF_DWORD0 0x00000b00 +#define UDC_SETINTF_DWORD0_ALT_MASK 0xffff0000 +#define UDC_SETINTF_DWORD0_ALT_OFS 16 + +#define UDC_SETINTF_DWORD1 0x00000000 +#define UDC_SETINTF_DWORD1_INTF_MASK 0x0000ffff +#define UDC_SETINTF_DWORD1_INTF_OFS 0 + +/* Mass storage reset */ +#define UDC_MSCRES_DWORD0 0x0000ff21 +#define UDC_MSCRES_DWORD1 0x00000000 + +/* Global CSR's -------------------------------------------------------------*/ +#define UDC_CSR_ADDR 0x500 + +/* EP NE bits */ +/* EP number */ +#define UDC_CSR_NE_NUM_MASK 0x0000000f +#define UDC_CSR_NE_NUM_OFS 0 +/* EP direction */ +#define UDC_CSR_NE_DIR_MASK 0x00000010 +#define UDC_CSR_NE_DIR_OFS 4 +/* EP type */ +#define UDC_CSR_NE_TYPE_MASK 0x00000060 +#define UDC_CSR_NE_TYPE_OFS 5 +/* EP config number */ +#define UDC_CSR_NE_CFG_MASK 0x00000780 +#define UDC_CSR_NE_CFG_OFS 7 +/* EP interface number */ +#define UDC_CSR_NE_INTF_MASK 0x00007800 +#define UDC_CSR_NE_INTF_OFS 11 +/* EP alt setting */ +#define UDC_CSR_NE_ALT_MASK 0x00078000 +#define UDC_CSR_NE_ALT_OFS 15 + +/* max pkt */ +#define UDC_CSR_NE_MAX_PKT_MASK 0x3ff80000 +#define UDC_CSR_NE_MAX_PKT_OFS 19 + +/* Device Config Register ---------------------------------------------------*/ +#define UDC_DEVCFG_ADDR 0x400 + +#define UDC_DEVCFG_SOFTRESET 31 +#define UDC_DEVCFG_HNPSFEN 30 +#define UDC_DEVCFG_DMARST 29 +#define UDC_DEVCFG_SET_DESC 18 +#define UDC_DEVCFG_CSR_PRG 17 +#define UDC_DEVCFG_STATUS 7 +#define UDC_DEVCFG_DIR 6 +#define UDC_DEVCFG_PI 5 +#define UDC_DEVCFG_SS 4 +#define UDC_DEVCFG_SP 3 +#define UDC_DEVCFG_RWKP 2 + +#define UDC_DEVCFG_SPD_MASK 0x3 +#define UDC_DEVCFG_SPD_OFS 0 +#define UDC_DEVCFG_SPD_HS 0x0 +#define UDC_DEVCFG_SPD_FS 0x1 +#define UDC_DEVCFG_SPD_LS 0x2 +/*#define UDC_DEVCFG_SPD_FS 0x3*/ + + +/* Device Control Register --------------------------------------------------*/ +#define UDC_DEVCTL_ADDR 0x404 + +#define UDC_DEVCTL_THLEN_MASK 0xff000000 +#define UDC_DEVCTL_THLEN_OFS 24 + +#define UDC_DEVCTL_BRLEN_MASK 0x00ff0000 +#define UDC_DEVCTL_BRLEN_OFS 16 + +#define UDC_DEVCTL_CSR_DONE 13 +#define UDC_DEVCTL_DEVNAK 12 +#define UDC_DEVCTL_SD 10 +#define UDC_DEVCTL_MODE 9 +#define UDC_DEVCTL_BREN 8 +#define UDC_DEVCTL_THE 7 +#define UDC_DEVCTL_BF 6 +#define UDC_DEVCTL_BE 5 +#define UDC_DEVCTL_DU 4 +#define UDC_DEVCTL_TDE 3 +#define UDC_DEVCTL_RDE 2 +#define UDC_DEVCTL_RES 0 + + +/* Device Status Register ---------------------------------------------------*/ +#define UDC_DEVSTS_ADDR 0x408 + +#define UDC_DEVSTS_TS_MASK 0xfffc0000 +#define UDC_DEVSTS_TS_OFS 18 + +#define UDC_DEVSTS_SESSVLD 17 +#define UDC_DEVSTS_PHY_ERROR 16 +#define UDC_DEVSTS_RXFIFO_EMPTY 15 + +#define UDC_DEVSTS_ENUM_SPEED_MASK 0x00006000 +#define UDC_DEVSTS_ENUM_SPEED_OFS 13 +#define UDC_DEVSTS_ENUM_SPEED_FULL 1 +#define UDC_DEVSTS_ENUM_SPEED_HIGH 0 + +#define UDC_DEVSTS_SUSP 12 + +#define UDC_DEVSTS_ALT_MASK 0x00000f00 +#define UDC_DEVSTS_ALT_OFS 8 + +#define UDC_DEVSTS_INTF_MASK 0x000000f0 +#define UDC_DEVSTS_INTF_OFS 4 + +#define UDC_DEVSTS_CFG_MASK 0x0000000f +#define UDC_DEVSTS_CFG_OFS 0 + + +/* Device Interrupt Register ------------------------------------------------*/ +#define UDC_DEVINT_ADDR 0x40c + +#define UDC_DEVINT_SVC 7 +#define UDC_DEVINT_ENUM 6 +#define UDC_DEVINT_SOF 5 +#define UDC_DEVINT_US 4 +#define UDC_DEVINT_UR 3 +#define UDC_DEVINT_ES 2 +#define UDC_DEVINT_SI 1 +#define UDC_DEVINT_SC 0 + +/* Device Interrupt Mask Register -------------------------------------------*/ +#define UDC_DEVINT_MSK_ADDR 0x410 + +#define UDC_DEVINT_MSK 0x7f + +/* Endpoint Interrupt Register ----------------------------------------------*/ +#define UDC_EPINT_ADDR 0x414 + +#define UDC_EPINT_OUT_MASK 0xffff0000 +#define UDC_EPINT_OUT_OFS 16 +#define UDC_EPINT_IN_MASK 0x0000ffff +#define UDC_EPINT_IN_OFS 0 + +#define UDC_EPINT_IN_EP0 0 +#define UDC_EPINT_IN_EP1 1 +#define UDC_EPINT_IN_EP2 2 +#define UDC_EPINT_IN_EP3 3 +#define UDC_EPINT_OUT_EP0 16 +#define UDC_EPINT_OUT_EP1 17 +#define UDC_EPINT_OUT_EP2 18 +#define UDC_EPINT_OUT_EP3 19 + +#define UDC_EPINT_EP0_ENABLE_MSK 0x001e001e + +/* Endpoint Interrupt Mask Register -----------------------------------------*/ +#define UDC_EPINT_MSK_ADDR 0x418 + +#define UDC_EPINT_OUT_MSK_MASK 0xffff0000 +#define UDC_EPINT_OUT_MSK_OFS 16 +#define UDC_EPINT_IN_MSK_MASK 0x0000ffff +#define UDC_EPINT_IN_MSK_OFS 0 + +#define UDC_EPINT_MSK_DISABLE_ALL 0xffffffff +/* mask non-EP0 endpoints */ +#define UDC_EPDATAINT_MSK_DISABLE 0xfffefffe +/* mask all dev interrupts */ +#define UDC_DEV_MSK_DISABLE 0x7f + +/* Endpoint-specific CSR's --------------------------------------------------*/ +#define UDC_EPREGS_ADDR 0x0 +#define UDC_EPIN_REGS_ADDR 0x0 +#define UDC_EPOUT_REGS_ADDR 0x200 + +#define UDC_EPCTL_ADDR 0x0 + +#define UDC_EPCTL_RRDY 9 +#define UDC_EPCTL_CNAK 8 +#define UDC_EPCTL_SNAK 7 +#define UDC_EPCTL_NAK 6 + +#define UDC_EPCTL_ET_MASK 0x00000030 +#define UDC_EPCTL_ET_OFS 4 +#define UDC_EPCTL_ET_CONTROL 0 +#define UDC_EPCTL_ET_ISO 1 +#define UDC_EPCTL_ET_BULK 2 +#define UDC_EPCTL_ET_INTERRUPT 3 + +#define UDC_EPCTL_P 3 +#define UDC_EPCTL_SN 2 +#define UDC_EPCTL_F 1 +#define UDC_EPCTL_S 0 + +/* Endpoint Status Registers ------------------------------------------------*/ +#define UDC_EPSTS_ADDR 0x4 + +#define UDC_EPSTS_RX_PKT_SIZE_MASK 0x007ff800 +#define UDC_EPSTS_RX_PKT_SIZE_OFS 11 + +#define UDC_EPSTS_TDC 10 +#define UDC_EPSTS_HE 9 +#define UDC_EPSTS_BNA 7 +#define UDC_EPSTS_IN 6 + +#define UDC_EPSTS_OUT_MASK 0x00000030 +#define UDC_EPSTS_OUT_OFS 4 +#define UDC_EPSTS_OUT_DATA 1 +#define UDC_EPSTS_OUT_DATA_CLEAR 0x10 +#define UDC_EPSTS_OUT_SETUP 2 +#define UDC_EPSTS_OUT_SETUP_CLEAR 0x20 +#define UDC_EPSTS_OUT_CLEAR 0x30 + +/* Endpoint Buffer Size IN/ Receive Packet Frame Number OUT Registers ------*/ +#define UDC_EPIN_BUFF_SIZE_ADDR 0x8 +#define UDC_EPOUT_FRAME_NUMBER_ADDR 0x8 + +#define UDC_EPIN_BUFF_SIZE_MASK 0x0000ffff +#define UDC_EPIN_BUFF_SIZE_OFS 0 +/* EP0in txfifo = 128 bytes*/ +#define UDC_EPIN0_BUFF_SIZE 32 +/* EP0in fullspeed txfifo = 128 bytes*/ +#define UDC_FS_EPIN0_BUFF_SIZE 32 + +/* fifo size mult = fifo size / max packet */ +#define UDC_EPIN_BUFF_SIZE_MULT 2 + +/* EPin data fifo size = 1024 bytes DOUBLE BUFFERING */ +#define UDC_EPIN_BUFF_SIZE 256 +/* EPin small INT data fifo size = 128 bytes */ +#define UDC_EPIN_SMALLINT_BUFF_SIZE 32 + +/* EPin fullspeed data fifo size = 128 bytes DOUBLE BUFFERING */ +#define UDC_FS_EPIN_BUFF_SIZE 32 + +#define UDC_EPOUT_FRAME_NUMBER_MASK 0x0000ffff +#define UDC_EPOUT_FRAME_NUMBER_OFS 0 + +/* Endpoint Buffer Size OUT/Max Packet Size Registers -----------------------*/ +#define UDC_EPOUT_BUFF_SIZE_ADDR 0x0c +#define UDC_EP_MAX_PKT_SIZE_ADDR 0x0c + +#define UDC_EPOUT_BUFF_SIZE_MASK 0xffff0000 +#define UDC_EPOUT_BUFF_SIZE_OFS 16 +#define UDC_EP_MAX_PKT_SIZE_MASK 0x0000ffff +#define UDC_EP_MAX_PKT_SIZE_OFS 0 +/* EP0in max packet size = 64 bytes */ +#define UDC_EP0IN_MAX_PKT_SIZE 64 +/* EP0out max packet size = 64 bytes */ +#define UDC_EP0OUT_MAX_PKT_SIZE 64 +/* EP0in fullspeed max packet size = 64 bytes */ +#define UDC_FS_EP0IN_MAX_PKT_SIZE 64 +/* EP0out fullspeed max packet size = 64 bytes */ +#define UDC_FS_EP0OUT_MAX_PKT_SIZE 64 + +/* + * Endpoint dma descriptors ------------------------------------------------ + * + * Setup data, Status dword + */ +#define UDC_DMA_STP_STS_CFG_MASK 0x0fff0000 +#define UDC_DMA_STP_STS_CFG_OFS 16 +#define UDC_DMA_STP_STS_CFG_ALT_MASK 0x000f0000 +#define UDC_DMA_STP_STS_CFG_ALT_OFS 16 +#define UDC_DMA_STP_STS_CFG_INTF_MASK 0x00f00000 +#define UDC_DMA_STP_STS_CFG_INTF_OFS 20 +#define UDC_DMA_STP_STS_CFG_NUM_MASK 0x0f000000 +#define UDC_DMA_STP_STS_CFG_NUM_OFS 24 +#define UDC_DMA_STP_STS_RX_MASK 0x30000000 +#define UDC_DMA_STP_STS_RX_OFS 28 +#define UDC_DMA_STP_STS_BS_MASK 0xc0000000 +#define UDC_DMA_STP_STS_BS_OFS 30 +#define UDC_DMA_STP_STS_BS_HOST_READY 0 +#define UDC_DMA_STP_STS_BS_DMA_BUSY 1 +#define UDC_DMA_STP_STS_BS_DMA_DONE 2 +#define UDC_DMA_STP_STS_BS_HOST_BUSY 3 +/* IN data, Status dword */ +#define UDC_DMA_IN_STS_TXBYTES_MASK 0x0000ffff +#define UDC_DMA_IN_STS_TXBYTES_OFS 0 +#define UDC_DMA_IN_STS_FRAMENUM_MASK 0x07ff0000 +#define UDC_DMA_IN_STS_FRAMENUM_OFS 0 +#define UDC_DMA_IN_STS_L 27 +#define UDC_DMA_IN_STS_TX_MASK 0x30000000 +#define UDC_DMA_IN_STS_TX_OFS 28 +#define UDC_DMA_IN_STS_BS_MASK 0xc0000000 +#define UDC_DMA_IN_STS_BS_OFS 30 +#define UDC_DMA_IN_STS_BS_HOST_READY 0 +#define UDC_DMA_IN_STS_BS_DMA_BUSY 1 +#define UDC_DMA_IN_STS_BS_DMA_DONE 2 +#define UDC_DMA_IN_STS_BS_HOST_BUSY 3 +/* OUT data, Status dword */ +#define UDC_DMA_OUT_STS_RXBYTES_MASK 0x0000ffff +#define UDC_DMA_OUT_STS_RXBYTES_OFS 0 +#define UDC_DMA_OUT_STS_FRAMENUM_MASK 0x07ff0000 +#define UDC_DMA_OUT_STS_FRAMENUM_OFS 0 +#define UDC_DMA_OUT_STS_L 27 +#define UDC_DMA_OUT_STS_RX_MASK 0x30000000 +#define UDC_DMA_OUT_STS_RX_OFS 28 +#define UDC_DMA_OUT_STS_BS_MASK 0xc0000000 +#define UDC_DMA_OUT_STS_BS_OFS 30 +#define UDC_DMA_OUT_STS_BS_HOST_READY 0 +#define UDC_DMA_OUT_STS_BS_DMA_BUSY 1 +#define UDC_DMA_OUT_STS_BS_DMA_DONE 2 +#define UDC_DMA_OUT_STS_BS_HOST_BUSY 3 +/* max ep0in packet */ +#define UDC_EP0IN_MAXPACKET 1000 +/* max dma packet */ +#define UDC_DMA_MAXPACKET 65536 + +/* un-usable DMA address */ +#define DMA_DONT_USE (~(dma_addr_t) 0 ) + +/* other Endpoint register addresses and values-----------------------------*/ +#define UDC_EP_SUBPTR_ADDR 0x10 +#define UDC_EP_DESPTR_ADDR 0x14 +#define UDC_EP_WRITE_CONFIRM_ADDR 0x1c + +/* EP number as layouted in AHB space */ +#define UDC_EP_NUM 32 +#define UDC_EPIN_NUM 16 +#define UDC_EPIN_NUM_USED 5 +#define UDC_EPOUT_NUM 16 +/* EP number of EP's really used = EP0 + 8 data EP's */ +#define UDC_USED_EP_NUM 9 +/* UDC CSR regs are aligned but AHB regs not - offset for OUT EP's */ +#define UDC_CSR_EP_OUT_IX_OFS 12 + +#define UDC_EP0OUT_IX 16 +#define UDC_EP0IN_IX 0 + +/* Rx fifo address and size = 1k -------------------------------------------*/ +#define UDC_RXFIFO_ADDR 0x800 +#define UDC_RXFIFO_SIZE 0x400 + +/* Tx fifo address and size = 1.5k -----------------------------------------*/ +#define UDC_TXFIFO_ADDR 0xc00 +#define UDC_TXFIFO_SIZE 0x600 + +/* default data endpoints --------------------------------------------------*/ +#define UDC_EPIN_STATUS_IX 1 +#define UDC_EPIN_IX 2 +#define UDC_EPOUT_IX 18 + +/* general constants -------------------------------------------------------*/ +#define UDC_DWORD_BYTES 4 +#define UDC_BITS_PER_BYTE_SHIFT 3 +#define UDC_BYTE_MASK 0xff +#define UDC_BITS_PER_BYTE 8 + +/*---------------------------------------------------------------------------*/ +/* UDC CSR's */ +struct udc_csrs { + + /* sca - setup command address */ + u32 sca; + + /* ep ne's */ + u32 ne[UDC_USED_EP_NUM]; +} __attribute__ ((packed)); + +/* AHB subsystem CSR registers */ +struct udc_regs { + + /* device configuration */ + u32 cfg; + + /* device control */ + u32 ctl; + + /* device status */ + u32 sts; + + /* device interrupt */ + u32 irqsts; + + /* device interrupt mask */ + u32 irqmsk; + + /* endpoint interrupt */ + u32 ep_irqsts; + + /* endpoint interrupt mask */ + u32 ep_irqmsk; +} __attribute__ ((packed)); + +/* endpoint specific registers */ +struct udc_ep_regs { + + /* endpoint control */ + u32 ctl; + + /* endpoint status */ + u32 sts; + + /* endpoint buffer size in/ receive packet frame number out */ + u32 bufin_framenum; + + /* endpoint buffer size out/max packet size */ + u32 bufout_maxpkt; + + /* endpoint setup buffer pointer */ + u32 subptr; + + /* endpoint data descriptor pointer */ + u32 desptr; + + /* reserverd */ + u32 reserved; + + /* write/read confirmation */ + u32 confirm; + +} __attribute__ ((packed)); + +/* control data DMA desc */ +struct udc_stp_dma { + /* status quadlet */ + u32 status; + /* reserved */ + u32 _reserved; + /* first setup word */ + u32 data12; + /* second setup word */ + u32 data34; +} __attribute__ ((aligned (16))); + +/* normal data DMA desc */ +struct udc_data_dma { + /* status quadlet */ + u32 status; + /* reserved */ + u32 _reserved; + /* buffer pointer */ + u32 bufptr; + /* next descriptor pointer */ + u32 next; +} __attribute__ ((aligned (16))); + +/* request packet */ +struct udc_request { + /* embedded gadget ep */ + struct usb_request req; + + /* flags */ + unsigned dma_going : 1, + dma_mapping : 1, + dma_done : 1; + /* phys. address */ + dma_addr_t td_phys; + /* first dma desc. of chain */ + struct udc_data_dma *td_data; + /* last dma desc. of chain */ + struct udc_data_dma *td_data_last; + struct list_head queue; + + /* chain length */ + unsigned chain_len; + +}; + +/* UDC specific endpoint parameters */ +struct udc_ep { + struct usb_ep ep; + struct udc_ep_regs __iomem *regs; + u32 __iomem *txfifo; + u32 __iomem *dma; + dma_addr_t td_phys; + dma_addr_t td_stp_dma; + struct udc_stp_dma *td_stp; + struct udc_data_dma *td; + /* temp request */ + struct udc_request *req; + unsigned req_used; + unsigned req_completed; + /* dummy DMA desc for BNA dummy */ + struct udc_request *bna_dummy_req; + unsigned bna_occurred; + + /* NAK state */ + unsigned naking; + + struct udc *dev; + + /* queue for requests */ + struct list_head queue; + const struct usb_endpoint_descriptor *desc; + unsigned halted; + unsigned cancel_transfer; + unsigned num : 5, + fifo_depth : 14, + in : 1; +}; + +/* device struct */ +struct udc { + struct usb_gadget gadget; + spinlock_t lock; /* protects all state */ + /* all endpoints */ + struct udc_ep ep[UDC_EP_NUM]; + struct usb_gadget_driver *driver; + /* operational flags */ + unsigned active : 1, + stall_ep0in : 1, + waiting_zlp_ack_ep0in : 1, + set_cfg_not_acked : 1, + irq_registered : 1, + data_ep_enabled : 1, + data_ep_queued : 1, + mem_region : 1, + sys_suspended : 1, + connected; + + u16 chiprev; + + /* registers */ + struct pci_dev *pdev; + struct udc_csrs __iomem *csr; + struct udc_regs __iomem *regs; + struct udc_ep_regs __iomem *ep_regs; + u32 __iomem *rxfifo; + u32 __iomem *txfifo; + + /* DMA desc pools */ + struct pci_pool *data_requests; + struct pci_pool *stp_requests; + + /* device data */ + unsigned long phys_addr; + void __iomem *virt_addr; + unsigned irq; + + /* states */ + u16 cur_config; + u16 cur_intf; + u16 cur_alt; +}; + +/* setup request data */ +union udc_setup_data { + u32 data[2]; + struct usb_ctrlrequest request; +}; + +/* + *--------------------------------------------------------------------------- + * SET and GET bitfields in u32 values + * via constants for mask/offset: + * <bit_field_stub_name> is the text between + * UDC_ and _MASK|_OFS of appropiate + * constant + * + * set bitfield value in u32 u32Val + */ +#define AMD_ADDBITS(u32Val, bitfield_val, bitfield_stub_name) \ + (((u32Val) & (((u32) ~((u32) bitfield_stub_name##_MASK)))) \ + | (((bitfield_val) << ((u32) bitfield_stub_name##_OFS)) \ + & ((u32) bitfield_stub_name##_MASK))) + +/* + * set bitfield value in zero-initialized u32 u32Val + * => bitfield bits in u32Val are all zero + */ +#define AMD_INIT_SETBITS(u32Val, bitfield_val, bitfield_stub_name) \ + ((u32Val) \ + | (((bitfield_val) << ((u32) bitfield_stub_name##_OFS)) \ + & ((u32) bitfield_stub_name##_MASK))) + +/* get bitfield value from u32 u32Val */ +#define AMD_GETBITS(u32Val, bitfield_stub_name) \ + ((u32Val & ((u32) bitfield_stub_name##_MASK)) \ + >> ((u32) bitfield_stub_name##_OFS)) + +/* SET and GET bits in u32 values ------------------------------------------*/ +#define AMD_BIT(bit_stub_name) (1 << bit_stub_name) +#define AMD_UNMASK_BIT(bit_stub_name) (~AMD_BIT(bit_stub_name)) +#define AMD_CLEAR_BIT(bit_stub_name) (~AMD_BIT(bit_stub_name)) + +/* debug macros ------------------------------------------------------------*/ + +#define DBG(udc , args...) dev_dbg(&(udc)->pdev->dev, args) + +#ifdef UDC_VERBOSE +#define VDBG DBG +#else +#define VDBG(udc , args...) do {} while (0) +#endif + +#endif /* #ifdef AMD5536UDC_H */ diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index dbaf867436d..a3376739a81 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -305,6 +305,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); #define DEV_CONFIG_CDC #endif +#ifdef CONFIG_USB_GADGET_AMD5536UDC +#define DEV_CONFIG_CDC +#endif + /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h index 53e9139ba38..f7f159c1002 100644 --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h @@ -17,6 +17,12 @@ #define gadget_is_net2280(g) 0 #endif +#ifdef CONFIG_USB_GADGET_AMD5536UDC +#define gadget_is_amd5536udc(g) !strcmp("amd5536udc", (g)->name) +#else +#define gadget_is_amd5536udc(g) 0 +#endif + #ifdef CONFIG_USB_GADGET_DUMMY_HCD #define gadget_is_dummy(g) !strcmp("dummy_udc", (g)->name) #else @@ -202,7 +208,9 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget) return 0x18; else if (gadget_is_fsl_usb2(gadget)) return 0x19; - else if (gadget_is_m66592(gadget)) + else if (gadget_is_amd5536udc(gadget)) return 0x20; + else if (gadget_is_m66592(gadget)) + return 0x21; return -ENOENT; } diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 0174a322e00..700dda8a915 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -21,26 +21,18 @@ */ #include <linux/module.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/smp_lock.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/timer.h> -#include <linux/delay.h> -#include <linux/list.h> #include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/io.h> #include <linux/platform_device.h> + #include <linux/usb/ch9.h> #include <linux/usb_gadget.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/system.h> - #include "m66592-udc.h" -MODULE_DESCRIPTION("M66592 USB gadget driiver"); + +MODULE_DESCRIPTION("M66592 USB gadget driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Yoshihiro Shimoda"); @@ -49,16 +41,21 @@ MODULE_AUTHOR("Yoshihiro Shimoda"); /* module parameters */ static unsigned short clock = M66592_XTAL24; module_param(clock, ushort, 0644); -MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0(default=16384)"); +MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 " + "(default=16384)"); + static unsigned short vif = M66592_LDRV; module_param(vif, ushort, 0644); -MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0(default=32768)"); -static unsigned short endian = 0; +MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0 (default=32768)"); + +static unsigned short endian; module_param(endian, ushort, 0644); -MODULE_PARM_DESC(endian, "data endian: big=256, little=0(default=0)"); +MODULE_PARM_DESC(endian, "data endian: big=256, little=0 (default=0)"); + static unsigned short irq_sense = M66592_INTL; module_param(irq_sense, ushort, 0644); -MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=2, falling edge=0(default=2)"); +MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=2, falling edge=0 " + "(default=2)"); static const char udc_name[] = "m66592_udc"; static const char *m66592_ep_name[] = { @@ -72,8 +69,8 @@ static int m66592_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags); static void transfer_complete(struct m66592_ep *ep, - struct m66592_request *req, - int status); + struct m66592_request *req, int status); + /*-------------------------------------------------------------------------*/ static inline u16 get_usb_speed(struct m66592 *m66592) { @@ -81,25 +78,25 @@ static inline u16 get_usb_speed(struct m66592 *m66592) } static void enable_pipe_irq(struct m66592 *m66592, u16 pipenum, - unsigned long reg) + unsigned long reg) { u16 tmp; tmp = m66592_read(m66592, M66592_INTENB0); m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE, - M66592_INTENB0); + M66592_INTENB0); m66592_bset(m66592, (1 << pipenum), reg); m66592_write(m66592, tmp, M66592_INTENB0); } static void disable_pipe_irq(struct m66592 *m66592, u16 pipenum, - unsigned long reg) + unsigned long reg) { u16 tmp; tmp = m66592_read(m66592, M66592_INTENB0); m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE, - M66592_INTENB0); + M66592_INTENB0); m66592_bclr(m66592, (1 << pipenum), reg); m66592_write(m66592, tmp, M66592_INTENB0); } @@ -108,17 +105,19 @@ static void m66592_usb_connect(struct m66592 *m66592) { m66592_bset(m66592, M66592_CTRE, M66592_INTENB0); m66592_bset(m66592, M66592_WDST | M66592_RDST | M66592_CMPL, - M66592_INTENB0); + M66592_INTENB0); m66592_bset(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0); m66592_bset(m66592, M66592_DPRPU, M66592_SYSCFG); } static void m66592_usb_disconnect(struct m66592 *m66592) +__releases(m66592->lock) +__acquires(m66592->lock) { m66592_bclr(m66592, M66592_CTRE, M66592_INTENB0); m66592_bclr(m66592, M66592_WDST | M66592_RDST | M66592_CMPL, - M66592_INTENB0); + M66592_INTENB0); m66592_bclr(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0); m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG); @@ -148,7 +147,7 @@ static inline u16 control_reg_get_pid(struct m66592 *m66592, u16 pipenum) } static inline void control_reg_set_pid(struct m66592 *m66592, u16 pipenum, - u16 pid) + u16 pid) { unsigned long offset; @@ -250,7 +249,7 @@ static inline void pipe_change(struct m66592 *m66592, u16 pipenum) } static int pipe_buffer_setting(struct m66592 *m66592, - struct m66592_pipe_info *info) + struct m66592_pipe_info *info) { u16 bufnum = 0, buf_bsize = 0; u16 pipecfg = 0; @@ -287,7 +286,7 @@ static int pipe_buffer_setting(struct m66592 *m66592, } if (m66592->bi_bufnum > M66592_MAX_BUFNUM) { printk(KERN_ERR "m66592 pipe memory is insufficient(%d)\n", - m66592->bi_bufnum); + m66592->bi_bufnum); return -ENOMEM; } @@ -328,7 +327,7 @@ static void pipe_buffer_release(struct m66592 *m66592, m66592->bulk--; } else printk(KERN_ERR "ep_release: unexpect pipenum (%d)\n", - info->pipe); + info->pipe); } static void pipe_initialize(struct m66592_ep *ep) @@ -350,8 +349,8 @@ static void pipe_initialize(struct m66592_ep *ep) } static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep, - const struct usb_endpoint_descriptor *desc, - u16 pipenum, int dma) + const struct usb_endpoint_descriptor *desc, + u16 pipenum, int dma) { if ((pipenum != 0) && dma) { if (m66592->num_dma == 0) { @@ -385,7 +384,7 @@ static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep, ep->pipectr = get_pipectr_addr(pipenum); ep->pipenum = pipenum; - ep->ep.maxpacket = desc->wMaxPacketSize; + ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize); m66592->pipenum2ep[pipenum] = ep; m66592->epaddr2ep[desc->bEndpointAddress&USB_ENDPOINT_NUMBER_MASK] = ep; INIT_LIST_HEAD(&ep->queue); @@ -407,7 +406,7 @@ static void m66592_ep_release(struct m66592_ep *ep) } static int alloc_pipe_config(struct m66592_ep *ep, - const struct usb_endpoint_descriptor *desc) + const struct usb_endpoint_descriptor *desc) { struct m66592 *m66592 = ep->m66592; struct m66592_pipe_info info; @@ -419,15 +418,15 @@ static int alloc_pipe_config(struct m66592_ep *ep, BUG_ON(ep->pipenum); - switch(desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { case USB_ENDPOINT_XFER_BULK: if (m66592->bulk >= M66592_MAX_NUM_BULK) { if (m66592->isochronous >= M66592_MAX_NUM_ISOC) { printk(KERN_ERR "bulk pipe is insufficient\n"); return -ENODEV; } else { - info.pipe = M66592_BASE_PIPENUM_ISOC + - m66592->isochronous; + info.pipe = M66592_BASE_PIPENUM_ISOC + + m66592->isochronous; counter = &m66592->isochronous; } } else { @@ -462,7 +461,7 @@ static int alloc_pipe_config(struct m66592_ep *ep, ep->type = info.type; info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - info.maxpacket = desc->wMaxPacketSize; + info.maxpacket = le16_to_cpu(desc->wMaxPacketSize); info.interval = desc->bInterval; if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) info.dir_in = 1; @@ -525,8 +524,8 @@ static void start_ep0_write(struct m66592_ep *ep, struct m66592_request *req) pipe_change(m66592, ep->pipenum); m66592_mdfy(m66592, M66592_ISEL | M66592_PIPE0, - (M66592_ISEL | M66592_CURPIPE), - M66592_CFIFOSEL); + (M66592_ISEL | M66592_CURPIPE), + M66592_CFIFOSEL); m66592_write(m66592, M66592_BCLR, ep->fifoctr); if (req->req.length == 0) { m66592_bset(m66592, M66592_BVAL, ep->fifoctr); @@ -561,8 +560,8 @@ static void start_packet_read(struct m66592_ep *ep, struct m66592_request *req) if (ep->pipenum == 0) { m66592_mdfy(m66592, M66592_PIPE0, - (M66592_ISEL | M66592_CURPIPE), - M66592_CFIFOSEL); + (M66592_ISEL | M66592_CURPIPE), + M66592_CFIFOSEL); m66592_write(m66592, M66592_BCLR, ep->fifoctr); pipe_start(m66592, pipenum); pipe_irq_enable(m66592, pipenum); @@ -572,8 +571,9 @@ static void start_packet_read(struct m66592_ep *ep, struct m66592_request *req) pipe_change(m66592, pipenum); m66592_bset(m66592, M66592_TRENB, ep->fifosel); m66592_write(m66592, - (req->req.length + ep->ep.maxpacket - 1) / - ep->ep.maxpacket, ep->fifotrn); + (req->req.length + ep->ep.maxpacket - 1) + / ep->ep.maxpacket, + ep->fifotrn); } pipe_start(m66592, pipenum); /* trigger once */ pipe_irq_enable(m66592, pipenum); @@ -614,7 +614,7 @@ static void start_ep0(struct m66592_ep *ep, struct m66592_request *req) static void init_controller(struct m66592 *m66592) { m66592_bset(m66592, (vif & M66592_LDRV) | (endian & M66592_BIGEND), - M66592_PINCFG); + M66592_PINCFG); m66592_bset(m66592, M66592_HSE, M66592_SYSCFG); /* High spd */ m66592_mdfy(m66592, clock & M66592_XTAL, M66592_XTAL, M66592_SYSCFG); @@ -634,7 +634,7 @@ static void init_controller(struct m66592 *m66592) m66592_bset(m66592, irq_sense & M66592_INTL, M66592_INTENB1); m66592_write(m66592, M66592_BURST | M66592_CPU_ADR_RD_WR, - M66592_DMA0CFG); + M66592_DMA0CFG); } static void disable_controller(struct m66592 *m66592) @@ -659,8 +659,9 @@ static void m66592_start_xclock(struct m66592 *m66592) /*-------------------------------------------------------------------------*/ static void transfer_complete(struct m66592_ep *ep, - struct m66592_request *req, - int status) + struct m66592_request *req, int status) +__releases(m66592->lock) +__acquires(m66592->lock) { int restart = 0; @@ -680,8 +681,9 @@ static void transfer_complete(struct m66592_ep *ep, if (!list_empty(&ep->queue)) restart = 1; - if (likely(req->req.complete)) - req->req.complete(&ep->ep, &req->req); + spin_unlock(&ep->m66592->lock); + req->req.complete(&ep->ep, &req->req); + spin_lock(&ep->m66592->lock); if (restart) { req = list_entry(ep->queue.next, struct m66592_request, queue); @@ -693,7 +695,7 @@ static void transfer_complete(struct m66592_ep *ep, static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req) { int i; - volatile u16 tmp; + u16 tmp; unsigned bufsize; size_t size; void *buf; @@ -731,8 +733,9 @@ static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req) req->req.actual += size; /* check transfer finish */ - if ((!req->req.zero && (req->req.actual == req->req.length)) || - (size % ep->ep.maxpacket) || (size == 0)) { + if ((!req->req.zero && (req->req.actual == req->req.length)) + || (size % ep->ep.maxpacket) + || (size == 0)) { disable_irq_ready(m66592, pipenum); disable_irq_empty(m66592, pipenum); } else { @@ -768,16 +771,19 @@ static void irq_packet_write(struct m66592_ep *ep, struct m66592_request *req) /* write fifo */ if (req->req.buf) { m66592_write_fifo(m66592, ep->fifoaddr, buf, size); - if ((size == 0) || ((size % ep->ep.maxpacket) != 0) || - ((bufsize != ep->ep.maxpacket) && (bufsize > size))) + if ((size == 0) + || ((size % ep->ep.maxpacket) != 0) + || ((bufsize != ep->ep.maxpacket) + && (bufsize > size))) m66592_bset(m66592, M66592_BVAL, ep->fifoctr); } /* update parameters */ req->req.actual += size; /* check transfer finish */ - if ((!req->req.zero && (req->req.actual == req->req.length)) || - (size % ep->ep.maxpacket) || (size == 0)) { + if ((!req->req.zero && (req->req.actual == req->req.length)) + || (size % ep->ep.maxpacket) + || (size == 0)) { disable_irq_ready(m66592, pipenum); enable_irq_empty(m66592, pipenum); } else { @@ -821,8 +827,9 @@ static void irq_packet_read(struct m66592_ep *ep, struct m66592_request *req) req->req.actual += size; /* check transfer finish */ - if ((!req->req.zero && (req->req.actual == req->req.length)) || - (size % ep->ep.maxpacket) || (size == 0)) { + if ((!req->req.zero && (req->req.actual == req->req.length)) + || (size % ep->ep.maxpacket) + || (size == 0)) { pipe_stop(m66592, pipenum); pipe_irq_disable(m66592, pipenum); finish = 1; @@ -850,7 +857,7 @@ static void irq_pipe_ready(struct m66592 *m66592, u16 status, u16 enb) if ((status & M66592_BRDY0) && (enb & M66592_BRDY0)) { m66592_write(m66592, ~M66592_BRDY0, M66592_BRDYSTS); m66592_mdfy(m66592, M66592_PIPE0, M66592_CURPIPE, - M66592_CFIFOSEL); + M66592_CFIFOSEL); ep = &m66592->ep[0]; req = list_entry(ep->queue.next, struct m66592_request, queue); @@ -909,23 +916,26 @@ static void irq_pipe_empty(struct m66592 *m66592, u16 status, u16 enb) } static void get_status(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) +__releases(m66592->lock) +__acquires(m66592->lock) { struct m66592_ep *ep; u16 pid; u16 status = 0; + u16 w_index = le16_to_cpu(ctrl->wIndex); switch (ctrl->bRequestType & USB_RECIP_MASK) { case USB_RECIP_DEVICE: - status = 1; /* selfpower */ + status = 1 << USB_DEVICE_SELF_POWERED; break; case USB_RECIP_INTERFACE: status = 0; break; case USB_RECIP_ENDPOINT: - ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK]; + ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK]; pid = control_reg_get_pid(m66592, ep->pipenum); if (pid == M66592_PID_STALL) - status = 1; + status = 1 << USB_ENDPOINT_HALT; else status = 0; break; @@ -934,11 +944,13 @@ static void get_status(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) return; /* exit */ } - *m66592->ep0_buf = status; - m66592->ep0_req->buf = m66592->ep0_buf; + m66592->ep0_data = cpu_to_le16(status); + m66592->ep0_req->buf = &m66592->ep0_data; m66592->ep0_req->length = 2; /* AV: what happens if we get called again before that gets through? */ + spin_unlock(&m66592->lock); m66592_queue(m66592->gadget.ep0, m66592->ep0_req, GFP_KERNEL); + spin_lock(&m66592->lock); } static void clear_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) @@ -953,8 +965,9 @@ static void clear_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) case USB_RECIP_ENDPOINT: { struct m66592_ep *ep; struct m66592_request *req; + u16 w_index = le16_to_cpu(ctrl->wIndex); - ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK]; + ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK]; pipe_stop(m66592, ep->pipenum); control_reg_sqclr(m66592, ep->pipenum); @@ -989,8 +1002,9 @@ static void set_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) break; case USB_RECIP_ENDPOINT: { struct m66592_ep *ep; + u16 w_index = le16_to_cpu(ctrl->wIndex); - ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK]; + ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK]; pipe_stall(m66592, ep->pipenum); control_end(m66592, 1); @@ -1066,14 +1080,16 @@ static void irq_device_state(struct m66592 *m66592) } if (m66592->old_dvsq == M66592_DS_CNFG && dvsq != M66592_DS_CNFG) m66592_update_usb_speed(m66592); - if ((dvsq == M66592_DS_CNFG || dvsq == M66592_DS_ADDS) && - m66592->gadget.speed == USB_SPEED_UNKNOWN) + if ((dvsq == M66592_DS_CNFG || dvsq == M66592_DS_ADDS) + && m66592->gadget.speed == USB_SPEED_UNKNOWN) m66592_update_usb_speed(m66592); m66592->old_dvsq = dvsq; } static void irq_control_stage(struct m66592 *m66592) +__releases(m66592->lock) +__acquires(m66592->lock) { struct usb_ctrlrequest ctrl; u16 ctsq; @@ -1095,8 +1111,10 @@ static void irq_control_stage(struct m66592 *m66592) case M66592_CS_WRDS: case M66592_CS_WRND: if (setup_packet(m66592, &ctrl)) { + spin_unlock(&m66592->lock); if (m66592->driver->setup(&m66592->gadget, &ctrl) < 0) pipe_stall(m66592, 0); + spin_lock(&m66592->lock); } break; case M66592_CS_RDSS: @@ -1119,6 +1137,8 @@ static irqreturn_t m66592_irq(int irq, void *_m66592) u16 savepipe; u16 mask0; + spin_lock(&m66592->lock); + intsts0 = m66592_read(m66592, M66592_INTSTS0); intenb0 = m66592_read(m66592, M66592_INTENB0); @@ -1134,27 +1154,27 @@ static irqreturn_t m66592_irq(int irq, void *_m66592) bempenb = m66592_read(m66592, M66592_BEMPENB); if (mask0 & M66592_VBINT) { - m66592_write(m66592, (u16)~M66592_VBINT, - M66592_INTSTS0); + m66592_write(m66592, 0xffff & ~M66592_VBINT, + M66592_INTSTS0); m66592_start_xclock(m66592); /* start vbus sampling */ m66592->old_vbus = m66592_read(m66592, M66592_INTSTS0) - & M66592_VBSTS; + & M66592_VBSTS; m66592->scount = M66592_MAX_SAMPLING; mod_timer(&m66592->timer, - jiffies + msecs_to_jiffies(50)); + jiffies + msecs_to_jiffies(50)); } if (intsts0 & M66592_DVSQ) irq_device_state(m66592); - if ((intsts0 & M66592_BRDY) && (intenb0 & M66592_BRDYE) && - (brdysts & brdyenb)) { + if ((intsts0 & M66592_BRDY) && (intenb0 & M66592_BRDYE) + && (brdysts & brdyenb)) { irq_pipe_ready(m66592, brdysts, brdyenb); } - if ((intsts0 & M66592_BEMP) && (intenb0 & M66592_BEMPE) && - (bempsts & bempenb)) { + if ((intsts0 & M66592_BEMP) && (intenb0 & M66592_BEMPE) + && (bempsts & bempenb)) { irq_pipe_empty(m66592, bempsts, bempenb); } @@ -1164,6 +1184,7 @@ static irqreturn_t m66592_irq(int irq, void *_m66592) m66592_write(m66592, savepipe, M66592_CFIFOSEL); + spin_unlock(&m66592->lock); return IRQ_HANDLED; } @@ -1191,13 +1212,13 @@ static void m66592_timer(unsigned long _m66592) m66592_usb_disconnect(m66592); } else { mod_timer(&m66592->timer, - jiffies + msecs_to_jiffies(50)); + jiffies + msecs_to_jiffies(50)); } } else { m66592->scount = M66592_MAX_SAMPLING; m66592->old_vbus = tmp; mod_timer(&m66592->timer, - jiffies + msecs_to_jiffies(50)); + jiffies + msecs_to_jiffies(50)); } } spin_unlock_irqrestore(&m66592->lock, flags); @@ -1335,11 +1356,6 @@ out: return ret; } -static int m66592_fifo_status(struct usb_ep *_ep) -{ - return -EOPNOTSUPP; -} - static void m66592_fifo_flush(struct usb_ep *_ep) { struct m66592_ep *ep; @@ -1365,7 +1381,6 @@ static struct usb_ep_ops m66592_ep_ops = { .dequeue = m66592_dequeue, .set_halt = m66592_set_halt, - .fifo_status = m66592_fifo_status, .fifo_flush = m66592_fifo_flush, }; @@ -1377,11 +1392,10 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) struct m66592 *m66592 = the_controller; int retval; - if (!driver || - driver->speed != USB_SPEED_HIGH || - !driver->bind || - !driver->unbind || - !driver->setup) + if (!driver + || driver->speed != USB_SPEED_HIGH + || !driver->bind + || !driver->setup) return -EINVAL; if (!m66592) return -ENODEV; @@ -1413,8 +1427,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) m66592->old_vbus = m66592_read(m66592, M66592_INTSTS0) & M66592_VBSTS; m66592->scount = M66592_MAX_SAMPLING; - mod_timer(&m66592->timer, - jiffies + msecs_to_jiffies(50)); + mod_timer(&m66592->timer, jiffies + msecs_to_jiffies(50)); } return 0; @@ -1432,6 +1445,9 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) struct m66592 *m66592 = the_controller; unsigned long flags; + if (driver != m66592->driver || !driver->unbind) + return -EINVAL; + spin_lock_irqsave(&m66592->lock, flags); if (m66592->gadget.speed != USB_SPEED_UNKNOWN) m66592_usb_disconnect(m66592); @@ -1461,46 +1477,35 @@ static struct usb_gadget_ops m66592_gadget_ops = { .get_frame = m66592_get_frame, }; -#if defined(CONFIG_PM) -static int m66592_suspend(struct platform_device *pdev, pm_message_t state) -{ - pdev->dev.power.power_state = state; - return 0; -} - -static int m66592_resume(struct platform_device *pdev) -{ - pdev->dev.power.power_state = PMSG_ON; - return 0; -} -#else /* if defined(CONFIG_PM) */ -#define m66592_suspend NULL -#define m66592_resume NULL -#endif - -static int __init_or_module m66592_remove(struct platform_device *pdev) +static int __exit m66592_remove(struct platform_device *pdev) { struct m66592 *m66592 = dev_get_drvdata(&pdev->dev); del_timer_sync(&m66592->timer); iounmap(m66592->reg); free_irq(platform_get_irq(pdev, 0), m66592); + m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req); kfree(m66592); return 0; } +static void nop_completion(struct usb_ep *ep, struct usb_request *r) +{ +} + #define resource_len(r) (((r)->end - (r)->start) + 1) + static int __init m66592_probe(struct platform_device *pdev) { - struct resource *res = NULL; - int irq = -1; + struct resource *res; + int irq; void __iomem *reg = NULL; struct m66592 *m66592 = NULL; int ret = 0; int i; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - (char *)udc_name); + (char *)udc_name); if (!res) { ret = -ENODEV; printk(KERN_ERR "platform_get_resource_byname error.\n"); @@ -1548,7 +1553,7 @@ static int __init m66592_probe(struct platform_device *pdev) m66592->bi_bufnum = M66592_BASE_BUFNUM; ret = request_irq(irq, m66592_irq, IRQF_DISABLED | IRQF_SHARED, - udc_name, m66592); + udc_name, m66592); if (ret < 0) { printk(KERN_ERR "request_irq error (%d)\n", ret); goto clean_up; @@ -1563,7 +1568,7 @@ static int __init m66592_probe(struct platform_device *pdev) if (i != 0) { INIT_LIST_HEAD(&m66592->ep[i].ep.ep_list); list_add_tail(&m66592->ep[i].ep.ep_list, - &m66592->gadget.ep_list); + &m66592->gadget.ep_list); } ep->m66592 = m66592; INIT_LIST_HEAD(&ep->queue); @@ -1583,20 +1588,18 @@ static int __init m66592_probe(struct platform_device *pdev) the_controller = m66592; - /* AV: leaks */ m66592->ep0_req = m66592_alloc_request(&m66592->ep[0].ep, GFP_KERNEL); if (m66592->ep0_req == NULL) - goto clean_up; - /* AV: leaks, and do we really need it separately allocated? */ - m66592->ep0_buf = kzalloc(2, GFP_KERNEL); - if (m66592->ep0_buf == NULL) - goto clean_up; + goto clean_up2; + m66592->ep0_req->complete = nop_completion; init_controller(m66592); - printk("driver %s, %s\n", udc_name, DRIVER_VERSION); + dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION); return 0; +clean_up2: + free_irq(irq, m66592); clean_up: if (m66592) { if (m66592->ep0_req) @@ -1611,10 +1614,7 @@ clean_up: /*-------------------------------------------------------------------------*/ static struct platform_driver m66592_driver = { - .probe = m66592_probe, - .remove = m66592_remove, - .suspend = m66592_suspend, - .resume = m66592_resume, + .remove = __exit_p(m66592_remove), .driver = { .name = (char *) udc_name, }, @@ -1622,7 +1622,7 @@ static struct platform_driver m66592_driver = { static int __init m66592_udc_init(void) { - return platform_driver_register(&m66592_driver); + return platform_driver_probe(&m66592_driver, m66592_probe); } module_init(m66592_udc_init); @@ -1631,4 +1631,3 @@ static void __exit m66592_udc_cleanup(void) platform_driver_unregister(&m66592_driver); } module_exit(m66592_udc_cleanup); - diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h index 26b54f8b894..bfa0c645f22 100644 --- a/drivers/usb/gadget/m66592-udc.h +++ b/drivers/usb/gadget/m66592-udc.h @@ -24,73 +24,73 @@ #define __M66592_UDC_H__ #define M66592_SYSCFG 0x00 -#define M66592_XTAL 0xC000 /* b15-14: Crystal selection */ -#define M66592_XTAL48 0x8000 /* 48MHz */ -#define M66592_XTAL24 0x4000 /* 24MHz */ -#define M66592_XTAL12 0x0000 /* 12MHz */ -#define M66592_XCKE 0x2000 /* b13: External clock enable */ -#define M66592_RCKE 0x1000 /* b12: Register clock enable */ -#define M66592_PLLC 0x0800 /* b11: PLL control */ -#define M66592_SCKE 0x0400 /* b10: USB clock enable */ -#define M66592_ATCKM 0x0100 /* b8: Automatic supply functional enable */ -#define M66592_HSE 0x0080 /* b7: Hi-speed enable */ -#define M66592_DCFM 0x0040 /* b6: Controller function select */ -#define M66592_DMRPD 0x0020 /* b5: D- pull down control */ -#define M66592_DPRPU 0x0010 /* b4: D+ pull up control */ -#define M66592_FSRPC 0x0004 /* b2: Full-speed receiver enable */ -#define M66592_PCUT 0x0002 /* b1: Low power sleep enable */ -#define M66592_USBE 0x0001 /* b0: USB module operation enable */ +#define M66592_XTAL 0xC000 /* b15-14: Crystal selection */ +#define M66592_XTAL48 0x8000 /* 48MHz */ +#define M66592_XTAL24 0x4000 /* 24MHz */ +#define M66592_XTAL12 0x0000 /* 12MHz */ +#define M66592_XCKE 0x2000 /* b13: External clock enable */ +#define M66592_RCKE 0x1000 /* b12: Register clock enable */ +#define M66592_PLLC 0x0800 /* b11: PLL control */ +#define M66592_SCKE 0x0400 /* b10: USB clock enable */ +#define M66592_ATCKM 0x0100 /* b8: Automatic clock supply */ +#define M66592_HSE 0x0080 /* b7: Hi-speed enable */ +#define M66592_DCFM 0x0040 /* b6: Controller function select */ +#define M66592_DMRPD 0x0020 /* b5: D- pull down control */ +#define M66592_DPRPU 0x0010 /* b4: D+ pull up control */ +#define M66592_FSRPC 0x0004 /* b2: Full-speed receiver enable */ +#define M66592_PCUT 0x0002 /* b1: Low power sleep enable */ +#define M66592_USBE 0x0001 /* b0: USB module operation enable */ #define M66592_SYSSTS 0x02 -#define M66592_LNST 0x0003 /* b1-0: D+, D- line status */ -#define M66592_SE1 0x0003 /* SE1 */ -#define M66592_KSTS 0x0002 /* K State */ -#define M66592_JSTS 0x0001 /* J State */ -#define M66592_SE0 0x0000 /* SE0 */ +#define M66592_LNST 0x0003 /* b1-0: D+, D- line status */ +#define M66592_SE1 0x0003 /* SE1 */ +#define M66592_KSTS 0x0002 /* K State */ +#define M66592_JSTS 0x0001 /* J State */ +#define M66592_SE0 0x0000 /* SE0 */ #define M66592_DVSTCTR 0x04 -#define M66592_WKUP 0x0100 /* b8: Remote wakeup */ -#define M66592_RWUPE 0x0080 /* b7: Remote wakeup sense */ -#define M66592_USBRST 0x0040 /* b6: USB reset enable */ -#define M66592_RESUME 0x0020 /* b5: Resume enable */ -#define M66592_UACT 0x0010 /* b4: USB bus enable */ -#define M66592_RHST 0x0003 /* b1-0: Reset handshake status */ -#define M66592_HSMODE 0x0003 /* Hi-Speed mode */ -#define M66592_FSMODE 0x0002 /* Full-Speed mode */ -#define M66592_HSPROC 0x0001 /* HS handshake is processing */ +#define M66592_WKUP 0x0100 /* b8: Remote wakeup */ +#define M66592_RWUPE 0x0080 /* b7: Remote wakeup sense */ +#define M66592_USBRST 0x0040 /* b6: USB reset enable */ +#define M66592_RESUME 0x0020 /* b5: Resume enable */ +#define M66592_UACT 0x0010 /* b4: USB bus enable */ +#define M66592_RHST 0x0003 /* b1-0: Reset handshake status */ +#define M66592_HSMODE 0x0003 /* Hi-Speed mode */ +#define M66592_FSMODE 0x0002 /* Full-Speed mode */ +#define M66592_HSPROC 0x0001 /* HS handshake is processing */ #define M66592_TESTMODE 0x06 -#define M66592_UTST 0x000F /* b4-0: Test select */ -#define M66592_H_TST_PACKET 0x000C /* HOST TEST Packet */ -#define M66592_H_TST_SE0_NAK 0x000B /* HOST TEST SE0 NAK */ -#define M66592_H_TST_K 0x000A /* HOST TEST K */ -#define M66592_H_TST_J 0x0009 /* HOST TEST J */ -#define M66592_H_TST_NORMAL 0x0000 /* HOST Normal Mode */ -#define M66592_P_TST_PACKET 0x0004 /* PERI TEST Packet */ -#define M66592_P_TST_SE0_NAK 0x0003 /* PERI TEST SE0 NAK */ -#define M66592_P_TST_K 0x0002 /* PERI TEST K */ -#define M66592_P_TST_J 0x0001 /* PERI TEST J */ -#define M66592_P_TST_NORMAL 0x0000 /* PERI Normal Mode */ +#define M66592_UTST 0x000F /* b4-0: Test select */ +#define M66592_H_TST_PACKET 0x000C /* HOST TEST Packet */ +#define M66592_H_TST_SE0_NAK 0x000B /* HOST TEST SE0 NAK */ +#define M66592_H_TST_K 0x000A /* HOST TEST K */ +#define M66592_H_TST_J 0x0009 /* HOST TEST J */ +#define M66592_H_TST_NORMAL 0x0000 /* HOST Normal Mode */ +#define M66592_P_TST_PACKET 0x0004 /* PERI TEST Packet */ +#define M66592_P_TST_SE0_NAK 0x0003 /* PERI TEST SE0 NAK */ +#define M66592_P_TST_K 0x0002 /* PERI TEST K */ +#define M66592_P_TST_J 0x0001 /* PERI TEST J */ +#define M66592_P_TST_NORMAL 0x0000 /* PERI Normal Mode */ #define M66592_PINCFG 0x0A -#define M66592_LDRV 0x8000 /* b15: Drive Current Adjust */ -#define M66592_BIGEND 0x0100 /* b8: Big endian mode */ +#define M66592_LDRV 0x8000 /* b15: Drive Current Adjust */ +#define M66592_BIGEND 0x0100 /* b8: Big endian mode */ #define M66592_DMA0CFG 0x0C #define M66592_DMA1CFG 0x0E -#define M66592_DREQA 0x4000 /* b14: Dreq active select */ -#define M66592_BURST 0x2000 /* b13: Burst mode */ -#define M66592_DACKA 0x0400 /* b10: Dack active select */ -#define M66592_DFORM 0x0380 /* b9-7: DMA mode select */ -#define M66592_CPU_ADR_RD_WR 0x0000 /* Address + RD/WR mode (CPU bus) */ -#define M66592_CPU_DACK_RD_WR 0x0100 /* DACK + RD/WR mode (CPU bus) */ -#define M66592_CPU_DACK_ONLY 0x0180 /* DACK only mode (CPU bus) */ -#define M66592_SPLIT_DACK_ONLY 0x0200 /* DACK only mode (SPLIT bus) */ -#define M66592_SPLIT_DACK_DSTB 0x0300 /* DACK + DSTB0 mode (SPLIT bus) */ -#define M66592_DENDA 0x0040 /* b6: Dend active select */ -#define M66592_PKTM 0x0020 /* b5: Packet mode */ -#define M66592_DENDE 0x0010 /* b4: Dend enable */ -#define M66592_OBUS 0x0004 /* b2: OUTbus mode */ +#define M66592_DREQA 0x4000 /* b14: Dreq active select */ +#define M66592_BURST 0x2000 /* b13: Burst mode */ +#define M66592_DACKA 0x0400 /* b10: Dack active select */ +#define M66592_DFORM 0x0380 /* b9-7: DMA mode select */ +#define M66592_CPU_ADR_RD_WR 0x0000 /* Address + RD/WR mode (CPU bus) */ +#define M66592_CPU_DACK_RD_WR 0x0100 /* DACK + RD/WR mode (CPU bus) */ +#define M66592_CPU_DACK_ONLY 0x0180 /* DACK only mode (CPU bus) */ +#define M66592_SPLIT_DACK_ONLY 0x0200 /* DACK only mode (SPLIT bus) */ +#define M66592_SPLIT_DACK_DSTB 0x0300 /* DACK + DSTB0 mode (SPLIT bus) */ +#define M66592_DENDA 0x0040 /* b6: Dend active select */ +#define M66592_PKTM 0x0020 /* b5: Packet mode */ +#define M66592_DENDE 0x0010 /* b4: Dend enable */ +#define M66592_OBUS 0x0004 /* b2: OUTbus mode */ #define M66592_CFIFO 0x10 #define M66592_D0FIFO 0x14 @@ -99,300 +99,300 @@ #define M66592_CFIFOSEL 0x1E #define M66592_D0FIFOSEL 0x24 #define M66592_D1FIFOSEL 0x2A -#define M66592_RCNT 0x8000 /* b15: Read count mode */ -#define M66592_REW 0x4000 /* b14: Buffer rewind */ -#define M66592_DCLRM 0x2000 /* b13: DMA buffer clear mode */ -#define M66592_DREQE 0x1000 /* b12: DREQ output enable */ -#define M66592_MBW 0x0400 /* b10: Maximum bit width for FIFO access */ -#define M66592_MBW_8 0x0000 /* 8bit */ -#define M66592_MBW_16 0x0400 /* 16bit */ -#define M66592_TRENB 0x0200 /* b9: Transaction counter enable */ -#define M66592_TRCLR 0x0100 /* b8: Transaction counter clear */ -#define M66592_DEZPM 0x0080 /* b7: Zero-length packet additional mode */ -#define M66592_ISEL 0x0020 /* b5: DCP FIFO port direction select */ -#define M66592_CURPIPE 0x0007 /* b2-0: PIPE select */ +#define M66592_RCNT 0x8000 /* b15: Read count mode */ +#define M66592_REW 0x4000 /* b14: Buffer rewind */ +#define M66592_DCLRM 0x2000 /* b13: DMA buffer clear mode */ +#define M66592_DREQE 0x1000 /* b12: DREQ output enable */ +#define M66592_MBW 0x0400 /* b10: Maximum bit width for FIFO */ +#define M66592_MBW_8 0x0000 /* 8bit */ +#define M66592_MBW_16 0x0400 /* 16bit */ +#define M66592_TRENB 0x0200 /* b9: Transaction counter enable */ +#define M66592_TRCLR 0x0100 /* b8: Transaction counter clear */ +#define M66592_DEZPM 0x0080 /* b7: Zero-length packet mode */ +#define M66592_ISEL 0x0020 /* b5: DCP FIFO port direction select */ +#define M66592_CURPIPE 0x0007 /* b2-0: PIPE select */ #define M66592_CFIFOCTR 0x20 #define M66592_D0FIFOCTR 0x26 #define M66592_D1FIFOCTR 0x2c -#define M66592_BVAL 0x8000 /* b15: Buffer valid flag */ -#define M66592_BCLR 0x4000 /* b14: Buffer clear */ -#define M66592_FRDY 0x2000 /* b13: FIFO ready */ -#define M66592_DTLN 0x0FFF /* b11-0: FIFO received data length */ +#define M66592_BVAL 0x8000 /* b15: Buffer valid flag */ +#define M66592_BCLR 0x4000 /* b14: Buffer clear */ +#define M66592_FRDY 0x2000 /* b13: FIFO ready */ +#define M66592_DTLN 0x0FFF /* b11-0: FIFO received data length */ #define M66592_CFIFOSIE 0x22 -#define M66592_TGL 0x8000 /* b15: Buffer toggle */ -#define M66592_SCLR 0x4000 /* b14: Buffer clear */ -#define M66592_SBUSY 0x2000 /* b13: SIE_FIFO busy */ +#define M66592_TGL 0x8000 /* b15: Buffer toggle */ +#define M66592_SCLR 0x4000 /* b14: Buffer clear */ +#define M66592_SBUSY 0x2000 /* b13: SIE_FIFO busy */ #define M66592_D0FIFOTRN 0x28 #define M66592_D1FIFOTRN 0x2E -#define M66592_TRNCNT 0xFFFF /* b15-0: Transaction counter */ +#define M66592_TRNCNT 0xFFFF /* b15-0: Transaction counter */ #define M66592_INTENB0 0x30 -#define M66592_VBSE 0x8000 /* b15: VBUS interrupt */ -#define M66592_RSME 0x4000 /* b14: Resume interrupt */ -#define M66592_SOFE 0x2000 /* b13: Frame update interrupt */ -#define M66592_DVSE 0x1000 /* b12: Device state transition interrupt */ -#define M66592_CTRE 0x0800 /* b11: Control transfer stage transition interrupt */ -#define M66592_BEMPE 0x0400 /* b10: Buffer empty interrupt */ -#define M66592_NRDYE 0x0200 /* b9: Buffer not ready interrupt */ -#define M66592_BRDYE 0x0100 /* b8: Buffer ready interrupt */ -#define M66592_URST 0x0080 /* b7: USB reset detected interrupt */ -#define M66592_SADR 0x0040 /* b6: Set address executed interrupt */ -#define M66592_SCFG 0x0020 /* b5: Set configuration executed interrupt */ -#define M66592_SUSP 0x0010 /* b4: Suspend detected interrupt */ -#define M66592_WDST 0x0008 /* b3: Control write data stage completed interrupt */ -#define M66592_RDST 0x0004 /* b2: Control read data stage completed interrupt */ -#define M66592_CMPL 0x0002 /* b1: Control transfer complete interrupt */ -#define M66592_SERR 0x0001 /* b0: Sequence error interrupt */ +#define M66592_VBSE 0x8000 /* b15: VBUS interrupt */ +#define M66592_RSME 0x4000 /* b14: Resume interrupt */ +#define M66592_SOFE 0x2000 /* b13: Frame update interrupt */ +#define M66592_DVSE 0x1000 /* b12: Device state transition interrupt */ +#define M66592_CTRE 0x0800 /* b11: Control transfer stage transition irq */ +#define M66592_BEMPE 0x0400 /* b10: Buffer empty interrupt */ +#define M66592_NRDYE 0x0200 /* b9: Buffer not ready interrupt */ +#define M66592_BRDYE 0x0100 /* b8: Buffer ready interrupt */ +#define M66592_URST 0x0080 /* b7: USB reset detected interrupt */ +#define M66592_SADR 0x0040 /* b6: Set address executed interrupt */ +#define M66592_SCFG 0x0020 /* b5: Set configuration executed interrupt */ +#define M66592_SUSP 0x0010 /* b4: Suspend detected interrupt */ +#define M66592_WDST 0x0008 /* b3: Control write data stage completed irq */ +#define M66592_RDST 0x0004 /* b2: Control read data stage completed irq */ +#define M66592_CMPL 0x0002 /* b1: Control transfer complete interrupt */ +#define M66592_SERR 0x0001 /* b0: Sequence error interrupt */ #define M66592_INTENB1 0x32 -#define M66592_BCHGE 0x4000 /* b14: USB us chenge interrupt */ -#define M66592_DTCHE 0x1000 /* b12: Detach sense interrupt */ -#define M66592_SIGNE 0x0020 /* b5: SETUP IGNORE interrupt */ -#define M66592_SACKE 0x0010 /* b4: SETUP ACK interrupt */ -#define M66592_BRDYM 0x0004 /* b2: BRDY clear timing */ -#define M66592_INTL 0x0002 /* b1: Interrupt sense select */ -#define M66592_PCSE 0x0001 /* b0: PCUT enable by CS assert */ +#define M66592_BCHGE 0x4000 /* b14: USB us chenge interrupt */ +#define M66592_DTCHE 0x1000 /* b12: Detach sense interrupt */ +#define M66592_SIGNE 0x0020 /* b5: SETUP IGNORE interrupt */ +#define M66592_SACKE 0x0010 /* b4: SETUP ACK interrupt */ +#define M66592_BRDYM 0x0004 /* b2: BRDY clear timing */ +#define M66592_INTL 0x0002 /* b1: Interrupt sense select */ +#define M66592_PCSE 0x0001 /* b0: PCUT enable by CS assert */ #define M66592_BRDYENB 0x36 #define M66592_BRDYSTS 0x46 -#define M66592_BRDY7 0x0080 /* b7: PIPE7 */ -#define M66592_BRDY6 0x0040 /* b6: PIPE6 */ -#define M66592_BRDY5 0x0020 /* b5: PIPE5 */ -#define M66592_BRDY4 0x0010 /* b4: PIPE4 */ -#define M66592_BRDY3 0x0008 /* b3: PIPE3 */ -#define M66592_BRDY2 0x0004 /* b2: PIPE2 */ -#define M66592_BRDY1 0x0002 /* b1: PIPE1 */ -#define M66592_BRDY0 0x0001 /* b1: PIPE0 */ +#define M66592_BRDY7 0x0080 /* b7: PIPE7 */ +#define M66592_BRDY6 0x0040 /* b6: PIPE6 */ +#define M66592_BRDY5 0x0020 /* b5: PIPE5 */ +#define M66592_BRDY4 0x0010 /* b4: PIPE4 */ +#define M66592_BRDY3 0x0008 /* b3: PIPE3 */ +#define M66592_BRDY2 0x0004 /* b2: PIPE2 */ +#define M66592_BRDY1 0x0002 /* b1: PIPE1 */ +#define M66592_BRDY0 0x0001 /* b1: PIPE0 */ #define M66592_NRDYENB 0x38 #define M66592_NRDYSTS 0x48 -#define M66592_NRDY7 0x0080 /* b7: PIPE7 */ -#define M66592_NRDY6 0x0040 /* b6: PIPE6 */ -#define M66592_NRDY5 0x0020 /* b5: PIPE5 */ -#define M66592_NRDY4 0x0010 /* b4: PIPE4 */ -#define M66592_NRDY3 0x0008 /* b3: PIPE3 */ -#define M66592_NRDY2 0x0004 /* b2: PIPE2 */ -#define M66592_NRDY1 0x0002 /* b1: PIPE1 */ -#define M66592_NRDY0 0x0001 /* b1: PIPE0 */ +#define M66592_NRDY7 0x0080 /* b7: PIPE7 */ +#define M66592_NRDY6 0x0040 /* b6: PIPE6 */ +#define M66592_NRDY5 0x0020 /* b5: PIPE5 */ +#define M66592_NRDY4 0x0010 /* b4: PIPE4 */ +#define M66592_NRDY3 0x0008 /* b3: PIPE3 */ +#define M66592_NRDY2 0x0004 /* b2: PIPE2 */ +#define M66592_NRDY1 0x0002 /* b1: PIPE1 */ +#define M66592_NRDY0 0x0001 /* b1: PIPE0 */ #define M66592_BEMPENB 0x3A #define M66592_BEMPSTS 0x4A -#define M66592_BEMP7 0x0080 /* b7: PIPE7 */ -#define M66592_BEMP6 0x0040 /* b6: PIPE6 */ -#define M66592_BEMP5 0x0020 /* b5: PIPE5 */ -#define M66592_BEMP4 0x0010 /* b4: PIPE4 */ -#define M66592_BEMP3 0x0008 /* b3: PIPE3 */ -#define M66592_BEMP2 0x0004 /* b2: PIPE2 */ -#define M66592_BEMP1 0x0002 /* b1: PIPE1 */ -#define M66592_BEMP0 0x0001 /* b0: PIPE0 */ +#define M66592_BEMP7 0x0080 /* b7: PIPE7 */ +#define M66592_BEMP6 0x0040 /* b6: PIPE6 */ +#define M66592_BEMP5 0x0020 /* b5: PIPE5 */ +#define M66592_BEMP4 0x0010 /* b4: PIPE4 */ +#define M66592_BEMP3 0x0008 /* b3: PIPE3 */ +#define M66592_BEMP2 0x0004 /* b2: PIPE2 */ +#define M66592_BEMP1 0x0002 /* b1: PIPE1 */ +#define M66592_BEMP0 0x0001 /* b0: PIPE0 */ #define M66592_SOFCFG 0x3C -#define M66592_SOFM 0x000C /* b3-2: SOF palse mode */ -#define M66592_SOF_125US 0x0008 /* SOF OUT 125us uFrame Signal */ -#define M66592_SOF_1MS 0x0004 /* SOF OUT 1ms Frame Signal */ -#define M66592_SOF_DISABLE 0x0000 /* SOF OUT Disable */ +#define M66592_SOFM 0x000C /* b3-2: SOF palse mode */ +#define M66592_SOF_125US 0x0008 /* SOF OUT 125us uFrame Signal */ +#define M66592_SOF_1MS 0x0004 /* SOF OUT 1ms Frame Signal */ +#define M66592_SOF_DISABLE 0x0000 /* SOF OUT Disable */ #define M66592_INTSTS0 0x40 -#define M66592_VBINT 0x8000 /* b15: VBUS interrupt */ -#define M66592_RESM 0x4000 /* b14: Resume interrupt */ -#define M66592_SOFR 0x2000 /* b13: SOF frame update interrupt */ -#define M66592_DVST 0x1000 /* b12: Device state transition interrupt */ -#define M66592_CTRT 0x0800 /* b11: Control transfer stage transition interrupt */ -#define M66592_BEMP 0x0400 /* b10: Buffer empty interrupt */ -#define M66592_NRDY 0x0200 /* b9: Buffer not ready interrupt */ -#define M66592_BRDY 0x0100 /* b8: Buffer ready interrupt */ -#define M66592_VBSTS 0x0080 /* b7: VBUS input port */ -#define M66592_DVSQ 0x0070 /* b6-4: Device state */ -#define M66592_DS_SPD_CNFG 0x0070 /* Suspend Configured */ -#define M66592_DS_SPD_ADDR 0x0060 /* Suspend Address */ -#define M66592_DS_SPD_DFLT 0x0050 /* Suspend Default */ -#define M66592_DS_SPD_POWR 0x0040 /* Suspend Powered */ -#define M66592_DS_SUSP 0x0040 /* Suspend */ -#define M66592_DS_CNFG 0x0030 /* Configured */ -#define M66592_DS_ADDS 0x0020 /* Address */ -#define M66592_DS_DFLT 0x0010 /* Default */ -#define M66592_DS_POWR 0x0000 /* Powered */ -#define M66592_DVSQS 0x0030 /* b5-4: Device state */ -#define M66592_VALID 0x0008 /* b3: Setup packet detected flag */ -#define M66592_CTSQ 0x0007 /* b2-0: Control transfer stage */ -#define M66592_CS_SQER 0x0006 /* Sequence error */ -#define M66592_CS_WRND 0x0005 /* Control write nodata status stage */ -#define M66592_CS_WRSS 0x0004 /* Control write status stage */ -#define M66592_CS_WRDS 0x0003 /* Control write data stage */ -#define M66592_CS_RDSS 0x0002 /* Control read status stage */ -#define M66592_CS_RDDS 0x0001 /* Control read data stage */ -#define M66592_CS_IDST 0x0000 /* Idle or setup stage */ +#define M66592_VBINT 0x8000 /* b15: VBUS interrupt */ +#define M66592_RESM 0x4000 /* b14: Resume interrupt */ +#define M66592_SOFR 0x2000 /* b13: SOF frame update interrupt */ +#define M66592_DVST 0x1000 /* b12: Device state transition */ +#define M66592_CTRT 0x0800 /* b11: Control stage transition */ +#define M66592_BEMP 0x0400 /* b10: Buffer empty interrupt */ +#define M66592_NRDY 0x0200 /* b9: Buffer not ready interrupt */ +#define M66592_BRDY 0x0100 /* b8: Buffer ready interrupt */ +#define M66592_VBSTS 0x0080 /* b7: VBUS input port */ +#define M66592_DVSQ 0x0070 /* b6-4: Device state */ +#define M66592_DS_SPD_CNFG 0x0070 /* Suspend Configured */ +#define M66592_DS_SPD_ADDR 0x0060 /* Suspend Address */ +#define M66592_DS_SPD_DFLT 0x0050 /* Suspend Default */ +#define M66592_DS_SPD_POWR 0x0040 /* Suspend Powered */ +#define M66592_DS_SUSP 0x0040 /* Suspend */ +#define M66592_DS_CNFG 0x0030 /* Configured */ +#define M66592_DS_ADDS 0x0020 /* Address */ +#define M66592_DS_DFLT 0x0010 /* Default */ +#define M66592_DS_POWR 0x0000 /* Powered */ +#define M66592_DVSQS 0x0030 /* b5-4: Device state */ +#define M66592_VALID 0x0008 /* b3: Setup packet detected flag */ +#define M66592_CTSQ 0x0007 /* b2-0: Control transfer stage */ +#define M66592_CS_SQER 0x0006 /* Sequence error */ +#define M66592_CS_WRND 0x0005 /* Control write nodata status */ +#define M66592_CS_WRSS 0x0004 /* Control write status stage */ +#define M66592_CS_WRDS 0x0003 /* Control write data stage */ +#define M66592_CS_RDSS 0x0002 /* Control read status stage */ +#define M66592_CS_RDDS 0x0001 /* Control read data stage */ +#define M66592_CS_IDST 0x0000 /* Idle or setup stage */ #define M66592_INTSTS1 0x42 -#define M66592_BCHG 0x4000 /* b14: USB bus chenge interrupt */ -#define M66592_DTCH 0x1000 /* b12: Detach sense interrupt */ -#define M66592_SIGN 0x0020 /* b5: SETUP IGNORE interrupt */ -#define M66592_SACK 0x0010 /* b4: SETUP ACK interrupt */ +#define M66592_BCHG 0x4000 /* b14: USB bus chenge interrupt */ +#define M66592_DTCH 0x1000 /* b12: Detach sense interrupt */ +#define M66592_SIGN 0x0020 /* b5: SETUP IGNORE interrupt */ +#define M66592_SACK 0x0010 /* b4: SETUP ACK interrupt */ #define M66592_FRMNUM 0x4C -#define M66592_OVRN 0x8000 /* b15: Overrun error */ -#define M66592_CRCE 0x4000 /* b14: Received data error */ -#define M66592_SOFRM 0x0800 /* b11: SOF output mode */ -#define M66592_FRNM 0x07FF /* b10-0: Frame number */ +#define M66592_OVRN 0x8000 /* b15: Overrun error */ +#define M66592_CRCE 0x4000 /* b14: Received data error */ +#define M66592_SOFRM 0x0800 /* b11: SOF output mode */ +#define M66592_FRNM 0x07FF /* b10-0: Frame number */ #define M66592_UFRMNUM 0x4E -#define M66592_UFRNM 0x0007 /* b2-0: Micro frame number */ +#define M66592_UFRNM 0x0007 /* b2-0: Micro frame number */ #define M66592_RECOVER 0x50 -#define M66592_STSRECOV 0x0700 /* Status recovery */ -#define M66592_STSR_HI 0x0400 /* FULL(0) or HI(1) Speed */ -#define M66592_STSR_DEFAULT 0x0100 /* Default state */ -#define M66592_STSR_ADDRESS 0x0200 /* Address state */ -#define M66592_STSR_CONFIG 0x0300 /* Configured state */ -#define M66592_USBADDR 0x007F /* b6-0: USB address */ +#define M66592_STSRECOV 0x0700 /* Status recovery */ +#define M66592_STSR_HI 0x0400 /* FULL(0) or HI(1) Speed */ +#define M66592_STSR_DEFAULT 0x0100 /* Default state */ +#define M66592_STSR_ADDRESS 0x0200 /* Address state */ +#define M66592_STSR_CONFIG 0x0300 /* Configured state */ +#define M66592_USBADDR 0x007F /* b6-0: USB address */ #define M66592_USBREQ 0x54 -#define M66592_bRequest 0xFF00 /* b15-8: bRequest */ -#define M66592_GET_STATUS 0x0000 -#define M66592_CLEAR_FEATURE 0x0100 -#define M66592_ReqRESERVED 0x0200 -#define M66592_SET_FEATURE 0x0300 -#define M66592_ReqRESERVED1 0x0400 -#define M66592_SET_ADDRESS 0x0500 -#define M66592_GET_DESCRIPTOR 0x0600 -#define M66592_SET_DESCRIPTOR 0x0700 -#define M66592_GET_CONFIGURATION 0x0800 -#define M66592_SET_CONFIGURATION 0x0900 -#define M66592_GET_INTERFACE 0x0A00 -#define M66592_SET_INTERFACE 0x0B00 -#define M66592_SYNCH_FRAME 0x0C00 -#define M66592_bmRequestType 0x00FF /* b7-0: bmRequestType */ -#define M66592_bmRequestTypeDir 0x0080 /* b7 : Data transfer direction */ -#define M66592_HOST_TO_DEVICE 0x0000 -#define M66592_DEVICE_TO_HOST 0x0080 -#define M66592_bmRequestTypeType 0x0060 /* b6-5: Type */ -#define M66592_STANDARD 0x0000 -#define M66592_CLASS 0x0020 -#define M66592_VENDOR 0x0040 -#define M66592_bmRequestTypeRecip 0x001F /* b4-0: Recipient */ -#define M66592_DEVICE 0x0000 -#define M66592_INTERFACE 0x0001 -#define M66592_ENDPOINT 0x0002 +#define M66592_bRequest 0xFF00 /* b15-8: bRequest */ +#define M66592_GET_STATUS 0x0000 +#define M66592_CLEAR_FEATURE 0x0100 +#define M66592_ReqRESERVED 0x0200 +#define M66592_SET_FEATURE 0x0300 +#define M66592_ReqRESERVED1 0x0400 +#define M66592_SET_ADDRESS 0x0500 +#define M66592_GET_DESCRIPTOR 0x0600 +#define M66592_SET_DESCRIPTOR 0x0700 +#define M66592_GET_CONFIGURATION 0x0800 +#define M66592_SET_CONFIGURATION 0x0900 +#define M66592_GET_INTERFACE 0x0A00 +#define M66592_SET_INTERFACE 0x0B00 +#define M66592_SYNCH_FRAME 0x0C00 +#define M66592_bmRequestType 0x00FF /* b7-0: bmRequestType */ +#define M66592_bmRequestTypeDir 0x0080 /* b7 : Data direction */ +#define M66592_HOST_TO_DEVICE 0x0000 +#define M66592_DEVICE_TO_HOST 0x0080 +#define M66592_bmRequestTypeType 0x0060 /* b6-5: Type */ +#define M66592_STANDARD 0x0000 +#define M66592_CLASS 0x0020 +#define M66592_VENDOR 0x0040 +#define M66592_bmRequestTypeRecip 0x001F /* b4-0: Recipient */ +#define M66592_DEVICE 0x0000 +#define M66592_INTERFACE 0x0001 +#define M66592_ENDPOINT 0x0002 #define M66592_USBVAL 0x56 -#define M66592_wValue 0xFFFF /* b15-0: wValue */ +#define M66592_wValue 0xFFFF /* b15-0: wValue */ /* Standard Feature Selector */ -#define M66592_ENDPOINT_HALT 0x0000 -#define M66592_DEVICE_REMOTE_WAKEUP 0x0001 -#define M66592_TEST_MODE 0x0002 +#define M66592_ENDPOINT_HALT 0x0000 +#define M66592_DEVICE_REMOTE_WAKEUP 0x0001 +#define M66592_TEST_MODE 0x0002 /* Descriptor Types */ -#define M66592_DT_TYPE 0xFF00 -#define M66592_GET_DT_TYPE(v) (((v) & DT_TYPE) >> 8) -#define M66592_DT_DEVICE 0x01 -#define M66592_DT_CONFIGURATION 0x02 -#define M66592_DT_STRING 0x03 -#define M66592_DT_INTERFACE 0x04 -#define M66592_DT_ENDPOINT 0x05 -#define M66592_DT_DEVICE_QUALIFIER 0x06 -#define M66592_DT_OTHER_SPEED_CONFIGURATION 0x07 -#define M66592_DT_INTERFACE_POWER 0x08 -#define M66592_DT_INDEX 0x00FF -#define M66592_CONF_NUM 0x00FF -#define M66592_ALT_SET 0x00FF +#define M66592_DT_TYPE 0xFF00 +#define M66592_GET_DT_TYPE(v) (((v) & DT_TYPE) >> 8) +#define M66592_DT_DEVICE 0x01 +#define M66592_DT_CONFIGURATION 0x02 +#define M66592_DT_STRING 0x03 +#define M66592_DT_INTERFACE 0x04 +#define M66592_DT_ENDPOINT 0x05 +#define M66592_DT_DEVICE_QUALIFIER 0x06 +#define M66592_DT_OTHER_SPEED_CONFIGURATION 0x07 +#define M66592_DT_INTERFACE_POWER 0x08 +#define M66592_DT_INDEX 0x00FF +#define M66592_CONF_NUM 0x00FF +#define M66592_ALT_SET 0x00FF #define M66592_USBINDEX 0x58 -#define M66592_wIndex 0xFFFF /* b15-0: wIndex */ -#define M66592_TEST_SELECT 0xFF00 /* b15-b8: Test Mode Selectors */ -#define M66592_TEST_J 0x0100 /* Test_J */ -#define M66592_TEST_K 0x0200 /* Test_K */ -#define M66592_TEST_SE0_NAK 0x0300 /* Test_SE0_NAK */ -#define M66592_TEST_PACKET 0x0400 /* Test_Packet */ -#define M66592_TEST_FORCE_ENABLE 0x0500 /* Test_Force_Enable */ -#define M66592_TEST_STSelectors 0x0600 /* Standard test selectors */ -#define M66592_TEST_Reserved 0x4000 /* Reserved */ -#define M66592_TEST_VSTModes 0xC000 /* Vendor-specific test modes */ -#define M66592_EP_DIR 0x0080 /* b7: Endpoint Direction */ -#define M66592_EP_DIR_IN 0x0080 -#define M66592_EP_DIR_OUT 0x0000 +#define M66592_wIndex 0xFFFF /* b15-0: wIndex */ +#define M66592_TEST_SELECT 0xFF00 /* b15-b8: Test Mode */ +#define M66592_TEST_J 0x0100 /* Test_J */ +#define M66592_TEST_K 0x0200 /* Test_K */ +#define M66592_TEST_SE0_NAK 0x0300 /* Test_SE0_NAK */ +#define M66592_TEST_PACKET 0x0400 /* Test_Packet */ +#define M66592_TEST_FORCE_ENABLE 0x0500 /* Test_Force_Enable */ +#define M66592_TEST_STSelectors 0x0600 /* Standard test selectors */ +#define M66592_TEST_Reserved 0x4000 /* Reserved */ +#define M66592_TEST_VSTModes 0xC000 /* Vendor-specific tests */ +#define M66592_EP_DIR 0x0080 /* b7: Endpoint Direction */ +#define M66592_EP_DIR_IN 0x0080 +#define M66592_EP_DIR_OUT 0x0000 #define M66592_USBLENG 0x5A -#define M66592_wLength 0xFFFF /* b15-0: wLength */ +#define M66592_wLength 0xFFFF /* b15-0: wLength */ #define M66592_DCPCFG 0x5C -#define M66592_CNTMD 0x0100 /* b8: Continuous transfer mode select */ -#define M66592_DIR 0x0010 /* b4: Control transfer DIR select */ +#define M66592_CNTMD 0x0100 /* b8: Continuous transfer mode */ +#define M66592_DIR 0x0010 /* b4: Control transfer DIR select */ #define M66592_DCPMAXP 0x5E -#define M66592_DEVSEL 0xC000 /* b15-14: Device address select */ -#define M66592_DEVICE_0 0x0000 /* Device address 0 */ -#define M66592_DEVICE_1 0x4000 /* Device address 1 */ -#define M66592_DEVICE_2 0x8000 /* Device address 2 */ -#define M66592_DEVICE_3 0xC000 /* Device address 3 */ -#define M66592_MAXP 0x007F /* b6-0: Maxpacket size of default control pipe */ +#define M66592_DEVSEL 0xC000 /* b15-14: Device address select */ +#define M66592_DEVICE_0 0x0000 /* Device address 0 */ +#define M66592_DEVICE_1 0x4000 /* Device address 1 */ +#define M66592_DEVICE_2 0x8000 /* Device address 2 */ +#define M66592_DEVICE_3 0xC000 /* Device address 3 */ +#define M66592_MAXP 0x007F /* b6-0: Maxpacket size of ep0 */ #define M66592_DCPCTR 0x60 -#define M66592_BSTS 0x8000 /* b15: Buffer status */ -#define M66592_SUREQ 0x4000 /* b14: Send USB request */ -#define M66592_SQCLR 0x0100 /* b8: Sequence toggle bit clear */ -#define M66592_SQSET 0x0080 /* b7: Sequence toggle bit set */ -#define M66592_SQMON 0x0040 /* b6: Sequence toggle bit monitor */ -#define M66592_CCPL 0x0004 /* b2: Enable control transfer complete */ -#define M66592_PID 0x0003 /* b1-0: Response PID */ -#define M66592_PID_STALL 0x0002 /* STALL */ -#define M66592_PID_BUF 0x0001 /* BUF */ -#define M66592_PID_NAK 0x0000 /* NAK */ +#define M66592_BSTS 0x8000 /* b15: Buffer status */ +#define M66592_SUREQ 0x4000 /* b14: Send USB request */ +#define M66592_SQCLR 0x0100 /* b8: Sequence toggle bit clear */ +#define M66592_SQSET 0x0080 /* b7: Sequence toggle bit set */ +#define M66592_SQMON 0x0040 /* b6: Sequence toggle bit monitor */ +#define M66592_CCPL 0x0004 /* b2: control transfer complete */ +#define M66592_PID 0x0003 /* b1-0: Response PID */ +#define M66592_PID_STALL 0x0002 /* STALL */ +#define M66592_PID_BUF 0x0001 /* BUF */ +#define M66592_PID_NAK 0x0000 /* NAK */ #define M66592_PIPESEL 0x64 -#define M66592_PIPENM 0x0007 /* b2-0: Pipe select */ -#define M66592_PIPE0 0x0000 /* PIPE 0 */ -#define M66592_PIPE1 0x0001 /* PIPE 1 */ -#define M66592_PIPE2 0x0002 /* PIPE 2 */ -#define M66592_PIPE3 0x0003 /* PIPE 3 */ -#define M66592_PIPE4 0x0004 /* PIPE 4 */ -#define M66592_PIPE5 0x0005 /* PIPE 5 */ -#define M66592_PIPE6 0x0006 /* PIPE 6 */ -#define M66592_PIPE7 0x0007 /* PIPE 7 */ +#define M66592_PIPENM 0x0007 /* b2-0: Pipe select */ +#define M66592_PIPE0 0x0000 /* PIPE 0 */ +#define M66592_PIPE1 0x0001 /* PIPE 1 */ +#define M66592_PIPE2 0x0002 /* PIPE 2 */ +#define M66592_PIPE3 0x0003 /* PIPE 3 */ +#define M66592_PIPE4 0x0004 /* PIPE 4 */ +#define M66592_PIPE5 0x0005 /* PIPE 5 */ +#define M66592_PIPE6 0x0006 /* PIPE 6 */ +#define M66592_PIPE7 0x0007 /* PIPE 7 */ #define M66592_PIPECFG 0x66 -#define M66592_TYP 0xC000 /* b15-14: Transfer type */ -#define M66592_ISO 0xC000 /* Isochronous */ -#define M66592_INT 0x8000 /* Interrupt */ -#define M66592_BULK 0x4000 /* Bulk */ -#define M66592_BFRE 0x0400 /* b10: Buffer ready interrupt mode select */ -#define M66592_DBLB 0x0200 /* b9: Double buffer mode select */ -#define M66592_CNTMD 0x0100 /* b8: Continuous transfer mode select */ -#define M66592_SHTNAK 0x0080 /* b7: Transfer end NAK */ -#define M66592_DIR 0x0010 /* b4: Transfer direction select */ -#define M66592_DIR_H_OUT 0x0010 /* HOST OUT */ -#define M66592_DIR_P_IN 0x0010 /* PERI IN */ -#define M66592_DIR_H_IN 0x0000 /* HOST IN */ -#define M66592_DIR_P_OUT 0x0000 /* PERI OUT */ -#define M66592_EPNUM 0x000F /* b3-0: Eendpoint number select */ -#define M66592_EP1 0x0001 -#define M66592_EP2 0x0002 -#define M66592_EP3 0x0003 -#define M66592_EP4 0x0004 -#define M66592_EP5 0x0005 -#define M66592_EP6 0x0006 -#define M66592_EP7 0x0007 -#define M66592_EP8 0x0008 -#define M66592_EP9 0x0009 -#define M66592_EP10 0x000A -#define M66592_EP11 0x000B -#define M66592_EP12 0x000C -#define M66592_EP13 0x000D -#define M66592_EP14 0x000E -#define M66592_EP15 0x000F +#define M66592_TYP 0xC000 /* b15-14: Transfer type */ +#define M66592_ISO 0xC000 /* Isochronous */ +#define M66592_INT 0x8000 /* Interrupt */ +#define M66592_BULK 0x4000 /* Bulk */ +#define M66592_BFRE 0x0400 /* b10: Buffer ready interrupt mode */ +#define M66592_DBLB 0x0200 /* b9: Double buffer mode select */ +#define M66592_CNTMD 0x0100 /* b8: Continuous transfer mode */ +#define M66592_SHTNAK 0x0080 /* b7: Transfer end NAK */ +#define M66592_DIR 0x0010 /* b4: Transfer direction select */ +#define M66592_DIR_H_OUT 0x0010 /* HOST OUT */ +#define M66592_DIR_P_IN 0x0010 /* PERI IN */ +#define M66592_DIR_H_IN 0x0000 /* HOST IN */ +#define M66592_DIR_P_OUT 0x0000 /* PERI OUT */ +#define M66592_EPNUM 0x000F /* b3-0: Eendpoint number select */ +#define M66592_EP1 0x0001 +#define M66592_EP2 0x0002 +#define M66592_EP3 0x0003 +#define M66592_EP4 0x0004 +#define M66592_EP5 0x0005 +#define M66592_EP6 0x0006 +#define M66592_EP7 0x0007 +#define M66592_EP8 0x0008 +#define M66592_EP9 0x0009 +#define M66592_EP10 0x000A +#define M66592_EP11 0x000B +#define M66592_EP12 0x000C +#define M66592_EP13 0x000D +#define M66592_EP14 0x000E +#define M66592_EP15 0x000F #define M66592_PIPEBUF 0x68 -#define M66592_BUFSIZE 0x7C00 /* b14-10: Pipe buffer size */ -#define M66592_BUF_SIZE(x) ((((x) / 64) - 1) << 10) -#define M66592_BUFNMB 0x00FF /* b7-0: Pipe buffer number */ +#define M66592_BUFSIZE 0x7C00 /* b14-10: Pipe buffer size */ +#define M66592_BUF_SIZE(x) ((((x) / 64) - 1) << 10) +#define M66592_BUFNMB 0x00FF /* b7-0: Pipe buffer number */ #define M66592_PIPEMAXP 0x6A -#define M66592_MXPS 0x07FF /* b10-0: Maxpacket size */ +#define M66592_MXPS 0x07FF /* b10-0: Maxpacket size */ #define M66592_PIPEPERI 0x6C -#define M66592_IFIS 0x1000 /* b12: Isochronous in-buffer flush mode select */ -#define M66592_IITV 0x0007 /* b2-0: Isochronous interval */ +#define M66592_IFIS 0x1000 /* b12: ISO in-buffer flush mode */ +#define M66592_IITV 0x0007 /* b2-0: ISO interval */ #define M66592_PIPE1CTR 0x70 #define M66592_PIPE2CTR 0x72 @@ -401,19 +401,17 @@ #define M66592_PIPE5CTR 0x78 #define M66592_PIPE6CTR 0x7A #define M66592_PIPE7CTR 0x7C -#define M66592_BSTS 0x8000 /* b15: Buffer status */ -#define M66592_INBUFM 0x4000 /* b14: IN buffer monitor (Only for PIPE1 to 5) */ -#define M66592_ACLRM 0x0200 /* b9: Out buffer auto clear mode */ -#define M66592_SQCLR 0x0100 /* b8: Sequence toggle bit clear */ -#define M66592_SQSET 0x0080 /* b7: Sequence toggle bit set */ -#define M66592_SQMON 0x0040 /* b6: Sequence toggle bit monitor */ -#define M66592_PID 0x0003 /* b1-0: Response PID */ +#define M66592_BSTS 0x8000 /* b15: Buffer status */ +#define M66592_INBUFM 0x4000 /* b14: IN buffer monitor (PIPE 1-5) */ +#define M66592_ACLRM 0x0200 /* b9: Out buffer auto clear mode */ +#define M66592_SQCLR 0x0100 /* b8: Sequence toggle bit clear */ +#define M66592_SQSET 0x0080 /* b7: Sequence toggle bit set */ +#define M66592_SQMON 0x0040 /* b6: Sequence toggle bit monitor */ +#define M66592_PID 0x0003 /* b1-0: Response PID */ #define M66592_INVALID_REG 0x7E -#define __iomem - #define get_pipectr_addr(pipenum) (M66592_PIPE1CTR + (pipenum - 1) * 2) #define M66592_MAX_SAMPLING 10 @@ -449,7 +447,7 @@ struct m66592_ep { struct m66592 *m66592; struct list_head queue; - unsigned busy:1; + unsigned busy:1; unsigned internal_ccpl:1; /* use only control */ /* this member can able to after m66592_enable */ @@ -477,7 +475,7 @@ struct m66592 { struct m66592_ep *epaddr2ep[16]; struct usb_request *ep0_req; /* for internal request */ - u16 *ep0_buf; /* for internal request */ + u16 ep0_data; /* for internal request */ struct timer_list timer; @@ -527,8 +525,8 @@ static inline u16 m66592_read(struct m66592 *m66592, unsigned long offset) } static inline void m66592_read_fifo(struct m66592 *m66592, - unsigned long offset, - void *buf, unsigned long len) + unsigned long offset, + void *buf, unsigned long len) { unsigned long fifoaddr = (unsigned long)m66592->reg + offset; @@ -543,8 +541,8 @@ static inline void m66592_write(struct m66592 *m66592, u16 val, } static inline void m66592_write_fifo(struct m66592 *m66592, - unsigned long offset, - void *buf, unsigned long len) + unsigned long offset, + void *buf, unsigned long len) { unsigned long fifoaddr = (unsigned long)m66592->reg + offset; unsigned long odd = len & 0x0001; @@ -558,7 +556,7 @@ static inline void m66592_write_fifo(struct m66592 *m66592, } static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat, - unsigned long offset) + unsigned long offset) { u16 tmp; tmp = m66592_read(m66592, offset); diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index 38138bb9ddb..9cd98e73dc1 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -33,6 +33,7 @@ #include <linux/device.h> #include <linux/tty.h> #include <linux/tty_flip.h> +#include <linux/mutex.h> #include <asm/byteorder.h> #include <asm/io.h> @@ -258,7 +259,7 @@ static const char *EP_IN_NAME; static const char *EP_OUT_NAME; static const char *EP_NOTIFY_NAME; -static struct semaphore gs_open_close_sem[GS_NUM_PORTS]; +static struct mutex gs_open_close_lock[GS_NUM_PORTS]; static unsigned int read_q_size = GS_DEFAULT_READ_Q_SIZE; static unsigned int write_q_size = GS_DEFAULT_WRITE_Q_SIZE; @@ -595,7 +596,7 @@ static int __init gs_module_init(void) tty_set_operations(gs_tty_driver, &gs_tty_ops); for (i=0; i < GS_NUM_PORTS; i++) - sema_init(&gs_open_close_sem[i], 1); + mutex_init(&gs_open_close_lock[i]); retval = tty_register_driver(gs_tty_driver); if (retval) { @@ -635,7 +636,7 @@ static int gs_open(struct tty_struct *tty, struct file *file) struct gs_port *port; struct gs_dev *dev; struct gs_buf *buf; - struct semaphore *sem; + struct mutex *mtx; int ret; port_num = tty->index; @@ -656,10 +657,10 @@ static int gs_open(struct tty_struct *tty, struct file *file) return -ENODEV; } - sem = &gs_open_close_sem[port_num]; - if (down_interruptible(sem)) { + mtx = &gs_open_close_lock[port_num]; + if (mutex_lock_interruptible(mtx)) { printk(KERN_ERR - "gs_open: (%d,%p,%p) interrupted waiting for semaphore\n", + "gs_open: (%d,%p,%p) interrupted waiting for mutex\n", port_num, tty, file); return -ERESTARTSYS; } @@ -754,12 +755,12 @@ static int gs_open(struct tty_struct *tty, struct file *file) exit_unlock_port: spin_unlock_irqrestore(&port->port_lock, flags); - up(sem); + mutex_unlock(mtx); return ret; exit_unlock_dev: spin_unlock_irqrestore(&dev->dev_lock, flags); - up(sem); + mutex_unlock(mtx); return ret; } @@ -781,7 +782,7 @@ exit_unlock_dev: static void gs_close(struct tty_struct *tty, struct file *file) { struct gs_port *port = tty->driver_data; - struct semaphore *sem; + struct mutex *mtx; if (port == NULL) { printk(KERN_ERR "gs_close: NULL port pointer\n"); @@ -790,8 +791,8 @@ static void gs_close(struct tty_struct *tty, struct file *file) gs_debug("gs_close: (%d,%p,%p)\n", port->port_num, tty, file); - sem = &gs_open_close_sem[port->port_num]; - down(sem); + mtx = &gs_open_close_lock[port->port_num]; + mutex_lock(mtx); spin_lock_irq(&port->port_lock); @@ -846,7 +847,7 @@ static void gs_close(struct tty_struct *tty, struct file *file) exit: spin_unlock_irq(&port->port_lock); - up(sem); + mutex_unlock(mtx); } /* diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 46873f2534b..5c851a36de7 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -228,7 +228,6 @@ static void preproc_atl_queue(struct isp116x *isp116x) struct urb, urb_list); ptd = &ep->ptd; len = ep->length; - spin_lock(&urb->lock); ep->data = (unsigned char *)urb->transfer_buffer + urb->actual_length; @@ -264,7 +263,6 @@ static void preproc_atl_queue(struct isp116x *isp116x) | PTD_EP(ep->epnum); ptd->len = PTD_LEN(len) | PTD_DIR(dir); ptd->faddr = PTD_FA(usb_pipedevice(urb->pipe)); - spin_unlock(&urb->lock); if (!ep->active) { ptd->mps |= PTD_LAST_MSK; isp116x->atl_last_dir = dir; @@ -275,6 +273,61 @@ static void preproc_atl_queue(struct isp116x *isp116x) } /* + Take done or failed requests out of schedule. Give back + processed urbs. +*/ +static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep, + struct urb *urb) +__releases(isp116x->lock) __acquires(isp116x->lock) +{ + unsigned i; + + urb->hcpriv = NULL; + ep->error_count = 0; + + if (usb_pipecontrol(urb->pipe)) + ep->nextpid = USB_PID_SETUP; + + urb_dbg(urb, "Finish"); + + spin_unlock(&isp116x->lock); + usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb); + spin_lock(&isp116x->lock); + + /* take idle endpoints out of the schedule */ + if (!list_empty(&ep->hep->urb_list)) + return; + + /* async deschedule */ + if (!list_empty(&ep->schedule)) { + list_del_init(&ep->schedule); + return; + } + + /* periodic deschedule */ + DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch); + for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) { + struct isp116x_ep *temp; + struct isp116x_ep **prev = &isp116x->periodic[i]; + + while (*prev && ((temp = *prev) != ep)) + prev = &temp->next; + if (*prev) + *prev = ep->next; + isp116x->load[i] -= ep->load; + } + ep->branch = PERIODIC_SIZE; + isp116x_to_hcd(isp116x)->self.bandwidth_allocated -= + ep->load / ep->period; + + /* switch irq type? */ + if (!--isp116x->periodic_count) { + isp116x->irqenb &= ~HCuPINT_SOF; + isp116x->irqenb |= HCuPINT_ATL; + } +} + +/* Analyze transfer results, handle partial transfers and errors */ static void postproc_atl_queue(struct isp116x *isp116x) @@ -284,6 +337,7 @@ static void postproc_atl_queue(struct isp116x *isp116x) struct usb_device *udev; struct ptd *ptd; int short_not_ok; + int status; u8 cc; for (ep = isp116x->atl_active; ep; ep = ep->active) { @@ -294,7 +348,7 @@ static void postproc_atl_queue(struct isp116x *isp116x) ptd = &ep->ptd; cc = PTD_GET_CC(ptd); short_not_ok = 1; - spin_lock(&urb->lock); + status = -EINPROGRESS; /* Data underrun is special. For allowed underrun we clear the error and continue as normal. For @@ -302,47 +356,36 @@ static void postproc_atl_queue(struct isp116x *isp116x) immediately while for control transfer, we do a STATUS stage. */ if (cc == TD_DATAUNDERRUN) { - if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) { - DBG("Allowed data underrun\n"); + if (!(urb->transfer_flags & URB_SHORT_NOT_OK) || + usb_pipecontrol(urb->pipe)) { + DBG("Allowed or control data underrun\n"); cc = TD_CC_NOERROR; short_not_ok = 0; } else { ep->error_count = 1; - if (usb_pipecontrol(urb->pipe)) - ep->nextpid = USB_PID_ACK; - else - usb_settoggle(udev, ep->epnum, - ep->nextpid == - USB_PID_OUT, - PTD_GET_TOGGLE(ptd)); + usb_settoggle(udev, ep->epnum, + ep->nextpid == USB_PID_OUT, + PTD_GET_TOGGLE(ptd)); urb->actual_length += PTD_GET_COUNT(ptd); - urb->status = cc_to_error[TD_DATAUNDERRUN]; - spin_unlock(&urb->lock); - continue; + status = cc_to_error[TD_DATAUNDERRUN]; + goto done; } } - /* Keep underrun error through the STATUS stage */ - if (urb->status == cc_to_error[TD_DATAUNDERRUN]) - cc = TD_DATAUNDERRUN; if (cc != TD_CC_NOERROR && cc != TD_NOTACCESSED && (++ep->error_count >= 3 || cc == TD_CC_STALL || cc == TD_DATAOVERRUN)) { - if (urb->status == -EINPROGRESS) - urb->status = cc_to_error[cc]; + status = cc_to_error[cc]; if (ep->nextpid == USB_PID_ACK) ep->nextpid = 0; - spin_unlock(&urb->lock); - continue; + goto done; } /* According to usb spec, zero-length Int transfer signals finishing of the urb. Hey, does this apply only for IN endpoints? */ if (usb_pipeint(urb->pipe) && !PTD_GET_LEN(ptd)) { - if (urb->status == -EINPROGRESS) - urb->status = 0; - spin_unlock(&urb->lock); - continue; + status = 0; + goto done; } /* Relax after previously failed, but later succeeded @@ -381,8 +424,8 @@ static void postproc_atl_queue(struct isp116x *isp116x) /* All data for this URB is transferred, let's finish */ if (usb_pipecontrol(urb->pipe)) ep->nextpid = USB_PID_ACK; - else if (urb->status == -EINPROGRESS) - urb->status = 0; + else + status = 0; break; case USB_PID_SETUP: if (PTD_GET_ACTIVE(ptd) @@ -402,69 +445,27 @@ static void postproc_atl_queue(struct isp116x *isp116x) if (PTD_GET_ACTIVE(ptd) || (cc != TD_CC_NOERROR && cc < 0x0E)) break; - if (urb->status == -EINPROGRESS) - urb->status = 0; + if ((urb->transfer_flags & URB_SHORT_NOT_OK) && + urb->actual_length < + urb->transfer_buffer_length) + status = -EREMOTEIO; + else + status = 0; ep->nextpid = 0; break; default: BUG(); } - spin_unlock(&urb->lock); - } -} - -/* - Take done or failed requests out of schedule. Give back - processed urbs. -*/ -static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep, - struct urb *urb) -__releases(isp116x->lock) __acquires(isp116x->lock) -{ - unsigned i; - - urb->hcpriv = NULL; - ep->error_count = 0; - - if (usb_pipecontrol(urb->pipe)) - ep->nextpid = USB_PID_SETUP; - - urb_dbg(urb, "Finish"); - - spin_unlock(&isp116x->lock); - usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb); - spin_lock(&isp116x->lock); - - /* take idle endpoints out of the schedule */ - if (!list_empty(&ep->hep->urb_list)) - return; - - /* async deschedule */ - if (!list_empty(&ep->schedule)) { - list_del_init(&ep->schedule); - return; - } - /* periodic deschedule */ - DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch); - for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) { - struct isp116x_ep *temp; - struct isp116x_ep **prev = &isp116x->periodic[i]; - - while (*prev && ((temp = *prev) != ep)) - prev = &temp->next; - if (*prev) - *prev = ep->next; - isp116x->load[i] -= ep->load; - } - ep->branch = PERIODIC_SIZE; - isp116x_to_hcd(isp116x)->self.bandwidth_allocated -= - ep->load / ep->period; - - /* switch irq type? */ - if (!--isp116x->periodic_count) { - isp116x->irqenb &= ~HCuPINT_SOF; - isp116x->irqenb |= HCuPINT_ATL; + done: + if (status != -EINPROGRESS) { + spin_lock(&urb->lock); + if (urb->status == -EINPROGRESS) + urb->status = status; + spin_unlock(&urb->lock); + } + if (urb->status != -EINPROGRESS) + finish_request(isp116x, ep, urb); } } @@ -570,9 +571,6 @@ static void start_atl_transfers(struct isp116x *isp116x) */ static void finish_atl_transfers(struct isp116x *isp116x) { - struct isp116x_ep *ep; - struct urb *urb; - if (!isp116x->atl_active) return; /* Fifo not ready? */ @@ -582,16 +580,6 @@ static void finish_atl_transfers(struct isp116x *isp116x) atomic_inc(&isp116x->atl_finishing); unpack_fifo(isp116x); postproc_atl_queue(isp116x); - for (ep = isp116x->atl_active; ep; ep = ep->active) { - urb = - container_of(ep->hep->urb_list.next, struct urb, urb_list); - /* USB_PID_ACK check here avoids finishing of - control transfers, for which TD_DATAUNDERRUN - occured, while URB_SHORT_NOT_OK was set */ - if (urb && urb->status != -EINPROGRESS - && ep->nextpid != USB_PID_ACK) - finish_request(isp116x, ep, urb); - } atomic_dec(&isp116x->atl_finishing); } @@ -821,15 +809,12 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, } /* in case of unlink-during-submit */ - spin_lock(&urb->lock); if (urb->status != -EINPROGRESS) { - spin_unlock(&urb->lock); finish_request(isp116x, ep, urb); ret = 0; goto fail; } urb->hcpriv = hep; - spin_unlock(&urb->lock); start_atl_transfers(isp116x); fail: diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index a7a7070c6e2..d60f1985320 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -35,10 +35,8 @@ #include <linux/interrupt.h> #include <linux/usb.h> #include <linux/platform_device.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/system.h> +#include <linux/io.h> +#include <linux/irq.h> #include "../core/hcd.h" #include "r8a66597.h" @@ -54,16 +52,21 @@ static const char hcd_name[] = "r8a66597_hcd"; /* module parameters */ static unsigned short clock = XTAL12; module_param(clock, ushort, 0644); -MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0(default=0)"); +MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 " + "(default=0)"); + static unsigned short vif = LDRV; module_param(vif, ushort, 0644); MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0(default=32768)"); -static unsigned short endian = 0; + +static unsigned short endian; module_param(endian, ushort, 0644); -MODULE_PARM_DESC(endian, "data endian: big=256, little=0(default=0)"); +MODULE_PARM_DESC(endian, "data endian: big=256, little=0 (default=0)"); + static unsigned short irq_sense = INTL; module_param(irq_sense, ushort, 0644); -MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=32, falling edge=0(default=32)"); +MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=32, falling edge=0 " + "(default=32)"); static void packet_write(struct r8a66597 *r8a66597, u16 pipenum); static int r8a66597_get_frame(struct usb_hcd *hcd); @@ -308,7 +311,7 @@ static int make_r8a66597_device(struct r8a66597 *r8a66597, struct r8a66597_device *dev; int usb_address = urb->setup_packet[2]; /* urb->pipe is address 0 */ - dev = kzalloc(sizeof(struct r8a66597_device), GFP_KERNEL); + dev = kzalloc(sizeof(struct r8a66597_device), GFP_ATOMIC); if (dev == NULL) return -ENOMEM; @@ -611,33 +614,33 @@ static u16 get_empty_pipenum(struct r8a66597 *r8a66597, u16 array[R8A66597_MAX_NUM_PIPE], i = 0, min; memset(array, 0, sizeof(array)); - switch(ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { - case USB_ENDPOINT_XFER_BULK: + switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_BULK: if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) array[i++] = 4; else { array[i++] = 3; array[i++] = 5; } - break; - case USB_ENDPOINT_XFER_INT: + break; + case USB_ENDPOINT_XFER_INT: if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) { array[i++] = 6; array[i++] = 7; array[i++] = 8; } else array[i++] = 9; - break; - case USB_ENDPOINT_XFER_ISOC: + break; + case USB_ENDPOINT_XFER_ISOC: if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) array[i++] = 2; else array[i++] = 1; - break; - default: - err("Illegal type"); - return 0; - } + break; + default: + err("Illegal type"); + return 0; + } i = 1; min = array[0]; @@ -654,7 +657,7 @@ static u16 get_r8a66597_type(__u8 type) { u16 r8a66597_type; - switch(type) { + switch (type) { case USB_ENDPOINT_XFER_BULK: r8a66597_type = R8A66597_BULK; break; @@ -874,7 +877,7 @@ static void r8a66597_usb_preconnect(struct r8a66597 *r8a66597, int port) { r8a66597->root_hub[port].port |= (1 << USB_PORT_FEAT_CONNECTION) | (1 << USB_PORT_FEAT_C_CONNECTION); - r8a66597_write(r8a66597, (u16)~DTCH, get_intsts_reg(port)); + r8a66597_write(r8a66597, ~DTCH, get_intsts_reg(port)); r8a66597_bset(r8a66597, DTCHE, get_intenb_reg(port)); } @@ -917,7 +920,7 @@ static void prepare_setup_packet(struct r8a66597 *r8a66597, r8a66597_write(r8a66597, make_devsel(td->address) | td->maxpacket, DCPMAXP); - r8a66597_write(r8a66597, (u16)~(SIGN | SACK), INTSTS1); + r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1); for (i = 0; i < 4; i++) { r8a66597_write(r8a66597, p[i], setup_addr); @@ -948,19 +951,18 @@ static void prepare_packet_read(struct r8a66597 *r8a66597, pipe_irq_disable(r8a66597, td->pipenum); pipe_setting(r8a66597, td); pipe_stop(r8a66597, td->pipe); - r8a66597_write(r8a66597, (u16)~(1 << td->pipenum), - BRDYSTS); + r8a66597_write(r8a66597, ~(1 << td->pipenum), BRDYSTS); if (td->pipe->pipetre) { r8a66597_write(r8a66597, TRCLR, - td->pipe->pipetre); + td->pipe->pipetre); r8a66597_write(r8a66597, - (urb->transfer_buffer_length - + td->maxpacket - 1) - / td->maxpacket, - td->pipe->pipetrn); + (urb->transfer_buffer_length + + td->maxpacket - 1) + / td->maxpacket, + td->pipe->pipetrn); r8a66597_bset(r8a66597, TRENB, - td->pipe->pipetre); + td->pipe->pipetre); } pipe_start(r8a66597, td->pipe); @@ -991,7 +993,7 @@ static void prepare_packet_write(struct r8a66597 *r8a66597, if (td->pipe->pipetre) r8a66597_bclr(r8a66597, TRENB, td->pipe->pipetre); } - r8a66597_write(r8a66597, (u16)~(1 << td->pipenum), BRDYSTS); + r8a66597_write(r8a66597, ~(1 << td->pipenum), BRDYSTS); fifo_change_from_pipe(r8a66597, td->pipe); tmp = r8a66597_read(r8a66597, td->pipe->fifoctr); @@ -1009,21 +1011,21 @@ static void prepare_status_packet(struct r8a66597 *r8a66597, struct urb *urb = td->urb; r8a66597_pipe_toggle(r8a66597, td->pipe, 1); + pipe_stop(r8a66597, td->pipe); if (urb->setup_packet[0] & USB_ENDPOINT_DIR_MASK) { r8a66597_bset(r8a66597, R8A66597_DIR, DCPCFG); r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL); r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0); - r8a66597_write(r8a66597, BVAL | BCLR, CFIFOCTR); - r8a66597_write(r8a66597, (u16)~BEMP0, BEMPSTS); + r8a66597_write(r8a66597, ~BEMP0, BEMPSTS); + r8a66597_write(r8a66597, BCLR, CFIFOCTR); + r8a66597_write(r8a66597, BVAL, CFIFOCTR); enable_irq_empty(r8a66597, 0); } else { r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG); r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL); r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0); r8a66597_write(r8a66597, BCLR, CFIFOCTR); - r8a66597_write(r8a66597, (u16)~BRDY0, BRDYSTS); - r8a66597_write(r8a66597, (u16)~BEMP0, BEMPSTS); enable_irq_ready(r8a66597, 0); } enable_irq_nrdy(r8a66597, 0); @@ -1269,7 +1271,7 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum) /* write fifo */ if (pipenum > 0) - r8a66597_write(r8a66597, (u16)~(1 << pipenum), BEMPSTS); + r8a66597_write(r8a66597, ~(1 << pipenum), BEMPSTS); if (urb->transfer_buffer) { r8a66597_write_fifo(r8a66597, td->pipe->fifoaddr, buf, size); if (!usb_pipebulk(urb->pipe) || td->maxpacket != size) @@ -1362,7 +1364,7 @@ static void irq_pipe_ready(struct r8a66597 *r8a66597) mask = r8a66597_read(r8a66597, BRDYSTS) & r8a66597_read(r8a66597, BRDYENB); - r8a66597_write(r8a66597, (u16)~mask, BRDYSTS); + r8a66597_write(r8a66597, ~mask, BRDYSTS); if (mask & BRDY0) { td = r8a66597_get_td(r8a66597, 0); if (td && td->type == USB_PID_IN) @@ -1397,7 +1399,7 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597) mask = r8a66597_read(r8a66597, BEMPSTS) & r8a66597_read(r8a66597, BEMPENB); - r8a66597_write(r8a66597, (u16)~mask, BEMPSTS); + r8a66597_write(r8a66597, ~mask, BEMPSTS); if (mask & BEMP0) { cfifo_change(r8a66597, 0); td = r8a66597_get_td(r8a66597, 0); @@ -1434,7 +1436,7 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597) mask = r8a66597_read(r8a66597, NRDYSTS) & r8a66597_read(r8a66597, NRDYENB); - r8a66597_write(r8a66597, (u16)~mask, NRDYSTS); + r8a66597_write(r8a66597, ~mask, NRDYSTS); if (mask & NRDY0) { cfifo_change(r8a66597, 0); set_urb_error(r8a66597, 0); @@ -1488,14 +1490,14 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd) mask0 = intsts0 & intenb0 & (BEMP | NRDY | BRDY); if (mask2) { if (mask2 & ATTCH) { - r8a66597_write(r8a66597, (u16)~ATTCH, INTSTS2); + r8a66597_write(r8a66597, ~ATTCH, INTSTS2); r8a66597_bclr(r8a66597, ATTCHE, INTENB2); /* start usb bus sampling */ start_root_hub_sampling(r8a66597, 1); } if (mask2 & DTCH) { - r8a66597_write(r8a66597, (u16)~DTCH, INTSTS2); + r8a66597_write(r8a66597, ~DTCH, INTSTS2); r8a66597_bclr(r8a66597, DTCHE, INTENB2); r8a66597_usb_disconnect(r8a66597, 1); } @@ -1503,24 +1505,24 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd) if (mask1) { if (mask1 & ATTCH) { - r8a66597_write(r8a66597, (u16)~ATTCH, INTSTS1); + r8a66597_write(r8a66597, ~ATTCH, INTSTS1); r8a66597_bclr(r8a66597, ATTCHE, INTENB1); /* start usb bus sampling */ start_root_hub_sampling(r8a66597, 0); } if (mask1 & DTCH) { - r8a66597_write(r8a66597, (u16)~DTCH, INTSTS1); + r8a66597_write(r8a66597, ~DTCH, INTSTS1); r8a66597_bclr(r8a66597, DTCHE, INTENB1); r8a66597_usb_disconnect(r8a66597, 0); } if (mask1 & SIGN) { - r8a66597_write(r8a66597, (u16)~SIGN, INTSTS1); + r8a66597_write(r8a66597, ~SIGN, INTSTS1); set_urb_error(r8a66597, 0); check_next_phase(r8a66597); } if (mask1 & SACK) { - r8a66597_write(r8a66597, (u16)~SACK, INTSTS1); + r8a66597_write(r8a66597, ~SACK, INTSTS1); check_next_phase(r8a66597); } } @@ -1663,13 +1665,9 @@ static int check_pipe_config(struct r8a66597 *r8a66597, struct urb *urb) static int r8a66597_start(struct usb_hcd *hcd) { struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd); - int ret; hcd->state = HC_STATE_RUNNING; - if ((ret = enable_controller(r8a66597)) < 0) - return ret; - - return 0; + return enable_controller(r8a66597); } static void r8a66597_stop(struct usb_hcd *hcd) @@ -1696,13 +1694,12 @@ static void set_address_zero(struct r8a66597 *r8a66597, struct urb *urb) static struct r8a66597_td *r8a66597_make_td(struct r8a66597 *r8a66597, struct urb *urb, - struct usb_host_endpoint *hep, - gfp_t mem_flags) + struct usb_host_endpoint *hep) { struct r8a66597_td *td; u16 pipenum; - td = kzalloc(sizeof(struct r8a66597_td), mem_flags); + td = kzalloc(sizeof(struct r8a66597_td), GFP_ATOMIC); if (td == NULL) return NULL; @@ -1741,7 +1738,8 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd, } if (!hep->hcpriv) { - hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe), mem_flags); + hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe), + GFP_ATOMIC); if (!hep->hcpriv) { ret = -ENOMEM; goto error; @@ -1755,7 +1753,7 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd, init_pipe_config(r8a66597, urb); set_address_zero(r8a66597, urb); - td = r8a66597_make_td(r8a66597, urb, hep, mem_flags); + td = r8a66597_make_td(r8a66597, urb, hep); if (td == NULL) { ret = -ENOMEM; goto error; diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h index 97c2a71ac7a..fe9ceb077d9 100644 --- a/drivers/usb/host/r8a66597.h +++ b/drivers/usb/host/r8a66597.h @@ -203,14 +203,14 @@ #define DTLN 0x0FFF /* b11-0: FIFO received data length */ /* Interrupt Enable Register 0 */ -#define VBSE 0x8000 /* b15: VBUS interrupt */ -#define RSME 0x4000 /* b14: Resume interrupt */ -#define SOFE 0x2000 /* b13: Frame update interrupt */ -#define DVSE 0x1000 /* b12: Device state transition interrupt */ -#define CTRE 0x0800 /* b11: Control transfer stage transition interrupt */ -#define BEMPE 0x0400 /* b10: Buffer empty interrupt */ -#define NRDYE 0x0200 /* b9: Buffer not ready interrupt */ -#define BRDYE 0x0100 /* b8: Buffer ready interrupt */ +#define VBSE 0x8000 /* b15: VBUS interrupt */ +#define RSME 0x4000 /* b14: Resume interrupt */ +#define SOFE 0x2000 /* b13: Frame update interrupt */ +#define DVSE 0x1000 /* b12: Device state transition interrupt */ +#define CTRE 0x0800 /* b11: Control transfer stage transition interrupt */ +#define BEMPE 0x0400 /* b10: Buffer empty interrupt */ +#define NRDYE 0x0200 /* b9: Buffer not ready interrupt */ +#define BRDYE 0x0100 /* b8: Buffer ready interrupt */ /* Interrupt Enable Register 1 */ #define OVRCRE 0x8000 /* b15: Over-current interrupt */ @@ -268,16 +268,16 @@ #define SOF_DISABLE 0x0000 /* SOF OUT Disable */ /* Interrupt Status Register 0 */ -#define VBINT 0x8000 /* b15: VBUS interrupt */ -#define RESM 0x4000 /* b14: Resume interrupt */ -#define SOFR 0x2000 /* b13: SOF frame update interrupt */ -#define DVST 0x1000 /* b12: Device state transition interrupt */ -#define CTRT 0x0800 /* b11: Control transfer stage transition interrupt */ -#define BEMP 0x0400 /* b10: Buffer empty interrupt */ -#define NRDY 0x0200 /* b9: Buffer not ready interrupt */ -#define BRDY 0x0100 /* b8: Buffer ready interrupt */ -#define VBSTS 0x0080 /* b7: VBUS input port */ -#define DVSQ 0x0070 /* b6-4: Device state */ +#define VBINT 0x8000 /* b15: VBUS interrupt */ +#define RESM 0x4000 /* b14: Resume interrupt */ +#define SOFR 0x2000 /* b13: SOF frame update interrupt */ +#define DVST 0x1000 /* b12: Device state transition interrupt */ +#define CTRT 0x0800 /* b11: Control transfer stage transition interrupt */ +#define BEMP 0x0400 /* b10: Buffer empty interrupt */ +#define NRDY 0x0200 /* b9: Buffer not ready interrupt */ +#define BRDY 0x0100 /* b8: Buffer ready interrupt */ +#define VBSTS 0x0080 /* b7: VBUS input port */ +#define DVSQ 0x0070 /* b6-4: Device state */ #define DS_SPD_CNFG 0x0070 /* Suspend Configured */ #define DS_SPD_ADDR 0x0060 /* Suspend Address */ #define DS_SPD_DFLT 0x0050 /* Suspend Default */ @@ -315,13 +315,10 @@ /* Micro Frame Number Register */ #define UFRNM 0x0007 /* b2-0: Micro frame number */ -/* USB Address / Low Power Status Recovery Register */ -//#define USBADDR 0x007F /* b6-0: USB address */ - /* Default Control Pipe Maxpacket Size Register */ /* Pipe Maxpacket Size Register */ -#define DEVSEL 0xF000 /* b15-14: Device address select */ -#define MAXP 0x007F /* b6-0: Maxpacket size of default control pipe */ +#define DEVSEL 0xF000 /* b15-14: Device address select */ +#define MAXP 0x007F /* b6-0: Maxpacket size of default control pipe */ /* Default Control Pipe Control Register */ #define BSTS 0x8000 /* b15: Buffer status */ @@ -366,21 +363,21 @@ #define MXPS 0x07FF /* b10-0: Maxpacket size */ /* Pipe Cycle Configuration Register */ -#define IFIS 0x1000 /* b12: Isochronous in-buffer flush mode select */ -#define IITV 0x0007 /* b2-0: Isochronous interval */ +#define IFIS 0x1000 /* b12: Isochronous in-buffer flush mode select */ +#define IITV 0x0007 /* b2-0: Isochronous interval */ /* Pipex Control Register */ -#define BSTS 0x8000 /* b15: Buffer status */ -#define INBUFM 0x4000 /* b14: IN buffer monitor (Only for PIPE1 to 5) */ -#define CSCLR 0x2000 /* b13: complete-split status clear */ -#define CSSTS 0x1000 /* b12: complete-split status */ -#define ATREPM 0x0400 /* b10: Auto repeat mode */ -#define ACLRM 0x0200 /* b9: Out buffer auto clear mode */ -#define SQCLR 0x0100 /* b8: Sequence toggle bit clear */ -#define SQSET 0x0080 /* b7: Sequence toggle bit set */ -#define SQMON 0x0040 /* b6: Sequence toggle bit monitor */ -#define PBUSY 0x0020 /* b5: pipe busy */ -#define PID 0x0003 /* b1-0: Response PID */ +#define BSTS 0x8000 /* b15: Buffer status */ +#define INBUFM 0x4000 /* b14: IN buffer monitor (Only for PIPE1 to 5) */ +#define CSCLR 0x2000 /* b13: complete-split status clear */ +#define CSSTS 0x1000 /* b12: complete-split status */ +#define ATREPM 0x0400 /* b10: Auto repeat mode */ +#define ACLRM 0x0200 /* b9: Out buffer auto clear mode */ +#define SQCLR 0x0100 /* b8: Sequence toggle bit clear */ +#define SQSET 0x0080 /* b7: Sequence toggle bit set */ +#define SQMON 0x0040 /* b6: Sequence toggle bit monitor */ +#define PBUSY 0x0020 /* b5: pipe busy */ +#define PID 0x0003 /* b1-0: Response PID */ /* PIPExTRE */ #define TRENB 0x0200 /* b9: Transaction counter enable */ @@ -407,15 +404,15 @@ #define make_devsel(addr) (addr << 12) struct r8a66597_pipe_info { - u16 pipenum; - u16 address; /* R8A66597 HCD usb addres */ - u16 epnum; - u16 maxpacket; - u16 type; - u16 bufnum; - u16 buf_bsize; - u16 interval; - u16 dir_in; + u16 pipenum; + u16 address; /* R8A66597 HCD usb addres */ + u16 epnum; + u16 maxpacket; + u16 type; + u16 bufnum; + u16 buf_bsize; + u16 interval; + u16 dir_in; }; struct r8a66597_pipe { diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index e98df2ee990..7f765ec038c 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -52,6 +52,7 @@ #include <linux/workqueue.h> #include <linux/platform_device.h> #include <linux/pci_ids.h> +#include <linux/mutex.h> #include <asm/io.h> #include <asm/irq.h> #include <asm/system.h> @@ -83,7 +84,7 @@ static DECLARE_WAIT_QUEUE_HEAD(u132_hcd_wait); * u132_module_lock exists to protect access to global variables * */ -static struct semaphore u132_module_lock; +static struct mutex u132_module_lock; static int u132_exiting = 0; static int u132_instances = 0; static struct list_head u132_static_list; @@ -258,10 +259,10 @@ static void u132_hcd_delete(struct kref *kref) struct platform_device *pdev = u132->platform_dev; struct usb_hcd *hcd = u132_to_hcd(u132); u132->going += 1; - down(&u132_module_lock); + mutex_lock(&u132_module_lock); list_del_init(&u132->u132_list); u132_instances -= 1; - up(&u132_module_lock); + mutex_unlock(&u132_module_lock); dev_warn(&u132->platform_dev->dev, "FREEING the hcd=%p and thus the u13" "2=%p going=%d pdev=%p\n", hcd, u132, u132->going, pdev); usb_put_hcd(hcd); @@ -3111,10 +3112,10 @@ static int __devinit u132_probe(struct platform_device *pdev) int retval = 0; struct u132 *u132 = hcd_to_u132(hcd); hcd->rsrc_start = 0; - down(&u132_module_lock); + mutex_lock(&u132_module_lock); list_add_tail(&u132->u132_list, &u132_static_list); u132->sequence_num = ++u132_instances; - up(&u132_module_lock); + mutex_unlock(&u132_module_lock); u132_u132_init_kref(u132); u132_initialise(u132, pdev); hcd->product_desc = "ELAN U132 Host Controller"; @@ -3216,7 +3217,7 @@ static int __init u132_hcd_init(void) INIT_LIST_HEAD(&u132_static_list); u132_instances = 0; u132_exiting = 0; - init_MUTEX(&u132_module_lock); + mutex_init(&u132_module_lock); if (usb_disabled()) return -ENODEV; printk(KERN_INFO "driver %s built at %s on %s\n", hcd_name, __TIME__, @@ -3232,9 +3233,9 @@ static void __exit u132_hcd_exit(void) { struct u132 *u132; struct u132 *temp; - down(&u132_module_lock); + mutex_lock(&u132_module_lock); u132_exiting += 1; - up(&u132_module_lock); + mutex_unlock(&u132_module_lock); list_for_each_entry_safe(u132, temp, &u132_static_list, u132_list) { platform_device_unregister(u132->platform_dev); } platform_driver_unregister(&u132_platform_driver); diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 4aed305982e..3bb908ca38e 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -827,8 +827,10 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, * If direction is "send", change the packet ID from SETUP (0x2D) * to OUT (0xE1). Else change it from SETUP to IN (0x69) and * set Short Packet Detect (SPD) for all data packets. + * + * 0-length transfers always get treated as "send". */ - if (usb_pipeout(urb->pipe)) + if (usb_pipeout(urb->pipe) || len == 0) destination ^= (USB_PID_SETUP ^ USB_PID_OUT); else { destination ^= (USB_PID_SETUP ^ USB_PID_IN); @@ -839,7 +841,12 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, * Build the DATA TDs */ while (len > 0) { - int pktsze = min(len, maxsze); + int pktsze = maxsze; + + if (len <= pktsze) { /* The last data packet */ + pktsze = len; + status &= ~TD_CTRL_SPD; + } td = uhci_alloc_td(uhci); if (!td) @@ -866,20 +873,10 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, goto nomem; *plink = LINK_TO_TD(td); - /* - * It's IN if the pipe is an output pipe or we're not expecting - * data back. - */ - destination &= ~TD_TOKEN_PID_MASK; - if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length) - destination |= USB_PID_IN; - else - destination |= USB_PID_OUT; - + /* Change direction for the status transaction */ + destination ^= (USB_PID_IN ^ USB_PID_OUT); destination |= TD_TOKEN_TOGGLE; /* End in Data1 */ - status &= ~TD_CTRL_SPD; - uhci_add_td_to_urbp(td, urbp); uhci_fill_td(td, status | TD_CTRL_IOC, destination | uhci_explen(0), 0); @@ -1185,10 +1182,18 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb) } } + /* Did we receive a short packet? */ } else if (len < uhci_expected_length(td_token(td))) { - /* We received a short packet */ - if (urb->transfer_flags & URB_SHORT_NOT_OK) + /* For control transfers, go to the status TD if + * this isn't already the last data TD */ + if (qh->type == USB_ENDPOINT_XFER_CONTROL) { + if (td->list.next != urbp->td_list.prev) + ret = 1; + } + + /* For bulk and interrupt, this may be an error */ + else if (urb->transfer_flags & URB_SHORT_NOT_OK) ret = -EREMOTEIO; /* Fixup needed only if this isn't the URB's last TD */ @@ -1208,10 +1213,6 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb) err: if (ret < 0) { - /* In case a control transfer gets an error - * during the setup stage */ - urb->actual_length = max(urb->actual_length, 0); - /* Note that the queue has stopped and save * the next toggle value */ qh->element = UHCI_PTR_TERM; @@ -1489,9 +1490,25 @@ __acquires(uhci->lock) { struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; + if (qh->type == USB_ENDPOINT_XFER_CONTROL) { + + /* urb->actual_length < 0 means the setup transaction didn't + * complete successfully. Either it failed or the URB was + * 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, * reinitialize the QH's iso-related members for the next URB. */ - if (qh->type == USB_ENDPOINT_XFER_ISOC && + else if (qh->type == USB_ENDPOINT_XFER_ISOC && urbp->node.prev == &qh->queue && urbp->node.next != &qh->queue) { struct urb *nurb = list_entry(urbp->node.next, diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c index 36502a06f73..d1131a87a5b 100644 --- a/drivers/usb/image/mdc800.c +++ b/drivers/usb/image/mdc800.c @@ -284,9 +284,9 @@ static void mdc800_usb_irq (struct urb *urb) int data_received=0, wake_up; unsigned char* b=urb->transfer_buffer; struct mdc800_data* mdc800=urb->context; + int status = urb->status; - if (urb->status >= 0) - { + if (status >= 0) { //dbg ("%i %i %i %i %i %i %i %i \n",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]); @@ -324,7 +324,7 @@ static void mdc800_usb_irq (struct urb *urb) || ((mdc800->camera_request_ready == 3) && (mdc800->camera_busy)) || - (urb->status < 0) + (status < 0) ); if (wake_up) @@ -376,15 +376,12 @@ static int mdc800_usb_waitForIRQ (int mode, int msec) static void mdc800_usb_write_notify (struct urb *urb) { struct mdc800_data* mdc800=urb->context; + int status = urb->status; - if (urb->status != 0) - { - err ("writing command fails (status=%i)", urb->status); - } + if (status != 0) + err ("writing command fails (status=%i)", status); else - { mdc800->state=READY; - } mdc800->written = 1; wake_up (&mdc800->write_wait); } @@ -396,9 +393,9 @@ static void mdc800_usb_write_notify (struct urb *urb) static void mdc800_usb_download_notify (struct urb *urb) { struct mdc800_data* mdc800=urb->context; + int status = urb->status; - if (urb->status == 0) - { + if (status == 0) { /* Fill output buffer with these data */ memcpy (mdc800->out, urb->transfer_buffer, 64); mdc800->out_count=64; @@ -408,10 +405,8 @@ static void mdc800_usb_download_notify (struct urb *urb) { mdc800->state=READY; } - } - else - { - err ("request bytes fails (status:%i)", urb->status); + } else { + err ("request bytes fails (status:%i)", status); } mdc800->downloaded = 1; wake_up (&mdc800->download_wait); @@ -649,9 +644,9 @@ static int mdc800_device_open (struct inode* inode, struct file *file) retval=0; mdc800->irq_urb->dev = mdc800->dev; - if (usb_submit_urb (mdc800->irq_urb, GFP_KERNEL)) - { - err ("request USB irq fails (submit_retval=%i urb_status=%i).",retval, mdc800->irq_urb->status); + retval = usb_submit_urb (mdc800->irq_urb, GFP_KERNEL); + if (retval) { + err ("request USB irq fails (submit_retval=%i).", retval); errn = -EIO; goto error_out; } @@ -698,6 +693,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l { size_t left=len, sts=len; /* single transfer size */ char __user *ptr = buf; + int retval; mutex_lock(&mdc800->io_lock); if (mdc800->state == NOT_CONNECTED) @@ -737,9 +733,9 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l /* Download -> Request new bytes */ mdc800->download_urb->dev = mdc800->dev; - if (usb_submit_urb (mdc800->download_urb, GFP_KERNEL)) - { - err ("Can't submit download urb (status=%i)",mdc800->download_urb->status); + retval = usb_submit_urb (mdc800->download_urb, GFP_KERNEL); + if (retval) { + err ("Can't submit download urb (retval=%i)",retval); mutex_unlock(&mdc800->io_lock); return len-left; } @@ -788,6 +784,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l static ssize_t mdc800_device_write (struct file *file, const char __user *buf, size_t len, loff_t *pos) { size_t i=0; + int retval; mutex_lock(&mdc800->io_lock); if (mdc800->state != READY) @@ -854,9 +851,9 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s mdc800->state=WORKING; memcpy (mdc800->write_urb->transfer_buffer, mdc800->in,8); mdc800->write_urb->dev = mdc800->dev; - if (usb_submit_urb (mdc800->write_urb, GFP_KERNEL)) - { - err ("submitting write urb fails (status=%i)", mdc800->write_urb->status); + retval = usb_submit_urb (mdc800->write_urb, GFP_KERNEL); + if (retval) { + err ("submitting write urb fails (retval=%i)", retval); mutex_unlock(&mdc800->io_lock); return -EIO; } diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c index 51bd80d2b8c..768b2c11a23 100644 --- a/drivers/usb/image/microtek.c +++ b/drivers/usb/image/microtek.c @@ -189,7 +189,7 @@ static struct usb_driver mts_usb_driver = { #define MTS_DEBUG_INT() \ do { MTS_DEBUG_GOT_HERE(); \ MTS_DEBUG("transfer = 0x%x context = 0x%x\n",(int)transfer,(int)context ); \ - MTS_DEBUG("status = 0x%x data-length = 0x%x sent = 0x%x\n",(int)transfer->status,(int)context->data_length, (int)transfer->actual_length ); \ + MTS_DEBUG("status = 0x%x data-length = 0x%x sent = 0x%x\n",transfer->status,(int)context->data_length, (int)transfer->actual_length ); \ mts_debug_dump(context->instance);\ } while(0) #else @@ -393,8 +393,6 @@ void mts_int_submit_urb (struct urb* transfer, context ); - transfer->status = 0; - res = usb_submit_urb( transfer, GFP_ATOMIC ); if ( unlikely(res) ) { MTS_INT_ERROR( "could not submit URB! Error was %d\n",(int)res ); @@ -444,12 +442,13 @@ static void mts_get_status( struct urb *transfer ) static void mts_data_done( struct urb* transfer ) /* Interrupt context! */ { + int status = transfer->status; MTS_INT_INIT(); if ( context->data_length != transfer->actual_length ) { context->srb->resid = context->data_length - transfer->actual_length; - } else if ( unlikely(transfer->status) ) { - context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16; + } else if ( unlikely(status) ) { + context->srb->result = (status == -ENOENT ? DID_ABORT : DID_ERROR)<<16; } mts_get_status(transfer); @@ -461,10 +460,11 @@ static void mts_data_done( struct urb* transfer ) static void mts_command_done( struct urb *transfer ) /* Interrupt context! */ { + int status = transfer->status; MTS_INT_INIT(); - if ( unlikely(transfer->status) ) { - if (transfer->status == -ENOENT) { + if ( unlikely(status) ) { + if (status == -ENOENT) { /* We are being killed */ MTS_DEBUG_GOT_HERE(); context->srb->result = DID_ABORT<<16; @@ -502,12 +502,13 @@ static void mts_command_done( struct urb *transfer ) static void mts_do_sg (struct urb* transfer) { struct scatterlist * sg; + int status = transfer->status; MTS_INT_INIT(); MTS_DEBUG("Processing fragment %d of %d\n", context->fragment,context->srb->use_sg); - if (unlikely(transfer->status)) { - context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16; + if (unlikely(status)) { + context->srb->result = (status == -ENOENT ? DID_ABORT : DID_ERROR)<<16; mts_transfer_cleanup(transfer); } diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index d72c42e5f22..e9fdbc8997b 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -24,6 +24,7 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/usb.h> +#include <linux/mutex.h> #include <asm/uaccess.h> #ifdef CONFIG_USB_DEBUG @@ -80,7 +81,7 @@ MODULE_DEVICE_TABLE(usb, device_table); /* Structure to hold all of our device specific stuff */ struct adu_device { - struct semaphore sem; /* locks this structure */ + struct mutex mtx; /* locks this structure */ struct usb_device* udev; /* save off the usb device pointer */ struct usb_interface* interface; unsigned char minor; /* the starting minor number for this device */ @@ -178,17 +179,18 @@ static void adu_delete(struct adu_device *dev) static void adu_interrupt_in_callback(struct urb *urb) { struct adu_device *dev = urb->context; + int status = urb->status; - dbg(4," %s : enter, status %d", __FUNCTION__, urb->status); + dbg(4," %s : enter, status %d", __FUNCTION__, status); adu_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer); spin_lock(&dev->buflock); - if (urb->status != 0) { - if ((urb->status != -ENOENT) && (urb->status != -ECONNRESET)) { + if (status != 0) { + if ((status != -ENOENT) && (status != -ECONNRESET)) { dbg(1," %s : nonzero status received: %d", - __FUNCTION__, urb->status); + __FUNCTION__, status); } goto exit; } @@ -216,21 +218,22 @@ exit: wake_up_interruptible(&dev->read_wait); adu_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer); - dbg(4," %s : leave, status %d", __FUNCTION__, urb->status); + dbg(4," %s : leave, status %d", __FUNCTION__, status); } static void adu_interrupt_out_callback(struct urb *urb) { struct adu_device *dev = urb->context; + int status = urb->status; - dbg(4," %s : enter, status %d", __FUNCTION__, urb->status); + dbg(4," %s : enter, status %d", __FUNCTION__, status); adu_debug_data(5,__FUNCTION__, urb->actual_length, urb->transfer_buffer); - if (urb->status != 0) { - if ((urb->status != -ENOENT) && - (urb->status != -ECONNRESET)) { + if (status != 0) { + if ((status != -ENOENT) && + (status != -ECONNRESET)) { dbg(1, " %s :nonzero status received: %d", - __FUNCTION__, urb->status); + __FUNCTION__, status); } goto exit; } @@ -240,7 +243,7 @@ exit: adu_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer); - dbg(4," %s : leave, status %d", __FUNCTION__, urb->status); + dbg(4," %s : leave, status %d", __FUNCTION__, status); } static int adu_open(struct inode *inode, struct file *file) @@ -269,8 +272,8 @@ static int adu_open(struct inode *inode, struct file *file) } /* lock this device */ - if ((retval = down_interruptible(&dev->sem))) { - dbg(2, "%s : sem down failed", __FUNCTION__); + if ((retval = mutex_lock_interruptible(&dev->mtx))) { + dbg(2, "%s : mutex lock failed", __FUNCTION__); goto exit_no_device; } @@ -299,7 +302,7 @@ static int adu_open(struct inode *inode, struct file *file) if (retval) --dev->open_count; } - up(&dev->sem); + mutex_unlock(&dev->mtx); exit_no_device: dbg(2,"%s : leave, return value %d ", __FUNCTION__, retval); @@ -347,7 +350,7 @@ static int adu_release(struct inode *inode, struct file *file) } /* lock our device */ - down(&dev->sem); /* not interruptible */ + mutex_lock(&dev->mtx); /* not interruptible */ if (dev->open_count <= 0) { dbg(1," %s : device not opened", __FUNCTION__); @@ -357,7 +360,7 @@ static int adu_release(struct inode *inode, struct file *file) if (dev->udev == NULL) { /* the device was unplugged before the file was released */ - up(&dev->sem); + mutex_unlock(&dev->mtx); adu_delete(dev); dev = NULL; } else { @@ -367,7 +370,7 @@ static int adu_release(struct inode *inode, struct file *file) exit: if (dev) - up(&dev->sem); + mutex_unlock(&dev->mtx); dbg(2," %s : leave, return value %d", __FUNCTION__, retval); return retval; } @@ -390,7 +393,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count, dev = file->private_data; dbg(2," %s : dev=%p", __FUNCTION__, dev); /* lock this object */ - if (down_interruptible(&dev->sem)) + if (mutex_lock_interruptible(&dev->mtx)) return -ERESTARTSYS; /* verify that the device wasn't unplugged */ @@ -522,7 +525,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count, exit: /* unlock the device */ - up(&dev->sem); + mutex_unlock(&dev->mtx); dbg(2," %s : leave, return value %d", __FUNCTION__, retval); return retval; @@ -543,7 +546,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer, dev = file->private_data; /* lock this object */ - retval = down_interruptible(&dev->sem); + retval = mutex_lock_interruptible(&dev->mtx); if (retval) goto exit_nolock; @@ -571,9 +574,9 @@ static ssize_t adu_write(struct file *file, const __user char *buffer, retval = -EINTR; goto exit; } - up(&dev->sem); + mutex_unlock(&dev->mtx); timeout = interruptible_sleep_on_timeout(&dev->write_wait, timeout); - retval = down_interruptible(&dev->sem); + retval = mutex_lock_interruptible(&dev->mtx); if (retval) { retval = bytes_written ? bytes_written : retval; goto exit_nolock; @@ -638,7 +641,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer, exit: /* unlock the device */ - up(&dev->sem); + mutex_unlock(&dev->mtx); exit_nolock: dbg(2," %s : leave, return value %d", __FUNCTION__, retval); @@ -698,7 +701,7 @@ static int adu_probe(struct usb_interface *interface, goto exit; } - init_MUTEX(&dev->sem); + mutex_init(&dev->mtx); spin_lock_init(&dev->buflock); dev->udev = udev; init_waitqueue_head(&dev->read_wait); @@ -835,16 +838,16 @@ static void adu_disconnect(struct usb_interface *interface) usb_deregister_dev(interface, &adu_class); dev->minor = 0; - down(&dev->sem); /* not interruptible */ + mutex_lock(&dev->mtx); /* not interruptible */ /* if the device is not opened, then we clean up right now */ dbg(2," %s : open count %d", __FUNCTION__, dev->open_count); if (!dev->open_count) { - up(&dev->sem); + mutex_unlock(&dev->mtx); adu_delete(dev); } else { dev->udev = NULL; - up(&dev->sem); + mutex_unlock(&dev->mtx); } dev_info(&interface->dev, "ADU device adutux%d now disconnected", diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index cf70c16f0e3..b09c83568c1 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -88,9 +88,10 @@ static void appledisplay_complete(struct urb *urb) { struct appledisplay *pdata = urb->context; unsigned long flags; + int status = urb->status; int retval; - switch (urb->status) { + switch (status) { case 0: /* success */ break; @@ -102,12 +103,12 @@ static void appledisplay_complete(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* This urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __FUNCTION__, urb->status); + dbg("%s - urb shuttingdown with status: %d", + __FUNCTION__, status); return; default: dbg("%s - nonzero urb status received: %d", - __FUNCTION__, urb->status); + __FUNCTION__, status); goto exit; } diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c index 42d4e6454a7..df7e1ecc810 100644 --- a/drivers/usb/misc/auerswald.c +++ b/drivers/usb/misc/auerswald.c @@ -862,14 +862,16 @@ static void auerswald_ctrlread_wretcomplete (struct urb * urb) pauerbuf_t bp = (pauerbuf_t) urb->context; pauerswald_t cp; int ret; + int status = urb->status; + dbg ("auerswald_ctrlread_wretcomplete called"); - dbg ("complete with status: %d", urb->status); + dbg ("complete with status: %d", status); cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl))); /* check if it is possible to advance */ - if (!auerswald_status_retry (urb->status) || !cp->usbdev) { + if (!auerswald_status_retry(status) || !cp->usbdev) { /* reuse the buffer */ - err ("control dummy: transmission error %d, can not retry", urb->status); + err ("control dummy: transmission error %d, can not retry", status); auerbuf_releasebuf (bp); /* Wake up all processes waiting for a buffer */ wake_up (&cp->bufferwait); @@ -902,21 +904,23 @@ static void auerswald_ctrlread_complete (struct urb * urb) pauerswald_t cp; pauerscon_t scp; pauerbuf_t bp = (pauerbuf_t) urb->context; + int status = urb->status; int ret; + dbg ("auerswald_ctrlread_complete called"); cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl))); /* check if there is valid data in this urb */ - if (urb->status) { - dbg ("complete with non-zero status: %d", urb->status); + if (status) { + dbg ("complete with non-zero status: %d", status); /* should we do a retry? */ - if (!auerswald_status_retry (urb->status) + if (!auerswald_status_retry(status) || !cp->usbdev || (cp->version < AUV_RETRY) || (bp->retries >= AU_RETRIES)) { /* reuse the buffer */ - err ("control read: transmission error %d, can not retry", urb->status); + err ("control read: transmission error %d, can not retry", status); auerbuf_releasebuf (bp); /* Wake up all processes waiting for a buffer */ wake_up (&cp->bufferwait); @@ -974,12 +978,13 @@ static void auerswald_int_complete (struct urb * urb) unsigned int channelid; unsigned int bytecount; int ret; + int status = urb->status; pauerbuf_t bp = NULL; pauerswald_t cp = (pauerswald_t) urb->context; dbg ("%s called", __FUNCTION__); - switch (urb->status) { + switch (status) { case 0: /* success */ break; @@ -987,10 +992,10 @@ static void auerswald_int_complete (struct urb * urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); + dbg("%s - urb shutting down with status: %d", __FUNCTION__, status); return; default: - dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); + dbg("%s - nonzero urb status received: %d", __FUNCTION__, status); goto exit; } diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index e0f122e131d..538b535e955 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -44,6 +44,7 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/kref.h> +#include <linux/mutex.h> #include <asm/uaccess.h> #include <linux/usb.h> #include <linux/workqueue.h> @@ -64,7 +65,7 @@ static struct workqueue_struct *respond_queue; * ftdi_module_lock exists to protect access to global variables * */ -static struct semaphore ftdi_module_lock; +static struct mutex ftdi_module_lock; static int ftdi_instances = 0; static struct list_head ftdi_static_list; /* @@ -199,10 +200,10 @@ static void ftdi_elan_delete(struct kref *kref) dev_warn(&ftdi->udev->dev, "FREEING ftdi=%p\n", ftdi); usb_put_dev(ftdi->udev); ftdi->disconnected += 1; - down(&ftdi_module_lock); + mutex_lock(&ftdi_module_lock); list_del_init(&ftdi->ftdi_list); ftdi_instances -= 1; - up(&ftdi_module_lock); + mutex_unlock(&ftdi_module_lock); kfree(ftdi->bulk_in_buffer); ftdi->bulk_in_buffer = NULL; } @@ -746,10 +747,12 @@ static ssize_t ftdi_elan_read(struct file *file, char __user *buffer, static void ftdi_elan_write_bulk_callback(struct urb *urb) { struct usb_ftdi *ftdi = (struct usb_ftdi *)urb->context; - if (urb->status && !(urb->status == -ENOENT || urb->status == - -ECONNRESET || urb->status == -ESHUTDOWN)) { + int status = urb->status; + + if (status && !(status == -ENOENT || status == -ECONNRESET || + status == -ESHUTDOWN)) { dev_err(&ftdi->udev->dev, "urb=%p write bulk status received: %" - "d\n", urb, urb->status); + "d\n", urb, status); } usb_buffer_free(urb->dev, urb->transfer_buffer_length, urb->transfer_buffer, urb->transfer_dma); @@ -2780,10 +2783,10 @@ static int ftdi_elan_probe(struct usb_interface *interface, return -ENOMEM; } memset(ftdi, 0x00, sizeof(struct usb_ftdi)); - down(&ftdi_module_lock); + mutex_lock(&ftdi_module_lock); list_add_tail(&ftdi->ftdi_list, &ftdi_static_list); ftdi->sequence_num = ++ftdi_instances; - up(&ftdi_module_lock); + mutex_unlock(&ftdi_module_lock); ftdi_elan_init_kref(ftdi); init_MUTEX(&ftdi->sw_lock); ftdi->udev = usb_get_dev(interface_to_usbdev(interface)); @@ -2909,7 +2912,7 @@ static int __init ftdi_elan_init(void) int result; printk(KERN_INFO "driver %s built at %s on %s\n", ftdi_elan_driver.name, __TIME__, __DATE__); - init_MUTEX(&ftdi_module_lock); + mutex_init(&ftdi_module_lock); INIT_LIST_HEAD(&ftdi_static_list); status_queue = create_singlethread_workqueue("ftdi-status-control"); if (!status_queue) diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index 28548d18671..46d9f27ec17 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -158,9 +158,10 @@ static void iowarrior_callback(struct urb *urb) int read_idx; int aux_idx; int offset; - int status; + int status = urb->status; + int retval; - switch (urb->status) { + switch (status) { case 0: /* success */ break; @@ -213,10 +214,10 @@ static void iowarrior_callback(struct urb *urb) wake_up_interruptible(&dev->read_wait); exit: - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) dev_err(&dev->interface->dev, "%s - usb_submit_urb failed with result %d", - __FUNCTION__, status); + __FUNCTION__, retval); } @@ -226,13 +227,15 @@ exit: static void iowarrior_write_callback(struct urb *urb) { struct iowarrior *dev; + int status = urb->status; + dev = (struct iowarrior *)urb->context; /* sync/async unlink faults aren't errors */ - if (urb->status && - !(urb->status == -ENOENT || - urb->status == -ECONNRESET || urb->status == -ESHUTDOWN)) { + if (status && + !(status == -ENOENT || + status == -ECONNRESET || status == -ESHUTDOWN)) { dbg("%s - nonzero write bulk status received: %d", - __func__, urb->status); + __func__, status); } /* free up our allocated buffer */ usb_buffer_free(urb->dev, urb->transfer_buffer_length, diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index 5e950b90c54..8208496dfc6 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -219,16 +219,17 @@ static void ld_usb_interrupt_in_callback(struct urb *urb) struct ld_usb *dev = urb->context; size_t *actual_buffer; unsigned int next_ring_head; + int status = urb->status; int retval; - if (urb->status) { - if (urb->status == -ENOENT || - urb->status == -ECONNRESET || - urb->status == -ESHUTDOWN) { + if (status) { + if (status == -ENOENT || + status == -ECONNRESET || + status == -ESHUTDOWN) { goto exit; } else { dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n", - __FUNCTION__, urb->status); + __FUNCTION__, status); spin_lock(&dev->rbsl); goto resubmit; /* maybe we can recover */ } @@ -275,14 +276,15 @@ exit: static void ld_usb_interrupt_out_callback(struct urb *urb) { struct ld_usb *dev = urb->context; + int status = urb->status; /* sync/async unlink faults aren't errors */ - if (urb->status && !(urb->status == -ENOENT || - urb->status == -ECONNRESET || - urb->status == -ESHUTDOWN)) + if (status && !(status == -ENOENT || + status == -ECONNRESET || + status == -ESHUTDOWN)) dbg_info(&dev->intf->dev, "%s - nonzero write interrupt status received: %d\n", - __FUNCTION__, urb->status); + __FUNCTION__, status); dev->interrupt_out_busy = 0; wake_up_interruptible(&dev->write_wait); diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index 2ed0daea894..561970b889a 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -742,19 +742,20 @@ exit: static void tower_interrupt_in_callback (struct urb *urb) { struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context; + int status = urb->status; int retval; - dbg(4, "%s: enter, status %d", __FUNCTION__, urb->status); + dbg(4, "%s: enter, status %d", __FUNCTION__, status); lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer); - if (urb->status) { - if (urb->status == -ENOENT || - urb->status == -ECONNRESET || - urb->status == -ESHUTDOWN) { + if (status) { + if (status == -ENOENT || + status == -ECONNRESET || + status == -ESHUTDOWN) { goto exit; } else { - dbg(1, "%s: nonzero status received: %d", __FUNCTION__, urb->status); + dbg(1, "%s: nonzero status received: %d", __FUNCTION__, status); goto resubmit; /* maybe we can recover */ } } @@ -788,7 +789,7 @@ exit: wake_up_interruptible (&dev->read_wait); lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer); - dbg(4, "%s: leave, status %d", __FUNCTION__, urb->status); + dbg(4, "%s: leave, status %d", __FUNCTION__, status); } @@ -798,23 +799,24 @@ exit: static void tower_interrupt_out_callback (struct urb *urb) { struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context; + int status = urb->status; - dbg(4, "%s: enter, status %d", __FUNCTION__, urb->status); + dbg(4, "%s: enter, status %d", __FUNCTION__, status); lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer); /* sync/async unlink faults aren't errors */ - if (urb->status && !(urb->status == -ENOENT || - urb->status == -ECONNRESET || - urb->status == -ESHUTDOWN)) { + if (status && !(status == -ENOENT || + status == -ECONNRESET || + status == -ESHUTDOWN)) { dbg(1, "%s - nonzero write bulk status received: %d", - __FUNCTION__, urb->status); + __FUNCTION__, status); } dev->interrupt_out_busy = 0; wake_up_interruptible(&dev->write_wait); lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer); - dbg(4, "%s: leave, status %d", __FUNCTION__, urb->status); + dbg(4, "%s: leave, status %d", __FUNCTION__, status); } diff --git a/drivers/usb/misc/phidgetkit.c b/drivers/usb/misc/phidgetkit.c index 371bf2b1197..aa9bcceabe7 100644 --- a/drivers/usb/misc/phidgetkit.c +++ b/drivers/usb/misc/phidgetkit.c @@ -305,9 +305,10 @@ static void interfacekit_irq(struct urb *urb) struct interfacekit *kit = urb->context; unsigned char *buffer = kit->data; int i, level, sensor; - int status; + int retval; + int status = urb->status; - switch (urb->status) { + switch (status) { case 0: /* success */ break; case -ECONNRESET: /* unlink */ @@ -377,11 +378,11 @@ static void interfacekit_irq(struct urb *urb) schedule_delayed_work(&kit->do_notify, 0); resubmit: - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) - err("can't resubmit intr, %s-%s/interfacekit0, status %d", + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) + err("can't resubmit intr, %s-%s/interfacekit0, retval %d", kit->udev->bus->bus_name, - kit->udev->devpath, status); + kit->udev->devpath, retval); } static void do_notify(struct work_struct *work) diff --git a/drivers/usb/misc/phidgetmotorcontrol.c b/drivers/usb/misc/phidgetmotorcontrol.c index 5727e1ea2f9..df0ebcdb9d6 100644 --- a/drivers/usb/misc/phidgetmotorcontrol.c +++ b/drivers/usb/misc/phidgetmotorcontrol.c @@ -95,9 +95,10 @@ static void motorcontrol_irq(struct urb *urb) struct motorcontrol *mc = urb->context; unsigned char *buffer = mc->data; int i, level; - int status; + int retval; + int status = urb->status;; - switch (urb->status) { + switch (status) { case 0: /* success */ break; case -ECONNRESET: /* unlink */ @@ -151,12 +152,12 @@ static void motorcontrol_irq(struct urb *urb) schedule_delayed_work(&mc->do_notify, 0); resubmit: - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) dev_err(&mc->intf->dev, - "can't resubmit intr, %s-%s/motorcontrol0, status %d", + "can't resubmit intr, %s-%s/motorcontrol0, retval %d", mc->udev->bus->bus_name, - mc->udev->devpath, status); + mc->udev->devpath, retval); } static void do_notify(struct work_struct *work) diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c index 504f7221b0d..71984203271 100644 --- a/drivers/usb/misc/usblcd.c +++ b/drivers/usb/misc/usblcd.c @@ -176,16 +176,17 @@ static int lcd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u static void lcd_write_bulk_callback(struct urb *urb) { struct usb_lcd *dev; + int status = urb->status; dev = (struct usb_lcd *)urb->context; /* sync/async unlink faults aren't errors */ - if (urb->status && - !(urb->status == -ENOENT || - urb->status == -ECONNRESET || - urb->status == -ESHUTDOWN)) { + if (status && + !(status == -ENOENT || + status == -ECONNRESET || + status == -ESHUTDOWN)) { dbg("USBLCD: %s - nonzero write bulk status received: %d", - __FUNCTION__, urb->status); + __FUNCTION__, status); } /* free up our allocated buffer */ diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index fb321864a92..e901d31e051 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -768,8 +768,8 @@ static void ctrl_complete (struct urb *urb) /* some faults are allowed, not required */ if (subcase->expected > 0 && ( - ((urb->status == -subcase->expected /* happened */ - || urb->status == 0)))) /* didn't */ + ((status == -subcase->expected /* happened */ + || status == 0)))) /* didn't */ status = 0; /* sometimes more than one fault is allowed */ else if (subcase->number == 12 && status == -EPIPE) diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c index 1a60f9c473a..2734fe2b9c4 100644 --- a/drivers/usb/misc/uss720.c +++ b/drivers/usb/misc/uss720.c @@ -111,12 +111,13 @@ static void async_complete(struct urb *urb) struct uss720_async_request *rq; struct parport *pp; struct parport_uss720_private *priv; + int status = urb->status; rq = urb->context; priv = rq->priv; pp = priv->pp; - if (urb->status) { - err("async_complete: urb error %d", urb->status); + if (status) { + err("async_complete: urb error %d", status); } else if (rq->dr.bRequest == 3) { memcpy(priv->reg, rq->reg, sizeof(priv->reg)); #if 0 diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 0d3903691e8..b8670905bc3 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -2794,16 +2794,14 @@ static void edge_shutdown (struct usb_serial *serial) dbg ("%s", __FUNCTION__); - for (i=0; i < serial->num_ports; ++i) { + for (i = 0; i < serial->num_ports; ++i) { edge_port = usb_get_serial_port_data(serial->port[i]); edge_remove_sysfs_attrs(edge_port->port); - if (edge_port) { - edge_buf_free(edge_port->ep_out_buf); - kfree(edge_port); - } + edge_buf_free(edge_port->ep_out_buf); + kfree(edge_port); usb_set_serial_port_data(serial->port[i], NULL); } - kfree (usb_get_serial_data(serial)); + kfree(usb_get_serial_data(serial)); usb_set_serial_data(serial, NULL); } diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 231b584f6d0..01e811becec 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -110,11 +110,6 @@ static void mos7720_interrupt_callback(struct urb *urb) dbg("%s"," : Entering\n"); - if (!urb) { - dbg("%s","Invalid Pointer !!!!:\n"); - return; - } - switch (status) { case 0: /* success */ diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 37f41f576d3..f76480f1455 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -436,11 +436,6 @@ static void mos7840_control_callback(struct urb *urb) int result = 0; int status = urb->status; - if (!urb) { - dbg("%s", "Invalid Pointer !!!!:\n"); - return; - } - mos7840_port = (struct moschip_port *)urb->context; switch (status) { @@ -525,10 +520,6 @@ static void mos7840_interrupt_callback(struct urb *urb) int status = urb->status; dbg("%s", " : Entering\n"); - if (!urb) { - dbg("%s", "Invalid Pointer !!!!:\n"); - return; - } switch (status) { case 0: @@ -676,11 +667,6 @@ static void mos7840_bulk_in_callback(struct urb *urb) struct tty_struct *tty; int status = urb->status; - if (!urb) { - dbg("%s", "Invalid Pointer !!!!:\n"); - return; - } - if (status) { dbg("nonzero read bulk status received: %d", status); return; @@ -753,11 +739,6 @@ static void mos7840_bulk_out_data_callback(struct urb *urb) int status = urb->status; int i; - if (!urb) { - dbg("%s", "Invalid Pointer !!!!:\n"); - return; - } - mos7840_port = (struct moschip_port *)urb->context; spin_lock(&mos7840_port->pool_lock); for (i = 0; i < NUM_URBS; i++) { diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index e7db20343d1..0794ccdebfd 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -1,7 +1,7 @@ /* USB Driver for Sierra Wireless - Copyright (C) 2006 Kevin Lloyd <linux@sierrawireless.com> + Copyright (C) 2006, 2007 Kevin Lloyd <linux@sierrawireless.com> IMPORTANT DISCLAIMER: This driver is not commercially supported by Sierra Wireless. Use at your own risk. @@ -12,10 +12,9 @@ Portions based on the option driver by Matthias Urlichs <smurf@smurf.noris.de> Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org> - */ -#define DRIVER_VERSION "v.1.0.6" +#define DRIVER_VERSION "v.1.2.5b" #define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>" #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems" @@ -28,23 +27,98 @@ #include <linux/usb.h> #include <linux/usb/serial.h> +#define SWIMS_USB_REQUEST_SetMode 0x0B +#define SWIMS_USB_REQUEST_TYPE_SetMode 0x40 +#define SWIMS_USB_INDEX_SetMode 0x0000 +#define SWIMS_SET_MODE_Modem 0x0001 + +/* per port private data */ +#define N_IN_URB 4 +#define N_OUT_URB 4 +#define IN_BUFLEN 4096 + +static int debug; + +enum devicetype { + DEVICE_3_PORT = 0, + DEVICE_1_PORT = 1, + DEVICE_INSTALLER = 2, +}; + +int sierra_set_power_state(struct usb_device *udev, __u16 swiState) +{ + int result; + dev_dbg(&udev->dev, "%s", "SET POWER STATE"); + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x00, /* __u8 request */ + 0x40, /* __u8 request type */ + swiState, /* __u16 value */ + 0, /* __u16 index */ + NULL, /* void *data */ + 0, /* __u16 size */ + USB_CTRL_SET_TIMEOUT); /* int timeout */ + return result; +} + +int sierra_set_ms_mode(struct usb_device *udev, __u16 eSocMode) +{ + int result; + dev_dbg(&udev->dev, "%s", "DEVICE MODE SWITCH"); + result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + SWIMS_USB_REQUEST_SetMode, /* __u8 request */ + SWIMS_USB_REQUEST_TYPE_SetMode, /* __u8 request type */ + eSocMode, /* __u16 value */ + SWIMS_USB_INDEX_SetMode, /* __u16 index */ + NULL, /* void *data */ + 0, /* __u16 size */ + USB_CTRL_SET_TIMEOUT); /* int timeout */ + return result; +} + +int sierra_probe(struct usb_interface *iface, const struct usb_device_id *id) +{ + int result; + struct usb_device *udev; + + udev = usb_get_dev(interface_to_usbdev(iface)); + + /* Check if in installer mode */ + if (id->driver_info == DEVICE_INSTALLER) { + dev_dbg(&udev->dev, "%s", "FOUND DEVICE(SW)\n"); + result = sierra_set_ms_mode(udev, SWIMS_SET_MODE_Modem); + /*We do not want to bind to the device when in installer mode*/ + return -EIO; + } + + return usb_serial_probe(iface, id); +} static struct usb_device_id id_table [] = { { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ + { USB_DEVICE(0x0f30, 0x1b1d) }, /* Sierra Wireless MC5720 */ { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */ { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ - { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless AirCard 595U */ { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */ + { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U */ + { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */ { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */ { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */ - { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */ + { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 & AC 875U */ { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */ + { USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780*/ + { USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781*/ + { USB_DEVICE(0x1199, 0x6850) }, /* Sierra Wireless AirCard 880 */ + { USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */ + { USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880 E */ + { USB_DEVICE(0x1199, 0x6853) }, /* Sierra Wireless AirCard 881 E */ - { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */ - { USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */ + { USB_DEVICE(0x1199, 0x0112), .driver_info = DEVICE_1_PORT }, /* Sierra Wireless AirCard 580 */ + { USB_DEVICE(0x0F3D, 0x0112), .driver_info = DEVICE_1_PORT }, /* Airprime/Sierra PC 5220 */ + + { USB_DEVICE(0x1199, 0x0FFF), .driver_info = DEVICE_INSTALLER}, { } }; MODULE_DEVICE_TABLE(usb, id_table); @@ -58,35 +132,36 @@ static struct usb_device_id id_table_1port [] = { static struct usb_device_id id_table_3port [] = { { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ + { USB_DEVICE(0x0f30, 0x1b1d) }, /* Sierra Wireless MC5720 */ { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */ { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ - { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless AirCard 595U */ { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */ + { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U*/ + { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */ { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */ { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */ - { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */ + { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 & AC 875U */ { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */ + { USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780*/ + { USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781*/ + { USB_DEVICE(0x1199, 0x6850) }, /* Sierra Wireless AirCard 880 */ + { USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */ + { USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880E */ + { USB_DEVICE(0x1199, 0x6853) }, /* Sierra Wireless AirCard 881E */ { } }; static struct usb_driver sierra_driver = { .name = "sierra", - .probe = usb_serial_probe, + .probe = sierra_probe, .disconnect = usb_serial_disconnect, .id_table = id_table, .no_dynamic_id = 1, }; -static int debug; - -/* per port private data */ -#define N_IN_URB 4 -#define N_OUT_URB 4 -#define IN_BUFLEN 4096 - struct sierra_port_private { spinlock_t lock; /* lock the structure */ int outstanding_urbs; /* number of out urbs in flight */ @@ -421,7 +496,6 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp) int i; struct urb *urb; int result; - __u16 set_mode_dzero = 0x0000; portdata = usb_get_serial_port_data(port); @@ -457,12 +531,6 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp) port->tty->low_latency = 1; - /* set mode to D0 */ - result = usb_control_msg(serial->dev, - usb_rcvctrlpipe(serial->dev, 0), - 0x00, 0x40, set_mode_dzero, 0, NULL, - 0, USB_CTRL_SET_TIMEOUT); - sierra_send_setup(port); /* start up the interrupt endpoint if we have one */ @@ -510,6 +578,9 @@ static int sierra_startup(struct usb_serial *serial) dbg("%s", __FUNCTION__); + /*Set Device mode to D0 */ + sierra_set_power_state(serial->dev, 0x0000); + /* Now setup per port private data */ for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; diff --git a/drivers/usb/storage/dpcm.c b/drivers/usb/storage/dpcm.c index 1628cb25856..9a410b5a6e5 100644 --- a/drivers/usb/storage/dpcm.c +++ b/drivers/usb/storage/dpcm.c @@ -46,43 +46,43 @@ */ int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us) { - int ret; + int ret; - if(srb == NULL) - return USB_STOR_TRANSPORT_ERROR; + if (srb == NULL) + return USB_STOR_TRANSPORT_ERROR; - US_DEBUGP("dpcm_transport: LUN=%d\n", srb->device->lun); + US_DEBUGP("dpcm_transport: LUN=%d\n", srb->device->lun); - switch(srb->device->lun) { - case 0: + switch (srb->device->lun) { + case 0: - /* - * LUN 0 corresponds to the CompactFlash card reader. - */ - ret = usb_stor_CB_transport(srb, us); - break; + /* + * LUN 0 corresponds to the CompactFlash card reader. + */ + ret = usb_stor_CB_transport(srb, us); + break; #ifdef CONFIG_USB_STORAGE_SDDR09 - case 1: + case 1: - /* - * LUN 1 corresponds to the SmartMedia card reader. - */ + /* + * LUN 1 corresponds to the SmartMedia card reader. + */ - /* - * Set the LUN to 0 (just in case). - */ - srb->device->lun = 0; us->srb->device->lun = 0; - ret = sddr09_transport(srb, us); - srb->device->lun = 1; us->srb->device->lun = 1; - break; + /* + * Set the LUN to 0 (just in case). + */ + srb->device->lun = 0; us->srb->device->lun = 0; + ret = sddr09_transport(srb, us); + srb->device->lun = 1; us->srb->device->lun = 1; + break; #endif - default: - US_DEBUGP("dpcm_transport: Invalid LUN %d\n", srb->device->lun); - ret = USB_STOR_TRANSPORT_ERROR; - break; - } - return ret; + default: + US_DEBUGP("dpcm_transport: Invalid LUN %d\n", srb->device->lun); + ret = USB_STOR_TRANSPORT_ERROR; + break; + } + return ret; } diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c index d35369392fe..dfd42fe9e5f 100644 --- a/drivers/usb/storage/onetouch.c +++ b/drivers/usb/storage/onetouch.c @@ -57,9 +57,10 @@ static void usb_onetouch_irq(struct urb *urb) struct usb_onetouch *onetouch = urb->context; signed char *data = onetouch->data; struct input_dev *dev = onetouch->dev; - int status; + int status = urb->status; + int retval; - switch (urb->status) { + switch (status) { case 0: /* success */ break; case -ECONNRESET: /* unlink */ @@ -75,11 +76,11 @@ static void usb_onetouch_irq(struct urb *urb) input_sync(dev); resubmit: - status = usb_submit_urb (urb, GFP_ATOMIC); - if (status) - err ("can't resubmit intr, %s-%s/input0, status %d", + retval = usb_submit_urb (urb, GFP_ATOMIC); + if (retval) + err ("can't resubmit intr, %s-%s/input0, retval %d", onetouch->udev->bus->bus_name, - onetouch->udev->devpath, status); + onetouch->udev->devpath, retval); } static int usb_onetouch_open(struct input_dev *dev) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index b6bf31a97b6..a624e72f81d 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -313,6 +313,13 @@ UNUSUAL_DEV( 0x04b0, 0x0301, 0x0010, 0x0010, US_SC_DEVICE, US_PR_DEVICE,NULL, US_FL_NOT_LOCKABLE ), +/* Reported by Stefan de Konink <skinkie@xs4all.nl> */ +UNUSUAL_DEV( 0x04b0, 0x0401, 0x0200, 0x0200, + "NIKON", + "NIKON DSC D100", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY), + /* Reported by Andreas Bockhold <andreas@bockionline.de> */ UNUSUAL_DEV( 0x04b0, 0x0405, 0x0100, 0x0100, "NIKON", @@ -1384,6 +1391,17 @@ UNUSUAL_DEV( 0x1019, 0x0c55, 0x0000, 0x0110, US_SC_DEVICE, US_PR_DEVICE, usb_stor_ucr61s2b_init, 0 ), +/* Reported by Kevin Lloyd <linux@sierrawireless.com> + * Entry is needed for the initializer function override, + * which instructs the device to load as a modem + * device. + */ +UNUSUAL_DEV( 0x1199, 0x0fff, 0x0000, 0x9999, + "Sierra Wireless", + "USB MMC Storage", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_DEVICE), + /* Reported by Jaco Kroon <jaco@kroon.co.za> * The usb-storage module found on the Digitech GNX4 (and supposedly other * devices) misbehaves and causes a bunch of invalid I/O errors. |