Commit d27099da authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

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

into kroah.com:/home/greg/linux/BK/usb-2.6
parents 70b19320 da741905
...@@ -603,7 +603,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t ...@@ -603,7 +603,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
{ {
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
struct usblp *usblp = file->private_data; struct usblp *usblp = file->private_data;
int timeout, err = 0; int timeout, err = 0, transfer_length;
size_t writecount = 0; size_t writecount = 0;
while (writecount < count) { while (writecount < count) {
...@@ -654,19 +654,13 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t ...@@ -654,19 +654,13 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
continue; continue;
} }
writecount += usblp->writeurb->transfer_buffer_length; transfer_length=(count - writecount);
usblp->writeurb->transfer_buffer_length = 0; if (transfer_length > USBLP_BUF_SIZE)
transfer_length = USBLP_BUF_SIZE;
if (writecount == count) { usblp->writeurb->transfer_buffer_length = transfer_length;
up (&usblp->sem);
break;
}
usblp->writeurb->transfer_buffer_length = (count - writecount) < USBLP_BUF_SIZE ? if (copy_from_user(usblp->writeurb->transfer_buffer, buffer + writecount, transfer_length)) {
(count - writecount) : USBLP_BUF_SIZE;
if (copy_from_user(usblp->writeurb->transfer_buffer, buffer + writecount,
usblp->writeurb->transfer_buffer_length)) {
up(&usblp->sem); up(&usblp->sem);
return writecount ? writecount : -EFAULT; return writecount ? writecount : -EFAULT;
} }
...@@ -683,6 +677,8 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t ...@@ -683,6 +677,8 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
break; break;
} }
up (&usblp->sem); up (&usblp->sem);
writecount += transfer_length;
} }
return count; return count;
......
...@@ -2,14 +2,19 @@ ...@@ -2,14 +2,19 @@
* DMA memory management for framework level HCD code (hc_driver) * DMA memory management for framework level HCD code (hc_driver)
* *
* This implementation plugs in through generic "usb_bus" level methods, * This implementation plugs in through generic "usb_bus" level methods,
* and works with real PCI, or when "pci device == null" makes sense. * and should work with all USB controllers, regardles of bus type.
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/pci.h> #include <linux/device.h>
#include <linux/mm.h>
#include <asm/io.h>
#include <asm/scatterlist.h>
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#ifdef CONFIG_USB_DEBUG #ifdef CONFIG_USB_DEBUG
...@@ -62,7 +67,7 @@ int hcd_buffer_create (struct usb_hcd *hcd) ...@@ -62,7 +67,7 @@ int hcd_buffer_create (struct usb_hcd *hcd)
if (!(size = pool_max [i])) if (!(size = pool_max [i]))
continue; continue;
snprintf (name, sizeof name, "buffer-%d", size); snprintf (name, sizeof name, "buffer-%d", size);
hcd->pool [i] = pci_pool_create (name, hcd->pdev, hcd->pool [i] = dma_pool_create (name, hcd->self.controller,
size, size, 0); size, size, 0);
if (!hcd->pool [i]) { if (!hcd->pool [i]) {
hcd_buffer_destroy (hcd); hcd_buffer_destroy (hcd);
...@@ -86,9 +91,9 @@ void hcd_buffer_destroy (struct usb_hcd *hcd) ...@@ -86,9 +91,9 @@ void hcd_buffer_destroy (struct usb_hcd *hcd)
int i; int i;
for (i = 0; i < HCD_BUFFER_POOLS; i++) { for (i = 0; i < HCD_BUFFER_POOLS; i++) {
struct pci_pool *pool = hcd->pool [i]; struct dma_pool *pool = hcd->pool [i];
if (pool) { if (pool) {
pci_pool_destroy (pool); dma_pool_destroy (pool);
hcd->pool [i] = 0; hcd->pool [i] = 0;
} }
} }
...@@ -112,9 +117,9 @@ void *hcd_buffer_alloc ( ...@@ -112,9 +117,9 @@ void *hcd_buffer_alloc (
for (i = 0; i < HCD_BUFFER_POOLS; i++) { for (i = 0; i < HCD_BUFFER_POOLS; i++) {
if (size <= pool_max [i]) if (size <= pool_max [i])
return pci_pool_alloc (hcd->pool [i], mem_flags, dma); return dma_pool_alloc (hcd->pool [i], mem_flags, dma);
} }
return pci_alloc_consistent (hcd->pdev, size, dma); return dma_alloc_coherent (hcd->self.controller, size, dma, 0);
} }
void hcd_buffer_free ( void hcd_buffer_free (
...@@ -131,9 +136,9 @@ void hcd_buffer_free ( ...@@ -131,9 +136,9 @@ void hcd_buffer_free (
return; return;
for (i = 0; i < HCD_BUFFER_POOLS; i++) { for (i = 0; i < HCD_BUFFER_POOLS; i++) {
if (size <= pool_max [i]) { if (size <= pool_max [i]) {
pci_pool_free (hcd->pool [i], addr, dma); dma_pool_free (hcd->pool [i], addr, dma);
return; return;
} }
} }
pci_free_consistent (hcd->pdev, size, addr, dma); dma_free_coherent (hcd->self.controller, size, addr, dma);
} }
...@@ -146,12 +146,10 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) ...@@ -146,12 +146,10 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
pci_set_drvdata (dev, hcd); pci_set_drvdata (dev, hcd);
hcd->driver = driver; hcd->driver = driver;
hcd->description = driver->description; hcd->description = driver->description;
hcd->pdev = dev;
hcd->self.bus_name = pci_name(dev); hcd->self.bus_name = pci_name(dev);
if (hcd->product_desc == NULL) if (hcd->product_desc == NULL)
hcd->product_desc = "USB Host Controller"; hcd->product_desc = "USB Host Controller";
hcd->self.controller = &dev->dev; hcd->self.controller = &dev->dev;
hcd->controller = hcd->self.controller;
if ((retval = hcd_buffer_create (hcd)) != 0) { if ((retval = hcd_buffer_create (hcd)) != 0) {
clean_3: clean_3:
...@@ -159,11 +157,11 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) ...@@ -159,11 +157,11 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
goto clean_2; goto clean_2;
} }
dev_info (hcd->controller, "%s\n", hcd->product_desc); dev_info (hcd->self.controller, "%s\n", hcd->product_desc);
/* till now HC has been in an indeterminate state ... */ /* till now HC has been in an indeterminate state ... */
if (driver->reset && (retval = driver->reset (hcd)) < 0) { if (driver->reset && (retval = driver->reset (hcd)) < 0) {
dev_err (hcd->controller, "can't reset\n"); dev_err (hcd->self.controller, "can't reset\n");
goto clean_3; goto clean_3;
} }
hcd->state = USB_STATE_HALT; hcd->state = USB_STATE_HALT;
...@@ -177,13 +175,13 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) ...@@ -177,13 +175,13 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
retval = request_irq (dev->irq, usb_hcd_irq, SA_SHIRQ, retval = request_irq (dev->irq, usb_hcd_irq, SA_SHIRQ,
hcd->description, hcd); hcd->description, hcd);
if (retval != 0) { if (retval != 0) {
dev_err (hcd->controller, dev_err (hcd->self.controller,
"request interrupt %s failed\n", bufp); "request interrupt %s failed\n", bufp);
goto clean_3; goto clean_3;
} }
hcd->irq = dev->irq; hcd->irq = dev->irq;
dev_info (hcd->controller, "irq %s, %s %p\n", bufp, dev_info (hcd->self.controller, "irq %s, %s %p\n", bufp,
(driver->flags & HCD_MEMORY) ? "pci mem" : "io base", (driver->flags & HCD_MEMORY) ? "pci mem" : "io base",
base); base);
...@@ -226,7 +224,7 @@ void usb_hcd_pci_remove (struct pci_dev *dev) ...@@ -226,7 +224,7 @@ void usb_hcd_pci_remove (struct pci_dev *dev)
hcd = pci_get_drvdata(dev); hcd = pci_get_drvdata(dev);
if (!hcd) if (!hcd)
return; return;
dev_info (hcd->controller, "remove, state %x\n", hcd->state); dev_info (hcd->self.controller, "remove, state %x\n", hcd->state);
if (in_interrupt ()) if (in_interrupt ())
BUG (); BUG ();
...@@ -235,7 +233,7 @@ void usb_hcd_pci_remove (struct pci_dev *dev) ...@@ -235,7 +233,7 @@ void usb_hcd_pci_remove (struct pci_dev *dev)
if (HCD_IS_RUNNING (hcd->state)) if (HCD_IS_RUNNING (hcd->state))
hcd->state = USB_STATE_QUIESCING; hcd->state = USB_STATE_QUIESCING;
dev_dbg (hcd->controller, "roothub graceful disconnect\n"); dev_dbg (hcd->self.controller, "roothub graceful disconnect\n");
usb_disconnect (&hub); usb_disconnect (&hub);
hcd->driver->stop (hcd); hcd->driver->stop (hcd);
...@@ -273,15 +271,15 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state) ...@@ -273,15 +271,15 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
int retval = 0; int retval = 0;
hcd = pci_get_drvdata(dev); hcd = pci_get_drvdata(dev);
dev_dbg (hcd->controller, "suspend D%d --> D%d\n", dev_dbg (hcd->self.controller, "suspend D%d --> D%d\n",
dev->current_state, state); dev->current_state, state);
switch (hcd->state) { switch (hcd->state) {
case USB_STATE_HALT: case USB_STATE_HALT:
dev_dbg (hcd->controller, "halted; hcd not suspended\n"); dev_dbg (hcd->self.controller, "halted; hcd not suspended\n");
break; break;
case USB_STATE_SUSPENDED: case USB_STATE_SUSPENDED:
dev_dbg (hcd->controller, "hcd already suspended\n"); dev_dbg (hcd->self.controller, "hcd already suspended\n");
break; break;
default: default:
/* remote wakeup needs hub->suspend() cooperation */ /* remote wakeup needs hub->suspend() cooperation */
...@@ -293,7 +291,8 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state) ...@@ -293,7 +291,8 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
hcd->state = USB_STATE_QUIESCING; hcd->state = USB_STATE_QUIESCING;
retval = hcd->driver->suspend (hcd, state); retval = hcd->driver->suspend (hcd, state);
if (retval) if (retval)
dev_dbg (hcd->controller, "suspend fail, retval %d\n", dev_dbg (hcd->self.controller,
"suspend fail, retval %d\n",
retval); retval);
else else
hcd->state = USB_STATE_SUSPENDED; hcd->state = USB_STATE_SUSPENDED;
...@@ -316,11 +315,12 @@ int usb_hcd_pci_resume (struct pci_dev *dev) ...@@ -316,11 +315,12 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
int retval; int retval;
hcd = pci_get_drvdata(dev); hcd = pci_get_drvdata(dev);
dev_dbg (hcd->controller, "resume from state D%d\n", dev_dbg (hcd->self.controller, "resume from state D%d\n",
dev->current_state); dev->current_state);
if (hcd->state != USB_STATE_SUSPENDED) { if (hcd->state != USB_STATE_SUSPENDED) {
dev_dbg (hcd->controller, "can't resume, not suspended!\n"); dev_dbg (hcd->self.controller,
"can't resume, not suspended!\n");
return -EL3HLT; return -EL3HLT;
} }
hcd->state = USB_STATE_RESUMING; hcd->state = USB_STATE_RESUMING;
...@@ -333,7 +333,8 @@ int usb_hcd_pci_resume (struct pci_dev *dev) ...@@ -333,7 +333,8 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
retval = hcd->driver->resume (hcd); retval = hcd->driver->resume (hcd);
if (!HCD_IS_RUNNING (hcd->state)) { if (!HCD_IS_RUNNING (hcd->state)) {
dev_dbg (hcd->controller, "resume fail, retval %d\n", retval); dev_dbg (hcd->self.controller,
"resume fail, retval %d\n", retval);
usb_hc_died (hcd); usb_hc_died (hcd);
} }
......
...@@ -351,7 +351,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) ...@@ -351,7 +351,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
/* FALLTHROUGH */ /* FALLTHROUGH */
case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
case DeviceOutRequest | USB_REQ_SET_FEATURE: case DeviceOutRequest | USB_REQ_SET_FEATURE:
dev_dbg (hcd->controller, "no device features yet yet\n"); dev_dbg (hcd->self.controller, "no device features yet yet\n");
break; break;
case DeviceRequest | USB_REQ_GET_CONFIGURATION: case DeviceRequest | USB_REQ_GET_CONFIGURATION:
ubuf [0] = 1; ubuf [0] = 1;
...@@ -394,7 +394,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) ...@@ -394,7 +394,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
break; break;
case DeviceOutRequest | USB_REQ_SET_ADDRESS: case DeviceOutRequest | USB_REQ_SET_ADDRESS:
// wValue == urb->dev->devaddr // wValue == urb->dev->devaddr
dev_dbg (hcd->controller, "root hub device address %d\n", dev_dbg (hcd->self.controller, "root hub device address %d\n",
wValue); wValue);
break; break;
...@@ -409,7 +409,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) ...@@ -409,7 +409,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
/* FALLTHROUGH */ /* FALLTHROUGH */
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
case EndpointOutRequest | USB_REQ_SET_FEATURE: case EndpointOutRequest | USB_REQ_SET_FEATURE:
dev_dbg (hcd->controller, "no endpoint features yet\n"); dev_dbg (hcd->self.controller, "no endpoint features yet\n");
break; break;
/* CLASS REQUESTS (and errors) */ /* CLASS REQUESTS (and errors) */
...@@ -423,12 +423,12 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) ...@@ -423,12 +423,12 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
error: error:
/* "protocol stall" on error */ /* "protocol stall" on error */
urb->status = -EPIPE; urb->status = -EPIPE;
dev_dbg (hcd->controller, "unsupported hub control message (maxchild %d)\n", dev_dbg (hcd->self.controller, "unsupported hub control message (maxchild %d)\n",
urb->dev->maxchild); urb->dev->maxchild);
} }
if (urb->status) { if (urb->status) {
urb->actual_length = 0; urb->actual_length = 0;
dev_dbg (hcd->controller, "CTRL: TypeReq=0x%x val=0x%x idx=0x%x len=%d ==> %d\n", dev_dbg (hcd->self.controller, "CTRL: TypeReq=0x%x val=0x%x idx=0x%x len=%d ==> %d\n",
typeReq, wValue, wIndex, wLength, urb->status); typeReq, wValue, wIndex, wLength, urb->status);
} }
if (bufp) { if (bufp) {
...@@ -464,7 +464,7 @@ static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb) ...@@ -464,7 +464,7 @@ static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb)
|| urb->status != -EINPROGRESS || urb->status != -EINPROGRESS
|| urb->transfer_buffer_length < len || urb->transfer_buffer_length < len
|| !HCD_IS_RUNNING (hcd->state)) { || !HCD_IS_RUNNING (hcd->state)) {
dev_dbg (hcd->controller, dev_dbg (hcd->self.controller,
"not queuing rh status urb, stat %d\n", "not queuing rh status urb, stat %d\n",
urb->status); urb->status);
return -EINVAL; return -EINVAL;
...@@ -1068,18 +1068,18 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags) ...@@ -1068,18 +1068,18 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
/* lower level hcd code should use *_dma exclusively, /* lower level hcd code should use *_dma exclusively,
* unless it uses pio or talks to another transport. * unless it uses pio or talks to another transport.
*/ */
if (hcd->controller->dma_mask) { if (hcd->self.controller->dma_mask) {
if (usb_pipecontrol (urb->pipe) if (usb_pipecontrol (urb->pipe)
&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
urb->setup_dma = dma_map_single ( urb->setup_dma = dma_map_single (
hcd->controller, hcd->self.controller,
urb->setup_packet, urb->setup_packet,
sizeof (struct usb_ctrlrequest), sizeof (struct usb_ctrlrequest),
DMA_TO_DEVICE); DMA_TO_DEVICE);
if (urb->transfer_buffer_length != 0 if (urb->transfer_buffer_length != 0
&& !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
urb->transfer_dma = dma_map_single ( urb->transfer_dma = dma_map_single (
hcd->controller, hcd->self.controller,
urb->transfer_buffer, urb->transfer_buffer,
urb->transfer_buffer_length, urb->transfer_buffer_length,
usb_pipein (urb->pipe) usb_pipein (urb->pipe)
...@@ -1125,7 +1125,7 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb) ...@@ -1125,7 +1125,7 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb)
/* failures "should" be harmless */ /* failures "should" be harmless */
value = hcd->driver->urb_dequeue (hcd, urb); value = hcd->driver->urb_dequeue (hcd, urb);
if (value != 0) if (value != 0)
dev_dbg (hcd->controller, dev_dbg (hcd->self.controller,
"dequeue %p --> %d\n", "dequeue %p --> %d\n",
urb, value); urb, value);
} }
...@@ -1232,7 +1232,7 @@ static int hcd_unlink_urb (struct urb *urb) ...@@ -1232,7 +1232,7 @@ static int hcd_unlink_urb (struct urb *urb)
* finish unlinking the initial failed usb_set_address(). * finish unlinking the initial failed usb_set_address().
*/ */
if (!hcd->saw_irq) { if (!hcd->saw_irq) {
dev_warn (hcd->controller, "Unlink after no-IRQ? " dev_warn (hcd->self.controller, "Unlink after no-IRQ? "
"Different ACPI or APIC settings may help." "Different ACPI or APIC settings may help."
"\n"); "\n");
hcd->saw_irq = 1; hcd->saw_irq = 1;
...@@ -1244,7 +1244,8 @@ static int hcd_unlink_urb (struct urb *urb) ...@@ -1244,7 +1244,8 @@ static int hcd_unlink_urb (struct urb *urb)
*/ */
if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) { if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) {
if (in_interrupt ()) { if (in_interrupt ()) {
dev_dbg (hcd->controller, "non-async unlink in_interrupt"); dev_dbg (hcd->self.controller,
"non-async unlink in_interrupt");
retval = -EWOULDBLOCK; retval = -EWOULDBLOCK;
goto done; goto done;
} }
...@@ -1363,7 +1364,7 @@ static void hcd_endpoint_disable (struct usb_device *udev, int endpoint) ...@@ -1363,7 +1364,7 @@ static void hcd_endpoint_disable (struct usb_device *udev, int endpoint)
if (tmp == -EINPROGRESS) { if (tmp == -EINPROGRESS) {
tmp = urb->pipe; tmp = urb->pipe;
unlink1 (hcd, urb); unlink1 (hcd, urb);
dev_dbg (hcd->controller, dev_dbg (hcd->self.controller,
"shutdown urb %p pipe %08x ep%d%s%s\n", "shutdown urb %p pipe %08x ep%d%s%s\n",
urb, tmp, usb_pipeendpoint (tmp), urb, tmp, usb_pipeendpoint (tmp),
(tmp & USB_DIR_IN) ? "in" : "out", (tmp & USB_DIR_IN) ? "in" : "out",
...@@ -1417,7 +1418,7 @@ static int hcd_free_dev (struct usb_device *udev) ...@@ -1417,7 +1418,7 @@ static int hcd_free_dev (struct usb_device *udev)
/* device driver problem with refcounts? */ /* device driver problem with refcounts? */
if (!list_empty (&dev->urb_list)) { if (!list_empty (&dev->urb_list)) {
dev_dbg (hcd->controller, "free busy dev, %s devnum %d (bug!)\n", dev_dbg (hcd->self.controller, "free busy dev, %s devnum %d (bug!)\n",
hcd->self.bus_name, udev->devnum); hcd->self.bus_name, udev->devnum);
return -EINVAL; return -EINVAL;
} }
...@@ -1474,15 +1475,16 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs ...@@ -1474,15 +1475,16 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs
// It would catch exit/unlink paths for all urbs. // It would catch exit/unlink paths for all urbs.
/* lower level hcd code should use *_dma exclusively */ /* lower level hcd code should use *_dma exclusively */
if (hcd->controller->dma_mask) { if (hcd->self.controller->dma_mask) {
if (usb_pipecontrol (urb->pipe) if (usb_pipecontrol (urb->pipe)
&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
dma_unmap_single (hcd->controller, urb->setup_dma, dma_unmap_single (hcd->self.controller, urb->setup_dma,
sizeof (struct usb_ctrlrequest), sizeof (struct usb_ctrlrequest),
DMA_TO_DEVICE); DMA_TO_DEVICE);
if (urb->transfer_buffer_length != 0 if (urb->transfer_buffer_length != 0
&& !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
dma_unmap_single (hcd->controller, urb->transfer_dma, dma_unmap_single (hcd->self.controller,
urb->transfer_dma,
urb->transfer_buffer_length, urb->transfer_buffer_length,
usb_pipein (urb->pipe) usb_pipein (urb->pipe)
? DMA_FROM_DEVICE ? DMA_FROM_DEVICE
...@@ -1551,7 +1553,7 @@ static void hcd_panic (void *_hcd) ...@@ -1551,7 +1553,7 @@ static void hcd_panic (void *_hcd)
*/ */
void usb_hc_died (struct usb_hcd *hcd) void usb_hc_died (struct usb_hcd *hcd)
{ {
dev_err (hcd->controller, "HC died; cleaning up\n"); dev_err (hcd->self.controller, "HC died; cleaning up\n");
/* clean up old urbs and devices; needs a task context */ /* clean up old urbs and devices; needs a task context */
INIT_WORK (&hcd->work, hcd_panic, hcd); INIT_WORK (&hcd->work, hcd_panic, hcd);
......
...@@ -76,17 +76,14 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */ ...@@ -76,17 +76,14 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
unsigned saw_irq : 1; unsigned saw_irq : 1;
int irq; /* irq allocated */ int irq; /* irq allocated */
void *regs; /* device memory/io */ void *regs; /* device memory/io */
struct device *controller; /* handle to hardware */
/* a few non-PCI controllers exist, mostly for OHCI */
struct pci_dev *pdev; /* pci is typical */
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
int region; /* pci region for regs */ int region; /* pci region for regs */
u32 pci_state [16]; /* for PM state save */ u32 pci_state [16]; /* for PM state save */
#endif #endif
#define HCD_BUFFER_POOLS 4 #define HCD_BUFFER_POOLS 4
struct pci_pool *pool [HCD_BUFFER_POOLS]; struct dma_pool *pool [HCD_BUFFER_POOLS];
int state; int state;
# define __ACTIVE 0x01 # define __ACTIVE 0x01
...@@ -355,7 +352,7 @@ extern int usb_register_root_hub (struct usb_device *usb_dev, ...@@ -355,7 +352,7 @@ extern int usb_register_root_hub (struct usb_device *usb_dev,
static inline int hcd_register_root (struct usb_hcd *hcd) static inline int hcd_register_root (struct usb_hcd *hcd)
{ {
return usb_register_root_hub ( return usb_register_root_hub (
hcd_to_bus (hcd)->root_hub, hcd->controller); hcd_to_bus (hcd)->root_hub, hcd->self.controller);
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
......
...@@ -405,9 +405,14 @@ static int hub_configure(struct usb_hub *hub, ...@@ -405,9 +405,14 @@ static int hub_configure(struct usb_hub *hub,
hub->tt.hub = dev; hub->tt.hub = dev;
break; break;
case 2: case 2:
dev_dbg(hub_dev, "TT per port\n"); ret = usb_set_interface(dev, 0, 1);
if (ret == 0) {
dev_dbg(hub_dev, "TT per port\n");
hub->tt.multi = 1;
} else
dev_err(hub_dev, "Using single TT (err %d)\n",
ret);
hub->tt.hub = dev; hub->tt.hub = dev;
hub->tt.multi = 1;
break; break;
default: default:
dev_dbg(hub_dev, "Unrecognized hub protocol %d\n", dev_dbg(hub_dev, "Unrecognized hub protocol %d\n",
......
...@@ -213,9 +213,8 @@ static void sg_clean (struct usb_sg_request *io) ...@@ -213,9 +213,8 @@ static void sg_clean (struct usb_sg_request *io)
static void sg_complete (struct urb *urb, struct pt_regs *regs) static void sg_complete (struct urb *urb, struct pt_regs *regs)
{ {
struct usb_sg_request *io = (struct usb_sg_request *) urb->context; struct usb_sg_request *io = (struct usb_sg_request *) urb->context;
unsigned long flags;
spin_lock_irqsave (&io->lock, flags); spin_lock (&io->lock);
/* In 2.5 we require hcds' endpoint queues not to progress after fault /* In 2.5 we require hcds' endpoint queues not to progress after fault
* reports, until the completion callback (this!) returns. That lets * reports, until the completion callback (this!) returns. That lets
...@@ -269,7 +268,7 @@ static void sg_complete (struct urb *urb, struct pt_regs *regs) ...@@ -269,7 +268,7 @@ static void sg_complete (struct urb *urb, struct pt_regs *regs)
if (!io->count) if (!io->count)
complete (&io->complete); complete (&io->complete);
spin_unlock_irqrestore (&io->lock, flags); spin_unlock (&io->lock);
} }
...@@ -441,12 +440,11 @@ int usb_sg_init ( ...@@ -441,12 +440,11 @@ int usb_sg_init (
*/ */
void usb_sg_wait (struct usb_sg_request *io) void usb_sg_wait (struct usb_sg_request *io)
{ {
int i; int i, entries = io->entries;
unsigned long flags;
/* queue the urbs. */ /* queue the urbs. */
spin_lock_irqsave (&io->lock, flags); spin_lock_irq (&io->lock);
for (i = 0; i < io->entries && !io->status; i++) { for (i = 0; i < entries && !io->status; i++) {
int retval; int retval;
io->urbs [i]->dev = io->dev; io->urbs [i]->dev = io->dev;
...@@ -455,7 +453,7 @@ void usb_sg_wait (struct usb_sg_request *io) ...@@ -455,7 +453,7 @@ void usb_sg_wait (struct usb_sg_request *io)
/* after we submit, let completions or cancelations fire; /* after we submit, let completions or cancelations fire;
* we handshake using io->status. * we handshake using io->status.
*/ */
spin_unlock_irqrestore (&io->lock, flags); spin_unlock_irq (&io->lock);
switch (retval) { switch (retval) {
/* maybe we retrying will recover */ /* maybe we retrying will recover */
case -ENXIO: // hc didn't queue this one case -ENXIO: // hc didn't queue this one
...@@ -479,17 +477,25 @@ void usb_sg_wait (struct usb_sg_request *io) ...@@ -479,17 +477,25 @@ void usb_sg_wait (struct usb_sg_request *io)
/* fail any uncompleted urbs */ /* fail any uncompleted urbs */
default: default:
spin_lock_irq (&io->lock);
io->count -= entries - i;
if (io->status == -EINPROGRESS)
io->status = retval;
if (io->count == 0)
complete (&io->complete);
spin_unlock_irq (&io->lock);
io->urbs [i]->dev = 0; io->urbs [i]->dev = 0;
io->urbs [i]->status = retval; io->urbs [i]->status = retval;
dev_dbg (&io->dev->dev, "%s, submit --> %d\n", dev_dbg (&io->dev->dev, "%s, submit --> %d\n",
__FUNCTION__, retval); __FUNCTION__, retval);
usb_sg_cancel (io); usb_sg_cancel (io);
} }
spin_lock_irqsave (&io->lock, flags); spin_lock_irq (&io->lock);
if (retval && io->status == -ECONNRESET) if (retval && io->status == -ECONNRESET)
io->status = retval; io->status = retval;
} }
spin_unlock_irqrestore (&io->lock, flags); spin_unlock_irq (&io->lock);
/* OK, yes, this could be packaged as non-blocking. /* OK, yes, this could be packaged as non-blocking.
* So could the submit loop above ... but it's easier to * So could the submit loop above ... but it's easier to
......
...@@ -1152,12 +1152,19 @@ int usb_new_device(struct usb_device *dev) ...@@ -1152,12 +1152,19 @@ int usb_new_device(struct usb_device *dev)
config = dev->config[0].desc.bConfigurationValue; config = dev->config[0].desc.bConfigurationValue;
if (dev->descriptor.bNumConfigurations != 1) { if (dev->descriptor.bNumConfigurations != 1) {
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
struct usb_interface_descriptor *desc;
/* heuristic: Linux is more likely to have class /* heuristic: Linux is more likely to have class
* drivers, so avoid vendor-specific interfaces. * drivers, so avoid vendor-specific interfaces.
*/ */
if (dev->config[i].interface[0]->altsetting desc = &dev->config[i].interface[0]
->desc.bInterfaceClass ->altsetting->desc;
== USB_CLASS_VENDOR_SPEC) if (desc->bInterfaceClass == USB_CLASS_VENDOR_SPEC)
continue;
/* COMM/2/all is CDC ACM, except 0xff is MSFT RNDIS */
if (desc->bInterfaceClass == USB_CLASS_COMM
&& desc->bInterfaceSubClass == 2
&& desc->bInterfaceProtocol == 0xff)
continue; continue;
config = dev->config[i].desc.bConfigurationValue; config = dev->config[i].desc.bConfigurationValue;
break; break;
......
...@@ -19,13 +19,13 @@ ...@@ -19,13 +19,13 @@
/* this file is part of ehci-hcd.c */ /* this file is part of ehci-hcd.c */
#define ehci_dbg(ehci, fmt, args...) \ #define ehci_dbg(ehci, fmt, args...) \
dev_dbg ((ehci)->hcd.controller , fmt , ## args ) dev_dbg ((ehci)->hcd.self.controller , fmt , ## args )
#define ehci_err(ehci, fmt, args...) \ #define ehci_err(ehci, fmt, args...) \
dev_err ((ehci)->hcd.controller , fmt , ## args ) dev_err ((ehci)->hcd.self.controller , fmt , ## args )
#define ehci_info(ehci, fmt, args...) \ #define ehci_info(ehci, fmt, args...) \
dev_info ((ehci)->hcd.controller , fmt , ## args ) dev_info ((ehci)->hcd.self.controller , fmt , ## args )
#define ehci_warn(ehci, fmt, args...) \ #define ehci_warn(ehci, fmt, args...) \
dev_warn ((ehci)->hcd.controller , fmt , ## args ) dev_warn ((ehci)->hcd.self.controller , fmt , ## args )
#ifdef EHCI_VERBOSE_DEBUG #ifdef EHCI_VERBOSE_DEBUG
# define vdbg dbg # define vdbg dbg
...@@ -367,7 +367,7 @@ static void qh_lines ( ...@@ -367,7 +367,7 @@ static void qh_lines (
scratch, cpu_to_le32p (&qh->hw_info2), scratch, cpu_to_le32p (&qh->hw_info2),
cpu_to_le32p (&qh->hw_token), mark, cpu_to_le32p (&qh->hw_token), mark,
(__constant_cpu_to_le32 (QTD_TOGGLE) & qh->hw_token) (__constant_cpu_to_le32 (QTD_TOGGLE) & qh->hw_token)
? "data0" : "data1", ? "data1" : "data0",
(cpu_to_le32p (&qh->hw_alt_next) >> 1) & 0x0f); (cpu_to_le32p (&qh->hw_alt_next) >> 1) & 0x0f);
size -= temp; size -= temp;
next += temp; next += temp;
...@@ -625,7 +625,7 @@ show_registers (struct class_device *class_dev, char *buf) ...@@ -625,7 +625,7 @@ show_registers (struct class_device *class_dev, char *buf)
i = HC_VERSION(readl (&ehci->caps->hc_capbase)); i = HC_VERSION(readl (&ehci->caps->hc_capbase));
temp = scnprintf (next, size, temp = scnprintf (next, size,
"PCI device %s\nEHCI %x.%02x, hcd state %d (driver " DRIVER_VERSION ")\n", "PCI device %s\nEHCI %x.%02x, hcd state %d (driver " DRIVER_VERSION ")\n",
pci_name(hcd->pdev), pci_name(to_pci_dev(hcd->self.controller)),
i >> 8, i & 0x0ff, ehci->hcd.state); i >> 8, i & 0x0ff, ehci->hcd.state);
size -= temp; size -= temp;
next += temp; next += temp;
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/dmapool.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/ioport.h> #include <linux/ioport.h>
...@@ -67,6 +68,7 @@ ...@@ -67,6 +68,7 @@
* *
* HISTORY: * HISTORY:
* *
* 2004-02-24 Replace pci_* with generic dma_* API calls (dsaxena@plexity.net)
* 2003-12-29 Rewritten high speed iso transfer support (by Michal Sojka, * 2003-12-29 Rewritten high speed iso transfer support (by Michal Sojka,
* <sojkam@centrum.cz>, updates by DB). * <sojkam@centrum.cz>, updates by DB).
* *
...@@ -288,13 +290,13 @@ static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap) ...@@ -288,13 +290,13 @@ static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap)
/* request handoff to OS */ /* request handoff to OS */
cap &= 1 << 24; cap &= 1 << 24;
pci_write_config_dword (ehci->hcd.pdev, where, cap); pci_write_config_dword (to_pci_dev(ehci->hcd.self.controller), where, cap);
/* and wait a while for it to happen */ /* and wait a while for it to happen */
do { do {
wait_ms (10); wait_ms (10);
msec -= 10; msec -= 10;
pci_read_config_dword (ehci->hcd.pdev, where, &cap); pci_read_config_dword (to_pci_dev(ehci->hcd.self.controller), where, &cap);
} while ((cap & (1 << 16)) && msec); } while ((cap & (1 << 16)) && msec);
if (cap & (1 << 16)) { if (cap & (1 << 16)) {
ehci_err (ehci, "BIOS handoff failed (%d, %04x)\n", ehci_err (ehci, "BIOS handoff failed (%d, %04x)\n",
...@@ -339,7 +341,7 @@ static int ehci_hc_reset (struct usb_hcd *hcd) ...@@ -339,7 +341,7 @@ static int ehci_hc_reset (struct usb_hcd *hcd)
while (temp) { while (temp) {
u32 cap; u32 cap;
pci_read_config_dword (ehci->hcd.pdev, temp, &cap); pci_read_config_dword (to_pci_dev(ehci->hcd.self.controller), temp, &cap);
ehci_dbg (ehci, "capability %04x at %02x\n", cap, temp); ehci_dbg (ehci, "capability %04x at %02x\n", cap, temp);
switch (cap & 0xff) { switch (cap & 0xff) {
case 1: /* BIOS/SMM/... handoff */ case 1: /* BIOS/SMM/... handoff */
...@@ -378,7 +380,7 @@ static int ehci_start (struct usb_hcd *hcd) ...@@ -378,7 +380,7 @@ static int ehci_start (struct usb_hcd *hcd)
* periodic_size can shrink by USBCMD update if hcc_params allows. * periodic_size can shrink by USBCMD update if hcc_params allows.
*/ */
ehci->periodic_size = DEFAULT_I_TDPS; ehci->periodic_size = DEFAULT_I_TDPS;
if ((retval = ehci_mem_init (ehci, SLAB_KERNEL)) < 0) if ((retval = ehci_mem_init (ehci, GFP_KERNEL)) < 0)
return retval; return retval;
/* controllers may cache some of the periodic schedule ... */ /* controllers may cache some of the periodic schedule ... */
...@@ -433,13 +435,13 @@ static int ehci_start (struct usb_hcd *hcd) ...@@ -433,13 +435,13 @@ static int ehci_start (struct usb_hcd *hcd)
writel (0, &ehci->regs->segment); writel (0, &ehci->regs->segment);
#if 0 #if 0
// this is deeply broken on almost all architectures // this is deeply broken on almost all architectures
if (!pci_set_dma_mask (ehci->hcd.pdev, 0xffffffffffffffffULL)) if (!pci_set_dma_mask (to_pci_dev(ehci->hcd.self.controller), 0xffffffffffffffffULL))
ehci_info (ehci, "enabled 64bit PCI DMA\n"); ehci_info (ehci, "enabled 64bit PCI DMA\n");
#endif #endif
} }
/* help hc dma work well with cachelines */ /* help hc dma work well with cachelines */
pci_set_mwi (ehci->hcd.pdev); pci_set_mwi (to_pci_dev(ehci->hcd.self.controller));
/* clear interrupt enables, set irq latency */ /* clear interrupt enables, set irq latency */
temp = readl (&ehci->regs->command) & 0x0fff; temp = readl (&ehci->regs->command) & 0x0fff;
...@@ -493,7 +495,7 @@ static int ehci_start (struct usb_hcd *hcd) ...@@ -493,7 +495,7 @@ static int ehci_start (struct usb_hcd *hcd)
readl (&ehci->regs->command); /* unblock posted write */ readl (&ehci->regs->command); /* unblock posted write */
/* PCI Serial Bus Release Number is at 0x60 offset */ /* PCI Serial Bus Release Number is at 0x60 offset */
pci_read_config_byte (hcd->pdev, 0x60, &tempbyte); pci_read_config_byte(to_pci_dev(hcd->self.controller), 0x60, &tempbyte);
temp = HC_VERSION(readl (&ehci->caps->hc_capbase)); temp = HC_VERSION(readl (&ehci->caps->hc_capbase));
ehci_info (ehci, ehci_info (ehci,
"USB %x.%x enabled, EHCI %x.%02x, driver %s\n", "USB %x.%x enabled, EHCI %x.%02x, driver %s\n",
...@@ -758,7 +760,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs) ...@@ -758,7 +760,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs)
* non-error returns are a promise to giveback() the urb later * non-error returns are a promise to giveback() the urb later
* we drop ownership so next owner (or urb unlink) can get it * we drop ownership so next owner (or urb unlink) can get it
* *
* urb + dev is in hcd_dev.urb_list * urb + dev is in hcd.self.controller.urb_list
* we're queueing TDs onto software and hardware lists * we're queueing TDs onto software and hardware lists
* *
* hcd-specific init for hcpriv hasn't been done yet * hcd-specific init for hcpriv hasn't been done yet
......
...@@ -113,7 +113,7 @@ ehci_hub_descriptor ( ...@@ -113,7 +113,7 @@ ehci_hub_descriptor (
u16 temp; u16 temp;
desc->bDescriptorType = 0x29; desc->bDescriptorType = 0x29;
desc->bPwrOn2PwrGood = 10; /* FIXME: f(system power) */ desc->bPwrOn2PwrGood = 10; /* ehci 1.0, 2.3.9 says 20ms max */
desc->bHubContrCurrent = 0; desc->bHubContrCurrent = 0;
desc->bNbrPorts = ports; desc->bNbrPorts = ports;
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
* There's basically three types of memory: * There's basically three types of memory:
* - data used only by the HCD ... kmalloc is fine * - data used only by the HCD ... kmalloc is fine
* - async and periodic schedules, shared by HC and HCD ... these * - async and periodic schedules, shared by HC and HCD ... these
* need to use pci_pool or pci_alloc_consistent * need to use dma_pool or dma_alloc_coherent
* - driver buffers, read/written by HC ... single shot DMA mapped * - driver buffers, read/written by HC ... single shot DMA mapped
* *
* There's also PCI "register" data, which is memory mapped. * There's also PCI "register" data, which is memory mapped.
...@@ -74,7 +74,7 @@ static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, int flags) ...@@ -74,7 +74,7 @@ static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, int flags)
struct ehci_qtd *qtd; struct ehci_qtd *qtd;
dma_addr_t dma; dma_addr_t dma;
qtd = pci_pool_alloc (ehci->qtd_pool, flags, &dma); qtd = dma_pool_alloc (ehci->qtd_pool, flags, &dma);
if (qtd != 0) { if (qtd != 0) {
ehci_qtd_init (qtd, dma); ehci_qtd_init (qtd, dma);
} }
...@@ -83,7 +83,7 @@ static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, int flags) ...@@ -83,7 +83,7 @@ static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, int flags)
static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd) static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd)
{ {
pci_pool_free (ehci->qtd_pool, qtd, qtd->qtd_dma); dma_pool_free (ehci->qtd_pool, qtd, qtd->qtd_dma);
} }
...@@ -93,7 +93,7 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags) ...@@ -93,7 +93,7 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags)
dma_addr_t dma; dma_addr_t dma;
qh = (struct ehci_qh *) qh = (struct ehci_qh *)
pci_pool_alloc (ehci->qh_pool, flags, &dma); dma_pool_alloc (ehci->qh_pool, flags, &dma);
if (!qh) if (!qh)
return qh; return qh;
...@@ -107,7 +107,7 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags) ...@@ -107,7 +107,7 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags)
qh->dummy = ehci_qtd_alloc (ehci, flags); qh->dummy = ehci_qtd_alloc (ehci, flags);
if (qh->dummy == 0) { if (qh->dummy == 0) {
ehci_dbg (ehci, "no dummy td\n"); ehci_dbg (ehci, "no dummy td\n");
pci_pool_free (ehci->qh_pool, qh, qh->qh_dma); dma_pool_free (ehci->qh_pool, qh, qh->qh_dma);
qh = 0; qh = 0;
} }
return qh; return qh;
...@@ -132,7 +132,7 @@ static void qh_put (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -132,7 +132,7 @@ static void qh_put (struct ehci_hcd *ehci, struct ehci_qh *qh)
if (qh->dummy) if (qh->dummy)
ehci_qtd_free (ehci, qh->dummy); ehci_qtd_free (ehci, qh->dummy);
usb_put_dev (qh->dev); usb_put_dev (qh->dev);
pci_pool_free (ehci->qh_pool, qh, qh->qh_dma); dma_pool_free (ehci->qh_pool, qh, qh->qh_dma);
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -148,26 +148,26 @@ static void ehci_mem_cleanup (struct ehci_hcd *ehci) ...@@ -148,26 +148,26 @@ static void ehci_mem_cleanup (struct ehci_hcd *ehci)
qh_put (ehci, ehci->async); qh_put (ehci, ehci->async);
ehci->async = 0; ehci->async = 0;
/* PCI consistent memory and pools */ /* DMA consistent memory and pools */
if (ehci->qtd_pool) if (ehci->qtd_pool)
pci_pool_destroy (ehci->qtd_pool); dma_pool_destroy (ehci->qtd_pool);
ehci->qtd_pool = 0; ehci->qtd_pool = 0;
if (ehci->qh_pool) { if (ehci->qh_pool) {
pci_pool_destroy (ehci->qh_pool); dma_pool_destroy (ehci->qh_pool);
ehci->qh_pool = 0; ehci->qh_pool = 0;
} }
if (ehci->itd_pool) if (ehci->itd_pool)
pci_pool_destroy (ehci->itd_pool); dma_pool_destroy (ehci->itd_pool);
ehci->itd_pool = 0; ehci->itd_pool = 0;
if (ehci->sitd_pool) if (ehci->sitd_pool)
pci_pool_destroy (ehci->sitd_pool); dma_pool_destroy (ehci->sitd_pool);
ehci->sitd_pool = 0; ehci->sitd_pool = 0;
if (ehci->periodic) if (ehci->periodic)
pci_free_consistent (ehci->hcd.pdev, dma_free_coherent (ehci->hcd.self.controller,
ehci->periodic_size * sizeof (u32), ehci->periodic_size * sizeof (u32),
ehci->periodic, ehci->periodic_dma); ehci->periodic, ehci->periodic_dma);
ehci->periodic = 0; ehci->periodic = 0;
...@@ -184,7 +184,8 @@ static int ehci_mem_init (struct ehci_hcd *ehci, int flags) ...@@ -184,7 +184,8 @@ static int ehci_mem_init (struct ehci_hcd *ehci, int flags)
int i; int i;
/* QTDs for control/bulk/intr transfers */ /* QTDs for control/bulk/intr transfers */
ehci->qtd_pool = pci_pool_create ("ehci_qtd", ehci->hcd.pdev, ehci->qtd_pool = dma_pool_create ("ehci_qtd",
ehci->hcd.self.controller,
sizeof (struct ehci_qtd), sizeof (struct ehci_qtd),
32 /* byte alignment (for hw parts) */, 32 /* byte alignment (for hw parts) */,
4096 /* can't cross 4K */); 4096 /* can't cross 4K */);
...@@ -193,7 +194,8 @@ static int ehci_mem_init (struct ehci_hcd *ehci, int flags) ...@@ -193,7 +194,8 @@ static int ehci_mem_init (struct ehci_hcd *ehci, int flags)
} }
/* QHs for control/bulk/intr transfers */ /* QHs for control/bulk/intr transfers */
ehci->qh_pool = pci_pool_create ("ehci_qh", ehci->hcd.pdev, ehci->qh_pool = dma_pool_create ("ehci_qh",
ehci->hcd.self.controller,
sizeof (struct ehci_qh), sizeof (struct ehci_qh),
32 /* byte alignment (for hw parts) */, 32 /* byte alignment (for hw parts) */,
4096 /* can't cross 4K */); 4096 /* can't cross 4K */);
...@@ -206,7 +208,8 @@ static int ehci_mem_init (struct ehci_hcd *ehci, int flags) ...@@ -206,7 +208,8 @@ static int ehci_mem_init (struct ehci_hcd *ehci, int flags)
} }
/* ITD for high speed ISO transfers */ /* ITD for high speed ISO transfers */
ehci->itd_pool = pci_pool_create ("ehci_itd", ehci->hcd.pdev, ehci->itd_pool = dma_pool_create ("ehci_itd",
ehci->hcd.self.controller,
sizeof (struct ehci_itd), sizeof (struct ehci_itd),
32 /* byte alignment (for hw parts) */, 32 /* byte alignment (for hw parts) */,
4096 /* can't cross 4K */); 4096 /* can't cross 4K */);
...@@ -215,7 +218,8 @@ static int ehci_mem_init (struct ehci_hcd *ehci, int flags) ...@@ -215,7 +218,8 @@ static int ehci_mem_init (struct ehci_hcd *ehci, int flags)
} }
/* SITD for full/low speed split ISO transfers */ /* SITD for full/low speed split ISO transfers */
ehci->sitd_pool = pci_pool_create ("ehci_sitd", ehci->hcd.pdev, ehci->sitd_pool = dma_pool_create ("ehci_sitd",
ehci->hcd.self.controller,
sizeof (struct ehci_sitd), sizeof (struct ehci_sitd),
32 /* byte alignment (for hw parts) */, 32 /* byte alignment (for hw parts) */,
4096 /* can't cross 4K */); 4096 /* can't cross 4K */);
...@@ -225,9 +229,9 @@ static int ehci_mem_init (struct ehci_hcd *ehci, int flags) ...@@ -225,9 +229,9 @@ static int ehci_mem_init (struct ehci_hcd *ehci, int flags)
/* Hardware periodic table */ /* Hardware periodic table */
ehci->periodic = (u32 *) ehci->periodic = (u32 *)
pci_alloc_consistent (ehci->hcd.pdev, dma_alloc_coherent (ehci->hcd.self.controller,
ehci->periodic_size * sizeof (u32), ehci->periodic_size * sizeof (u32),
&ehci->periodic_dma); &ehci->periodic_dma, 0);
if (ehci->periodic == 0) { if (ehci->periodic == 0) {
goto fail; goto fail;
} }
......
...@@ -776,7 +776,7 @@ static struct ehci_qh *qh_append_tds ( ...@@ -776,7 +776,7 @@ static struct ehci_qh *qh_append_tds (
qh = (struct ehci_qh *) *ptr; qh = (struct ehci_qh *) *ptr;
if (unlikely (qh == 0)) { if (unlikely (qh == 0)) {
/* can't sleep here, we have ehci->lock... */ /* can't sleep here, we have ehci->lock... */
qh = qh_make (ehci, urb, SLAB_ATOMIC); qh = qh_make (ehci, urb, GFP_ATOMIC);
*ptr = qh; *ptr = qh;
} }
if (likely (qh != 0)) { if (likely (qh != 0)) {
......
...@@ -115,6 +115,7 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe) ...@@ -115,6 +115,7 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
/* ... or C-mask? */ /* ... or C-mask? */
if (q->qh->hw_info2 & cpu_to_le32 (1 << (8 + uframe))) if (q->qh->hw_info2 & cpu_to_le32 (1 << (8 + uframe)))
usecs += q->qh->c_usecs; usecs += q->qh->c_usecs;
hw_p = &q->qh->hw_next;
q = &q->qh->qh_next; q = &q->qh->qh_next;
break; break;
case Q_TYPE_FSTN: case Q_TYPE_FSTN:
...@@ -122,37 +123,35 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe) ...@@ -122,37 +123,35 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
* bandwidth from the previous frame * bandwidth from the previous frame
*/ */
if (q->fstn->hw_prev != EHCI_LIST_END) { if (q->fstn->hw_prev != EHCI_LIST_END) {
dbg ("not counting FSTN bandwidth yet ..."); ehci_dbg (ehci, "ignoring FSTN cost ...\n");
} }
hw_p = &q->fstn->hw_next;
q = &q->fstn->fstn_next; q = &q->fstn->fstn_next;
break; break;
case Q_TYPE_ITD: case Q_TYPE_ITD:
usecs += q->itd->usecs [uframe]; usecs += q->itd->usecs [uframe];
hw_p = &q->itd->hw_next;
q = &q->itd->itd_next; q = &q->itd->itd_next;
break; break;
#ifdef have_split_iso #ifdef have_split_iso
case Q_TYPE_SITD: case Q_TYPE_SITD:
temp = q->sitd->hw_fullspeed_ep &
__constant_cpu_to_le32 (1 << 31);
// FIXME: this doesn't count data bytes right...
/* is it in the S-mask? (count SPLIT, DATA) */ /* is it in the S-mask? (count SPLIT, DATA) */
if (q->sitd->hw_uframe & cpu_to_le32 (1 << uframe)) { if (q->sitd->hw_uframe & cpu_to_le32 (1 << uframe)) {
if (temp) if (q->sitd->hw_fullspeed_ep &
usecs += HS_USECS (188); __constant_cpu_to_le32 (1<<31))
else usecs += q->sitd->stream->usecs;
usecs += HS_USECS (1); else /* worst case for OUT start-split */
usecs += HS_USECS_ISO (188);
} }
/* ... C-mask? (count CSPLIT, DATA) */ /* ... C-mask? (count CSPLIT, DATA) */
if (q->sitd->hw_uframe & if (q->sitd->hw_uframe &
cpu_to_le32 (1 << (8 + uframe))) { cpu_to_le32 (1 << (8 + uframe))) {
if (temp) /* worst case for IN complete-split */
usecs += HS_USECS (0); usecs += q->sitd->stream->c_usecs;
else
usecs += HS_USECS (188);
} }
hw_p = &q->sitd->hw_next;
q = &q->sitd->sitd_next; q = &q->sitd->sitd_next;
break; break;
#endif /* have_split_iso */ #endif /* have_split_iso */
...@@ -170,6 +169,93 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe) ...@@ -170,6 +169,93 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static int same_tt (struct usb_device *dev1, struct usb_device *dev2)
{
if (!dev1->tt || !dev2->tt)
return 0;
if (dev1->tt != dev2->tt)
return 0;
if (dev1->tt->multi)
return dev1->ttport == dev2->ttport;
else
return 1;
}
/* return true iff the device's transaction translator is available
* for a periodic transfer starting at the specified frame, using
* all the uframes in the mask.
*/
static int tt_no_collision (
struct ehci_hcd *ehci,
unsigned period,
struct usb_device *dev,
unsigned frame,
u32 uf_mask
)
{
if (period == 0) /* error */
return 0;
/* note bandwidth wastage: split never follows csplit
* (different dev or endpoint) until the next uframe.
* calling convention doesn't make that distinction.
*/
for (; frame < ehci->periodic_size; frame += period) {
union ehci_shadow here;
u32 type;
here = ehci->pshadow [frame];
type = Q_NEXT_TYPE (ehci->periodic [frame]);
while (here.ptr) {
switch (type) {
case Q_TYPE_ITD:
type = Q_NEXT_TYPE (here.itd->hw_next);
here = here.itd->itd_next;
continue;
case Q_TYPE_QH:
if (same_tt (dev, here.qh->dev)) {
u32 mask;
mask = le32_to_cpu (here.qh->hw_info2);
/* "knows" no gap is needed */
mask |= mask >> 8;
if (mask & uf_mask)
break;
}
type = Q_NEXT_TYPE (here.qh->hw_next);
here = here.qh->qh_next;
continue;
case Q_TYPE_SITD:
if (same_tt (dev, here.itd->urb->dev)) {
u16 mask;
mask = le32_to_cpu (here.sitd->hw_uframe);
/* FIXME assumes no gap for IN! */
mask |= mask >> 8;
if (mask & uf_mask)
break;
}
type = Q_NEXT_TYPE (here.qh->hw_next);
here = here.sitd->sitd_next;
break;
// case Q_TYPE_FSTN:
default:
ehci_dbg (ehci,
"periodic frame %d bogus type %d\n",
frame, type);
}
/* collision or error */
return 0;
}
}
/* no collision */
return 1;
}
/*-------------------------------------------------------------------------*/
static int enable_periodic (struct ehci_hcd *ehci) static int enable_periodic (struct ehci_hcd *ehci)
{ {
u32 cmd; u32 cmd;
...@@ -490,36 +576,11 @@ static int intr_submit ( ...@@ -490,36 +576,11 @@ static int intr_submit (
return status; return status;
} }
static unsigned
intr_complete (
struct ehci_hcd *ehci,
unsigned frame,
struct ehci_qh *qh,
struct pt_regs *regs
) {
unsigned count;
/* nothing to report? */
if (likely ((qh->hw_token & __constant_cpu_to_le32 (QTD_STS_ACTIVE))
!= 0))
return 0;
if (unlikely (list_empty (&qh->qtd_list))) {
dbg ("intr qh %p no TDs?", qh);
return 0;
}
/* handle any completions */
count = qh_completions (ehci, qh, regs);
if (unlikely (list_empty (&qh->qtd_list)))
intr_deschedule (ehci, qh, 0);
return count;
}
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static inline struct ehci_iso_stream * /* ehci_iso_stream ops work with both ITD and SITD */
static struct ehci_iso_stream *
iso_stream_alloc (int mem_flags) iso_stream_alloc (int mem_flags)
{ {
struct ehci_iso_stream *stream; struct ehci_iso_stream *stream;
...@@ -527,15 +588,15 @@ iso_stream_alloc (int mem_flags) ...@@ -527,15 +588,15 @@ iso_stream_alloc (int mem_flags)
stream = kmalloc(sizeof *stream, mem_flags); stream = kmalloc(sizeof *stream, mem_flags);
if (likely (stream != 0)) { if (likely (stream != 0)) {
memset (stream, 0, sizeof(*stream)); memset (stream, 0, sizeof(*stream));
INIT_LIST_HEAD(&stream->itd_list); INIT_LIST_HEAD(&stream->td_list);
INIT_LIST_HEAD(&stream->free_itd_list); INIT_LIST_HEAD(&stream->free_list);
stream->next_uframe = -1; stream->next_uframe = -1;
stream->refcount = 1; stream->refcount = 1;
} }
return stream; return stream;
} }
static inline void static void
iso_stream_init ( iso_stream_init (
struct ehci_iso_stream *stream, struct ehci_iso_stream *stream,
struct usb_device *dev, struct usb_device *dev,
...@@ -543,8 +604,10 @@ iso_stream_init ( ...@@ -543,8 +604,10 @@ iso_stream_init (
unsigned interval unsigned interval
) )
{ {
static const u8 smask_out [] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f };
u32 buf1; u32 buf1;
unsigned epnum, maxp, multi; unsigned epnum, maxp;
int is_input; int is_input;
long bandwidth; long bandwidth;
...@@ -562,28 +625,62 @@ iso_stream_init ( ...@@ -562,28 +625,62 @@ iso_stream_init (
buf1 = 0; buf1 = 0;
} }
multi = hb_mult(maxp); /* knows about ITD vs SITD */
maxp = max_packet(maxp); if (dev->speed == USB_SPEED_HIGH) {
buf1 |= maxp; unsigned multi = hb_mult(maxp);
maxp *= multi;
stream->dev = (struct hcd_dev *)dev->hcpriv; stream->highspeed = 1;
stream->bEndpointAddress = is_input | epnum; maxp = max_packet(maxp);
stream->interval = interval; buf1 |= maxp;
stream->maxp = maxp; maxp *= multi;
stream->buf0 = cpu_to_le32 ((epnum << 8) | dev->devnum); stream->buf0 = cpu_to_le32 ((epnum << 8) | dev->devnum);
stream->buf1 = cpu_to_le32 (buf1); stream->buf1 = cpu_to_le32 (buf1);
stream->buf2 = cpu_to_le32 (multi); stream->buf2 = cpu_to_le32 (multi);
/* usbfs wants to report the average usecs per frame tied up /* usbfs wants to report the average usecs per frame tied up
* when transfers on this endpoint are scheduled ... * when transfers on this endpoint are scheduled ...
*/ */
stream->usecs = HS_USECS_ISO (maxp); stream->usecs = HS_USECS_ISO (maxp);
bandwidth = stream->usecs * 8; bandwidth = stream->usecs * 8;
bandwidth /= 1 << (interval - 1); bandwidth /= 1 << (interval - 1);
} else {
u32 addr;
addr = dev->ttport << 24;
addr |= dev->tt->hub->devnum << 16;
addr |= epnum << 8;
addr |= dev->devnum;
stream->usecs = HS_USECS_ISO (maxp);
if (is_input) {
u32 tmp;
addr |= 1 << 31;
stream->c_usecs = stream->usecs;
stream->usecs = HS_USECS_ISO (1);
stream->raw_mask = 1;
/* pessimistic c-mask */
tmp = usb_calc_bus_time (USB_SPEED_FULL, 1, 0, maxp)
/ (125 * 1000);
stream->raw_mask |= 3 << (tmp + 9);
} else
stream->raw_mask = smask_out [maxp / 188];
bandwidth = stream->usecs + stream->c_usecs;
bandwidth /= 1 << (interval + 2);
/* stream->splits gets created from raw_mask later */
stream->address = cpu_to_le32 (addr);
}
stream->bandwidth = bandwidth; stream->bandwidth = bandwidth;
stream->udev = dev;
stream->bEndpointAddress = is_input | epnum;
stream->interval = interval;
stream->maxp = maxp;
} }
static void static void
...@@ -595,22 +692,23 @@ iso_stream_put(struct ehci_hcd *ehci, struct ehci_iso_stream *stream) ...@@ -595,22 +692,23 @@ iso_stream_put(struct ehci_hcd *ehci, struct ehci_iso_stream *stream)
* not like a QH -- no persistent state (toggle, halt) * not like a QH -- no persistent state (toggle, halt)
*/ */
if (stream->refcount == 1) { if (stream->refcount == 1) {
int is_in; int is_in;
struct hcd_dev *dev = stream->udev->hcpriv;
// BUG_ON (!list_empty(&stream->itd_list)); // BUG_ON (!list_empty(&stream->td_list));
while (!list_empty (&stream->free_itd_list)) { while (!list_empty (&stream->free_list)) {
struct ehci_itd *itd; struct ehci_itd *itd;
itd = list_entry (stream->free_itd_list.next, itd = list_entry (stream->free_list.next,
struct ehci_itd, itd_list); struct ehci_itd, itd_list);
list_del (&itd->itd_list); list_del (&itd->itd_list);
pci_pool_free (ehci->itd_pool, itd, itd->itd_dma); dma_pool_free (ehci->itd_pool, itd, itd->itd_dma);
} }
is_in = (stream->bEndpointAddress & USB_DIR_IN) ? 0x10 : 0; is_in = (stream->bEndpointAddress & USB_DIR_IN) ? 0x10 : 0;
stream->bEndpointAddress &= 0x0f; stream->bEndpointAddress &= 0x0f;
stream->dev->ep [is_in + stream->bEndpointAddress] = 0; dev->ep [is_in + stream->bEndpointAddress] = 0;
if (stream->rescheduled) { if (stream->rescheduled) {
ehci_info (ehci, "ep%d%s-iso rescheduled " ehci_info (ehci, "ep%d%s-iso rescheduled "
...@@ -676,24 +774,26 @@ iso_stream_find (struct ehci_hcd *ehci, struct urb *urb) ...@@ -676,24 +774,26 @@ iso_stream_find (struct ehci_hcd *ehci, struct urb *urb)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static inline struct ehci_itd_sched * /* ehci_iso_sched ops can be shared, ITD-only, or SITD-only */
itd_sched_alloc (unsigned packets, int mem_flags)
static struct ehci_iso_sched *
iso_sched_alloc (unsigned packets, int mem_flags)
{ {
struct ehci_itd_sched *itd_sched; struct ehci_iso_sched *iso_sched;
int size = sizeof *itd_sched; int size = sizeof *iso_sched;
size += packets * sizeof (struct ehci_iso_uframe); size += packets * sizeof (struct ehci_iso_packet);
itd_sched = kmalloc (size, mem_flags); iso_sched = kmalloc (size, mem_flags);
if (likely (itd_sched != 0)) { if (likely (iso_sched != 0)) {
memset(itd_sched, 0, size); memset(iso_sched, 0, size);
INIT_LIST_HEAD (&itd_sched->itd_list); INIT_LIST_HEAD (&iso_sched->td_list);
} }
return itd_sched; return iso_sched;
} }
static int static inline void
itd_sched_init ( itd_sched_init (
struct ehci_itd_sched *itd_sched, struct ehci_iso_sched *iso_sched,
struct ehci_iso_stream *stream, struct ehci_iso_stream *stream,
struct urb *urb struct urb *urb
) )
...@@ -702,13 +802,13 @@ itd_sched_init ( ...@@ -702,13 +802,13 @@ itd_sched_init (
dma_addr_t dma = urb->transfer_dma; dma_addr_t dma = urb->transfer_dma;
/* how many uframes are needed for these transfers */ /* how many uframes are needed for these transfers */
itd_sched->span = urb->number_of_packets * stream->interval; iso_sched->span = urb->number_of_packets * stream->interval;
/* figure out per-uframe itd fields that we'll need later /* figure out per-uframe itd fields that we'll need later
* when we fit new itds into the schedule. * when we fit new itds into the schedule.
*/ */
for (i = 0; i < urb->number_of_packets; i++) { for (i = 0; i < urb->number_of_packets; i++) {
struct ehci_iso_uframe *uframe = &itd_sched->packet [i]; struct ehci_iso_packet *uframe = &iso_sched->packet [i];
unsigned length; unsigned length;
dma_addr_t buf; dma_addr_t buf;
u32 trans; u32 trans;
...@@ -718,7 +818,8 @@ itd_sched_init ( ...@@ -718,7 +818,8 @@ itd_sched_init (
trans = EHCI_ISOC_ACTIVE; trans = EHCI_ISOC_ACTIVE;
trans |= buf & 0x0fff; trans |= buf & 0x0fff;
if (unlikely ((i + 1) == urb->number_of_packets)) if (unlikely (((i + 1) == urb->number_of_packets))
&& !(urb->transfer_flags & URB_NO_INTERRUPT))
trans |= EHCI_ITD_IOC; trans |= EHCI_ITD_IOC;
trans |= length << 16; trans |= length << 16;
uframe->transaction = cpu_to_le32 (trans); uframe->transaction = cpu_to_le32 (trans);
...@@ -729,17 +830,19 @@ itd_sched_init ( ...@@ -729,17 +830,19 @@ itd_sched_init (
if (unlikely ((uframe->bufp != (buf & ~(u64)0x0fff)))) if (unlikely ((uframe->bufp != (buf & ~(u64)0x0fff))))
uframe->cross = 1; uframe->cross = 1;
} }
return 0;
} }
static void static void
itd_sched_free ( iso_sched_free (
struct ehci_iso_stream *stream, struct ehci_iso_stream *stream,
struct ehci_itd_sched *itd_sched struct ehci_iso_sched *iso_sched
) )
{ {
list_splice (&itd_sched->itd_list, &stream->free_itd_list); if (!iso_sched)
kfree (itd_sched); return;
// caller must hold ehci->lock!
list_splice (&iso_sched->td_list, &stream->free_list);
kfree (iso_sched);
} }
static int static int
...@@ -751,110 +854,201 @@ itd_urb_transaction ( ...@@ -751,110 +854,201 @@ itd_urb_transaction (
) )
{ {
struct ehci_itd *itd; struct ehci_itd *itd;
int status;
dma_addr_t itd_dma; dma_addr_t itd_dma;
int i; int i;
unsigned num_itds; unsigned num_itds;
struct ehci_itd_sched *itd_sched; struct ehci_iso_sched *sched;
itd_sched = itd_sched_alloc (urb->number_of_packets, mem_flags); sched = iso_sched_alloc (urb->number_of_packets, mem_flags);
if (unlikely (itd_sched == 0)) if (unlikely (sched == 0))
return -ENOMEM; return -ENOMEM;
status = itd_sched_init (itd_sched, stream, urb); itd_sched_init (sched, stream, urb);
if (unlikely (status != 0)) {
itd_sched_free (stream, itd_sched);
return status;
}
if (urb->interval < 8) if (urb->interval < 8)
num_itds = 1 + (itd_sched->span + 7) / 8; num_itds = 1 + (sched->span + 7) / 8;
else else
num_itds = urb->number_of_packets; num_itds = urb->number_of_packets;
/* allocate/init ITDs */ /* allocate/init ITDs */
for (i = 0; i < num_itds; i++) { for (i = 0; i < num_itds; i++) {
/* free_itd_list.next might be cache-hot ... but maybe /* free_list.next might be cache-hot ... but maybe
* the HC caches it too. avoid that issue for now. * the HC caches it too. avoid that issue for now.
*/ */
/* prefer previously-allocated itds */ /* prefer previously-allocated itds */
if (likely (!list_empty(&stream->free_itd_list))) { if (likely (!list_empty(&stream->free_list))) {
itd = list_entry (stream->free_itd_list.prev, itd = list_entry (stream->free_list.prev,
struct ehci_itd, itd_list); struct ehci_itd, itd_list);
list_del (&itd->itd_list); list_del (&itd->itd_list);
itd_dma = itd->itd_dma; itd_dma = itd->itd_dma;
} else } else
itd = pci_pool_alloc (ehci->itd_pool, mem_flags, itd = dma_pool_alloc (ehci->itd_pool, mem_flags,
&itd_dma); &itd_dma);
if (unlikely (0 == itd)) { if (unlikely (0 == itd)) {
itd_sched_free (stream, itd_sched); iso_sched_free (stream, sched);
return -ENOMEM; return -ENOMEM;
} }
memset (itd, 0, sizeof *itd); memset (itd, 0, sizeof *itd);
itd->itd_dma = itd_dma; itd->itd_dma = itd_dma;
list_add (&itd->itd_list, &itd_sched->itd_list); list_add (&itd->itd_list, &sched->td_list);
} }
/* temporarily store schedule info in hcpriv */ /* temporarily store schedule info in hcpriv */
urb->hcpriv = itd_sched; urb->hcpriv = sched;
urb->error_count = 0; urb->error_count = 0;
return 0; return 0;
} }
/*-------------------------------------------------------------------------*/
static inline int
itd_slot_ok (
struct ehci_hcd *ehci,
u32 mod,
u32 uframe,
u32 end,
u8 usecs,
u32 period
)
{
do {
/* can't commit more than 80% periodic == 100 usec */
if (periodic_usecs (ehci, uframe >> 3, uframe & 0x7)
> (100 - usecs))
return 0;
/* we know urb->interval is 2^N uframes */
uframe += period;
uframe %= mod;
} while (uframe != end);
return 1;
}
static inline int
sitd_slot_ok (
struct ehci_hcd *ehci,
u32 mod,
struct ehci_iso_stream *stream,
u32 uframe,
u32 end,
struct ehci_iso_sched *sched,
u32 period_uframes
)
{
u32 mask, tmp;
u32 frame, uf;
mask = stream->raw_mask << (uframe & 7);
/* for IN, don't wrap CSPLIT into the next frame */
if (mask & ~0xffff)
return 0;
/* this multi-pass logic is simple, but performance may
* suffer when the schedule data isn't cached.
*/
/* check bandwidth */
do {
u32 max_used;
frame = uframe >> 3;
uf = uframe & 7;
/* check starts (OUT uses more than one) */
max_used = 100 - stream->usecs;
for (tmp = stream->raw_mask & 0xff; tmp; tmp >>= 1, uf++) {
if (periodic_usecs (ehci, frame, uf) > max_used)
return 0;
}
/* for IN, check CSPLIT */
if (stream->c_usecs) {
max_used = 100 - stream->c_usecs;
do {
/* tt is busy in the gap before CSPLIT */
tmp = 1 << uf;
mask |= tmp;
tmp <<= 8;
if (stream->raw_mask & tmp)
break;
} while (++uf < 8);
if (periodic_usecs (ehci, frame, uf) > max_used)
return 0;
}
/* we know urb->interval is 2^N uframes */
uframe += period_uframes;
uframe %= mod;
} while (uframe != end);
/* tt must be idle for start(s), any gap, and csplit */
if (!tt_no_collision (ehci, period_uframes, stream->udev, frame, mask))
return 0;
stream->splits = stream->raw_mask << (uframe & 7);
cpu_to_le32s (&stream->splits);
return 1;
}
/* /*
* This scheduler plans almost as far into the future as it has actual * This scheduler plans almost as far into the future as it has actual
* periodic schedule slots. (Affected by TUNE_FLS, which defaults to * periodic schedule slots. (Affected by TUNE_FLS, which defaults to
* "as small as possible" to be cache-friendlier.) That limits the size * "as small as possible" to be cache-friendlier.) That limits the size
* transfers you can stream reliably; avoid more than 64 msec per urb. * transfers you can stream reliably; avoid more than 64 msec per urb.
* Also avoid queue depths of less than the system's worst irq latency. * Also avoid queue depths of less than ehci's worst irq latency (affected
* by the per-urb URB_NO_INTERRUPT hint, the log2_irq_thresh module parameter,
* and other factors); or more than about 230 msec total (for portability,
* given EHCI_TUNE_FLS and the slop). Or, write a smarter scheduler!
*/ */
#define SCHEDULE_SLOP 10 /* frames */ #define SCHEDULE_SLOP 10 /* frames */
static int static int
itd_stream_schedule ( iso_stream_schedule (
struct ehci_hcd *ehci, struct ehci_hcd *ehci,
struct urb *urb, struct urb *urb,
struct ehci_iso_stream *stream struct ehci_iso_stream *stream
) )
{ {
u32 now, start, end, max; u32 now, start, end, max, period;
int status; int status;
unsigned mod = ehci->periodic_size << 3; unsigned mod = ehci->periodic_size << 3;
struct ehci_itd_sched *itd_sched = urb->hcpriv; struct ehci_iso_sched *sched = urb->hcpriv;
if (unlikely (itd_sched->span > (mod - 8 * SCHEDULE_SLOP))) { if (sched->span > (mod - 8 * SCHEDULE_SLOP)) {
ehci_dbg (ehci, "iso request %p too long\n", urb); ehci_dbg (ehci, "iso request %p too long\n", urb);
status = -EFBIG; status = -EFBIG;
goto fail; goto fail;
} }
if ((stream->depth + sched->span) > mod) {
ehci_dbg (ehci, "request %p would overflow (%d+%d>%d)\n",
urb, stream->depth, sched->span, mod);
status = -EFBIG;
goto fail;
}
now = readl (&ehci->regs->frame_index) % mod; now = readl (&ehci->regs->frame_index) % mod;
/* when's the last uframe this urb could start? */ /* when's the last uframe this urb could start? */
max = now + mod; max = now + mod;
max -= itd_sched->span; max -= sched->span;
max -= 8 * SCHEDULE_SLOP; max -= 8 * SCHEDULE_SLOP;
/* typical case: reuse current schedule. stream is still active, /* typical case: reuse current schedule. stream is still active,
* and no gaps from host falling behind (irq delays etc) * and no gaps from host falling behind (irq delays etc)
*/ */
if (likely (!list_empty (&stream->itd_list))) { if (likely (!list_empty (&stream->td_list))) {
start = stream->next_uframe; start = stream->next_uframe;
if (start < now) if (start < now)
start += mod; start += mod;
if (likely (start < max)) if (likely (start < max))
goto ready; goto ready;
/* else fell behind; try to reschedule */
/* two cases:
* (a) we missed some uframes ... can reschedule
* (b) trying to overcommit the schedule
* FIXME (b) should be a hard failure
*/
} }
/* need to schedule; when's the next (u)frame we could start? /* need to schedule; when's the next (u)frame we could start?
...@@ -864,47 +1058,41 @@ itd_stream_schedule ( ...@@ -864,47 +1058,41 @@ itd_stream_schedule (
* jump until after the queue is primed. * jump until after the queue is primed.
*/ */
start = SCHEDULE_SLOP * 8 + (now & ~0x07); start = SCHEDULE_SLOP * 8 + (now & ~0x07);
start %= mod;
end = start; end = start;
ehci_vdbg (ehci, "%s schedule from %d (%d..%d), was %d\n",
__FUNCTION__, now, start, max,
stream->next_uframe);
/* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */ /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */
if (likely (max > (start + urb->interval))) period = urb->interval;
max = start + urb->interval; if (!stream->highspeed)
period <<= 3;
if (max > (start + period))
max = start + period;
/* hack: account for itds already scheduled to this endpoint */ /* hack: account for itds already scheduled to this endpoint */
if (unlikely (list_empty (&stream->itd_list))) if (list_empty (&stream->td_list))
end = max; end = max;
/* within [start..max] find a uframe slot with enough bandwidth */ /* within [start..max] find a uframe slot with enough bandwidth */
end %= mod; end %= mod;
do { do {
unsigned uframe; int enough_space;
int enough_space = 1;
/* check schedule: enough space? */ /* check schedule: enough space? */
uframe = start; if (stream->highspeed)
do { enough_space = itd_slot_ok (ehci, mod, start, end,
uframe %= mod; stream->usecs, period);
else {
/* can't commit more than 80% periodic == 100 usec */ if ((start % 8) >= 6)
if (periodic_usecs (ehci, uframe >> 3, uframe & 0x7) continue;
> (100 - stream->usecs)) { enough_space = sitd_slot_ok (ehci, mod, stream,
enough_space = 0; start, end, sched, period);
break; }
}
/* we know urb->interval is 2^N uframes */
uframe += urb->interval;
} while (uframe != end);
/* (re)schedule it here if there's enough bandwidth */ /* (re)schedule it here if there's enough bandwidth */
if (enough_space) { if (enough_space) {
start %= mod; start %= mod;
if (unlikely (!list_empty (&stream->itd_list))) { if (unlikely (!list_empty (&stream->td_list))) {
/* host fell behind ... maybe irq latencies /* host fell behind ... maybe irq latencies
* delayed this request queue for too long. * delayed this request queue for too long.
*/ */
...@@ -926,12 +1114,12 @@ itd_stream_schedule ( ...@@ -926,12 +1114,12 @@ itd_stream_schedule (
/* no room in the schedule */ /* no room in the schedule */
ehci_dbg (ehci, "iso %ssched full %p (now %d end %d max %d)\n", ehci_dbg (ehci, "iso %ssched full %p (now %d end %d max %d)\n",
list_empty (&stream->itd_list) ? "" : "re", list_empty (&stream->td_list) ? "" : "re",
urb, now, end, max); urb, now, end, max);
status = -ENOSPC; status = -ENOSPC;
fail: fail:
itd_sched_free (stream, itd_sched); iso_sched_free (stream, sched);
urb->hcpriv = 0; urb->hcpriv = 0;
return status; return status;
...@@ -961,13 +1149,13 @@ itd_init (struct ehci_iso_stream *stream, struct ehci_itd *itd) ...@@ -961,13 +1149,13 @@ itd_init (struct ehci_iso_stream *stream, struct ehci_itd *itd)
static inline void static inline void
itd_patch ( itd_patch (
struct ehci_itd *itd, struct ehci_itd *itd,
struct ehci_itd_sched *itd_sched, struct ehci_iso_sched *iso_sched,
unsigned index, unsigned index,
u16 uframe, u16 uframe,
int first int first
) )
{ {
struct ehci_iso_uframe *uf = &itd_sched->packet [index]; struct ehci_iso_packet *uf = &iso_sched->packet [index];
unsigned pg = itd->pg; unsigned pg = itd->pg;
// BUG_ON (pg == 6 && uf->cross); // BUG_ON (pg == 6 && uf->cross);
...@@ -1012,12 +1200,12 @@ itd_link_urb ( ...@@ -1012,12 +1200,12 @@ itd_link_urb (
{ {
int packet, first = 1; int packet, first = 1;
unsigned next_uframe, uframe, frame; unsigned next_uframe, uframe, frame;
struct ehci_itd_sched *itd_sched = urb->hcpriv; struct ehci_iso_sched *iso_sched = urb->hcpriv;
struct ehci_itd *itd; struct ehci_itd *itd;
next_uframe = stream->next_uframe % mod; next_uframe = stream->next_uframe % mod;
if (unlikely (list_empty(&stream->itd_list))) { if (unlikely (list_empty(&stream->td_list))) {
hcd_to_bus (&ehci->hcd)->bandwidth_allocated hcd_to_bus (&ehci->hcd)->bandwidth_allocated
+= stream->bandwidth; += stream->bandwidth;
ehci_vdbg (ehci, ehci_vdbg (ehci,
...@@ -1034,13 +1222,13 @@ itd_link_urb ( ...@@ -1034,13 +1222,13 @@ itd_link_urb (
for (packet = 0, itd = 0; packet < urb->number_of_packets; ) { for (packet = 0, itd = 0; packet < urb->number_of_packets; ) {
if (itd == 0) { if (itd == 0) {
/* ASSERT: we have all necessary itds */ /* ASSERT: we have all necessary itds */
// BUG_ON (list_empty (&itd_sched->itd_list)); // BUG_ON (list_empty (&iso_sched->td_list));
/* ASSERT: no itds for this endpoint in this uframe */ /* ASSERT: no itds for this endpoint in this uframe */
itd = list_entry (itd_sched->itd_list.next, itd = list_entry (iso_sched->td_list.next,
struct ehci_itd, itd_list); struct ehci_itd, itd_list);
list_move_tail (&itd->itd_list, &stream->itd_list); list_move_tail (&itd->itd_list, &stream->td_list);
itd->stream = iso_stream_get (stream); itd->stream = iso_stream_get (stream);
itd->urb = usb_get_urb (urb); itd->urb = usb_get_urb (urb);
first = 1; first = 1;
...@@ -1051,10 +1239,11 @@ itd_link_urb ( ...@@ -1051,10 +1239,11 @@ itd_link_urb (
frame = next_uframe >> 3; frame = next_uframe >> 3;
itd->usecs [uframe] = stream->usecs; itd->usecs [uframe] = stream->usecs;
itd_patch (itd, itd_sched, packet, uframe, first); itd_patch (itd, iso_sched, packet, uframe, first);
first = 0; first = 0;
next_uframe += stream->interval; next_uframe += stream->interval;
stream->depth += stream->interval;
next_uframe %= mod; next_uframe %= mod;
packet++; packet++;
...@@ -1068,7 +1257,7 @@ itd_link_urb ( ...@@ -1068,7 +1257,7 @@ itd_link_urb (
stream->next_uframe = next_uframe; stream->next_uframe = next_uframe;
/* don't need that schedule data any more */ /* don't need that schedule data any more */
itd_sched_free (stream, itd_sched); iso_sched_free (stream, iso_sched);
urb->hcpriv = 0; urb->hcpriv = 0;
if (unlikely (!ehci->periodic_sched++)) if (unlikely (!ehci->periodic_sched++))
...@@ -1101,6 +1290,7 @@ itd_complete ( ...@@ -1101,6 +1290,7 @@ itd_complete (
t = le32_to_cpup (&itd->hw_transaction [uframe]); t = le32_to_cpup (&itd->hw_transaction [uframe]);
itd->hw_transaction [uframe] = 0; itd->hw_transaction [uframe] = 0;
stream->depth -= stream->interval;
/* report transfer status */ /* report transfer status */
if (unlikely (t & ISO_ERRS)) { if (unlikely (t & ISO_ERRS)) {
...@@ -1126,7 +1316,7 @@ itd_complete ( ...@@ -1126,7 +1316,7 @@ itd_complete (
usb_put_urb (urb); usb_put_urb (urb);
itd->urb = 0; itd->urb = 0;
itd->stream = 0; itd->stream = 0;
list_move (&itd->itd_list, &stream->free_itd_list); list_move (&itd->itd_list, &stream->free_list);
iso_stream_put (ehci, stream); iso_stream_put (ehci, stream);
/* handle completion now? */ /* handle completion now? */
...@@ -1134,7 +1324,7 @@ itd_complete ( ...@@ -1134,7 +1324,7 @@ itd_complete (
return 0; return 0;
/* ASSERT: it's really the last itd for this urb /* ASSERT: it's really the last itd for this urb
list_for_each_entry (itd, &stream->itd_list, itd_list) list_for_each_entry (itd, &stream->td_list, itd_list)
BUG_ON (itd->urb == urb); BUG_ON (itd->urb == urb);
*/ */
...@@ -1149,7 +1339,7 @@ itd_complete ( ...@@ -1149,7 +1339,7 @@ itd_complete (
(void) disable_periodic (ehci); (void) disable_periodic (ehci);
hcd_to_bus (&ehci->hcd)->bandwidth_isoc_reqs--; hcd_to_bus (&ehci->hcd)->bandwidth_isoc_reqs--;
if (unlikely (list_empty (&stream->itd_list))) { if (unlikely (list_empty (&stream->td_list))) {
hcd_to_bus (&ehci->hcd)->bandwidth_allocated hcd_to_bus (&ehci->hcd)->bandwidth_allocated
-= stream->bandwidth; -= stream->bandwidth;
ehci_vdbg (ehci, ehci_vdbg (ehci,
...@@ -1203,7 +1393,7 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags) ...@@ -1203,7 +1393,7 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
/* schedule ... need to lock */ /* schedule ... need to lock */
spin_lock_irqsave (&ehci->lock, flags); spin_lock_irqsave (&ehci->lock, flags);
status = itd_stream_schedule (ehci, urb, stream); status = iso_stream_schedule (ehci, urb, stream);
if (likely (status == 0)) if (likely (status == 0))
itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
spin_unlock_irqrestore (&ehci->lock, flags); spin_unlock_irqrestore (&ehci->lock, flags);
...@@ -1233,7 +1423,7 @@ static void ...@@ -1233,7 +1423,7 @@ static void
scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs) scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs)
{ {
unsigned frame, clock, now_uframe, mod; unsigned frame, clock, now_uframe, mod;
unsigned count = 0; unsigned modified;
mod = ehci->periodic_size << 3; mod = ehci->periodic_size << 3;
...@@ -1244,47 +1434,50 @@ scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs) ...@@ -1244,47 +1434,50 @@ scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs)
*/ */
now_uframe = ehci->next_uframe; now_uframe = ehci->next_uframe;
if (HCD_IS_RUNNING (ehci->hcd.state)) if (HCD_IS_RUNNING (ehci->hcd.state))
clock = readl (&ehci->regs->frame_index) % mod; clock = readl (&ehci->regs->frame_index);
else else
clock = now_uframe + mod - 1; clock = now_uframe + mod - 1;
clock %= mod;
for (;;) { for (;;) {
union ehci_shadow q, *q_p; union ehci_shadow q, *q_p;
u32 type, *hw_p; u32 type, *hw_p;
unsigned uframes; unsigned uframes;
/* don't scan past the live uframe */
frame = now_uframe >> 3; frame = now_uframe >> 3;
restart: if (frame == (clock >> 3))
/* scan schedule to _before_ current frame index */
if ((frame == (clock >> 3))
&& HCD_IS_RUNNING (ehci->hcd.state))
uframes = now_uframe & 0x07; uframes = now_uframe & 0x07;
else else {
/* safe to scan the whole frame at once */
now_uframe |= 0x07;
uframes = 8; uframes = 8;
}
restart:
/* scan each element in frame's queue for completions */
q_p = &ehci->pshadow [frame]; q_p = &ehci->pshadow [frame];
hw_p = &ehci->periodic [frame]; hw_p = &ehci->periodic [frame];
q.ptr = q_p->ptr; q.ptr = q_p->ptr;
type = Q_NEXT_TYPE (*hw_p); type = Q_NEXT_TYPE (*hw_p);
modified = 0;
/* scan each element in frame's queue for completions */
while (q.ptr != 0) { while (q.ptr != 0) {
int last;
unsigned uf; unsigned uf;
union ehci_shadow temp; union ehci_shadow temp;
switch (type) { switch (type) {
case Q_TYPE_QH: case Q_TYPE_QH:
last = (q.qh->hw_next == EHCI_LIST_END); /* handle any completions */
temp = q.qh->qh_next; temp.qh = qh_get (q.qh);
type = Q_NEXT_TYPE (q.qh->hw_next); type = Q_NEXT_TYPE (q.qh->hw_next);
count += intr_complete (ehci, frame, q = q.qh->qh_next;
qh_get (q.qh), regs); modified = qh_completions (ehci, temp.qh, regs);
qh_put (ehci, q.qh); if (unlikely (list_empty (&temp.qh->qtd_list)))
q = temp; intr_deschedule (ehci, temp.qh, 0);
qh_put (ehci, temp.qh);
break; break;
case Q_TYPE_FSTN: case Q_TYPE_FSTN:
last = (q.fstn->hw_next == EHCI_LIST_END);
/* for "save place" FSTNs, look at QH entries /* for "save place" FSTNs, look at QH entries
* in the previous frame for completions. * in the previous frame for completions.
*/ */
...@@ -1295,13 +1488,11 @@ scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs) ...@@ -1295,13 +1488,11 @@ scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs)
q = q.fstn->fstn_next; q = q.fstn->fstn_next;
break; break;
case Q_TYPE_ITD: case Q_TYPE_ITD:
last = (q.itd->hw_next == EHCI_LIST_END);
/* skip itds for later in the frame */ /* skip itds for later in the frame */
rmb (); rmb ();
for (uf = uframes; uf < 8; uf++) { for (uf = uframes; uf < 8; uf++) {
if (0 == (q.itd->hw_transaction [uf] if (0 == (q.itd->hw_transaction [uf]
& ISO_ACTIVE)) & ITD_ACTIVE))
continue; continue;
q_p = &q.itd->itd_next; q_p = &q.itd->itd_next;
hw_p = &q.itd->hw_next; hw_p = &q.itd->hw_next;
...@@ -1317,31 +1508,37 @@ scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs) ...@@ -1317,31 +1508,37 @@ scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs)
*/ */
*q_p = q.itd->itd_next; *q_p = q.itd->itd_next;
*hw_p = q.itd->hw_next; *hw_p = q.itd->hw_next;
type = Q_NEXT_TYPE (q.itd->hw_next);
wmb(); wmb();
modified = itd_complete (ehci, q.itd, regs);
/* always rescan here; simpler */ q = *q_p;
count += itd_complete (ehci, q.itd, regs); break;
goto restart;
#ifdef have_split_iso #ifdef have_split_iso
case Q_TYPE_SITD: case Q_TYPE_SITD:
last = (q.sitd->hw_next == EHCI_LIST_END); if (q.sitd->hw_results & SITD_ACTIVE) {
sitd_complete (ehci, q.sitd); q_p = &q.sitd->sitd_next;
hw_p = &q.sitd->hw_next;
type = Q_NEXT_TYPE (q.sitd->hw_next);
q = *q_p;
break;
}
*q_p = q.sitd->sitd_next;
*hw_p = q.sitd->hw_next;
type = Q_NEXT_TYPE (q.sitd->hw_next); type = Q_NEXT_TYPE (q.sitd->hw_next);
wmb();
// FIXME unlink SITD after split completes modified = sitd_complete (ehci, q.sitd, regs);
q = q.sitd->sitd_next; q = *q_p;
break; break;
#endif /* have_split_iso */ #endif /* have_split_iso */
default: default:
dbg ("corrupt type %d frame %d shadow %p", dbg ("corrupt type %d frame %d shadow %p",
type, frame, q.ptr); type, frame, q.ptr);
// BUG (); // BUG ();
last = 1;
q.ptr = 0; q.ptr = 0;
} }
/* did completion remove an interior q entry? */ /* assume completion callbacks modify the queue */
if (unlikely (q.ptr == 0 && !last)) if (unlikely (modified))
goto restart; goto restart;
} }
...@@ -1368,9 +1565,6 @@ scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs) ...@@ -1368,9 +1565,6 @@ scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs)
/* rescan the rest of this frame, then ... */ /* rescan the rest of this frame, then ... */
clock = now; clock = now;
} else { } else {
/* FIXME sometimes we can scan the next frame
* right away, not always inching up on it ...
*/
now_uframe++; now_uframe++;
now_uframe %= mod; now_uframe %= mod;
} }
......
...@@ -74,11 +74,11 @@ struct ehci_hcd { /* one per controller */ ...@@ -74,11 +74,11 @@ struct ehci_hcd { /* one per controller */
struct ehci_regs *regs; struct ehci_regs *regs;
u32 hcs_params; /* cached register copy */ u32 hcs_params; /* cached register copy */
/* per-HC memory pools (could be per-PCI-bus, but ...) */ /* per-HC memory pools (could be per-bus, but ...) */
struct pci_pool *qh_pool; /* qh per active urb */ struct dma_pool *qh_pool; /* qh per active urb */
struct pci_pool *qtd_pool; /* one or more per qh */ struct dma_pool *qtd_pool; /* one or more per qh */
struct pci_pool *itd_pool; /* itd per iso urb */ struct dma_pool *itd_pool; /* itd per iso urb */
struct pci_pool *sitd_pool; /* sitd per split iso urb */ struct dma_pool *sitd_pool; /* sitd per split iso urb */
struct timer_list watchdog; struct timer_list watchdog;
struct notifier_block reboot_notifier; struct notifier_block reboot_notifier;
...@@ -386,22 +386,24 @@ struct ehci_qh { ...@@ -386,22 +386,24 @@ struct ehci_qh {
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/* description of one iso highspeed transaction (up to 3 KB data) */ /* description of one iso transaction (up to 3 KB data if highspeed) */
struct ehci_iso_uframe { struct ehci_iso_packet {
/* These will be copied to iTD when scheduling */ /* These will be copied to iTD when scheduling */
u64 bufp; /* itd->hw_bufp{,_hi}[pg] |= */ u64 bufp; /* itd->hw_bufp{,_hi}[pg] |= */
u32 transaction; /* itd->hw_transaction[i] |= */ u32 transaction; /* itd->hw_transaction[i] |= */
u8 cross; /* buf crosses pages */ u8 cross; /* buf crosses pages */
/* for full speed OUT splits */
u16 buf1;
}; };
/* temporary schedule data for highspeed packets from iso urbs /* temporary schedule data for packets from iso urbs (both speeds)
* each packet is one uframe's usb transactions, in some itd, * each packet is one logical usb transaction to the device (not TT),
* beginning at stream->next_uframe * beginning at stream->next_uframe
*/ */
struct ehci_itd_sched { struct ehci_iso_sched {
struct list_head itd_list; struct list_head td_list;
unsigned span; unsigned span;
struct ehci_iso_uframe packet [0]; struct ehci_iso_packet packet [0];
}; };
/* /*
...@@ -415,22 +417,26 @@ struct ehci_iso_stream { ...@@ -415,22 +417,26 @@ struct ehci_iso_stream {
u32 refcount; u32 refcount;
u8 bEndpointAddress; u8 bEndpointAddress;
struct list_head itd_list; /* queued itds */ u8 highspeed;
struct list_head free_itd_list; /* list of unused itds */ u16 depth; /* depth in uframes */
struct hcd_dev *dev; struct list_head td_list; /* queued itds/sitds */
struct list_head free_list; /* list of unused itds/sitds */
struct usb_device *udev;
/* output of (re)scheduling */ /* output of (re)scheduling */
unsigned long start; /* jiffies */ unsigned long start; /* jiffies */
unsigned long rescheduled; unsigned long rescheduled;
int next_uframe; int next_uframe;
u32 splits;
/* the rest is derived from the endpoint descriptor, /* the rest is derived from the endpoint descriptor,
* trusting urb->interval == (1 << (epdesc->bInterval - 1)), * trusting urb->interval == f(epdesc->bInterval) and
* including the extra info for hw_bufp[0..2] * including the extra info for hw_bufp[0..2]
*/ */
u8 interval; u8 interval;
u8 usecs; u8 usecs, c_usecs;
u16 maxp; u16 maxp;
u16 raw_mask;
unsigned bandwidth; unsigned bandwidth;
/* This is used to initialize iTD's hw_bufp fields */ /* This is used to initialize iTD's hw_bufp fields */
...@@ -438,7 +444,8 @@ struct ehci_iso_stream { ...@@ -438,7 +444,8 @@ struct ehci_iso_stream {
u32 buf1; u32 buf1;
u32 buf2; u32 buf2;
/* ... sITD won't use buf[012], and needs TT access ... */ /* this is used to initialize sITD's tt info */
u32 address;
}; };
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -460,7 +467,7 @@ struct ehci_itd { ...@@ -460,7 +467,7 @@ struct ehci_itd {
#define EHCI_ITD_LENGTH(tok) (((tok)>>16) & 0x0fff) #define EHCI_ITD_LENGTH(tok) (((tok)>>16) & 0x0fff)
#define EHCI_ITD_IOC (1 << 15) /* interrupt on complete */ #define EHCI_ITD_IOC (1 << 15) /* interrupt on complete */
#define ISO_ACTIVE __constant_cpu_to_le32(EHCI_ISOC_ACTIVE) #define ITD_ACTIVE __constant_cpu_to_le32(EHCI_ISOC_ACTIVE)
u32 hw_bufp [7]; /* see EHCI 3.3.3 */ u32 hw_bufp [7]; /* see EHCI 3.3.3 */
u32 hw_bufp_hi [7]; /* Appendix B */ u32 hw_bufp_hi [7]; /* Appendix B */
...@@ -492,22 +499,35 @@ struct ehci_sitd { ...@@ -492,22 +499,35 @@ struct ehci_sitd {
/* first part defined by EHCI spec */ /* first part defined by EHCI spec */
u32 hw_next; u32 hw_next;
/* uses bit field macros above - see EHCI 0.95 Table 3-8 */ /* uses bit field macros above - see EHCI 0.95 Table 3-8 */
u32 hw_fullspeed_ep; /* see EHCI table 3-9 */ u32 hw_fullspeed_ep; /* see EHCI table 3-9 */
u32 hw_uframe; /* see EHCI table 3-10 */ u32 hw_uframe; /* see EHCI table 3-10 */
u32 hw_tx_results1; /* see EHCI table 3-11 */ u32 hw_results; /* see EHCI table 3-11 */
u32 hw_tx_results2; /* see EHCI table 3-12 */ #define SITD_IOC (1 << 31) /* interrupt on completion */
u32 hw_tx_results3; /* see EHCI table 3-12 */ #define SITD_PAGE (1 << 30) /* buffer 0/1 */
u32 hw_backpointer; /* see EHCI table 3-13 */ #define SITD_LENGTH(x) (0x3ff & ((x)>>16))
u32 hw_buf_hi [2]; /* Appendix B */ #define SITD_STS_ACTIVE (1 << 7) /* HC may execute this */
#define SITD_STS_ERR (1 << 6) /* error from TT */
#define SITD_STS_DBE (1 << 5) /* data buffer error (in HC) */
#define SITD_STS_BABBLE (1 << 4) /* device was babbling */
#define SITD_STS_XACT (1 << 3) /* illegal IN response */
#define SITD_STS_MMF (1 << 2) /* incomplete split transaction */
#define SITD_STS_STS (1 << 1) /* split transaction state */
#define SITD_ACTIVE __constant_cpu_to_le32(SITD_STS_ACTIVE)
u32 hw_buf [2]; /* see EHCI table 3-12 */
u32 hw_backpointer; /* see EHCI table 3-13 */
u32 hw_buf_hi [2]; /* Appendix B */
/* the rest is HCD-private */ /* the rest is HCD-private */
dma_addr_t sitd_dma; dma_addr_t sitd_dma;
union ehci_shadow sitd_next; /* ptr to periodic q entry */ union ehci_shadow sitd_next; /* ptr to periodic q entry */
struct urb *urb;
dma_addr_t buf_dma; /* buffer address */
unsigned short usecs; /* start bandwidth */ struct urb *urb;
unsigned short c_usecs; /* completion bandwidth */ struct ehci_iso_stream *stream; /* endpoint's queue */
struct list_head sitd_list; /* list of stream's sitds */
unsigned frame;
unsigned index;
} __attribute__ ((aligned (32))); } __attribute__ ((aligned (32)));
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
* *
* History: * History:
* *
* 2004/02/04 use generic dma_* functions instead of pci_* (dsaxena@plexity.net)
* 2003/02/24 show registers in sysfs (Kevin Brosius) * 2003/02/24 show registers in sysfs (Kevin Brosius)
* *
* 2002/09/03 get rid of ed hashtables, rework periodic scheduling and * 2002/09/03 get rid of ed hashtables, rework periodic scheduling and
...@@ -96,6 +97,8 @@ ...@@ -96,6 +97,8 @@
#include <linux/interrupt.h> /* for in_interrupt () */ #include <linux/interrupt.h> /* for in_interrupt () */
#include <linux/usb.h> #include <linux/usb.h>
#include "../core/hcd.h" #include "../core/hcd.h"
#include <linux/dma-mapping.h>
#include <linux/dmapool.h> /* needed by ohci-mem.c when no PCI */
#include <asm/io.h> #include <asm/io.h>
#include <asm/irq.h> #include <asm/irq.h>
...@@ -642,8 +645,9 @@ static void ohci_stop (struct usb_hcd *hcd) ...@@ -642,8 +645,9 @@ static void ohci_stop (struct usb_hcd *hcd)
remove_debug_files (ohci); remove_debug_files (ohci);
ohci_mem_cleanup (ohci); ohci_mem_cleanup (ohci);
if (ohci->hcca) { if (ohci->hcca) {
pci_free_consistent (ohci->hcd.pdev, sizeof *ohci->hcca, dma_free_coherent (ohci->hcd.self.controller,
ohci->hcca, ohci->hcca_dma); sizeof *ohci->hcca,
ohci->hcca, ohci->hcca_dma);
ohci->hcca = NULL; ohci->hcca = NULL;
ohci->hcca_dma = 0; ohci->hcca_dma = 0;
} }
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* There's basically three types of memory: * There's basically three types of memory:
* - data used only by the HCD ... kmalloc is fine * - data used only by the HCD ... kmalloc is fine
* - async and periodic schedules, shared by HC and HCD ... these * - async and periodic schedules, shared by HC and HCD ... these
* need to use pci_pool or pci_alloc_consistent * need to use dma_pool or dma_alloc_coherent
* - driver buffers, read/written by HC ... the hcd glue or the * - driver buffers, read/written by HC ... the hcd glue or the
* device driver provides us with dma addresses * device driver provides us with dma addresses
* *
...@@ -45,18 +45,18 @@ static void ohci_hcd_free (struct usb_hcd *hcd) ...@@ -45,18 +45,18 @@ static void ohci_hcd_free (struct usb_hcd *hcd)
static int ohci_mem_init (struct ohci_hcd *ohci) static int ohci_mem_init (struct ohci_hcd *ohci)
{ {
ohci->td_cache = pci_pool_create ("ohci_td", ohci->hcd.pdev, ohci->td_cache = dma_pool_create ("ohci_td", ohci->hcd.self.controller,
sizeof (struct td), sizeof (struct td),
32 /* byte alignment */, 32 /* byte alignment */,
0 /* no page-crossing issues */); 0 /* no page-crossing issues */);
if (!ohci->td_cache) if (!ohci->td_cache)
return -ENOMEM; return -ENOMEM;
ohci->ed_cache = pci_pool_create ("ohci_ed", ohci->hcd.pdev, ohci->ed_cache = dma_pool_create ("ohci_ed", ohci->hcd.self.controller,
sizeof (struct ed), sizeof (struct ed),
16 /* byte alignment */, 16 /* byte alignment */,
0 /* no page-crossing issues */); 0 /* no page-crossing issues */);
if (!ohci->ed_cache) { if (!ohci->ed_cache) {
pci_pool_destroy (ohci->td_cache); dma_pool_destroy (ohci->td_cache);
return -ENOMEM; return -ENOMEM;
} }
return 0; return 0;
...@@ -65,11 +65,11 @@ static int ohci_mem_init (struct ohci_hcd *ohci) ...@@ -65,11 +65,11 @@ static int ohci_mem_init (struct ohci_hcd *ohci)
static void ohci_mem_cleanup (struct ohci_hcd *ohci) static void ohci_mem_cleanup (struct ohci_hcd *ohci)
{ {
if (ohci->td_cache) { if (ohci->td_cache) {
pci_pool_destroy (ohci->td_cache); dma_pool_destroy (ohci->td_cache);
ohci->td_cache = 0; ohci->td_cache = 0;
} }
if (ohci->ed_cache) { if (ohci->ed_cache) {
pci_pool_destroy (ohci->ed_cache); dma_pool_destroy (ohci->ed_cache);
ohci->ed_cache = 0; ohci->ed_cache = 0;
} }
} }
...@@ -96,7 +96,7 @@ td_alloc (struct ohci_hcd *hc, int mem_flags) ...@@ -96,7 +96,7 @@ td_alloc (struct ohci_hcd *hc, int mem_flags)
dma_addr_t dma; dma_addr_t dma;
struct td *td; struct td *td;
td = pci_pool_alloc (hc->td_cache, mem_flags, &dma); td = dma_pool_alloc (hc->td_cache, mem_flags, &dma);
if (td) { if (td) {
/* in case hc fetches it, make it look dead */ /* in case hc fetches it, make it look dead */
memset (td, 0, sizeof *td); memset (td, 0, sizeof *td);
...@@ -118,7 +118,7 @@ td_free (struct ohci_hcd *hc, struct td *td) ...@@ -118,7 +118,7 @@ td_free (struct ohci_hcd *hc, struct td *td)
*prev = td->td_hash; *prev = td->td_hash;
else if ((td->hwINFO & TD_DONE) != 0) else if ((td->hwINFO & TD_DONE) != 0)
ohci_dbg (hc, "no hash for td %p\n", td); ohci_dbg (hc, "no hash for td %p\n", td);
pci_pool_free (hc->td_cache, td, td->td_dma); dma_pool_free (hc->td_cache, td, td->td_dma);
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -130,7 +130,7 @@ ed_alloc (struct ohci_hcd *hc, int mem_flags) ...@@ -130,7 +130,7 @@ ed_alloc (struct ohci_hcd *hc, int mem_flags)
dma_addr_t dma; dma_addr_t dma;
struct ed *ed; struct ed *ed;
ed = pci_pool_alloc (hc->ed_cache, mem_flags, &dma); ed = dma_pool_alloc (hc->ed_cache, mem_flags, &dma);
if (ed) { if (ed) {
memset (ed, 0, sizeof (*ed)); memset (ed, 0, sizeof (*ed));
INIT_LIST_HEAD (&ed->td_list); INIT_LIST_HEAD (&ed->td_list);
...@@ -142,6 +142,6 @@ ed_alloc (struct ohci_hcd *hc, int mem_flags) ...@@ -142,6 +142,6 @@ ed_alloc (struct ohci_hcd *hc, int mem_flags)
static void static void
ed_free (struct ohci_hcd *hc, struct ed *ed) ed_free (struct ohci_hcd *hc, struct ed *ed)
{ {
pci_pool_free (hc->ed_cache, ed, ed->dma); dma_pool_free (hc->ed_cache, ed, ed->dma);
} }
...@@ -388,9 +388,7 @@ int usb_hcd_omap_probe (const struct hc_driver *driver, ...@@ -388,9 +388,7 @@ int usb_hcd_omap_probe (const struct hc_driver *driver,
hcd->description = driver->description; hcd->description = driver->description;
hcd->irq = dev->irq[0]; hcd->irq = dev->irq[0];
hcd->regs = dev->mapbase; hcd->regs = dev->mapbase;
hcd->pdev = OMAP_FAKE_PCIDEV;
hcd->self.controller = &dev->dev; hcd->self.controller = &dev->dev;
hcd->controller = hcd->self.controller;
retval = hcd_buffer_create (hcd); retval = hcd_buffer_create (hcd);
if (retval != 0) { if (retval != 0) {
...@@ -494,12 +492,10 @@ ohci_omap_start (struct usb_hcd *hcd) ...@@ -494,12 +492,10 @@ ohci_omap_start (struct usb_hcd *hcd)
struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int ret; int ret;
if (hcd->pdev) { ohci->hcca = dma_alloc_consistent (hcd->self.controller,
ohci->hcca = pci_alloc_consistent (hcd->pdev, sizeof *ohci->hcca, &ohci->hcca_dma);
sizeof *ohci->hcca, &ohci->hcca_dma); if (!ohci->hcca)
if (!ohci->hcca) return -ENOMEM;
return -ENOMEM;
}
memset (ohci->hcca, 0, sizeof (struct ohci_hcca)); memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
if ((ret = ohci_mem_init (ohci)) < 0) { if ((ret = ohci_mem_init (ohci)) < 0) {
......
...@@ -45,17 +45,19 @@ ohci_pci_start (struct usb_hcd *hcd) ...@@ -45,17 +45,19 @@ ohci_pci_start (struct usb_hcd *hcd)
struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int ret; int ret;
if (hcd->pdev) { ohci->hcca = dma_alloc_coherent (hcd->self.controller,
ohci->hcca = pci_alloc_consistent (hcd->pdev, sizeof *ohci->hcca, &ohci->hcca_dma, 0);
sizeof *ohci->hcca, &ohci->hcca_dma); if (!ohci->hcca)
if (!ohci->hcca) return -ENOMEM;
return -ENOMEM;
if(hcd->self.controller && hcd->self.controller->bus == &pci_bus_type) {
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
/* AMD 756, for most chips (early revs), corrupts register /* AMD 756, for most chips (early revs), corrupts register
* values on read ... so enable the vendor workaround. * values on read ... so enable the vendor workaround.
*/ */
if (hcd->pdev->vendor == PCI_VENDOR_ID_AMD if (pdev->vendor == PCI_VENDOR_ID_AMD
&& hcd->pdev->device == 0x740c) { && pdev->device == 0x740c) {
ohci->flags = OHCI_QUIRK_AMD756; ohci->flags = OHCI_QUIRK_AMD756;
ohci_info (ohci, "AMD756 erratum 4 workaround\n"); ohci_info (ohci, "AMD756 erratum 4 workaround\n");
} }
...@@ -68,8 +70,8 @@ ohci_pci_start (struct usb_hcd *hcd) ...@@ -68,8 +70,8 @@ ohci_pci_start (struct usb_hcd *hcd)
* for this chip. Evidently control and bulk lists * for this chip. Evidently control and bulk lists
* can get confused. (B&W G3 models, and ...) * can get confused. (B&W G3 models, and ...)
*/ */
else if (hcd->pdev->vendor == PCI_VENDOR_ID_OPTI else if (pdev->vendor == PCI_VENDOR_ID_OPTI
&& hcd->pdev->device == 0xc861) { && pdev->device == 0xc861) {
ohci_info (ohci, ohci_info (ohci,
"WARNING: OPTi workarounds unavailable\n"); "WARNING: OPTi workarounds unavailable\n");
} }
...@@ -78,12 +80,11 @@ ohci_pci_start (struct usb_hcd *hcd) ...@@ -78,12 +80,11 @@ ohci_pci_start (struct usb_hcd *hcd)
* identify the USB (fn2). This quirk might apply to more or * identify the USB (fn2). This quirk might apply to more or
* even all NSC stuff. * even all NSC stuff.
*/ */
else if (hcd->pdev->vendor == PCI_VENDOR_ID_NS) { else if (pdev->vendor == PCI_VENDOR_ID_NS) {
struct pci_dev *b, *hc; struct pci_dev *b;
hc = hcd->pdev; b = pci_find_slot (pdev->bus->number,
b = pci_find_slot (hc->bus->number, PCI_DEVFN (PCI_SLOT (pdev->devfn), 1));
PCI_DEVFN (PCI_SLOT (hc->devfn), 1));
if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
&& b->vendor == PCI_VENDOR_ID_NS) { && b->vendor == PCI_VENDOR_ID_NS) {
ohci->flags |= OHCI_QUIRK_SUPERIO; ohci->flags |= OHCI_QUIRK_SUPERIO;
...@@ -145,7 +146,7 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state) ...@@ -145,7 +146,7 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state)
#ifdef CONFIG_PMAC_PBOOK #ifdef CONFIG_PMAC_PBOOK
if (_machine == _MACH_Pmac) if (_machine == _MACH_Pmac)
disable_irq (hcd->pdev->irq); disable_irq ((to_pci_dev(hcd->self.controller))->irq);
/* else, 2.4 assumes shared irqs -- don't disable */ /* else, 2.4 assumes shared irqs -- don't disable */
#endif #endif
...@@ -179,15 +180,17 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state) ...@@ -179,15 +180,17 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state)
* memory during sleep. We disable its bus master bit during * memory during sleep. We disable its bus master bit during
* suspend * suspend
*/ */
pci_read_config_word (hcd->pdev, PCI_COMMAND, &cmd); pci_read_config_word (to_pci_dev(hcd->self.controller), PCI_COMMAND,
&cmd);
cmd &= ~PCI_COMMAND_MASTER; cmd &= ~PCI_COMMAND_MASTER;
pci_write_config_word (hcd->pdev, PCI_COMMAND, cmd); pci_write_config_word (to_pci_dev(hcd->self.controller), PCI_COMMAND,
cmd);
#ifdef CONFIG_PMAC_PBOOK #ifdef CONFIG_PMAC_PBOOK
{ {
struct device_node *of_node; struct device_node *of_node;
/* Disable USB PAD & cell clock */ /* Disable USB PAD & cell clock */
of_node = pci_device_to_OF_node (hcd->pdev); of_node = pci_device_to_OF_node (to_pci_dev(hcd->self.controller));
if (of_node) if (of_node)
pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0); pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
} }
...@@ -207,7 +210,7 @@ static int ohci_pci_resume (struct usb_hcd *hcd) ...@@ -207,7 +210,7 @@ static int ohci_pci_resume (struct usb_hcd *hcd)
struct device_node *of_node; struct device_node *of_node;
/* Re-enable USB PAD & cell clock */ /* Re-enable USB PAD & cell clock */
of_node = pci_device_to_OF_node (hcd->pdev); of_node = pci_device_to_OF_node (to_pci_dev(hcd->self.controller));
if (of_node) if (of_node)
pmac_call_feature (PMAC_FTR_USB_ENABLE, of_node, 0, 1); pmac_call_feature (PMAC_FTR_USB_ENABLE, of_node, 0, 1);
} }
...@@ -222,7 +225,7 @@ static int ohci_pci_resume (struct usb_hcd *hcd) ...@@ -222,7 +225,7 @@ static int ohci_pci_resume (struct usb_hcd *hcd)
#endif #endif
/* Re-enable bus mastering */ /* Re-enable bus mastering */
pci_set_master (ohci->hcd.pdev); pci_set_master (to_pci_dev(ohci->hcd.self.controller));
switch (temp) { switch (temp) {
...@@ -282,7 +285,7 @@ static int ohci_pci_resume (struct usb_hcd *hcd) ...@@ -282,7 +285,7 @@ static int ohci_pci_resume (struct usb_hcd *hcd)
#ifdef CONFIG_PMAC_PBOOK #ifdef CONFIG_PMAC_PBOOK
if (_machine == _MACH_Pmac) if (_machine == _MACH_Pmac)
enable_irq (hcd->pdev->irq); enable_irq (to_pci_dev(hcd->self.controller)->irq);
#endif #endif
/* Check for a pending done list */ /* Check for a pending done list */
......
...@@ -375,7 +375,7 @@ static struct ed *ed_get ( ...@@ -375,7 +375,7 @@ static struct ed *ed_get (
if (!(ed = dev->ep [ep])) { if (!(ed = dev->ep [ep])) {
struct td *td; struct td *td;
ed = ed_alloc (ohci, SLAB_ATOMIC); ed = ed_alloc (ohci, GFP_ATOMIC);
if (!ed) { if (!ed) {
/* out of memory */ /* out of memory */
goto done; goto done;
...@@ -383,7 +383,7 @@ static struct ed *ed_get ( ...@@ -383,7 +383,7 @@ static struct ed *ed_get (
dev->ep [ep] = ed; dev->ep [ep] = ed;
/* dummy td; end of td list for ed */ /* dummy td; end of td list for ed */
td = td_alloc (ohci, SLAB_ATOMIC); td = td_alloc (ohci, GFP_ATOMIC);
if (!td) { if (!td) {
/* out of memory */ /* out of memory */
ed_free (ohci, ed); ed_free (ohci, ed);
......
...@@ -167,9 +167,7 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver, ...@@ -167,9 +167,7 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver,
hcd->description = driver->description; hcd->description = driver->description;
hcd->irq = dev->irq[1]; hcd->irq = dev->irq[1];
hcd->regs = dev->mapbase; hcd->regs = dev->mapbase;
hcd->pdev = SA1111_FAKE_PCIDEV;
hcd->self.controller = &dev->dev; hcd->self.controller = &dev->dev;
hcd->controller = hcd->self.controller;
retval = hcd_buffer_create (hcd); retval = hcd_buffer_create (hcd);
if (retval != 0) { if (retval != 0) {
...@@ -270,14 +268,12 @@ ohci_sa1111_start (struct usb_hcd *hcd) ...@@ -270,14 +268,12 @@ ohci_sa1111_start (struct usb_hcd *hcd)
struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int ret; int ret;
if (hcd->pdev) { ohci->hcca = dma_alloc_coherent (hcd->self.controller,
ohci->hcca = pci_alloc_consistent (hcd->pdev, sizeof *ohci->hcca, &ohci->hcca_dma, 0);
sizeof *ohci->hcca, &ohci->hcca_dma); if (!ohci->hcca)
if (!ohci->hcca) return -ENOMEM;
return -ENOMEM;
} memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
if ((ret = ohci_mem_init (ohci)) < 0) { if ((ret = ohci_mem_init (ohci)) < 0) {
ohci_stop (hcd); ohci_stop (hcd);
return ret; return ret;
......
...@@ -361,8 +361,8 @@ struct ohci_hcd { ...@@ -361,8 +361,8 @@ struct ohci_hcd {
/* /*
* memory management for queue data structures * memory management for queue data structures
*/ */
struct pci_pool *td_cache; struct dma_pool *td_cache;
struct pci_pool *ed_cache; struct dma_pool *ed_cache;
struct td *td_hash [TD_HASH_SIZE]; struct td *td_hash [TD_HASH_SIZE];
/* /*
...@@ -391,13 +391,13 @@ struct ohci_hcd { ...@@ -391,13 +391,13 @@ struct ohci_hcd {
#endif /* DEBUG */ #endif /* DEBUG */
#define ohci_dbg(ohci, fmt, args...) \ #define ohci_dbg(ohci, fmt, args...) \
dev_dbg ((ohci)->hcd.controller , fmt , ## args ) dev_dbg ((ohci)->hcd.self.controller , fmt , ## args )
#define ohci_err(ohci, fmt, args...) \ #define ohci_err(ohci, fmt, args...) \
dev_err ((ohci)->hcd.controller , fmt , ## args ) dev_err ((ohci)->hcd.self.controller , fmt , ## args )
#define ohci_info(ohci, fmt, args...) \ #define ohci_info(ohci, fmt, args...) \
dev_info ((ohci)->hcd.controller , fmt , ## args ) dev_info ((ohci)->hcd.self.controller , fmt , ## args )
#define ohci_warn(ohci, fmt, args...) \ #define ohci_warn(ohci, fmt, args...) \
dev_warn ((ohci)->hcd.controller , fmt , ## args ) dev_warn ((ohci)->hcd.self.controller , fmt , ## args )
#ifdef OHCI_VERBOSE_DEBUG #ifdef OHCI_VERBOSE_DEBUG
# define ohci_vdbg ohci_dbg # define ohci_vdbg ohci_dbg
......
...@@ -225,20 +225,22 @@ static int uhci_show_sc(int port, unsigned short status, char *buf, int len) ...@@ -225,20 +225,22 @@ static int uhci_show_sc(int port, unsigned short status, char *buf, int len)
char *out = buf; char *out = buf;
/* Try to make sure there's enough memory */ /* Try to make sure there's enough memory */
if (len < 80) if (len < 160)
return 0; return 0;
out += sprintf(out, " stat%d = %04x %s%s%s%s%s%s%s%s\n", out += sprintf(out, " stat%d = %04x %s%s%s%s%s%s%s%s%s%s\n",
port, port,
status, status,
(status & USBPORTSC_SUSP) ? "PortSuspend " : "", (status & USBPORTSC_SUSP) ? " Suspend" : "",
(status & USBPORTSC_PR) ? "PortReset " : "", (status & USBPORTSC_OCC) ? " OverCurrentChange" : "",
(status & USBPORTSC_LSDA) ? "LowSpeed " : "", (status & USBPORTSC_OC) ? " OverCurrent" : "",
(status & USBPORTSC_RD) ? "ResumeDetect " : "", (status & USBPORTSC_PR) ? " Reset" : "",
(status & USBPORTSC_PEC) ? "EnableChange " : "", (status & USBPORTSC_LSDA) ? " LowSpeed" : "",
(status & USBPORTSC_PE) ? "PortEnabled " : "", (status & USBPORTSC_RD) ? " ResumeDetect" : "",
(status & USBPORTSC_CSC) ? "ConnectChange " : "", (status & USBPORTSC_PEC) ? " EnableChange" : "",
(status & USBPORTSC_CCS) ? "PortConnected " : ""); (status & USBPORTSC_PE) ? " Enabled" : "",
(status & USBPORTSC_CSC) ? " ConnectChange" : "",
(status & USBPORTSC_CCS) ? " Connected" : "");
return out - buf; return out - buf;
} }
...@@ -321,8 +323,8 @@ static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp, char *bu ...@@ -321,8 +323,8 @@ static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp, char *bu
out += sprintf(out, "%s", (urbp->fsbr ? "FSBR " : "")); out += sprintf(out, "%s", (urbp->fsbr ? "FSBR " : ""));
out += sprintf(out, "%s", (urbp->fsbr_timeout ? "FSBR_TO " : "")); out += sprintf(out, "%s", (urbp->fsbr_timeout ? "FSBR_TO " : ""));
if (urbp->status != -EINPROGRESS) if (urbp->urb->status != -EINPROGRESS)
out += sprintf(out, "Status=%d ", urbp->status); out += sprintf(out, "Status=%d ", urbp->urb->status);
//out += sprintf(out, "Inserttime=%lx ",urbp->inserttime); //out += sprintf(out, "Inserttime=%lx ",urbp->inserttime);
//out += sprintf(out, "FSBRtime=%lx ",urbp->fsbrtime); //out += sprintf(out, "FSBRtime=%lx ",urbp->fsbrtime);
...@@ -402,7 +404,7 @@ static int uhci_show_lists(struct uhci_hcd *uhci, char *buf, int len) ...@@ -402,7 +404,7 @@ static int uhci_show_lists(struct uhci_hcd *uhci, char *buf, int len)
head = &uhci->complete_list; head = &uhci->complete_list;
tmp = head->next; tmp = head->next;
while (tmp != head) { while (tmp != head) {
struct urb_priv *urbp = list_entry(tmp, struct urb_priv, complete_list); struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list);
out += sprintf(out, " %d: ", ++count); out += sprintf(out, " %d: ", ++count);
out += uhci_show_urbp(uhci, urbp, out, len - (out - buf)); out += uhci_show_urbp(uhci, urbp, out, len - (out - buf));
...@@ -418,7 +420,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) ...@@ -418,7 +420,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
{ {
unsigned long flags; unsigned long flags;
char *out = buf; char *out = buf;
int i; int i, j;
struct uhci_qh *qh; struct uhci_qh *qh;
struct uhci_td *td; struct uhci_td *td;
struct list_head *tmp, *head; struct list_head *tmp, *head;
...@@ -473,10 +475,11 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) ...@@ -473,10 +475,11 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
continue; continue;
} }
j = (i < 7) ? 7 : i+1; /* Next skeleton */
if (list_empty(&qh->list)) { if (list_empty(&qh->list)) {
if (i < UHCI_NUM_SKELQH - 1) { if (i < UHCI_NUM_SKELQH - 1) {
if (qh->link != if (qh->link !=
(cpu_to_le32(uhci->skelqh[i + 1]->dma_handle) | UHCI_PTR_QH)) { (cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH)) {
show_qh_name(); show_qh_name();
out += sprintf(out, " skeleton QH not linked to next skeleton QH!\n"); out += sprintf(out, " skeleton QH not linked to next skeleton QH!\n");
} }
...@@ -500,7 +503,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) ...@@ -500,7 +503,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
if (i < UHCI_NUM_SKELQH - 1) { if (i < UHCI_NUM_SKELQH - 1) {
if (qh->link != if (qh->link !=
(cpu_to_le32(uhci->skelqh[i + 1]->dma_handle) | UHCI_PTR_QH)) (cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH))
out += sprintf(out, " last QH not linked to next skeleton!\n"); out += sprintf(out, " last QH not linked to next skeleton!\n");
} }
} }
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
* (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
* support from usb-ohci.c by Adam Richter, adam@yggdrasil.com). * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
* (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
* (C) Copyright 2004 Alan Stern, stern@rowland.harvard.edu
* *
* Intel documents this fairly well, and as far as I know there * Intel documents this fairly well, and as far as I know there
* are no royalties or anything like that, but even so there are * are no royalties or anything like that, but even so there are
...@@ -27,6 +28,11 @@ ...@@ -27,6 +28,11 @@
*/ */
#include <linux/config.h> #include <linux/config.h>
#ifdef CONFIG_USB_DEBUG
#define DEBUG
#else
#undef DEBUG
#endif
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -41,13 +47,12 @@ ...@@ -41,13 +47,12 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#ifdef CONFIG_USB_DEBUG #include <linux/pm.h>
#define DEBUG #include <linux/dmapool.h>
#else #include <linux/dma-mapping.h>
#undef DEBUG
#endif
#include <linux/usb.h> #include <linux/usb.h>
#include <asm/bitops.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/irq.h> #include <asm/irq.h>
...@@ -56,13 +61,13 @@ ...@@ -56,13 +61,13 @@
#include "../core/hcd.h" #include "../core/hcd.h"
#include "uhci-hcd.h" #include "uhci-hcd.h"
#include <linux/pm.h>
/* /*
* Version Information * Version Information
*/ */
#define DRIVER_VERSION "v2.1" #define DRIVER_VERSION "v2.2"
#define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber" #define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, \
Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, \
Alan Stern"
#define DRIVER_DESC "USB Universal Host Controller Interface driver" #define DRIVER_DESC "USB Universal Host Controller Interface driver"
/* /*
...@@ -80,7 +85,7 @@ static int debug = 0; ...@@ -80,7 +85,7 @@ static int debug = 0;
MODULE_PARM(debug, "i"); MODULE_PARM(debug, "i");
MODULE_PARM_DESC(debug, "Debug level"); MODULE_PARM_DESC(debug, "Debug level");
static char *errbuf; static char *errbuf;
#define ERRBUF_LEN (PAGE_SIZE * 8) #define ERRBUF_LEN (32 * 1024)
#include "uhci-hub.c" #include "uhci-hub.c"
#include "uhci-debug.c" #include "uhci-debug.c"
...@@ -121,21 +126,17 @@ static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci) ...@@ -121,21 +126,17 @@ static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci)
static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci) static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci)
{ {
unsigned long flags; spin_lock(&uhci->frame_list_lock);
spin_lock_irqsave(&uhci->frame_list_lock, flags);
uhci->term_td->status &= ~cpu_to_le32(TD_CTRL_IOC); uhci->term_td->status &= ~cpu_to_le32(TD_CTRL_IOC);
spin_unlock_irqrestore(&uhci->frame_list_lock, flags); spin_unlock(&uhci->frame_list_lock);
} }
static inline void uhci_add_complete(struct uhci_hcd *uhci, struct urb *urb) static inline void uhci_moveto_complete(struct uhci_hcd *uhci,
struct urb_priv *urbp)
{ {
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; spin_lock(&uhci->complete_list_lock);
unsigned long flags; list_move_tail(&urbp->urb_list, &uhci->complete_list);
spin_unlock(&uhci->complete_list_lock);
spin_lock_irqsave(&uhci->complete_list_lock, flags);
list_add_tail(&urbp->complete_list, &uhci->complete_list);
spin_unlock_irqrestore(&uhci->complete_list_lock, flags);
} }
static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci, struct usb_device *dev) static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci, struct usb_device *dev)
...@@ -143,7 +144,7 @@ static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci, struct usb_device *d ...@@ -143,7 +144,7 @@ static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci, struct usb_device *d
dma_addr_t dma_handle; dma_addr_t dma_handle;
struct uhci_td *td; struct uhci_td *td;
td = pci_pool_alloc(uhci->td_pool, GFP_ATOMIC, &dma_handle); td = dma_pool_alloc(uhci->td_pool, GFP_ATOMIC, &dma_handle);
if (!td) if (!td)
return NULL; return NULL;
...@@ -286,16 +287,16 @@ static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, u32 bread ...@@ -286,16 +287,16 @@ static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, u32 bread
static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td) static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td)
{ {
if (!list_empty(&td->list)) if (!list_empty(&td->list))
dbg("td %p is still in list!", td); dev_warn(uhci_dev(uhci), "td %p still in list!\n", td);
if (!list_empty(&td->remove_list)) if (!list_empty(&td->remove_list))
dbg("td %p still in remove_list!", td); dev_warn(uhci_dev(uhci), "td %p still in remove_list!\n", td);
if (!list_empty(&td->fl_list)) if (!list_empty(&td->fl_list))
dbg("td %p is still in fl_list!", td); dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td);
if (td->dev) if (td->dev)
usb_put_dev(td->dev); usb_put_dev(td->dev);
pci_pool_free(uhci->td_pool, td, td->dma_handle); dma_pool_free(uhci->td_pool, td, td->dma_handle);
} }
static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, struct usb_device *dev) static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, struct usb_device *dev)
...@@ -303,7 +304,7 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, struct usb_device *d ...@@ -303,7 +304,7 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, struct usb_device *d
dma_addr_t dma_handle; dma_addr_t dma_handle;
struct uhci_qh *qh; struct uhci_qh *qh;
qh = pci_pool_alloc(uhci->qh_pool, GFP_ATOMIC, &dma_handle); qh = dma_pool_alloc(uhci->qh_pool, GFP_ATOMIC, &dma_handle);
if (!qh) if (!qh)
return NULL; return NULL;
...@@ -326,14 +327,14 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, struct usb_device *d ...@@ -326,14 +327,14 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, struct usb_device *d
static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
{ {
if (!list_empty(&qh->list)) if (!list_empty(&qh->list))
dbg("qh %p list not empty!", qh); dev_warn(uhci_dev(uhci), "qh %p list not empty!\n", qh);
if (!list_empty(&qh->remove_list)) if (!list_empty(&qh->remove_list))
dbg("qh %p still in remove_list!", qh); dev_warn(uhci_dev(uhci), "qh %p still in remove_list!\n", qh);
if (qh->dev) if (qh->dev)
usb_put_dev(qh->dev); usb_put_dev(qh->dev);
pci_pool_free(uhci->qh_pool, qh, qh->dma_handle); dma_pool_free(uhci->qh_pool, qh, qh->dma_handle);
} }
/* /*
...@@ -658,10 +659,8 @@ static struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *u ...@@ -658,10 +659,8 @@ static struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *u
struct urb_priv *urbp; struct urb_priv *urbp;
urbp = kmem_cache_alloc(uhci_up_cachep, SLAB_ATOMIC); urbp = kmem_cache_alloc(uhci_up_cachep, SLAB_ATOMIC);
if (!urbp) { if (!urbp)
err("uhci_alloc_urb_priv: couldn't allocate memory for urb_priv\n");
return NULL; return NULL;
}
memset((void *)urbp, 0, sizeof(*urbp)); memset((void *)urbp, 0, sizeof(*urbp));
...@@ -671,7 +670,6 @@ static struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *u ...@@ -671,7 +670,6 @@ static struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *u
INIT_LIST_HEAD(&urbp->td_list); INIT_LIST_HEAD(&urbp->td_list);
INIT_LIST_HEAD(&urbp->queue_list); INIT_LIST_HEAD(&urbp->queue_list);
INIT_LIST_HEAD(&urbp->complete_list);
INIT_LIST_HEAD(&urbp->urb_list); INIT_LIST_HEAD(&urbp->urb_list);
list_add_tail(&urbp->urb_list, &uhci->urb_list); list_add_tail(&urbp->urb_list, &uhci->urb_list);
...@@ -720,10 +718,8 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) ...@@ -720,10 +718,8 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
return; return;
if (!list_empty(&urbp->urb_list)) if (!list_empty(&urbp->urb_list))
warn("uhci_destroy_urb_priv: urb %p still on uhci->urb_list or uhci->remove_list", urb); dev_warn(uhci_dev(uhci), "urb %p still on uhci->urb_list "
"or uhci->remove_list!\n", urb);
if (!list_empty(&urbp->complete_list))
warn("uhci_destroy_urb_priv: urb %p still on uhci->complete_list", urb);
spin_lock_irqsave(&uhci->td_remove_list_lock, flags); spin_lock_irqsave(&uhci->td_remove_list_lock, flags);
...@@ -913,7 +909,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur ...@@ -913,7 +909,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur
uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH); uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH);
/* Low speed transfers get a different queue, and won't hog the bus */ /* Low-speed transfers get a different queue, and won't hog the bus */
if (urb->dev->speed == USB_SPEED_LOW) if (urb->dev->speed == USB_SPEED_LOW)
skelqh = uhci->skel_ls_control_qh; skelqh = uhci->skel_ls_control_qh;
else { else {
...@@ -961,17 +957,15 @@ static int usb_control_retrigger_status(struct uhci_hcd *uhci, struct urb *urb) ...@@ -961,17 +957,15 @@ static int usb_control_retrigger_status(struct uhci_hcd *uhci, struct urb *urb)
} }
urbp->qh = uhci_alloc_qh(uhci, urb->dev); urbp->qh = uhci_alloc_qh(uhci, urb->dev);
if (!urbp->qh) { if (!urbp->qh)
err("unable to allocate new QH for control retrigger");
return -ENOMEM; return -ENOMEM;
}
urbp->qh->urbp = urbp; urbp->qh->urbp = urbp;
/* One TD, who cares about Breadth first? */ /* One TD, who cares about Breadth first? */
uhci_insert_tds_in_qh(urbp->qh, urb, UHCI_PTR_DEPTH); uhci_insert_tds_in_qh(urbp->qh, urb, UHCI_PTR_DEPTH);
/* Low speed transfers get a different queue */ /* Low-speed transfers get a different queue */
if (urb->dev->speed == USB_SPEED_LOW) if (urb->dev->speed == USB_SPEED_LOW)
uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urb); uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urb);
else else
...@@ -1073,7 +1067,8 @@ static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb) ...@@ -1073,7 +1067,8 @@ static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb)
err: err:
if ((debug == 1 && ret != -EPIPE) || debug > 1) { if ((debug == 1 && ret != -EPIPE) || debug > 1) {
/* Some debugging code */ /* Some debugging code */
dbg("uhci_result_control() failed with status %x", status); dev_dbg(uhci_dev(uhci), "%s: failed with status %x\n",
__FUNCTION__, status);
if (errbuf) { if (errbuf) {
/* Print the chain for debugging purposes */ /* Print the chain for debugging purposes */
...@@ -1238,7 +1233,8 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb) ...@@ -1238,7 +1233,8 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
#if 0 #if 0
if ((debug == 1 && ret != -EPIPE) || debug > 1) { if ((debug == 1 && ret != -EPIPE) || debug > 1) {
/* Some debugging code */ /* Some debugging code */
dbg("uhci_result_common() failed with status %x", status); dev_dbg(uhci_dev(uhci), "%s: failed with status %x\n",
__FUNCTION__, status);
if (errbuf) { if (errbuf) {
/* Print the chain for debugging purposes */ /* Print the chain for debugging purposes */
...@@ -1255,7 +1251,7 @@ static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, struc ...@@ -1255,7 +1251,7 @@ static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, struc
{ {
int ret; int ret;
/* Can't have low speed bulk transfers */ /* Can't have low-speed bulk transfers */
if (urb->dev->speed == USB_SPEED_LOW) if (urb->dev->speed == USB_SPEED_LOW)
return -EINVAL; return -EINVAL;
...@@ -1462,11 +1458,14 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, int mem_flags) ...@@ -1462,11 +1458,14 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, int mem_flags)
spin_lock_irqsave(&uhci->urb_list_lock, flags); spin_lock_irqsave(&uhci->urb_list_lock, flags);
if (urb->status != -EINPROGRESS) /* URB already unlinked! */
goto out;
eurb = uhci_find_urb_ep(uhci, urb); eurb = uhci_find_urb_ep(uhci, urb);
if (!uhci_alloc_urb_priv(uhci, urb)) { if (!uhci_alloc_urb_priv(uhci, urb)) {
spin_unlock_irqrestore(&uhci->urb_list_lock, flags); ret = -ENOMEM;
return -ENOMEM; goto out;
} }
switch (usb_pipetype(urb->pipe)) { switch (usb_pipetype(urb->pipe)) {
...@@ -1514,10 +1513,11 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, int mem_flags) ...@@ -1514,10 +1513,11 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, int mem_flags)
return ret; return ret;
} }
ret = 0;
out:
spin_unlock_irqrestore(&uhci->urb_list_lock, flags); spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
return ret;
return 0;
} }
/* /*
...@@ -1527,18 +1527,15 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, int mem_flags) ...@@ -1527,18 +1527,15 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, int mem_flags)
*/ */
static void uhci_transfer_result(struct uhci_hcd *uhci, struct urb *urb) static void uhci_transfer_result(struct uhci_hcd *uhci, struct urb *urb)
{ {
int ret = -EINVAL; int ret = -EINPROGRESS;
unsigned long flags;
struct urb_priv *urbp; struct urb_priv *urbp;
spin_lock_irqsave(&urb->lock, flags); spin_lock(&urb->lock);
urbp = (struct urb_priv *)urb->hcpriv; urbp = (struct urb_priv *)urb->hcpriv;
if (urb->status != -EINPROGRESS) { if (urb->status != -EINPROGRESS) /* URB already dequeued */
info("uhci_transfer_result: called for URB %p not in flight?", urb);
goto out; goto out;
}
switch (usb_pipetype(urb->pipe)) { switch (usb_pipetype(urb->pipe)) {
case PIPE_CONTROL: case PIPE_CONTROL:
...@@ -1555,10 +1552,9 @@ static void uhci_transfer_result(struct uhci_hcd *uhci, struct urb *urb) ...@@ -1555,10 +1552,9 @@ static void uhci_transfer_result(struct uhci_hcd *uhci, struct urb *urb)
break; break;
} }
urbp->status = ret;
if (ret == -EINPROGRESS) if (ret == -EINPROGRESS)
goto out; goto out;
urb->status = ret;
switch (usb_pipetype(urb->pipe)) { switch (usb_pipetype(urb->pipe)) {
case PIPE_CONTROL: case PIPE_CONTROL:
...@@ -1585,17 +1581,16 @@ static void uhci_transfer_result(struct uhci_hcd *uhci, struct urb *urb) ...@@ -1585,17 +1581,16 @@ static void uhci_transfer_result(struct uhci_hcd *uhci, struct urb *urb)
uhci_unlink_generic(uhci, urb); uhci_unlink_generic(uhci, urb);
break; break;
default: default:
info("uhci_transfer_result: unknown pipe type %d for urb %p\n", dev_info(uhci_dev(uhci), "%s: unknown pipe type %d "
usb_pipetype(urb->pipe), urb); "for urb %p\n",
__FUNCTION__, usb_pipetype(urb->pipe), urb);
} }
/* Remove it from uhci->urb_list */ /* Move it from uhci->urb_list to uhci->complete_list */
list_del_init(&urbp->urb_list); uhci_moveto_complete(uhci, urbp);
uhci_add_complete(uhci, urb);
out: out:
spin_unlock_irqrestore(&urb->lock, flags); spin_unlock(&urb->lock);
} }
/* /*
...@@ -1607,10 +1602,6 @@ static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb) ...@@ -1607,10 +1602,6 @@ static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb)
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
int prevactive = 1; int prevactive = 1;
/* We can get called when urbp allocation fails, so check */
if (!urbp)
return;
uhci_dec_fsbr(uhci, urb); /* Safe since it checks */ uhci_dec_fsbr(uhci, urb); /* Safe since it checks */
/* /*
...@@ -1660,13 +1651,6 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) ...@@ -1660,13 +1651,6 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
unsigned long flags; unsigned long flags;
struct urb_priv *urbp = urb->hcpriv; struct urb_priv *urbp = urb->hcpriv;
/* If this is an interrupt URB that is being killed in urb->complete, */
/* then just set its status and return */
if (!urbp) {
urb->status = -ECONNRESET;
return 0;
}
spin_lock_irqsave(&uhci->urb_list_lock, flags); spin_lock_irqsave(&uhci->urb_list_lock, flags);
list_del_init(&urbp->urb_list); list_del_init(&urbp->urb_list);
...@@ -1678,7 +1662,7 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) ...@@ -1678,7 +1662,7 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
/* If we're the first, set the next interrupt bit */ /* If we're the first, set the next interrupt bit */
if (list_empty(&uhci->urb_remove_list)) if (list_empty(&uhci->urb_remove_list))
uhci_set_next_interrupt(uhci); uhci_set_next_interrupt(uhci);
list_add(&urbp->urb_list, &uhci->urb_remove_list); list_add_tail(&urbp->urb_list, &uhci->urb_remove_list);
spin_unlock(&uhci->urb_remove_list_lock); spin_unlock(&uhci->urb_remove_list_lock);
spin_unlock_irqrestore(&uhci->urb_list_lock, flags); spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
...@@ -1805,9 +1789,8 @@ static int init_stall_timer(struct usb_hcd *hcd) ...@@ -1805,9 +1789,8 @@ static int init_stall_timer(struct usb_hcd *hcd)
static void uhci_free_pending_qhs(struct uhci_hcd *uhci) static void uhci_free_pending_qhs(struct uhci_hcd *uhci)
{ {
struct list_head *tmp, *head; struct list_head *tmp, *head;
unsigned long flags;
spin_lock_irqsave(&uhci->qh_remove_list_lock, flags); spin_lock(&uhci->qh_remove_list_lock);
head = &uhci->qh_remove_list; head = &uhci->qh_remove_list;
tmp = head->next; tmp = head->next;
while (tmp != head) { while (tmp != head) {
...@@ -1819,15 +1802,14 @@ static void uhci_free_pending_qhs(struct uhci_hcd *uhci) ...@@ -1819,15 +1802,14 @@ static void uhci_free_pending_qhs(struct uhci_hcd *uhci)
uhci_free_qh(uhci, qh); uhci_free_qh(uhci, qh);
} }
spin_unlock_irqrestore(&uhci->qh_remove_list_lock, flags); spin_unlock(&uhci->qh_remove_list_lock);
} }
static void uhci_free_pending_tds(struct uhci_hcd *uhci) static void uhci_free_pending_tds(struct uhci_hcd *uhci)
{ {
struct list_head *tmp, *head; struct list_head *tmp, *head;
unsigned long flags;
spin_lock_irqsave(&uhci->td_remove_list_lock, flags); spin_lock(&uhci->td_remove_list_lock);
head = &uhci->td_remove_list; head = &uhci->td_remove_list;
tmp = head->next; tmp = head->next;
while (tmp != head) { while (tmp != head) {
...@@ -1839,23 +1821,16 @@ static void uhci_free_pending_tds(struct uhci_hcd *uhci) ...@@ -1839,23 +1821,16 @@ static void uhci_free_pending_tds(struct uhci_hcd *uhci)
uhci_free_td(uhci, td); uhci_free_td(uhci, td);
} }
spin_unlock_irqrestore(&uhci->td_remove_list_lock, flags); spin_unlock(&uhci->td_remove_list_lock);
} }
static void uhci_finish_urb(struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs) static void uhci_finish_urb(struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs)
{ {
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
struct uhci_hcd *uhci = hcd_to_uhci(hcd); struct uhci_hcd *uhci = hcd_to_uhci(hcd);
int status;
unsigned long flags;
spin_lock_irqsave(&urb->lock, flags); spin_lock(&urb->lock);
status = urbp->status;
uhci_destroy_urb_priv(uhci, urb); uhci_destroy_urb_priv(uhci, urb);
spin_unlock(&urb->lock);
if (urb->status != -ENOENT && urb->status != -ECONNRESET)
urb->status = status;
spin_unlock_irqrestore(&urb->lock, flags);
usb_hcd_giveback_urb(hcd, urb, regs); usb_hcd_giveback_urb(hcd, urb, regs);
} }
...@@ -1864,48 +1839,40 @@ static void uhci_finish_completion(struct usb_hcd *hcd, struct pt_regs *regs) ...@@ -1864,48 +1839,40 @@ static void uhci_finish_completion(struct usb_hcd *hcd, struct pt_regs *regs)
{ {
struct uhci_hcd *uhci = hcd_to_uhci(hcd); struct uhci_hcd *uhci = hcd_to_uhci(hcd);
struct list_head *tmp, *head; struct list_head *tmp, *head;
unsigned long flags;
spin_lock_irqsave(&uhci->complete_list_lock, flags); spin_lock(&uhci->complete_list_lock);
head = &uhci->complete_list; head = &uhci->complete_list;
tmp = head->next; tmp = head->next;
while (tmp != head) { while (tmp != head) {
struct urb_priv *urbp = list_entry(tmp, struct urb_priv, complete_list); struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list);
struct urb *urb = urbp->urb; struct urb *urb = urbp->urb;
list_del_init(&urbp->complete_list); list_del_init(&urbp->urb_list);
spin_unlock_irqrestore(&uhci->complete_list_lock, flags); spin_unlock(&uhci->complete_list_lock);
uhci_finish_urb(hcd, urb, regs); uhci_finish_urb(hcd, urb, regs);
spin_lock_irqsave(&uhci->complete_list_lock, flags); spin_lock(&uhci->complete_list_lock);
head = &uhci->complete_list; head = &uhci->complete_list;
tmp = head->next; tmp = head->next;
} }
spin_unlock_irqrestore(&uhci->complete_list_lock, flags); spin_unlock(&uhci->complete_list_lock);
} }
static void uhci_remove_pending_qhs(struct uhci_hcd *uhci) static void uhci_remove_pending_urbps(struct uhci_hcd *uhci)
{ {
struct list_head *tmp, *head; struct list_head *tmp, *head;
unsigned long flags;
spin_lock_irqsave(&uhci->urb_remove_list_lock, flags); spin_lock(&uhci->urb_remove_list_lock);
head = &uhci->urb_remove_list; head = &uhci->urb_remove_list;
tmp = head->next; tmp = head->next;
while (tmp != head) { while (tmp != head) {
struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list); struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list);
struct urb *urb = urbp->urb;
tmp = tmp->next; tmp = tmp->next;
uhci_moveto_complete(uhci, urbp);
list_del_init(&urbp->urb_list);
urbp->status = urb->status = -ECONNRESET;
uhci_add_complete(uhci, urb);
} }
spin_unlock_irqrestore(&uhci->urb_remove_list_lock, flags); spin_unlock(&uhci->urb_remove_list_lock);
} }
static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
...@@ -1917,20 +1884,24 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) ...@@ -1917,20 +1884,24 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
/* /*
* Read the interrupt status, and write it back to clear the * Read the interrupt status, and write it back to clear the
* interrupt cause * interrupt cause. Contrary to the UHCI specification, the
* "HC Halted" status bit is persistent: it is RO, not R/WC.
*/ */
status = inw(io_addr + USBSTS); status = inw(io_addr + USBSTS);
if (!status) /* shared interrupt, not mine */ if (!(status & ~USBSTS_HCH)) /* shared interrupt, not mine */
return IRQ_NONE; return IRQ_NONE;
outw(status, io_addr + USBSTS); /* Clear it */ outw(status, io_addr + USBSTS); /* Clear it */
if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) { if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) {
if (status & USBSTS_HSE) if (status & USBSTS_HSE)
err("%x: host system error, PCI problems?", io_addr); dev_err(uhci_dev(uhci), "host system error, "
"PCI problems?\n");
if (status & USBSTS_HCPE) if (status & USBSTS_HCPE)
err("%x: host controller process error. something bad happened", io_addr); dev_err(uhci_dev(uhci), "host controller process "
"error, something bad happened!\n");
if ((status & USBSTS_HCH) && uhci->state > 0) { if ((status & USBSTS_HCH) && uhci->state > 0) {
err("%x: host controller halted. very bad", io_addr); dev_err(uhci_dev(uhci), "host controller halted, "
"very bad!\n");
/* FIXME: Reset the controller, fix the offending TD */ /* FIXME: Reset the controller, fix the offending TD */
} }
} }
...@@ -1942,7 +1913,7 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) ...@@ -1942,7 +1913,7 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
uhci_free_pending_tds(uhci); uhci_free_pending_tds(uhci);
uhci_remove_pending_qhs(uhci); uhci_remove_pending_urbps(uhci);
uhci_clear_next_interrupt(uhci); uhci_clear_next_interrupt(uhci);
...@@ -1986,7 +1957,7 @@ static void suspend_hc(struct uhci_hcd *uhci) ...@@ -1986,7 +1957,7 @@ static void suspend_hc(struct uhci_hcd *uhci)
{ {
unsigned int io_addr = uhci->io_addr; unsigned int io_addr = uhci->io_addr;
dbg("%x: suspend_hc", io_addr); dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);
uhci->state = UHCI_SUSPENDED; uhci->state = UHCI_SUSPENDED;
uhci->resume_detect = 0; uhci->resume_detect = 0;
outw(USBCMD_EGSM, io_addr + USBCMD); outw(USBCMD_EGSM, io_addr + USBCMD);
...@@ -1998,7 +1969,7 @@ static void wakeup_hc(struct uhci_hcd *uhci) ...@@ -1998,7 +1969,7 @@ static void wakeup_hc(struct uhci_hcd *uhci)
switch (uhci->state) { switch (uhci->state) {
case UHCI_SUSPENDED: /* Start the resume */ case UHCI_SUSPENDED: /* Start the resume */
dbg("%x: wakeup_hc", io_addr); dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);
/* Global resume for >= 20ms */ /* Global resume for >= 20ms */
outw(USBCMD_FGR | USBCMD_EGSM, io_addr + USBCMD); outw(USBCMD_FGR | USBCMD_EGSM, io_addr + USBCMD);
...@@ -2049,7 +2020,7 @@ static int suspend_allowed(struct uhci_hcd *uhci) ...@@ -2049,7 +2020,7 @@ static int suspend_allowed(struct uhci_hcd *uhci)
unsigned int io_addr = uhci->io_addr; unsigned int io_addr = uhci->io_addr;
int i; int i;
if (!uhci->hcd.pdev || uhci->hcd.pdev->vendor != PCI_VENDOR_ID_INTEL) if (to_pci_dev(uhci_dev(uhci))->vendor != PCI_VENDOR_ID_INTEL)
return 1; return 1;
/* Some of Intel's USB controllers have a bug that causes false /* Some of Intel's USB controllers have a bug that causes false
...@@ -2123,7 +2094,7 @@ static void start_hc(struct uhci_hcd *uhci) ...@@ -2123,7 +2094,7 @@ static void start_hc(struct uhci_hcd *uhci)
outw(USBCMD_HCRESET, io_addr + USBCMD); outw(USBCMD_HCRESET, io_addr + USBCMD);
while (inw(io_addr + USBCMD) & USBCMD_HCRESET) { while (inw(io_addr + USBCMD) & USBCMD_HCRESET) {
if (!--timeout) { if (!--timeout) {
printk(KERN_ERR "uhci: USBCMD_HCRESET timed out!\n"); dev_err(uhci_dev(uhci), "USBCMD_HCRESET timed out!\n");
break; break;
} }
} }
...@@ -2163,17 +2134,18 @@ static void release_uhci(struct uhci_hcd *uhci) ...@@ -2163,17 +2134,18 @@ static void release_uhci(struct uhci_hcd *uhci)
} }
if (uhci->qh_pool) { if (uhci->qh_pool) {
pci_pool_destroy(uhci->qh_pool); dma_pool_destroy(uhci->qh_pool);
uhci->qh_pool = NULL; uhci->qh_pool = NULL;
} }
if (uhci->td_pool) { if (uhci->td_pool) {
pci_pool_destroy(uhci->td_pool); dma_pool_destroy(uhci->td_pool);
uhci->td_pool = NULL; uhci->td_pool = NULL;
} }
if (uhci->fl) { if (uhci->fl) {
pci_free_consistent(uhci->hcd.pdev, sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle); dma_free_coherent(uhci_dev(uhci), sizeof(*uhci->fl),
uhci->fl, uhci->fl->dma_handle);
uhci->fl = NULL; uhci->fl = NULL;
} }
...@@ -2198,7 +2170,8 @@ static int uhci_reset(struct usb_hcd *hcd) ...@@ -2198,7 +2170,8 @@ static int uhci_reset(struct usb_hcd *hcd)
* interrupts from any previous setup. * interrupts from any previous setup.
*/ */
reset_hc(uhci); reset_hc(uhci);
pci_write_config_word(hcd->pdev, USBLEGSUP, USBLEGSUP_DEFAULT); pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
USBLEGSUP_DEFAULT);
return 0; return 0;
} }
...@@ -2213,10 +2186,10 @@ static int uhci_reset(struct usb_hcd *hcd) ...@@ -2213,10 +2186,10 @@ static int uhci_reset(struct usb_hcd *hcd)
* of the queues. We don't do that here, because * of the queues. We don't do that here, because
* we'll create the actual TD entries on demand. * we'll create the actual TD entries on demand.
* - The first queue is the interrupt queue. * - The first queue is the interrupt queue.
* - The second queue is the control queue, split into low and high speed * - The second queue is the control queue, split into low- and full-speed
* - The third queue is bulk queue. * - The third queue is bulk queue.
* - The fourth queue is the bandwidth reclamation queue, which loops back * - The fourth queue is the bandwidth reclamation queue, which loops back
* to the high speed control queue. * to the full-speed control queue.
*/ */
static int uhci_start(struct usb_hcd *hcd) static int uhci_start(struct usb_hcd *hcd)
{ {
...@@ -2230,12 +2203,12 @@ static int uhci_start(struct usb_hcd *hcd) ...@@ -2230,12 +2203,12 @@ static int uhci_start(struct usb_hcd *hcd)
struct proc_dir_entry *ent; struct proc_dir_entry *ent;
#endif #endif
io_size = pci_resource_len(hcd->pdev, hcd->region); io_size = pci_resource_len(to_pci_dev(uhci_dev(uhci)), hcd->region);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
ent = create_proc_entry(hcd->self.bus_name, S_IFREG|S_IRUGO|S_IWUSR, uhci_proc_root); ent = create_proc_entry(hcd->self.bus_name, S_IFREG|S_IRUGO|S_IWUSR, uhci_proc_root);
if (!ent) { if (!ent) {
err("couldn't create uhci proc entry"); dev_err(uhci_dev(uhci), "couldn't create uhci proc entry\n");
retval = -ENOMEM; retval = -ENOMEM;
goto err_create_proc_entry; goto err_create_proc_entry;
} }
...@@ -2266,9 +2239,11 @@ static int uhci_start(struct usb_hcd *hcd) ...@@ -2266,9 +2239,11 @@ static int uhci_start(struct usb_hcd *hcd)
spin_lock_init(&uhci->frame_list_lock); spin_lock_init(&uhci->frame_list_lock);
uhci->fl = pci_alloc_consistent(hcd->pdev, sizeof(*uhci->fl), &dma_handle); uhci->fl = dma_alloc_coherent(uhci_dev(uhci), sizeof(*uhci->fl),
&dma_handle, 0);
if (!uhci->fl) { if (!uhci->fl) {
err("unable to allocate consistent memory for frame list"); dev_err(uhci_dev(uhci), "unable to allocate "
"consistent memory for frame list\n");
goto err_alloc_fl; goto err_alloc_fl;
} }
...@@ -2276,17 +2251,17 @@ static int uhci_start(struct usb_hcd *hcd) ...@@ -2276,17 +2251,17 @@ static int uhci_start(struct usb_hcd *hcd)
uhci->fl->dma_handle = dma_handle; uhci->fl->dma_handle = dma_handle;
uhci->td_pool = pci_pool_create("uhci_td", hcd->pdev, uhci->td_pool = dma_pool_create("uhci_td", uhci_dev(uhci),
sizeof(struct uhci_td), 16, 0); sizeof(struct uhci_td), 16, 0);
if (!uhci->td_pool) { if (!uhci->td_pool) {
err("unable to create td pci_pool"); dev_err(uhci_dev(uhci), "unable to create td dma_pool\n");
goto err_create_td_pool; goto err_create_td_pool;
} }
uhci->qh_pool = pci_pool_create("uhci_qh", hcd->pdev, uhci->qh_pool = dma_pool_create("uhci_qh", uhci_dev(uhci),
sizeof(struct uhci_qh), 16, 0); sizeof(struct uhci_qh), 16, 0);
if (!uhci->qh_pool) { if (!uhci->qh_pool) {
err("unable to create qh pci_pool"); dev_err(uhci_dev(uhci), "unable to create qh dma_pool\n");
goto err_create_qh_pool; goto err_create_qh_pool;
} }
...@@ -2304,12 +2279,13 @@ static int uhci_start(struct usb_hcd *hcd) ...@@ -2304,12 +2279,13 @@ static int uhci_start(struct usb_hcd *hcd)
break; break;
} }
if (debug) if (debug)
info("detected %d ports", port); dev_info(uhci_dev(uhci), "detected %d ports\n", port);
/* This is experimental so anything less than 2 or greater than 8 is */ /* This is experimental so anything less than 2 or greater than 8 is */
/* something weird and we'll ignore it */ /* something weird and we'll ignore it */
if (port < 2 || port > 8) { if (port < 2 || port > UHCI_RH_MAXCHILD) {
info("port count misdetected? forcing to 2 ports"); dev_info(uhci_dev(uhci), "port count misdetected? "
"forcing to 2 ports\n");
port = 2; port = 2;
} }
...@@ -2317,35 +2293,36 @@ static int uhci_start(struct usb_hcd *hcd) ...@@ -2317,35 +2293,36 @@ static int uhci_start(struct usb_hcd *hcd)
hcd->self.root_hub = udev = usb_alloc_dev(NULL, &hcd->self, 0); hcd->self.root_hub = udev = usb_alloc_dev(NULL, &hcd->self, 0);
if (!udev) { if (!udev) {
err("unable to allocate root hub"); dev_err(uhci_dev(uhci), "unable to allocate root hub\n");
goto err_alloc_root_hub; goto err_alloc_root_hub;
} }
uhci->term_td = uhci_alloc_td(uhci, udev); uhci->term_td = uhci_alloc_td(uhci, udev);
if (!uhci->term_td) { if (!uhci->term_td) {
err("unable to allocate terminating TD"); dev_err(uhci_dev(uhci), "unable to allocate terminating TD\n");
goto err_alloc_term_td; goto err_alloc_term_td;
} }
for (i = 0; i < UHCI_NUM_SKELQH; i++) { for (i = 0; i < UHCI_NUM_SKELQH; i++) {
uhci->skelqh[i] = uhci_alloc_qh(uhci, udev); uhci->skelqh[i] = uhci_alloc_qh(uhci, udev);
if (!uhci->skelqh[i]) { if (!uhci->skelqh[i]) {
err("unable to allocate QH %d", i); dev_err(uhci_dev(uhci), "unable to allocate QH\n");
goto err_alloc_skelqh; goto err_alloc_skelqh;
} }
} }
/* /*
* 8 Interrupt queues; link int2 to int1, int4 to int2, etc * 8 Interrupt queues; link all higher int queues to int1,
* then link int1 to control and control to bulk * then link int1 to control and control to bulk
*/ */
uhci->skel_int128_qh->link = cpu_to_le32(uhci->skel_int64_qh->dma_handle) | UHCI_PTR_QH; uhci->skel_int128_qh->link =
uhci->skel_int64_qh->link = cpu_to_le32(uhci->skel_int32_qh->dma_handle) | UHCI_PTR_QH; uhci->skel_int64_qh->link =
uhci->skel_int32_qh->link = cpu_to_le32(uhci->skel_int16_qh->dma_handle) | UHCI_PTR_QH; uhci->skel_int32_qh->link =
uhci->skel_int16_qh->link = cpu_to_le32(uhci->skel_int8_qh->dma_handle) | UHCI_PTR_QH; uhci->skel_int16_qh->link =
uhci->skel_int8_qh->link = cpu_to_le32(uhci->skel_int4_qh->dma_handle) | UHCI_PTR_QH; uhci->skel_int8_qh->link =
uhci->skel_int4_qh->link = cpu_to_le32(uhci->skel_int2_qh->dma_handle) | UHCI_PTR_QH; uhci->skel_int4_qh->link =
uhci->skel_int2_qh->link = cpu_to_le32(uhci->skel_int1_qh->dma_handle) | UHCI_PTR_QH; uhci->skel_int2_qh->link =
cpu_to_le32(uhci->skel_int1_qh->dma_handle) | UHCI_PTR_QH;
uhci->skel_int1_qh->link = cpu_to_le32(uhci->skel_ls_control_qh->dma_handle) | UHCI_PTR_QH; uhci->skel_int1_qh->link = cpu_to_le32(uhci->skel_ls_control_qh->dma_handle) | UHCI_PTR_QH;
uhci->skel_ls_control_qh->link = cpu_to_le32(uhci->skel_hs_control_qh->dma_handle) | UHCI_PTR_QH; uhci->skel_ls_control_qh->link = cpu_to_le32(uhci->skel_hs_control_qh->dma_handle) | UHCI_PTR_QH;
...@@ -2361,39 +2338,33 @@ static int uhci_start(struct usb_hcd *hcd) ...@@ -2361,39 +2338,33 @@ static int uhci_start(struct usb_hcd *hcd)
uhci->skel_term_qh->element = cpu_to_le32(uhci->term_td->dma_handle); uhci->skel_term_qh->element = cpu_to_le32(uhci->term_td->dma_handle);
/* /*
* Fill the frame list: make all entries point to * Fill the frame list: make all entries point to the proper
* the proper interrupt queue. * interrupt queue.
* *
* This is probably silly, but it's a simple way to * The interrupt queues will be interleaved as evenly as possible.
* scatter the interrupt queues in a way that gives * There's not much to be done about period-1 interrupts; they have
* us a reasonable dynamic range for irq latencies. * to occur in every frame. But we can schedule period-2 interrupts
* in odd-numbered frames, period-4 interrupts in frames congruent
* to 2 (mod 4), and so on. This way each frame only has two
* interrupt QHs, which will help spread out bandwidth utilization.
*/ */
for (i = 0; i < UHCI_NUMFRAMES; i++) { for (i = 0; i < UHCI_NUMFRAMES; i++) {
int irq = 0; int irq;
if (i & 1) { /*
irq++; * ffs (Find First bit Set) does exactly what we need:
if (i & 2) { * 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[6],
irq++; * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[5], etc.
if (i & 4) { * ffs > 6 => not on any high-period queue, so use
irq++; * skel_int1_qh = skelqh[7].
if (i & 8) { * Add UHCI_NUMFRAMES to insure at least one bit is set.
irq++; */
if (i & 16) { irq = 6 - (int) __ffs(i + UHCI_NUMFRAMES);
irq++; if (irq < 0)
if (i & 32) { irq = 7;
irq++;
if (i & 64)
irq++;
}
}
}
}
}
}
/* Only place we don't use the frame list routines */ /* Only place we don't use the frame list routines */
uhci->fl->frame[i] = cpu_to_le32(uhci->skelqh[7 - irq]->dma_handle); uhci->fl->frame[i] = cpu_to_le32(uhci->skelqh[irq]->dma_handle);
} }
start_hc(uhci); start_hc(uhci);
...@@ -2402,8 +2373,8 @@ static int uhci_start(struct usb_hcd *hcd) ...@@ -2402,8 +2373,8 @@ static int uhci_start(struct usb_hcd *hcd)
udev->speed = USB_SPEED_FULL; udev->speed = USB_SPEED_FULL;
if (usb_register_root_hub(udev, &hcd->pdev->dev) != 0) { if (usb_register_root_hub(udev, uhci_dev(uhci)) != 0) {
err("unable to start root hub"); dev_err(uhci_dev(uhci), "unable to start root hub\n");
retval = -ENOMEM; retval = -ENOMEM;
goto err_start_root_hub; goto err_start_root_hub;
} }
...@@ -2433,15 +2404,16 @@ static int uhci_start(struct usb_hcd *hcd) ...@@ -2433,15 +2404,16 @@ static int uhci_start(struct usb_hcd *hcd)
hcd->self.root_hub = NULL; hcd->self.root_hub = NULL;
err_alloc_root_hub: err_alloc_root_hub:
pci_pool_destroy(uhci->qh_pool); dma_pool_destroy(uhci->qh_pool);
uhci->qh_pool = NULL; uhci->qh_pool = NULL;
err_create_qh_pool: err_create_qh_pool:
pci_pool_destroy(uhci->td_pool); dma_pool_destroy(uhci->td_pool);
uhci->td_pool = NULL; uhci->td_pool = NULL;
err_create_td_pool: err_create_td_pool:
pci_free_consistent(hcd->pdev, sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle); dma_free_coherent(uhci_dev(uhci), sizeof(*uhci->fl),
uhci->fl, uhci->fl->dma_handle);
uhci->fl = NULL; uhci->fl = NULL;
err_alloc_fl: err_alloc_fl:
...@@ -2458,6 +2430,7 @@ static int uhci_start(struct usb_hcd *hcd) ...@@ -2458,6 +2430,7 @@ static int uhci_start(struct usb_hcd *hcd)
static void uhci_stop(struct usb_hcd *hcd) static void uhci_stop(struct usb_hcd *hcd)
{ {
struct uhci_hcd *uhci = hcd_to_uhci(hcd); struct uhci_hcd *uhci = hcd_to_uhci(hcd);
unsigned long flags;
del_timer_sync(&uhci->stall_timer); del_timer_sync(&uhci->stall_timer);
...@@ -2465,15 +2438,17 @@ static void uhci_stop(struct usb_hcd *hcd) ...@@ -2465,15 +2438,17 @@ static void uhci_stop(struct usb_hcd *hcd)
* At this point, we're guaranteed that no new connects can be made * At this point, we're guaranteed that no new connects can be made
* to this bus since there are no more parents * to this bus since there are no more parents
*/ */
local_irq_save(flags);
uhci_free_pending_qhs(uhci); uhci_free_pending_qhs(uhci);
uhci_free_pending_tds(uhci); uhci_free_pending_tds(uhci);
uhci_remove_pending_qhs(uhci); uhci_remove_pending_urbps(uhci);
reset_hc(uhci); reset_hc(uhci);
uhci_free_pending_qhs(uhci); uhci_free_pending_qhs(uhci);
uhci_free_pending_tds(uhci); uhci_free_pending_tds(uhci);
local_irq_restore(flags);
release_uhci(uhci); release_uhci(uhci);
} }
...@@ -2494,7 +2469,7 @@ static int uhci_resume(struct usb_hcd *hcd) ...@@ -2494,7 +2469,7 @@ static int uhci_resume(struct usb_hcd *hcd)
{ {
struct uhci_hcd *uhci = hcd_to_uhci(hcd); struct uhci_hcd *uhci = hcd_to_uhci(hcd);
pci_set_master(uhci->hcd.pdev); pci_set_master(to_pci_dev(uhci_dev(uhci)));
if (uhci->state == UHCI_SUSPENDED) if (uhci->state == UHCI_SUSPENDED)
uhci->resume_detect = 1; uhci->resume_detect = 1;
...@@ -2586,7 +2561,7 @@ static int __init uhci_hcd_init(void) ...@@ -2586,7 +2561,7 @@ static int __init uhci_hcd_init(void)
{ {
int retval = -ENOMEM; int retval = -ENOMEM;
info(DRIVER_DESC " " DRIVER_VERSION); printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION "\n");
if (usb_disabled()) if (usb_disabled())
return -ENODEV; return -ENODEV;
...@@ -2616,7 +2591,7 @@ static int __init uhci_hcd_init(void) ...@@ -2616,7 +2591,7 @@ static int __init uhci_hcd_init(void)
init_failed: init_failed:
if (kmem_cache_destroy(uhci_up_cachep)) if (kmem_cache_destroy(uhci_up_cachep))
printk(KERN_INFO "uhci: not all urb_priv's were freed\n"); warn("not all urb_priv's were freed!");
up_failed: up_failed:
...@@ -2638,7 +2613,7 @@ static void __exit uhci_hcd_cleanup(void) ...@@ -2638,7 +2613,7 @@ static void __exit uhci_hcd_cleanup(void)
pci_unregister_driver(&uhci_pci_driver); pci_unregister_driver(&uhci_pci_driver);
if (kmem_cache_destroy(uhci_up_cachep)) if (kmem_cache_destroy(uhci_up_cachep))
printk(KERN_INFO "uhci: not all urb_priv's were freed\n"); warn("not all urb_priv's were freed!");
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
remove_proc_entry("driver/uhci", 0); remove_proc_entry("driver/uhci", 0);
...@@ -2654,4 +2629,3 @@ module_exit(uhci_hcd_cleanup); ...@@ -2654,4 +2629,3 @@ module_exit(uhci_hcd_cleanup);
MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC); MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -49,12 +49,19 @@ ...@@ -49,12 +49,19 @@
#define USBPORTSC_CSC 0x0002 /* Connect Status Change */ #define USBPORTSC_CSC 0x0002 /* Connect Status Change */
#define USBPORTSC_PE 0x0004 /* Port Enable */ #define USBPORTSC_PE 0x0004 /* Port Enable */
#define USBPORTSC_PEC 0x0008 /* Port Enable Change */ #define USBPORTSC_PEC 0x0008 /* Port Enable Change */
#define USBPORTSC_LS 0x0030 /* Line Status */ #define USBPORTSC_DPLUS 0x0010 /* D+ high (line status) */
#define USBPORTSC_DMINUS 0x0020 /* D- high (line status) */
#define USBPORTSC_RD 0x0040 /* Resume Detect */ #define USBPORTSC_RD 0x0040 /* Resume Detect */
#define USBPORTSC_RES1 0x0080 /* reserved, always 1 */
#define USBPORTSC_LSDA 0x0100 /* Low Speed Device Attached */ #define USBPORTSC_LSDA 0x0100 /* Low Speed Device Attached */
#define USBPORTSC_PR 0x0200 /* Port Reset */ #define USBPORTSC_PR 0x0200 /* Port Reset */
/* OC and OCC from Intel 430TX and later (not UHCI 1.1d spec) */
#define USBPORTSC_OC 0x0400 /* Over Current condition */ #define USBPORTSC_OC 0x0400 /* Over Current condition */
#define USBPORTSC_OCC 0x0800 /* Over Current Change R/WC */
#define USBPORTSC_SUSP 0x1000 /* Suspend */ #define USBPORTSC_SUSP 0x1000 /* Suspend */
#define USBPORTSC_RES2 0x2000 /* reserved, write zeroes */
#define USBPORTSC_RES3 0x4000 /* reserved, write zeroes */
#define USBPORTSC_RES4 0x8000 /* reserved, write zeroes */
/* Legacy support register */ /* Legacy support register */
#define USBLEGSUP 0xc0 #define USBLEGSUP 0xc0
...@@ -200,8 +207,8 @@ struct uhci_td { ...@@ -200,8 +207,8 @@ struct uhci_td {
* The UHCI driver places Interrupt, Control and Bulk into QH's both * The UHCI driver places Interrupt, Control and Bulk into QH's both
* to group together TD's for one transfer, and also to faciliate queuing * to group together TD's for one transfer, and also to faciliate queuing
* of URB's. To make it easy to insert entries into the schedule, we have * of URB's. To make it easy to insert entries into the schedule, we have
* a skeleton of QH's for each predefined Interrupt latency, low speed * a skeleton of QH's for each predefined Interrupt latency, low-speed
* control, high speed control and terminating QH (see explanation for * control, full-speed control and terminating QH (see explanation for
* the terminating QH below). * the terminating QH below).
* *
* When we want to add a new QH, we add it to the end of the list for the * When we want to add a new QH, we add it to the end of the list for the
...@@ -216,9 +223,9 @@ struct uhci_td { ...@@ -216,9 +223,9 @@ struct uhci_td {
* skel int32 QH * skel int32 QH
* ... * ...
* skel int1 QH * skel int1 QH
* skel low speed control QH * skel low-speed control QH
* dev 5 control QH * dev 5 control QH
* skel high speed control QH * skel full-speed control QH
* skel bulk QH * skel bulk QH
* dev 1 bulk QH * dev 1 bulk QH
* dev 2 bulk QH * dev 2 bulk QH
...@@ -227,7 +234,7 @@ struct uhci_td { ...@@ -227,7 +234,7 @@ struct uhci_td {
* The terminating QH is used for 2 reasons: * The terminating QH is used for 2 reasons:
* - To place a terminating TD which is used to workaround a PIIX bug * - To place a terminating TD which is used to workaround a PIIX bug
* (see Intel errata for explanation) * (see Intel errata for explanation)
* - To loop back to the high speed control queue for full speed bandwidth * - To loop back to the full-speed control queue for full-speed bandwidth
* reclamation * reclamation
* *
* Isochronous transfers are stored before the start of the skeleton * Isochronous transfers are stored before the start of the skeleton
...@@ -308,6 +315,7 @@ enum uhci_state { ...@@ -308,6 +315,7 @@ enum uhci_state {
}; };
#define hcd_to_uhci(hcd_ptr) container_of(hcd_ptr, struct uhci_hcd, hcd) #define hcd_to_uhci(hcd_ptr) container_of(hcd_ptr, struct uhci_hcd, hcd)
#define uhci_dev(u) ((u)->hcd.self.controller)
/* /*
* This describes the full uhci information. * This describes the full uhci information.
...@@ -326,8 +334,8 @@ struct uhci_hcd { ...@@ -326,8 +334,8 @@ struct uhci_hcd {
/* Grabbed from PCI */ /* Grabbed from PCI */
unsigned long io_addr; unsigned long io_addr;
struct pci_pool *qh_pool; struct dma_pool *qh_pool;
struct pci_pool *td_pool; struct dma_pool *td_pool;
struct usb_bus *bus; struct usb_bus *bus;
...@@ -336,7 +344,7 @@ struct uhci_hcd { ...@@ -336,7 +344,7 @@ struct uhci_hcd {
spinlock_t frame_list_lock; spinlock_t frame_list_lock;
struct uhci_frame_list *fl; /* P: uhci->frame_list_lock */ struct uhci_frame_list *fl; /* P: uhci->frame_list_lock */
int fsbr; /* Full speed bandwidth reclamation */ int fsbr; /* Full-speed bandwidth reclamation */
unsigned long fsbrtimeout; /* FSBR delay */ unsigned long fsbrtimeout; /* FSBR delay */
enum uhci_state state; /* FIXME: needs a spinlock */ enum uhci_state state; /* FIXME: needs a spinlock */
...@@ -383,13 +391,10 @@ struct urb_priv { ...@@ -383,13 +391,10 @@ struct urb_priv {
/* a control transfer, retrigger */ /* a control transfer, retrigger */
/* the status phase */ /* the status phase */
int status; /* Final status */
unsigned long inserttime; /* In jiffies */ unsigned long inserttime; /* In jiffies */
unsigned long fsbrtime; /* In jiffies */ unsigned long fsbrtime; /* In jiffies */
struct list_head queue_list; /* P: uhci->frame_list_lock */ struct list_head queue_list; /* P: uhci->frame_list_lock */
struct list_head complete_list; /* P: uhci->complete_list_lock */
}; };
/* /*
...@@ -418,4 +423,3 @@ struct urb_priv { ...@@ -418,4 +423,3 @@ struct urb_priv {
*/ */
#endif #endif
/* /*
* Universal Host Controller Interface driver for USB. * Universal Host Controller Interface driver for USB.
* *
* Maintainer: Johannes Erdfelt <johannes@erdfelt.com> * Maintainer: Alan Stern <stern@rowland.harvard.edu>
* *
* (C) Copyright 1999 Linus Torvalds * (C) Copyright 1999 Linus Torvalds
* (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
* (C) Copyright 1999 Georg Acher, acher@in.tum.de * (C) Copyright 1999 Georg Acher, acher@in.tum.de
* (C) Copyright 1999 Deti Fliegl, deti@fliegl.de * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
* (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
* (C) Copyright 2004 Alan Stern, stern@rowland.harvard.edu
*/ */
static __u8 root_hub_hub_des[] = static __u8 root_hub_hub_des[] =
...@@ -16,40 +17,50 @@ static __u8 root_hub_hub_des[] = ...@@ -16,40 +17,50 @@ static __u8 root_hub_hub_des[] =
0x09, /* __u8 bLength; */ 0x09, /* __u8 bLength; */
0x29, /* __u8 bDescriptorType; Hub-descriptor */ 0x29, /* __u8 bDescriptorType; Hub-descriptor */
0x02, /* __u8 bNbrPorts; */ 0x02, /* __u8 bNbrPorts; */
0x00, /* __u16 wHubCharacteristics; */ 0x0a, /* __u16 wHubCharacteristics; */
0x00, 0x00, /* (per-port OC, no power switching) */
0x01, /* __u8 bPwrOn2pwrGood; 2ms */ 0x01, /* __u8 bPwrOn2pwrGood; 2ms */
0x00, /* __u8 bHubContrCurrent; 0 mA */ 0x00, /* __u8 bHubContrCurrent; 0 mA */
0x00, /* __u8 DeviceRemovable; *** 7 Ports max *** */ 0x00, /* __u8 DeviceRemovable; *** 7 Ports max *** */
0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */ 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */
}; };
#define UHCI_RH_MAXCHILD 7
/* must write as zeroes */
#define WZ_BITS (USBPORTSC_RES2 | USBPORTSC_RES3 | USBPORTSC_RES4)
/* status change bits: nonzero writes will clear */
#define RWC_BITS (USBPORTSC_OCC | USBPORTSC_PEC | USBPORTSC_CSC)
static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf) static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
{ {
struct uhci_hcd *uhci = hcd_to_uhci(hcd); struct uhci_hcd *uhci = hcd_to_uhci(hcd);
unsigned int io_addr = uhci->io_addr; unsigned int io_addr = uhci->io_addr;
int i, len = 1; int i;
*buf = 0; *buf = 0;
for (i = 0; i < uhci->rh_numports; i++) { for (i = 0; i < uhci->rh_numports; i++) {
*buf |= ((inw(io_addr + USBPORTSC1 + i * 2) & 0xa) > 0 ? (1 << (i + 1)) : 0); if (inw(io_addr + USBPORTSC1 + i * 2) & RWC_BITS)
len = (i + 1) / 8 + 1; *buf |= (1 << (i + 1));
} }
return !!*buf; return !!*buf;
} }
#define OK(x) len = (x); break #define OK(x) len = (x); break
#define CLR_RH_PORTSTAT(x) \ #define CLR_RH_PORTSTAT(x) \
status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \ status = inw(port_addr); \
status = (status & 0xfff5) & ~(x); \ status &= ~(RWC_BITS|WZ_BITS); \
outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1)) status &= ~(x); \
status |= RWC_BITS & (x); \
outw(status, port_addr)
#define SET_RH_PORTSTAT(x) \ #define SET_RH_PORTSTAT(x) \
status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \ status = inw(port_addr); \
status = (status & 0xfff5) | (x); \ status |= (x); \
outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1)) status &= ~(RWC_BITS|WZ_BITS); \
outw(status, port_addr)
/* size of returned buffer is part of USB spec */ /* size of returned buffer is part of USB spec */
...@@ -57,13 +68,9 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -57,13 +68,9 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength) u16 wIndex, char *buf, u16 wLength)
{ {
struct uhci_hcd *uhci = hcd_to_uhci(hcd); struct uhci_hcd *uhci = hcd_to_uhci(hcd);
int i, status, retval = 0, len = 0; int status, retval = 0, len = 0;
unsigned int io_addr = uhci->io_addr; unsigned int port_addr = uhci->io_addr + USBPORTSC1 + 2 * (wIndex-1);
__u16 cstatus; __u16 wPortChange, wPortStatus;
char c_p_r[8];
for (i = 0; i < 8; i++)
c_p_r[i] = 0;
switch (typeReq) { switch (typeReq) {
/* Request Destination: /* Request Destination:
...@@ -78,33 +85,56 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -78,33 +85,56 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
*(__u32 *)buf = cpu_to_le32(0); *(__u32 *)buf = cpu_to_le32(0);
OK(4); /* hub power */ OK(4); /* hub power */
case GetPortStatus: case GetPortStatus:
status = inw(io_addr + USBPORTSC1 + 2 * (wIndex - 1)); if (!wIndex || wIndex > uhci->rh_numports)
cstatus = ((status & USBPORTSC_CSC) >> (1 - 0)) |
((status & USBPORTSC_PEC) >> (3 - 1)) |
(c_p_r[wIndex - 1] << (0 + 4));
status = (status & USBPORTSC_CCS) |
((status & USBPORTSC_PE) >> (2 - 1)) |
((status & USBPORTSC_SUSP) >> (12 - 2)) |
((status & USBPORTSC_PR) >> (9 - 4)) |
(1 << 8) | /* power on */
((status & USBPORTSC_LSDA) << (-8 + 9));
*(__u16 *)buf = cpu_to_le16(status);
*(__u16 *)(buf + 2) = cpu_to_le16(cstatus);
OK(4);
case SetHubFeature:
switch (wValue) {
case C_HUB_OVER_CURRENT:
case C_HUB_LOCAL_POWER:
break;
default:
goto err; goto err;
status = inw(port_addr);
/* Intel controllers report the OverCurrent bit active on.
* VIA controllers report it active off, so we'll adjust the
* bit value. (It's not standardized in the UHCI spec.)
*/
if (to_pci_dev(hcd->self.controller)->vendor ==
PCI_VENDOR_ID_VIA)
status ^= USBPORTSC_OC;
/* UHCI doesn't support C_SUSPEND and C_RESET (always false) */
wPortChange = 0;
if (status & USBPORTSC_CSC)
wPortChange |= 1 << (USB_PORT_FEAT_C_CONNECTION - 16);
if (status & USBPORTSC_PEC)
wPortChange |= 1 << (USB_PORT_FEAT_C_ENABLE - 16);
if (status & USBPORTSC_OCC)
wPortChange |= 1 << (USB_PORT_FEAT_C_OVER_CURRENT - 16);
/* UHCI has no power switching (always on) */
wPortStatus = 1 << USB_PORT_FEAT_POWER;
if (status & USBPORTSC_CCS)
wPortStatus |= 1 << USB_PORT_FEAT_CONNECTION;
if (status & USBPORTSC_PE) {
wPortStatus |= 1 << USB_PORT_FEAT_ENABLE;
if (status & (USBPORTSC_SUSP | USBPORTSC_RD))
wPortStatus |= 1 << USB_PORT_FEAT_SUSPEND;
} }
break; if (status & USBPORTSC_OC)
wPortStatus |= 1 << USB_PORT_FEAT_OVER_CURRENT;
if (status & USBPORTSC_PR)
wPortStatus |= 1 << USB_PORT_FEAT_RESET;
if (status & USBPORTSC_LSDA)
wPortStatus |= 1 << USB_PORT_FEAT_LOWSPEED;
if (wPortChange)
dev_dbg(uhci_dev(uhci), "port %d portsc %04x\n",
wIndex, status);
*(__u16 *)buf = cpu_to_le16(wPortStatus);
*(__u16 *)(buf + 2) = cpu_to_le16(wPortChange);
OK(4);
case SetHubFeature: /* We don't implement these */
case ClearHubFeature: case ClearHubFeature:
switch (wValue) { switch (wValue) {
case C_HUB_OVER_CURRENT: case C_HUB_OVER_CURRENT:
OK(0); /* hub power over current */ case C_HUB_LOCAL_POWER:
OK(0);
default: default:
goto err; goto err;
} }
...@@ -120,17 +150,14 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -120,17 +150,14 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
case USB_PORT_FEAT_RESET: case USB_PORT_FEAT_RESET:
SET_RH_PORTSTAT(USBPORTSC_PR); SET_RH_PORTSTAT(USBPORTSC_PR);
mdelay(50); /* USB v1.1 7.1.7.3 */ mdelay(50); /* USB v1.1 7.1.7.3 */
c_p_r[wIndex - 1] = 1;
CLR_RH_PORTSTAT(USBPORTSC_PR); CLR_RH_PORTSTAT(USBPORTSC_PR);
udelay(10); udelay(10);
SET_RH_PORTSTAT(USBPORTSC_PE); SET_RH_PORTSTAT(USBPORTSC_PE);
mdelay(10); mdelay(10);
SET_RH_PORTSTAT(0xa); CLR_RH_PORTSTAT(USBPORTSC_PEC|USBPORTSC_CSC);
OK(0); OK(0);
case USB_PORT_FEAT_POWER: case USB_PORT_FEAT_POWER:
OK(0); /* port power ** */ /* UHCI has no power switching */
case USB_PORT_FEAT_ENABLE:
SET_RH_PORTSTAT(USBPORTSC_PE);
OK(0); OK(0);
default: default:
goto err; goto err;
...@@ -145,31 +172,32 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -145,31 +172,32 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
CLR_RH_PORTSTAT(USBPORTSC_PE); CLR_RH_PORTSTAT(USBPORTSC_PE);
OK(0); OK(0);
case USB_PORT_FEAT_C_ENABLE: case USB_PORT_FEAT_C_ENABLE:
SET_RH_PORTSTAT(USBPORTSC_PEC); CLR_RH_PORTSTAT(USBPORTSC_PEC);
OK(0); OK(0);
case USB_PORT_FEAT_SUSPEND: case USB_PORT_FEAT_SUSPEND:
CLR_RH_PORTSTAT(USBPORTSC_SUSP); CLR_RH_PORTSTAT(USBPORTSC_SUSP);
OK(0); OK(0);
case USB_PORT_FEAT_C_SUSPEND: case USB_PORT_FEAT_C_SUSPEND:
/*** WR_RH_PORTSTAT(RH_PS_PSSC); */ /* this driver won't report these */
OK(0); OK(0);
case USB_PORT_FEAT_POWER: case USB_PORT_FEAT_POWER:
OK(0); /* port power */ /* UHCI has no power switching */
goto err;
case USB_PORT_FEAT_C_CONNECTION: case USB_PORT_FEAT_C_CONNECTION:
SET_RH_PORTSTAT(USBPORTSC_CSC); CLR_RH_PORTSTAT(USBPORTSC_CSC);
OK(0); OK(0);
case USB_PORT_FEAT_C_OVER_CURRENT: case USB_PORT_FEAT_C_OVER_CURRENT:
OK(0); /* port power over current */ CLR_RH_PORTSTAT(USBPORTSC_OCC);
OK(0);
case USB_PORT_FEAT_C_RESET: case USB_PORT_FEAT_C_RESET:
c_p_r[wIndex - 1] = 0; /* this driver won't report these */
OK(0); OK(0);
default: default:
goto err; goto err;
} }
break; break;
case GetHubDescriptor: case GetHubDescriptor:
len = min_t(unsigned int, wLength, len = min_t(unsigned int, sizeof(root_hub_hub_des), wLength);
min_t(unsigned int, sizeof(root_hub_hub_des), wLength));
memcpy(buf, root_hub_hub_des, len); memcpy(buf, root_hub_hub_des, len);
if (len > 2) if (len > 2)
buf[2] = uhci->rh_numports; buf[2] = uhci->rh_numports;
...@@ -181,4 +209,3 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ...@@ -181,4 +209,3 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
return retval; return retval;
} }
...@@ -490,10 +490,9 @@ static int stv_init (struct usb_stv *stv680) ...@@ -490,10 +490,9 @@ static int stv_init (struct usb_stv *stv680)
stv680->hue = 32767; stv680->hue = 32767;
stv680->palette = STV_VIDEO_PALETTE; stv680->palette = STV_VIDEO_PALETTE;
stv680->depth = 24; /* rgb24 bits */ stv680->depth = 24; /* rgb24 bits */
swapRGB = 0;
if ((swapRGB_on == 0) && (swapRGB == 0)) if ((swapRGB_on == 0) && (swapRGB == 0))
PDEBUG (1, "STV(i): swapRGB is (auto) OFF"); PDEBUG (1, "STV(i): swapRGB is (auto) OFF");
else if ((swapRGB_on == 1) && (swapRGB == 1)) else if ((swapRGB_on == 0) && (swapRGB == 1))
PDEBUG (1, "STV(i): swapRGB is (auto) ON"); PDEBUG (1, "STV(i): swapRGB is (auto) ON");
else if (swapRGB_on == 1) else if (swapRGB_on == 1)
PDEBUG (1, "STV(i): swapRGB is (forced) ON"); PDEBUG (1, "STV(i): swapRGB is (forced) ON");
...@@ -657,7 +656,7 @@ static void stv680_video_irq (struct urb *urb, struct pt_regs *regs) ...@@ -657,7 +656,7 @@ static void stv680_video_irq (struct urb *urb, struct pt_regs *regs)
/* Resubmit urb for new data */ /* Resubmit urb for new data */
urb->status = 0; urb->status = 0;
urb->dev = stv680->udev; urb->dev = stv680->udev;
if (usb_submit_urb (urb, GFP_KERNEL)) if (usb_submit_urb (urb, GFP_ATOMIC))
PDEBUG (0, "STV(e): urb burned down in video irq"); PDEBUG (0, "STV(e): urb burned down in video irq");
return; return;
} /* _video_irq */ } /* _video_irq */
...@@ -1252,13 +1251,10 @@ static int stv680_do_ioctl (struct inode *inode, struct file *file, ...@@ -1252,13 +1251,10 @@ static int stv680_do_ioctl (struct inode *inode, struct file *file,
return -EINVAL; return -EINVAL;
} }
case VIDIOCSFBUF: case VIDIOCSFBUF:
return -EINVAL;
case VIDIOCGTUNER: case VIDIOCGTUNER:
case VIDIOCSTUNER: case VIDIOCSTUNER:
return -EINVAL;
case VIDIOCGFREQ: case VIDIOCGFREQ:
case VIDIOCSFREQ: case VIDIOCSFREQ:
return -EINVAL;
case VIDIOCGAUDIO: case VIDIOCGAUDIO:
case VIDIOCSAUDIO: case VIDIOCSAUDIO:
return -EINVAL; return -EINVAL;
...@@ -1434,7 +1430,7 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id ...@@ -1434,7 +1430,7 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id
if (video_register_device (stv680->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { if (video_register_device (stv680->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
PDEBUG (0, "STV(e): video_register_device failed"); PDEBUG (0, "STV(e): video_register_device failed");
retval = -EIO; retval = -EIO;
goto error; goto error_vdev;
} }
PDEBUG (0, "STV(i): registered new video device: video%d", stv680->vdev->minor); PDEBUG (0, "STV(i): registered new video device: video%d", stv680->vdev->minor);
...@@ -1442,6 +1438,8 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id ...@@ -1442,6 +1438,8 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id
stv680_create_sysfs_files(stv680->vdev); stv680_create_sysfs_files(stv680->vdev);
return 0; return 0;
error_vdev:
video_device_release(stv680->vdev);
error: error:
kfree(stv680); kfree(stv680);
return retval; return retval;
...@@ -1466,9 +1464,7 @@ static inline void usb_stv680_remove_disconnected (struct usb_stv *stv680) ...@@ -1466,9 +1464,7 @@ static inline void usb_stv680_remove_disconnected (struct usb_stv *stv680)
kfree (stv680->sbuf[i].data); kfree (stv680->sbuf[i].data);
} }
for (i = 0; i < STV680_NUMSCRATCH; i++) for (i = 0; i < STV680_NUMSCRATCH; i++)
if (stv680->scratch[i].data) { kfree (stv680->scratch[i].data);
kfree (stv680->scratch[i].data);
}
PDEBUG (0, "STV(i): %s disconnected", stv680->camera_name); PDEBUG (0, "STV(i): %s disconnected", stv680->camera_name);
/* Free the memory */ /* Free the memory */
......
...@@ -724,7 +724,7 @@ struct ctrl_ctx { ...@@ -724,7 +724,7 @@ struct ctrl_ctx {
int last; int last;
}; };
#define NUM_SUBCASES 13 /* how many test subcases here? */ #define NUM_SUBCASES 15 /* how many test subcases here? */
struct subcase { struct subcase {
struct usb_ctrlrequest setup; struct usb_ctrlrequest setup;
...@@ -952,8 +952,25 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) ...@@ -952,8 +952,25 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
req.wValue = cpu_to_le16 (USB_DT_STRING << 8); req.wValue = cpu_to_le16 (USB_DT_STRING << 8);
// string == 0, for language IDs // string == 0, for language IDs
len = sizeof (struct usb_interface_descriptor); len = sizeof (struct usb_interface_descriptor);
// may succeed when > 4 languages
expected = EREMOTEIO; // or EPIPE, if no strings expected = EREMOTEIO; // or EPIPE, if no strings
break; break;
case 13: // short read, resembling case 10
req.wValue = cpu_to_le16 ((USB_DT_CONFIG << 8) | 0);
// last data packet "should" be DATA1, not DATA0
len = 1024 - udev->epmaxpacketin [0];
expected = -EREMOTEIO;
break;
case 14: // short read; try to fill the last packet
req.wValue = cpu_to_le16 ((USB_DT_DEVICE << 8) | 0);
// device descriptor size == 18 bytes
len = udev->epmaxpacketin [0];
switch (len) {
case 8: len = 24; break;
case 16: len = 32; break;
}
expected = -EREMOTEIO;
break;
default: default:
err ("bogus number of ctrl queue testcases!"); err ("bogus number of ctrl queue testcases!");
context.status = -EINVAL; context.status = -EINVAL;
......
...@@ -17,6 +17,11 @@ ...@@ -17,6 +17,11 @@
* See http://ftdi-usb-sio.sourceforge.net for upto date testing info * See http://ftdi-usb-sio.sourceforge.net for upto date testing info
* and extra documentation * and extra documentation
* *
* (09/Feb/2004) Ian Abbott
* Changed full name of USB-UIRT device to avoid "/" character.
* Added FTDI's alternate PID (0x6006) for FT232/245 devices.
* Added PID for "ELV USB Module UO100" from Stefan Frings.
*
* (21/Oct/2003) Ian Abbott * (21/Oct/2003) Ian Abbott
* Renamed some VID/PID macros for Matrix Orbital and Perle Systems * Renamed some VID/PID macros for Matrix Orbital and Perle Systems
* devices. Removed Matrix Orbital and Perle Systems devices from the * devices. Removed Matrix Orbital and Perle Systems devices from the
...@@ -282,6 +287,7 @@ static struct usb_device_id id_table_sio [] = { ...@@ -282,6 +287,7 @@ static struct usb_device_id id_table_sio [] = {
static struct usb_device_id id_table_8U232AM [] = { static struct usb_device_id id_table_8U232AM [] = {
{ USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_ALT_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0, 0x3ff) },
...@@ -346,12 +352,14 @@ static struct usb_device_id id_table_8U232AM [] = { ...@@ -346,12 +352,14 @@ static struct usb_device_id id_table_8U232AM [] = {
{ USB_DEVICE_VER(FTDI_VID, PROTEGO_R2X0, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, PROTEGO_R2X0, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_3, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_3, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_4, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_4, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UO100_PID, 0, 0x3ff) },
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
static struct usb_device_id id_table_FT232BM [] = { static struct usb_device_id id_table_FT232BM [] = {
{ USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_ALT_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0x400, 0xffff) },
...@@ -425,6 +433,7 @@ static struct usb_device_id id_table_FT232BM [] = { ...@@ -425,6 +433,7 @@ static struct usb_device_id id_table_FT232BM [] = {
{ USB_DEVICE_VER(FTDI_VID, PROTEGO_R2X0, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, PROTEGO_R2X0, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_3, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_3, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_4, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_4, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UO100_PID, 0x400, 0xffff) },
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
...@@ -444,6 +453,7 @@ static struct usb_device_id id_table_HE_TIRA1 [] = { ...@@ -444,6 +453,7 @@ static struct usb_device_id id_table_HE_TIRA1 [] = {
static struct usb_device_id id_table_combined [] = { static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_SIO_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) }, { USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) }, { USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) },
...@@ -518,6 +528,7 @@ static struct usb_device_id id_table_combined [] = { ...@@ -518,6 +528,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, PROTEGO_R2X0) }, { USB_DEVICE(FTDI_VID, PROTEGO_R2X0) },
{ USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_3) }, { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_3) },
{ USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_4) }, { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_4) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_UO100_PID) },
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
...@@ -669,7 +680,7 @@ static struct usb_serial_device_type ftdi_FT232BM_device = { ...@@ -669,7 +680,7 @@ static struct usb_serial_device_type ftdi_FT232BM_device = {
static struct usb_serial_device_type ftdi_USB_UIRT_device = { static struct usb_serial_device_type ftdi_USB_UIRT_device = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "USB-UIRT Infrared Receiver/Transmitter", .name = "USB-UIRT Infrared Tranceiver",
.id_table = id_table_USB_UIRT, .id_table = id_table_USB_UIRT,
.num_interrupt_in = 0, .num_interrupt_in = 0,
.num_bulk_in = 1, .num_bulk_in = 1,
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#define FTDI_VID 0x0403 /* Vendor Id */ #define FTDI_VID 0x0403 /* Vendor Id */
#define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */ #define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */
#define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */ #define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */
#define FTDI_8U232AM_ALT_PID 0x6006 /* FTDI's alternate PID for above */
#define FTDI_RELAIS_PID 0xFA10 /* Relais device from Rudolf Gugler */ #define FTDI_RELAIS_PID 0xFA10 /* Relais device from Rudolf Gugler */
#define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */ #define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */
#define FTDI_NF_RIC_PID 0x0001 /* Product Id */ #define FTDI_NF_RIC_PID 0x0001 /* Product Id */
...@@ -132,6 +133,9 @@ ...@@ -132,6 +133,9 @@
/* http://home.earthlink.net/~jrhees/USBUIRT/index.htm */ /* http://home.earthlink.net/~jrhees/USBUIRT/index.htm */
#define FTDI_USB_UIRT_PID 0xF850 /* Product Id */ #define FTDI_USB_UIRT_PID 0xF850 /* Product Id */
/* ELV USB Module UO100 (PID sent by Stefan Frings) */
#define FTDI_ELV_UO100_PID 0xFB58 /* Product Id */
/* /*
* Definitions for ID TECH (www.idt-net.com) devices * Definitions for ID TECH (www.idt-net.com) devices
*/ */
......
...@@ -27,6 +27,20 @@ ...@@ -27,6 +27,20 @@
* 675 Mass Ave, Cambridge, MA 02139, USA. * 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
/*
* Known vendor commands: 12 bytes, first byte is opcode
*
* E7: read scatter gather
* E8: read
* E9: write
* EA: erase
* EB: reset
* EC: read status
* ED: read ID
* EE: write CIS (?)
* EF: compute checksum (?)
*/
#include "transport.h" #include "transport.h"
#include "protocol.h" #include "protocol.h"
#include "usb.h" #include "usb.h"
...@@ -461,6 +475,7 @@ sddr09_read23(struct us_data *us, unsigned long fromaddress, ...@@ -461,6 +475,7 @@ sddr09_read23(struct us_data *us, unsigned long fromaddress,
* *
* Always precisely one block is erased; bytes 2-5 and 10-11 are ignored. * Always precisely one block is erased; bytes 2-5 and 10-11 are ignored.
* The byte address being erased is 2*Eaddress. * The byte address being erased is 2*Eaddress.
* The CIS cannot be erased.
*/ */
static int static int
sddr09_erase(struct us_data *us, unsigned long Eaddress) { sddr09_erase(struct us_data *us, unsigned long Eaddress) {
...@@ -486,6 +501,20 @@ sddr09_erase(struct us_data *us, unsigned long Eaddress) { ...@@ -486,6 +501,20 @@ sddr09_erase(struct us_data *us, unsigned long Eaddress) {
return result; return result;
} }
/*
* Write CIS Command: 12 bytes.
* byte 0: opcode: EE
* bytes 2-5: write address in shorts
* bytes 10-11: sector count
*
* This writes at the indicated address. Don't know how it differs
* from E9. Maybe it does not erase? However, it will also write to
* the CIS.
*
* When two such commands on the same page follow each other directly,
* the second one is not done.
*/
/* /*
* Write Command: 12 bytes. * Write Command: 12 bytes.
* byte 0: opcode: E9 * byte 0: opcode: E9
...@@ -1478,7 +1507,7 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -1478,7 +1507,7 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
"mode page 0x%x\n", modepage); "mode page 0x%x\n", modepage);
memcpy(ptr, mode_page_01, sizeof(mode_page_01)); memcpy(ptr, mode_page_01, sizeof(mode_page_01));
((u16*)ptr)[0] = sizeof(mode_page_01) - 2; ((u16*)ptr)[0] = cpu_to_be16(sizeof(mode_page_01) - 2);
ptr[3] = (info->flags & SDDR09_WP) ? 0x80 : 0; ptr[3] = (info->flags & SDDR09_WP) ? 0x80 : 0;
usb_stor_set_xfer_buf(ptr, sizeof(mode_page_01), srb); usb_stor_set_xfer_buf(ptr, sizeof(mode_page_01), srb);
return USB_STOR_TRANSPORT_GOOD; return USB_STOR_TRANSPORT_GOOD;
......
...@@ -552,6 +552,8 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -552,6 +552,8 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
return; return;
} }
srb->result = SAM_STAT_GOOD;
/* Determine if we need to auto-sense /* Determine if we need to auto-sense
* *
* I normally don't use a flag like this, but it's almost impossible * I normally don't use a flag like this, but it's almost impossible
...@@ -561,23 +563,14 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -561,23 +563,14 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
/* /*
* If we're running the CB transport, which is incapable * If we're running the CB transport, which is incapable
* of determining status on it's own, we need to auto-sense almost * of determining status on its own, we need to auto-sense
* every time. * unless the operation involved a data-in transfer. Devices
* can signal data-in errors by stalling the bulk-in pipe.
*/ */
if (us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) { if ((us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) &&
srb->sc_data_direction != SCSI_DATA_READ) {
US_DEBUGP("-- CB transport device requiring auto-sense\n"); US_DEBUGP("-- CB transport device requiring auto-sense\n");
need_auto_sense = 1; need_auto_sense = 1;
/* There are some exceptions to this. Notably, if this is
* a UFI device and the command is REQUEST_SENSE or INQUIRY,
* then it is impossible to truly determine status.
*/
if (us->subclass == US_SC_UFI &&
((srb->cmnd[0] == REQUEST_SENSE) ||
(srb->cmnd[0] == INQUIRY))) {
US_DEBUGP("** no auto-sense for a special command\n");
need_auto_sense = 0;
}
} }
/* /*
...@@ -591,8 +584,8 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -591,8 +584,8 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
} }
/* /*
* Also, if we have a short transfer on a command that can't have * A short transfer on a command where we don't expect it
* a short transfer, we're going to do this. * is unusual, but it doesn't mean we need to auto-sense.
*/ */
if ((srb->resid > 0) && if ((srb->resid > 0) &&
!((srb->cmnd[0] == REQUEST_SENSE) || !((srb->cmnd[0] == REQUEST_SENSE) ||
...@@ -601,7 +594,6 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -601,7 +594,6 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
(srb->cmnd[0] == LOG_SENSE) || (srb->cmnd[0] == LOG_SENSE) ||
(srb->cmnd[0] == MODE_SENSE_10))) { (srb->cmnd[0] == MODE_SENSE_10))) {
US_DEBUGP("-- unexpectedly short transfer\n"); US_DEBUGP("-- unexpectedly short transfer\n");
need_auto_sense = 1;
} }
/* Now, if we need to do the auto-sense, let's do it */ /* Now, if we need to do the auto-sense, let's do it */
...@@ -614,6 +606,7 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -614,6 +606,7 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
unsigned char old_cmd_len; unsigned char old_cmd_len;
unsigned char old_cmnd[MAX_COMMAND_SIZE]; unsigned char old_cmnd[MAX_COMMAND_SIZE];
unsigned long old_serial_number; unsigned long old_serial_number;
int old_resid;
US_DEBUGP("Issuing auto-REQUEST_SENSE\n"); US_DEBUGP("Issuing auto-REQUEST_SENSE\n");
...@@ -654,9 +647,12 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -654,9 +647,12 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
srb->serial_number ^= 0x80000000; srb->serial_number ^= 0x80000000;
/* issue the auto-sense command */ /* issue the auto-sense command */
old_resid = srb->resid;
srb->resid = 0;
temp_result = us->transport(us->srb, us); temp_result = us->transport(us->srb, us);
/* let's clean up right away */ /* let's clean up right away */
srb->resid = old_resid;
srb->request_buffer = old_request_buffer; srb->request_buffer = old_request_buffer;
srb->request_bufflen = old_request_bufflen; srb->request_bufflen = old_request_bufflen;
srb->use_sg = old_sg; srb->use_sg = old_sg;
...@@ -698,26 +694,15 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -698,26 +694,15 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
/* set the result so the higher layers expect this data */ /* set the result so the higher layers expect this data */
srb->result = SAM_STAT_CHECK_CONDITION; srb->result = SAM_STAT_CHECK_CONDITION;
/* If things are really okay, then let's show that */ /* If things are really okay, then let's show that. Zero
if ((srb->sense_buffer[2] & 0xf) == 0x0) * out the sense buffer so the higher layers won't realize
* we did an unsolicited auto-sense. */
if (result == USB_STOR_TRANSPORT_GOOD &&
(srb->sense_buffer[2] & 0xf) == 0x0) {
srb->result = SAM_STAT_GOOD; srb->result = SAM_STAT_GOOD;
} else /* if (need_auto_sense) */ srb->sense_buffer[0] = 0x0;
srb->result = SAM_STAT_GOOD; }
}
/* Regardless of auto-sense, if we _know_ we have an error
* condition, show that in the result code
*/
if (result == USB_STOR_TRANSPORT_FAILED)
srb->result = SAM_STAT_CHECK_CONDITION;
/* If we think we're good, then make sure the sense data shows it.
* This is necessary because the auto-sense for some devices always
* sets byte 0 == 0x70, even if there is no error
*/
if ((us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) &&
(result == USB_STOR_TRANSPORT_GOOD) &&
((srb->sense_buffer[2] & 0xf) == 0x0))
srb->sense_buffer[0] = 0x0;
return; return;
/* abort processing: the bulk-only transport requires a reset /* abort processing: the bulk-only transport requires a reset
...@@ -792,6 +777,10 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -792,6 +777,10 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
srb->request_buffer, transfer_length, srb->request_buffer, transfer_length,
srb->use_sg, &srb->resid); srb->use_sg, &srb->resid);
US_DEBUGP("CBI data stage result is 0x%x\n", result); US_DEBUGP("CBI data stage result is 0x%x\n", result);
/* if we stalled the data transfer it means command failed */
if (result == USB_STOR_XFER_STALLED)
return USB_STOR_TRANSPORT_FAILED;
if (result > USB_STOR_XFER_STALLED) if (result > USB_STOR_XFER_STALLED)
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
} }
...@@ -883,6 +872,10 @@ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -883,6 +872,10 @@ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us)
srb->request_buffer, transfer_length, srb->request_buffer, transfer_length,
srb->use_sg, &srb->resid); srb->use_sg, &srb->resid);
US_DEBUGP("CB data stage result is 0x%x\n", result); US_DEBUGP("CB data stage result is 0x%x\n", result);
/* if we stalled the data transfer it means command failed */
if (result == USB_STOR_XFER_STALLED)
return USB_STOR_TRANSPORT_FAILED;
if (result > USB_STOR_XFER_STALLED) if (result > USB_STOR_XFER_STALLED)
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
} }
...@@ -929,6 +922,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -929,6 +922,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
unsigned int residue; unsigned int residue;
int result; int result;
int fake_sense = 0; int fake_sense = 0;
unsigned int cswlen;
/* set up the command wrapper */ /* set up the command wrapper */
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
...@@ -985,7 +979,17 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -985,7 +979,17 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
/* get CSW for device status */ /* get CSW for device status */
US_DEBUGP("Attempting to get CSW...\n"); US_DEBUGP("Attempting to get CSW...\n");
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
bcs, US_BULK_CS_WRAP_LEN, NULL); bcs, US_BULK_CS_WRAP_LEN, &cswlen);
/* Some broken devices add unnecessary zero-length packets to the
* end of their data transfers. Such packets show up as 0-length
* CSWs. If we encounter such a thing, try to read the CSW again.
*/
if (result == USB_STOR_XFER_SHORT && cswlen == 0) {
US_DEBUGP("Received 0-length CSW; retrying...\n");
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
bcs, US_BULK_CS_WRAP_LEN, &cswlen);
}
/* did the attempt to read the CSW fail? */ /* did the attempt to read the CSW fail? */
if (result == USB_STOR_XFER_STALLED) { if (result == USB_STOR_XFER_STALLED) {
......
...@@ -108,6 +108,15 @@ UNUSUAL_DEV( 0x0482, 0x0103, 0x0100, 0x0100, ...@@ -108,6 +108,15 @@ UNUSUAL_DEV( 0x0482, 0x0103, 0x0100, 0x0100,
"Finecam S5", "Finecam S5",
US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY), US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY),
/* Patch for Kyocera Finecam L3
* Submitted by Michael Krauth <michael.krauth@web.de>
*/
UNUSUAL_DEV( 0x0482, 0x0105, 0x0100, 0x0100,
"Kyocera",
"Finecam L3",
US_SC_SCSI, US_PR_BULK, NULL,
US_FL_FIX_INQUIRY),
/* Reported by Paul Stewart <stewart@wetlogic.net> /* Reported by Paul Stewart <stewart@wetlogic.net>
* This entry is needed because the device reports Sub=ff */ * This entry is needed because the device reports Sub=ff */
UNUSUAL_DEV( 0x04a4, 0x0004, 0x0001, 0x0001, UNUSUAL_DEV( 0x04a4, 0x0004, 0x0001, 0x0001,
...@@ -132,7 +141,7 @@ UNUSUAL_DEV( 0x04b8, 0x0602, 0x0110, 0x0110, ...@@ -132,7 +141,7 @@ UNUSUAL_DEV( 0x04b8, 0x0602, 0x0110, 0x0110,
UNUSUAL_DEV( 0x04cb, 0x0100, 0x0000, 0x2210, UNUSUAL_DEV( 0x04cb, 0x0100, 0x0000, 0x2210,
"Fujifilm", "Fujifilm",
"FinePix 1400Zoom", "FinePix 1400Zoom",
US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY), US_SC_UFI, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY),
/* Reported by Peter Wchtler <pwaechtler@loewe-komp.de> /* Reported by Peter Wchtler <pwaechtler@loewe-komp.de>
* The device needs the flags only. * The device needs the flags only.
...@@ -171,7 +180,7 @@ UNUSUAL_DEV( 0x04e6, 0x0001, 0x0200, 0x0200, ...@@ -171,7 +180,7 @@ UNUSUAL_DEV( 0x04e6, 0x0001, 0x0200, 0x0200,
UNUSUAL_DEV( 0x04e6, 0x0002, 0x0100, 0x0100, UNUSUAL_DEV( 0x04e6, 0x0002, 0x0100, 0x0100,
"Shuttle", "Shuttle",
"eUSCSI Bridge", "eUSCSI Bridge",
US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, US_SC_DEVICE, US_PR_DEVICE, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG ), US_FL_SCM_MULT_TARG ),
#ifdef CONFIG_USB_STORAGE_SDDR09 #ifdef CONFIG_USB_STORAGE_SDDR09
...@@ -285,6 +294,13 @@ UNUSUAL_DEV( 0x054c, 0x0032, 0x0000, 0x9999, ...@@ -285,6 +294,13 @@ UNUSUAL_DEV( 0x054c, 0x0032, 0x0000, 0x9999,
"Memorystick MSC-U01N", "Memorystick MSC-U01N",
US_SC_DEVICE, US_PR_DEVICE, NULL, US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_SINGLE_LUN ), US_FL_SINGLE_LUN ),
/* Submitted by Michal Mlotek <mlotek@foobar.pl> */
UNUSUAL_DEV( 0x054c, 0x0058, 0x0000, 0x9999,
"Sony",
"PEG N760c Memorystick",
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY ),
UNUSUAL_DEV( 0x054c, 0x0069, 0x0000, 0x9999, UNUSUAL_DEV( 0x054c, 0x0069, 0x0000, 0x9999,
"Sony", "Sony",
...@@ -414,6 +430,28 @@ UNUSUAL_DEV( 0x066b, 0x0105, 0x0100, 0x0100, ...@@ -414,6 +430,28 @@ UNUSUAL_DEV( 0x066b, 0x0105, 0x0100, 0x0100,
US_FL_SINGLE_LUN ), US_FL_SINGLE_LUN ),
#endif #endif
/* Following three Minolta cameras reported by Martin Pool
* <mbp@sourcefrog.net>. Originally discovered by Kedar Petankar,
* Matthew Geier, Mikael Lofj"ard, Marcel de Boer.
*/
UNUSUAL_DEV( 0x0686, 0x4006, 0x0001, 0x0001,
"Minolta",
"DiMAGE 7",
US_SC_SCSI, US_PR_DEVICE, NULL,
0 ),
UNUSUAL_DEV( 0x0686, 0x400b, 0x0001, 0x0001,
"Minolta",
"DiMAGE 7i",
US_SC_SCSI, US_PR_DEVICE, NULL,
0 ),
UNUSUAL_DEV( 0x0686, 0x400f, 0x0001, 0x0001,
"Minolta",
"DiMAGE 7Hi",
US_SC_SCSI, US_PR_DEVICE, NULL,
0 ),
/* Submitted by Benny Sjostrand <benny@hostmobility.com> */ /* Submitted by Benny Sjostrand <benny@hostmobility.com> */
UNUSUAL_DEV( 0x0686, 0x4011, 0x0001, 0x0001, UNUSUAL_DEV( 0x0686, 0x4011, 0x0001, 0x0001,
"Minolta", "Minolta",
...@@ -426,28 +464,6 @@ UNUSUAL_DEV( 0x0686, 0x4017, 0x0001, 0x0001, ...@@ -426,28 +464,6 @@ UNUSUAL_DEV( 0x0686, 0x4017, 0x0001, 0x0001,
"DIMAGE E223", "DIMAGE E223",
US_SC_SCSI, US_PR_DEVICE, NULL, 0 ), US_SC_SCSI, US_PR_DEVICE, NULL, 0 ),
/* Following three Minolta cameras reported by Martin Pool
* <mbp@sourcefrog.net>. Originally discovered by Kedar Petankar,
* Matthew Geier, Mikael Lofj"ard, Marcel de Boer.
*/
UNUSUAL_DEV( 0x0686, 0x4006, 0x0001, 0x0001,
"Minolta",
"DiMAGE 7",
US_SC_SCSI, US_PR_DEVICE, NULL,
0 ),
UNUSUAL_DEV( 0x0686, 0x400b, 0x0001, 0x0001,
"Minolta",
"DiMAGE 7i",
US_SC_SCSI, US_PR_DEVICE, NULL,
0 ),
UNUSUAL_DEV( 0x0686, 0x400f, 0x0001, 0x0001,
"Minolta",
"DiMAGE 7Hi",
US_SC_SCSI, US_PR_DEVICE, NULL,
0 ),
UNUSUAL_DEV( 0x0693, 0x0002, 0x0100, 0x0100, UNUSUAL_DEV( 0x0693, 0x0002, 0x0100, 0x0100,
"Hagiwara", "Hagiwara",
"FlashGate SmartMedia", "FlashGate SmartMedia",
...@@ -607,7 +623,7 @@ UNUSUAL_DEV( 0x07c4, 0xa400, 0x0000, 0xffff, ...@@ -607,7 +623,7 @@ UNUSUAL_DEV( 0x07c4, 0xa400, 0x0000, 0xffff,
UNUSUAL_DEV( 0x07cf, 0x1001, 0x1000, 0x9009, UNUSUAL_DEV( 0x07cf, 0x1001, 0x1000, 0x9009,
"Casio", "Casio",
"QV DigitalCamera", "QV DigitalCamera",
US_SC_8070, US_PR_CB, NULL, US_SC_DEVICE, US_PR_CB, NULL,
US_FL_FIX_INQUIRY ), US_FL_FIX_INQUIRY ),
/* Later Casio cameras apparently tell the truth */ /* Later Casio cameras apparently tell the truth */
...@@ -633,15 +649,6 @@ UNUSUAL_DEV( 0x08ca, 0x2011, 0x0000, 0x9999, ...@@ -633,15 +649,6 @@ UNUSUAL_DEV( 0x08ca, 0x2011, 0x0000, 0x9999,
US_SC_DEVICE, US_PR_DEVICE, NULL, US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_MODE_XLATE ), US_FL_MODE_XLATE ),
/*Medion 6047 Digital Camera
Davide Andrian <_nessuno_@katamail.com>
*/
UNUSUAL_DEV( 0x08ca, 0x2011, 0x0001, 0x0001,
"3MegaCam",
"3MegaCam",
US_SC_DEVICE, US_PR_BULK, NULL,
US_FL_MODE_XLATE ),
/* Trumpion Microelectronics MP3 player (felipe_alfaro@linuxmail.org) */ /* Trumpion Microelectronics MP3 player (felipe_alfaro@linuxmail.org) */
UNUSUAL_DEV( 0x090a, 0x1200, 0x0000, 0x9999, UNUSUAL_DEV( 0x090a, 0x1200, 0x0000, 0x9999,
"Trumpion", "Trumpion",
...@@ -720,6 +727,17 @@ UNUSUAL_DEV( 0x0d96, 0x5200, 0x0001, 0x0200, ...@@ -720,6 +727,17 @@ UNUSUAL_DEV( 0x0d96, 0x5200, 0x0001, 0x0200,
"JD 5200 z3", "JD 5200 z3",
US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY), US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY),
/* Reported by Lubomir Blaha <tritol@trilogic.cz>
* I _REALLY_ don't know what 3rd, 4th number and all defines mean, but this
* works for me. Can anybody correct these values? (I able to test corrected
* version.)
*/
UNUSUAL_DEV( 0x0dd8, 0x1060, 0x0000, 0xffff,
"Netac",
"USB-CF-Card",
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY ),
/* Submitted by Antoine Mairesse <antoine.mairesse@free.fr> */ /* Submitted by Antoine Mairesse <antoine.mairesse@free.fr> */
UNUSUAL_DEV( 0x0ed1, 0x6660, 0x0100, 0x0300, UNUSUAL_DEV( 0x0ed1, 0x6660, 0x0100, 0x0300,
"USB", "USB",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment