patch-2.3.15 linux/drivers/usb/uhci.c
Next file: linux/drivers/usb/uhci.h
Previous file: linux/drivers/usb/uhci-debug.c
Back to the patch index
Back to the overall index
- Lines: 1445
- Date:
Wed Aug 25 15:03:54 1999
- Orig file:
v2.3.14/linux/drivers/usb/uhci.c
- Orig date:
Wed Aug 18 16:22:23 1999
diff -u --recursive --new-file v2.3.14/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c
@@ -3,6 +3,7 @@
*
* (C) Copyright 1999 Linus Torvalds
* (C) Copyright 1999 Johannes Erdfelt
+ * (C) Copyright 1999 Randy Dunlap
*
* Intel documents this fairly well, and as far as I know there
* are no royalties or anything like that, but even so there are
@@ -63,32 +64,51 @@
#define UHCI_DEBUG
/*
- * Map status to standard result codes.
+ * function prototypes
+ */
+
+static int uhci_get_current_frame_number (struct usb_device *usb_dev);
+
+static int uhci_init_isoc (struct usb_device *usb_dev,
+ unsigned int pipe,
+ int frame_count,
+ void *context,
+ struct usb_isoc_desc **isocdesc);
+
+static void uhci_free_isoc (struct usb_isoc_desc *isocdesc);
+
+static int uhci_run_isoc (struct usb_isoc_desc *isocdesc,
+ struct usb_isoc_desc *pr_isocdesc);
+
+static int uhci_kill_isoc (struct usb_isoc_desc *isocdesc);
+
+/*
+ * Map status to standard result codes
*
- * <status> is ((td->status >> 16) & 0xff) [a.k.a. uhci_status_bits(td->status)]
+ * <status> is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status)
* <dir_out> is True for output TDs and False for input TDs.
*/
static int uhci_map_status(int status, int dir_out)
{
if (!status)
return USB_ST_NOERROR;
- if (status & 0x02) /* Bitstuff error*/
+ if (status & TD_CTRL_BITSTUFF) /* Bitstuff error */
return USB_ST_BITSTUFF;
- if (status & 0x04) { /* CRC/Timeout */
+ if (status & TD_CTRL_CRCTIMEO) { /* CRC/Timeout */
if (dir_out)
- return USB_ST_NORESPONSE;
+ return USB_ST_NORESPONSE;
else
return USB_ST_CRC;
}
- if (status & 0x08) /* NAK */
+ if (status & TD_CTRL_NAK) /* NAK */
return USB_ST_TIMEOUT;
- if (status & 0x10) /* Babble */
+ if (status & TD_CTRL_BABBLE) /* Babble */
return USB_ST_STALL;
- if (status & 0x20) /* Buffer error */
+ if (status & TD_CTRL_DBUFERR) /* Buffer error */
return USB_ST_BUFFERUNDERRUN;
- if (status & 0x40) /* Stalled */
+ if (status & TD_CTRL_STALLED) /* Stalled */
return USB_ST_STALL;
- if (status & 0x80) /* Active */
+ if (status & TD_CTRL_ACTIVE) /* Active */
return USB_ST_NOERROR;
return USB_ST_INTERNALERROR;
@@ -96,77 +116,83 @@
/*
* Return the result of a TD..
*/
-static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned long *rval)
+static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned long *rval, int debug)
{
unsigned int status;
struct uhci_td *tmp;
-
- if (!td->qh)
- tmp = td;
- else
- tmp = uhci_ptr_to_virt(td->qh->element);
+ int count = 1000;
if (rval)
*rval = 0;
- /* locate the first failing td, if any */
+ /* Start at the TD first in the chain, if possible */
+ if (td->qh && td->qh->first)
+ tmp = td->qh->first;
+ else
+ tmp = td;
+ if (!tmp)
+ return USB_ST_INTERNALERROR;
+
+ /* Locate the first failing td, if any */
do {
status = uhci_status_bits(tmp->status);
+
if (status) {
- /* must reset the toggle on first error */
- if (uhci_debug) {
- printk(KERN_DEBUG "Set toggle from %x rval %ld\n",
- (unsigned int)tmp, rval ? *rval : 0);
+ if (debug) {
+ /* Must reset the toggle on first error */
+ if (uhci_debug) {
+ printk(KERN_DEBUG "Set toggle from %x rval %ld\n",
+ (unsigned int)tmp, rval ? *rval : 0);
+ }
+
+ usb_settoggle(dev->usb, uhci_endpoint(tmp->info),
+ uhci_packetout(tmp->info) ^ 1,
+ uhci_toggle(tmp->info));
+ break;
}
- usb_settoggle(dev->usb, uhci_endpoint(tmp->info),
- uhci_packetout(tmp->info), uhci_toggle(tmp->info));
- break;
} else {
- if (rval)
- *rval += uhci_actual_length(tmp->status);
+ if (rval && ((tmp->info & 0xFF) == USB_PID_IN))
+ *rval += uhci_actual_length(tmp->status);
}
+
if ((tmp->link & UHCI_PTR_TERM) ||
(tmp->link & UHCI_PTR_QH))
break;
+
tmp = uhci_ptr_to_virt(tmp->link);
- } while (1);
+ } while (--count);
- if (!status)
+ if (!count) {
+ printk(KERN_ERR "runaway td's in uhci_td_result!\n");
+ /* Force debugging on */
+ debug = 1;
+ } else if (!status)
return USB_ST_NOERROR;
/* Some debugging code */
- if (uhci_debug) {
- int count = 10;
-
- if (!td->qh)
- tmp = td;
- else
- tmp = uhci_ptr_to_virt(td->qh->element);
+ if (debug && uhci_debug) {
printk(KERN_DEBUG "uhci_td_result() failed with status %x\n",
status);
- do {
- show_td(tmp);
- if ((tmp->link & UHCI_PTR_TERM) ||
- (tmp->link & UHCI_PTR_QH))
- break;
- tmp = uhci_ptr_to_virt(tmp->link);
- } while (--count);
+
+ /* Print the chain for debugging purposes */
+ if (td->qh)
+ uhci_show_queue(td->qh);
+ else
+ uhci_show_td(td);
}
- if (status & 0x40) {
+ if (status & TD_CTRL_STALLED) {
/* endpoint has stalled - mark it halted */
usb_endpoint_halt(dev->usb, uhci_endpoint(tmp->info),
uhci_packetout(tmp->info));
return USB_ST_STALL;
}
- if (status == 0x80) {
- /* still active */
- if (!rval)
- return USB_ST_DATAUNDERRUN;
- }
- return uhci_map_status(status, uhci_packetout(tmp->info));
+ if ((status == TD_CTRL_ACTIVE) && (!rval))
+ return USB_ST_DATAUNDERRUN;
+
+ return uhci_map_status(status, usb_pipeout(tmp->info) ^ 1);
}
/*
@@ -194,6 +220,7 @@
:"=q" (success), "=a" (link)
:"m" (qh->element), "1" (link), "r" (new)
:"memory");
+
if (success) {
/* Was there a successor entry? Fix it's backpointer */
if ((link & UHCI_PTR_TERM) == 0) {
@@ -203,6 +230,10 @@
break;
}
}
+
+ qh->first = first;
+ first->qh = qh;
+ last->qh = qh;
}
static inline void uhci_insert_td_in_qh(struct uhci_qh *qh, struct uhci_td *td)
@@ -279,6 +310,54 @@
:
:"r" (link), "m" (*backptr), "a" (me)
:"memory");
+
+ /* Reset it just in case */
+ td->link = UHCI_PTR_TERM;
+}
+
+/*
+ * Only the USB core should call uhci_alloc_dev and uhci_free_dev
+ */
+static int uhci_alloc_dev(struct usb_device *usb_dev)
+{
+ struct uhci_device *dev;
+
+ /* Allocate the UHCI device private data */
+ dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -1;
+
+ /* Initialize "dev" */
+ memset(dev, 0, sizeof(*dev));
+
+ usb_dev->hcpriv = dev;
+ dev->usb = usb_dev;
+ atomic_set(&dev->refcnt, 1);
+
+ if (usb_dev->parent)
+ dev->uhci = usb_to_uhci(usb_dev->parent)->uhci;
+
+ return 0;
+}
+
+static int uhci_free_dev(struct usb_device *usb_dev)
+{
+ struct uhci_device *dev = usb_to_uhci(usb_dev);
+
+ if (atomic_dec_and_test(&dev->refcnt))
+ kfree(dev);
+
+ return 0;
+}
+
+static void uhci_inc_dev_use(struct uhci_device *dev)
+{
+ atomic_inc(&dev->refcnt);
+}
+
+static void uhci_dec_dev_use(struct uhci_device *dev)
+{
+ uhci_free_dev(dev->usb);
}
static struct uhci_td *uhci_td_alloc(struct uhci_device *dev)
@@ -305,13 +384,19 @@
INIT_LIST_HEAD(&td->irq_list);
atomic_set(&td->refcnt, 1);
+ uhci_inc_dev_use(dev);
+
return td;
}
static void uhci_td_free(struct uhci_td *td)
{
- if (atomic_dec_and_test(&td->refcnt))
+ if (atomic_dec_and_test(&td->refcnt)) {
kmem_cache_free(uhci_td_cachep, td);
+
+ if (td->dev)
+ uhci_dec_dev_use(td->dev);
+ }
}
static struct uhci_qh *uhci_qh_alloc(struct uhci_device *dev)
@@ -332,16 +417,23 @@
qh->dev = dev;
qh->skel = NULL;
+ qh->first = NULL;
init_waitqueue_head(&qh->wakeup);
atomic_set(&qh->refcnt, 1);
+ uhci_inc_dev_use(dev);
+
return qh;
}
static void uhci_qh_free(struct uhci_qh *qh)
{
- if (atomic_dec_and_test(&qh->refcnt))
+ if (atomic_dec_and_test(&qh->refcnt)) {
kmem_cache_free(uhci_qh_cachep, qh);
+
+ if (qh->dev)
+ uhci_dec_dev_use(qh->dev);
+ }
}
/*
@@ -371,9 +463,9 @@
}
/*
- * This function removes and disallcoates all structures set up for an transfer.
+ * This function removes and disallocates all structures set up for a transfer.
* It takes the qh out of the skeleton, removes the tq and the td's.
- * It only removes the associated interrupt handler if removeirq ist set.
+ * It only removes the associated interrupt handler if removeirq is set.
* The *td argument is any td in the list of td's.
*/
static void uhci_remove_transfer(struct uhci_td *td, char removeirq)
@@ -382,10 +474,10 @@
struct uhci_td *curtd;
unsigned int nextlink;
- if (!td->qh)
- curtd = td;
+ if (td->qh && td->qh->first)
+ curtd = td->qh->first;
else
- curtd = uhci_ptr_to_virt(td->qh->element);
+ curtd = td;
/* Remove it from the skeleton */
uhci_remove_qh(td->qh->skel, td->qh);
@@ -436,7 +528,8 @@
td->link = UHCI_PTR_TERM; /* Terminate */
td->status = status; /* In */
td->info = destination | ((usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe)) - 1) << 21) |
- (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << TD_TOKEN_TOGGLE);
+ (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << TD_TOKEN_TOGGLE);
+
td->buffer = virt_to_bus(dev->data);
td->qh = qh;
td->dev = dev;
@@ -471,10 +564,6 @@
struct uhci_td *td;
struct uhci_qh *qh;
-#ifdef UHCI_DEBUG
- printk(KERN_DEBUG "usb-uhci: releasing irq handle %p\n", handle);
-#endif
-
td = (struct uhci_td *)handle;
if (!td)
return USB_ST_INTERNALERROR;
@@ -498,190 +587,327 @@
} /* uhci_release_irq() */
/*
- * Isochronous operations
+ * uhci_get_current_frame_number()
+ *
+ * returns the current frame number for a USB bus/controller.
*/
-static int uhci_compress_isochronous(struct usb_device *usb_dev, void *_isodesc)
+static int uhci_get_current_frame_number(struct usb_device *usb_dev)
{
- struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc;
- char *data = isodesc->data;
- int i, totlen = 0;
+ return inw (usb_to_uhci(usb_dev)->uhci->io_addr + USBFRNUM) & 0x3ff;
+}
- for (i = 0; i < isodesc->num; i++) {
- struct uhci_td *td = &isodesc->td[i];
- char *cdata = uhci_ptr_to_virt(td->buffer);
- int n = uhci_actual_length(td->status);
- if ((cdata != data) && (n))
- memmove(data, cdata, n);
+/*
+ * uhci_init_isoc()
+ *
+ * Checks bus bandwidth allocation for this USB bus.
+ * Allocates some data structures.
+ * Initializes parts of them from the function parameters.
+ *
+ * It does not associate any data/buffer pointers or
+ * driver (caller) callback functions with the allocated
+ * data structures. Such associations are left until
+ * uhci_run_isoc().
+ *
+ * Returns 0 for success or negative value for error.
+ * Sets isocdesc before successful return.
+ */
+static int uhci_init_isoc (struct usb_device *usb_dev,
+ unsigned int pipe,
+ int frame_count, /* bandwidth % = 100 * this / 1000 */
+ void *context,
+ struct usb_isoc_desc **isocdesc)
+{
+ struct usb_isoc_desc *id;
-#ifdef UHCI_DEBUG
- /* Debugging */
- if (uhci_status_bits(td->status))
- printk(KERN_DEBUG "error: %d %X\n", i,
- (td->status >> 16));
+#ifdef BANDWIDTH_ALLOCATION
+ /* TBD: add bandwidth allocation/checking/management HERE. */
+ /* TBD: some way to factor in frame_spacing ??? */
#endif
- data += n;
- totlen += n;
- }
-
- return totlen;
-}
+ *isocdesc = NULL;
-static int uhci_unschedule_isochronous(struct usb_device *usb_dev, void *_isodesc)
-{
- struct uhci_device *dev = usb_to_uhci(usb_dev);
- struct uhci *uhci = dev->uhci;
- struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc;
- int i;
-
- if ((isodesc->frame < 0) || (isodesc->frame > 1023)) {
- printk(KERN_ERR "illegal frame number %d\n", isodesc->frame);
- return 1;
+ /* Check some parameters. */
+ if ((frame_count < 0) || (frame_count > UHCI_NUMFRAMES)) {
+#ifdef CONFIG_USB_DEBUG_ISOC
+ printk (KERN_DEBUG "uhci_init_isoc: invalid frame_count (%d)\n",
+ frame_count);
+#endif
+ return -EINVAL;
}
- /* FIXME: Use uhci_remove_td */
-
- /* Remove from previous frames */
- for (i = 0; i < isodesc->num; i++) {
- struct uhci_td *td = &isodesc->td[i];
-
- /* Turn off Active and IOC bits */
- td->status &= ~(3 << 23);
- td->status &= ~(TD_CTRL_ACTIVE | TD_CTRL_IOC);
-
- uhci->fl->frame[(isodesc->frame + i) % 1024] = td->link;
+ if (!usb_pipeisoc (pipe)) {
+#ifdef CONFIG_USB_DEBUG_ISOC
+ printk (KERN_DEBUG "uhci_init_isoc: NOT an Isoc. pipe\n");
+#endif
+ return -EINVAL;
}
- isodesc->frame = -1;
-
- return 0;
-}
-
-/* td points to the one td we allocated for isochronous transfers */
-static int uhci_schedule_isochronous(struct usb_device *usb_dev, void *_isodesc, void *_pisodesc)
-{
- struct uhci_device *dev = usb_to_uhci(usb_dev);
- struct uhci *uhci = dev->uhci;
- struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc;
- struct uhci_iso_td *pisodesc = (struct uhci_iso_td *)_pisodesc;
- int frame, i;
-
- if (isodesc->frame != -1) {
- printk(KERN_ERR "isoc queue not removed\n");
- uhci_unschedule_isochronous(usb_dev, isodesc);
- }
-
- /* Insert TD into list */
- if (!pisodesc) {
- /* It's not guaranteed to be 1-1024 */
- frame = inw(uhci->io_addr + USBFRNUM) % 1024;
-
- /* HACK: Start 2 frames from now */
- frame = (frame + 2) % 1024;
- } else
- frame = (pisodesc->endframe + 1) % 1024;
-
- for (i = 0; i < isodesc->num; i++) {
- struct uhci_td *td = &isodesc->td[i];
+ id = kmalloc (sizeof (*id) +
+ (sizeof (struct isoc_frame_desc) * frame_count), GFP_KERNEL);
+ if (!id)
+ return -ENOMEM;
- /* Active */
- td->status |= TD_CTRL_ACTIVE;
- td->backptr = &uhci->fl->frame[(frame + i) % 1024];
- td->link = uhci->fl->frame[(frame + i) % 1024];
- uhci->fl->frame[(frame + i) % 1024] = virt_to_bus(td);
+ id->td = kmalloc (sizeof (struct uhci_td) * frame_count, GFP_KERNEL);
+ if (!id->td) {
+ kfree (id);
+ return -ENOMEM;
}
- /* IOC on the last TD */
- isodesc->td[i - 1].status |= TD_CTRL_IOC;
-
- isodesc->frame = frame;
- isodesc->endframe = (frame + isodesc->num - 1) % 1024;
+ memset (id, 0, sizeof (*id) +
+ (sizeof (struct isoc_frame_desc) * frame_count));
+ memset (id->td, 0, sizeof (struct uhci_td) * frame_count);
+
+ id->frame_count = frame_count;
+ id->frame_size = usb_maxpacket (usb_dev, pipe, usb_pipeout(pipe));
+ /* TBD: or make this a parameter to allow for frame_size
+ that is less than maxpacketsize */
+ id->start_frame = -1;
+ id->end_frame = -1;
+ id->usb_dev = usb_dev;
+ id->pipe = pipe;
+ id->context = context;
+ *isocdesc = id;
return 0;
-}
+} /* end uhci_init_isoc */
/*
- * Initialize isochronous queue
+ * uhci_run_isoc()
+ *
+ * Associates data/buffer pointers/lengths and
+ * driver (caller) callback functions with the
+ * allocated Isoc. data structures and TDs.
+ *
+ * Then inserts the TDs into the USB controller frame list
+ * for its processing.
+ * And inserts the callback function into its TD.
+ *
+ * pr_isocdesc (previous Isoc. desc.) may be NULL.
+ * It is used only for chaining one list of TDs onto the
+ * end of the previous list of TDs.
+ *
+ * Returns 0 (success) or error code (negative value).
*/
-static void *uhci_allocate_isochronous(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id)
+static int uhci_run_isoc (struct usb_isoc_desc *isocdesc,
+ struct usb_isoc_desc *pr_isocdesc)
{
- struct uhci_device *dev = usb_to_uhci(usb_dev);
- unsigned long destination, status;
- struct uhci_td *td;
- struct uhci_iso_td *isodesc;
- int i;
+ struct uhci_device *dev = usb_to_uhci (isocdesc->usb_dev);
+ struct uhci *uhci = dev->uhci;
+ unsigned long destination, status;
+ struct uhci_td *td;
+ int ix, cur_frame, pipeinput, frlen;
+ int cb_frames = 0;
+ struct isoc_frame_desc *fd;
+ unsigned char *bufptr;
+
+ if (!isocdesc->callback_fn) {
+#ifdef CONFIG_USB_DEBUG_ISOC
+ printk (KERN_DEBUG "uhci_run_isoc: caller must have a callback function\n");
+#endif
+ return -EINVAL;
+ }
- isodesc = kmalloc(sizeof(*isodesc), GFP_KERNEL);
- if (!isodesc) {
- printk(KERN_ERR "Couldn't allocate isodesc!\n");
- return NULL;
+ /* Check buffer size large enough for maxpacketsize * frame_count. */
+ if (isocdesc->buf_size < (isocdesc->frame_count * isocdesc->frame_size)) {
+#ifdef CONFIG_USB_DEBUG_ISOC
+ printk (KERN_DEBUG "uhci_init_isoc: buf_size too small (%d < %d)\n",
+ isocdesc->buf_size, isocdesc->frame_count * isocdesc->frame_size);
+#endif
+ return -EINVAL;
}
- memset(isodesc, 0, sizeof(*isodesc));
+ /* Check buffer ptr for Null. */
+ if (!isocdesc->data) {
+#ifdef CONFIG_USB_DEBUG_ISOC
+ printk (KERN_DEBUG "uhci_init_isoc: data ptr is null\n");
+#endif
+ return -EINVAL;
+ }
- /* Carefully work around the non contiguous pages */
- isodesc->num = len / maxsze;
- isodesc->td = kmalloc(sizeof(struct uhci_td) * isodesc->num, GFP_KERNEL);
- isodesc->frame = isodesc->endframe = -1;
- isodesc->data = data;
- isodesc->maxsze = maxsze;
-
- if (!isodesc->td) {
- printk(KERN_ERR "couldn't allocate td's\n");
- kfree(isodesc);
- return NULL;
+#ifdef NEED_ALIGNMENT
+ /* Check data page alignment. */
+ if (((int)(isocdesc->data) & (PAGE_SIZE - 1)) != 0) {
+#ifdef CONFIG_USB_DEBUG_ISOC
+ printk (KERN_DEBUG "uhci_init_isoc: buffer must be page-aligned (%p)\n",
+ isocdesc->data);
+#endif
+ return -EINVAL;
}
+#endif /* NEED_ALIGNMENT */
- isodesc->frame = isodesc->endframe = -1;
+ /*
+ * Check start_type unless pr_isocdesc is used.
+ */
+ if (!pr_isocdesc && (isocdesc->start_type > START_TYPE_MAX)) {
+#ifdef CONFIG_USB_DEBUG_ISOC
+ printk (KERN_DEBUG "uhci_run_isoc: invalid start_type (%d)\n",
+ isocdesc->start_type);
+#endif
+ return -EINVAL;
+ }
+
+ /* if not START_ASAP (i.e., RELATIVE or ABSOLUTE): */
+ if (!pr_isocdesc && (isocdesc->start_type != START_ASAP))
+ if ((isocdesc->start_frame < 0) || (isocdesc->start_frame > 1000)) {
+#ifdef CONFIG_USB_DEBUG_ISOC
+ printk (KERN_DEBUG "uhci_init_isoc: bad start_frame value (%d)\n",
+ isocdesc->start_frame);
+#endif
+ return -EINVAL;
+ }
/*
- * Build the DATA TD's
+ * Set the start/end frame numbers.
*/
- i = 0;
- do {
- /* Build the TD for control status */
- td = &isodesc->td[i];
+ if (!pr_isocdesc)
+ cur_frame = uhci_get_current_frame_number (isocdesc->usb_dev);
- /* The "pipe" thing contains the destination in bits 8--18 */
- destination = (pipe & PIPE_DEVEP_MASK)
- | usb_packetid (pipe); /* add IN or OUT */
+ if (pr_isocdesc) {
+ isocdesc->start_frame = pr_isocdesc->end_frame + 1;
+ } else if (isocdesc->start_type == START_ABSOLUTE) {
+ /* Use start_frame as is. */
+ } else if (isocdesc->start_type == START_RELATIVE) {
+ if (isocdesc->start_frame < START_FRAME_FUDGE)
+ isocdesc->start_frame = START_FRAME_FUDGE;
+ isocdesc->start_frame += cur_frame;
+ } else if (isocdesc->start_type == START_ASAP) {
+ isocdesc->start_frame = cur_frame + START_FRAME_FUDGE;
+ }
+
+ /* and see if start_frame needs any correction */
+ if (isocdesc->start_frame >= 1000)
+ isocdesc->start_frame -= 1000;
+
+ /* and fix the end_frame value */
+ isocdesc->end_frame = isocdesc->start_frame + isocdesc->frame_count - 1;
+ if (isocdesc->end_frame >= 1000)
+ isocdesc->end_frame -= 1000;
+
+ isocdesc->prev_completed_frame = -1;
+ isocdesc->cur_completed_frame = -1;
+
+ destination = (isocdesc->pipe & PIPE_DEVEP_MASK) |
+ usb_packetid (isocdesc->pipe);
+ status = TD_CTRL_ACTIVE | TD_CTRL_IOS; /* mark Isoc.; can't be low speed */
+ pipeinput = usb_pipein (isocdesc->pipe);
+ cur_frame = isocdesc->start_frame;
+ bufptr = isocdesc->data;
+
+ /*
+ * Build the Data TDs.
+ * TBD: Not using frame_spacing (Yet). Defaults to 1 (every frame).
+ * (frame_spacing is a way to request less bandwidth.)
+ * This can also be done by using frame_length = 0 in the
+ * frame_desc array, but this way won't take less bandwidth
+ * allocation into account.
+ */
+
+ if (isocdesc->frame_spacing <= 0)
+ isocdesc->frame_spacing = 1;
+
+ for (ix = 0, td = isocdesc->td, fd = isocdesc->frames;
+ ix < isocdesc->frame_count; ix++, td++, fd++, cur_frame++) {
+ frlen = fd->frame_length;
+ if (frlen > isocdesc->frame_size)
+ frlen = isocdesc->frame_size;
+
+#ifdef NOTDEF
+ td->info = destination | /* use Actual len on OUT; max. on IN */
+ (pipeinput ? ((isocdesc->frame_size - 1) << 21)
+ : ((frlen - 1) << 21));
+#endif
+
+ td->dev_id = isocdesc; /* can get dev_id or context from isocdesc */
+ td->status = status;
+ td->info = destination | ((frlen - 1) << 21);
+ td->buffer = virt_to_bus (bufptr);
+ td->dev = dev;
+ td->isoc_td_number = ix; /* 0-based; does not wrap 999 -> 0 */
+
+ if (isocdesc->callback_frames &&
+ (++cb_frames >= isocdesc->callback_frames)) {
+ td->status |= TD_CTRL_IOC;
+ td->completed = isocdesc->callback_fn;
+ cb_frames = 0;
+ }
- status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOS;
+ bufptr += fd->frame_length; /* or isocdesc->frame_size; */
/*
- * Build the TD for the control request
+ * Insert the TD in the frame list.
*/
- td->status = status;
- td->info = destination | ((maxsze - 1) << 21);
- td->buffer = virt_to_bus(data);
- td->backptr = NULL;
+ td->backptr = &uhci->fl->frame [cur_frame];
+ td->link = uhci->fl->frame [cur_frame];
+ uhci->fl->frame [cur_frame] = virt_to_bus (td);
+
+ if (cur_frame >= 999)
+ cur_frame = -1;
+ } /* end for ix */
- i++;
+ /*
+ * Add IOC on the last TD.
+ */
+ td--;
+ td->status |= TD_CTRL_IOC;
+ uhci_add_irq_list (dev->uhci, td, isocdesc->callback_fn, isocdesc->context); /* TBD: D.K. ??? */
- data += maxsze;
- len -= maxsze;
- } while (i < isodesc->num);
+ return 0;
+} /* end uhci_run_isoc */
- uhci_add_irq_list(dev->uhci, td, completed, dev_id);
+/*
+ * uhci_kill_isoc()
+ *
+ * Marks a TD list as Inactive and removes it from the Isoc.
+ * TD frame list.
+ *
+ * Does not free any memory resources.
+ *
+ * Returns 0 for success or negative value for error.
+ */
+static int uhci_kill_isoc (struct usb_isoc_desc *isocdesc)
+{
+ struct uhci_device *dev = usb_to_uhci (isocdesc->usb_dev);
+ struct uhci *uhci = dev->uhci;
+ struct uhci_td *td;
+ int ix, cur_frame;
- return isodesc;
-}
+ if ((isocdesc->start_frame < 0) || (isocdesc->start_frame >= 1000)) {
+#ifdef CONFIG_USB_DEBUG_ISOC
+ printk (KERN_DEBUG "uhci_kill_isoc: invalid start_frame (%d)\n",
+ isocdesc->start_frame);
+#endif
+ return -EINVAL;
+ }
+
+ for (ix = 0, td = isocdesc->td, cur_frame = isocdesc->start_frame;
+ ix < isocdesc->frame_count; ix++, td++) {
+ td->status &= ~(TD_CTRL_ACTIVE | TD_CTRL_IOC);
+ uhci->fl->frame [cur_frame] = td->link;
-static void uhci_delete_isochronous(struct usb_device *usb_dev, void *_isodesc)
+ if (++cur_frame >= 1000)
+ cur_frame = 0;
+ } /* end for ix */
+
+ isocdesc->start_frame = -1;
+ return 0;
+} /* end uhci_kill_isoc */
+
+static void uhci_free_isoc (struct usb_isoc_desc *isocdesc)
{
- struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc;
+ /* If still Active, kill it. */
+ if (isocdesc->start_frame >= 0)
+ uhci_kill_isoc (isocdesc);
- /* If it's still scheduled, unschedule them */
- if (isodesc->frame)
- uhci_unschedule_isochronous(usb_dev, isodesc);
+ /* Remove it from the IRQ list. */
+ uhci_remove_irq_list ((struct uhci_td *)&(isocdesc->td [isocdesc->frame_count - 1]));
- /* Remove it from the IRQ list */
- uhci_remove_irq_list(&isodesc->td[isodesc->num - 1]);
+ /* Free the associate memory. */
+ if (isocdesc->td)
+ kfree (isocdesc->td);
- kfree(isodesc->td);
- kfree(isodesc);
-}
+ kfree (isocdesc);
+} /* end uhci_free_isoc */
/*
* Control thread operations: we just mark the last TD
@@ -718,26 +944,6 @@
uhci_add_irq_list(dev->uhci, last, uhci_generic_completed, &qh->wakeup);
-#if 0
- /* FIXME: This is kinda kludged */
- /* Walk the TD list and update the QH pointer */
- {
- struct uhci_td *curtd;
- int count = 100;
-
- curtd = first;
- do {
- curtd->qh = ctrl_qh;
- if (curtd->link & TD_CTRL_TERM)
- break;
-
- curtd = uhci_ptr_to_virt(curtd->link);
- } while (--count);
- if (!count)
- printk(KERN_DEBUG "runaway tds!\n");
- }
-#endif
-
uhci_insert_tds_in_qh(qh, first, last);
/* Add it into the skeleton */
@@ -755,7 +961,7 @@
uhci_qh_free(qh);
- return uhci_td_result(dev, last, NULL);
+ return uhci_td_result(dev, last, NULL, 1);
}
/*
@@ -778,6 +984,11 @@
* 29 TD's is a minimum of 232 bytes worth of control
* information, that's just ridiculously high. Most
* control messages have just a few bytes of data.
+ *
+ * 232 is not ridiculously high with many of the
+ * configurations on audio devices, etc. anyway,
+ * there is no restriction on length of transfers
+ * anymore
*/
static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devrequest *cmd, void *data, int len)
{
@@ -787,12 +998,14 @@
int ret, count;
int maxsze = usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe));
__u32 nextlink;
+ unsigned long bytesrequested = len;
+ unsigned long bytesread = 0;
first = td = uhci_td_alloc(dev);
if (!td)
return -ENOMEM;
- /* The "pipe" thing contains the destination in bits 8--18. */
+ /* The "pipe" thing contains the destination in bits 8--18 */
destination = (pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
/* 3 errors */
@@ -811,7 +1024,7 @@
*/
destination ^= (USB_PID_SETUP ^ USB_PID_IN); /* SETUP -> IN */
if (usb_pipeout(pipe))
- destination ^= (USB_PID_OUT ^ USB_PID_IN); /* IN -> OUT */
+ destination ^= (USB_PID_IN ^ USB_PID_OUT); /* IN -> OUT */
prevtd = td;
td = uhci_td_alloc(dev);
@@ -851,7 +1064,13 @@
/*
* Build the final TD for control status
*/
- destination ^= (USB_PID_OUT ^ USB_PID_IN); /* OUT -> IN */
+ /* It's only IN if the pipe is out AND we aren't expecting data */
+ destination &= ~0xFF;
+ if (usb_pipeout(pipe) | (bytesrequested == 0))
+ destination |= USB_PID_IN;
+ else
+ destination |= USB_PID_OUT;
+
destination |= 1 << TD_TOKEN_TOGGLE; /* End in Data1 */
td->status = status | TD_CTRL_IOC; /* no limit on errors on final packet */
@@ -863,9 +1082,13 @@
/* Start it up.. */
ret = uhci_run_control(dev, first, td);
- count = 100;
+ count = 1000;
td = first;
do {
+ if (!uhci_status_bits(td->status) && ((td->info & 0xFF) ==
+ USB_PID_IN))
+ bytesread += uhci_actual_length(td->status);
+
nextlink = td->link;
uhci_remove_td(td);
uhci_td_free(td);
@@ -879,6 +1102,12 @@
if (!count)
printk(KERN_ERR "runaway td's!?\n");
+ if (ret && (bytesread >= bytesrequested)) {
+ printk(KERN_DEBUG "Recovered sufficient data (asked for %ld, got %ld) from failed cmd\n",
+ bytesrequested, bytesread);
+ ret = 0;
+ }
+
if (uhci_debug && ret) {
__u8 *p = (__u8 *)cmd;
@@ -911,32 +1140,12 @@
uhci_add_irq_list(dev->uhci, last, uhci_generic_completed, &qh->wakeup);
-#if 0
- /* FIXME: This is kinda kludged */
- /* Walk the TD list and update the QH pointer */
- {
- struct uhci_td *curtd;
- int count = 100;
-
- curtd = first;
- do {
- curtd->qh = bulk_qh;
- if (curtd->link & UHCI_PTR_TERM)
- break;
-
- curtd = uhci_ptr_to_virt(curtd->link);
- } while (--count);
- if (!count)
- printk(KERN_ERR "runaway tds!\n");
- }
-#endif
-
uhci_insert_tds_in_qh(qh, first, last);
/* Add it into the skeleton */
uhci_insert_qh(&dev->uhci->skel_bulk_qh, qh);
- schedule_timeout(HZ*5); /* 5 seconds */
+ schedule_timeout(HZ * 5); /* 5 seconds */
remove_wait_queue(&qh->wakeup, &wait);
@@ -947,7 +1156,7 @@
uhci_qh_free(qh);
- return uhci_td_result(dev, last, rval);
+ return uhci_td_result(dev, last, rval, 1);
}
/*
@@ -1107,82 +1316,36 @@
}
/*
- *Remove a handler from a pipe. This terminates the transfer.
- *We have some assumptions here:
+ * Remove a handler from a pipe. This terminates the transfer.
+ * We have some assumptions here:
* There is only one queue using this pipe. (the one we remove)
* Any data that is in the queue is useless for us, we throw it away.
*/
-static int uhci_terminate_bulk(struct usb_device *dev, void * first)
+static int uhci_terminate_bulk(struct usb_device *dev, void *first)
{
/* none found? there is nothing to remove! */
if (!first)
return 0;
- uhci_remove_transfer(first,1);
+ uhci_remove_transfer(first, 1);
return 1;
}
-static struct usb_device *uhci_usb_alloc(struct usb_device *parent)
-{
- struct usb_device *usb_dev;
- struct uhci_device *dev;
-
- /* Allocate the USB device */
- usb_dev = kmalloc(sizeof(*usb_dev), GFP_KERNEL);
- if (!usb_dev)
- return NULL;
-
- memset(usb_dev, 0, sizeof(*usb_dev));
-
- /* Allocate the UHCI device private data */
- dev = kmalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev) {
- kfree(usb_dev);
- return NULL;
- }
-
- /* Initialize "dev" */
- memset(dev, 0, sizeof(*dev));
-
- usb_dev->hcpriv = dev;
- dev->usb = usb_dev;
-
- usb_dev->parent = parent;
-
- if (parent) {
- usb_dev->bus = parent->bus;
- dev->uhci = usb_to_uhci(parent)->uhci;
- }
-
- return usb_dev;
-}
-
-static int uhci_usb_free(struct usb_device *usb_dev)
-{
- struct uhci_device *dev = usb_to_uhci(usb_dev);
-
- kfree(dev);
- usb_destroy_configuration(usb_dev);
- kfree(usb_dev);
-
- return 0;
-}
-
struct usb_operations uhci_device_operations = {
- uhci_usb_alloc,
- uhci_usb_free,
+ uhci_alloc_dev,
+ uhci_free_dev,
uhci_control_msg,
uhci_bulk_msg,
uhci_request_irq,
uhci_release_irq,
uhci_request_bulk,
uhci_terminate_bulk,
- uhci_allocate_isochronous,
- uhci_delete_isochronous,
- uhci_schedule_isochronous,
- uhci_unschedule_isochronous,
- uhci_compress_isochronous
+ uhci_get_current_frame_number,
+ uhci_init_isoc,
+ uhci_free_isoc,
+ uhci_run_isoc,
+ uhci_kill_isoc
};
/*
@@ -1207,7 +1370,7 @@
wait_ms(10);
status = inw(port);
- if(!(status & USBPORTSC_PE)) {
+ if (!(status & USBPORTSC_PE)) {
outw(status | USBPORTSC_PE, port); /* one more try at enabling port */
wait_ms(50);
}
@@ -1251,7 +1414,7 @@
* Ok, we got a new connection. Allocate a device to it,
* and find out what it wants to do..
*/
- usb_dev = uhci_usb_alloc(root_hub->usb);
+ usb_dev = usb_alloc_dev(root_hub->usb, root_hub->usb->bus);
if (!usb_dev)
return;
@@ -1303,6 +1466,58 @@
} while (nr < maxchild);
}
+static int fixup_isoc_desc (struct uhci_td *td)
+{
+ struct usb_isoc_desc *isocdesc = td->dev_id;
+ struct uhci_td *prtd;
+ struct isoc_frame_desc *frm;
+ int first_comp = isocdesc->cur_completed_frame + 1; /* 0-based */
+ int cur_comp = td->isoc_td_number; /* 0-based */
+ int ix, fx;
+ int num_comp;
+
+ if (first_comp >= isocdesc->frame_count)
+ first_comp = 0;
+ num_comp = cur_comp - first_comp + 1;
+
+#ifdef CONFIG_USB_DEBUG_ISOC
+ printk ("fixup_isoc_desc.1: td = %p, id = %p, first_comp = %d, cur_comp = %d, num_comp = %d\n",
+ td, isocdesc, first_comp, cur_comp, num_comp);
+#endif
+
+ for (ix = 0, fx = first_comp, prtd = &isocdesc->td [first_comp], frm = &isocdesc->frames [first_comp];
+ ix < num_comp; ix++) {
+ frm->frame_length = uhci_actual_length (prtd->status);
+ isocdesc->total_length += frm->frame_length;
+
+ if ((frm->frame_status = uhci_map_status (uhci_status_bits (prtd->status),
+ uhci_packetout (prtd->info))))
+ isocdesc->error_count++;
+
+ prtd++;
+ frm++;
+ if (++fx >= isocdesc->frame_count) { /* wrap fx, prtd, and frm */
+ fx = 0;
+ prtd = isocdesc->td;
+ frm = isocdesc->frames;
+ } /* end wrap */
+ } /* end for */
+
+ /*
+ * Update some other fields for drivers.
+ */
+ isocdesc->prev_completed_frame = isocdesc->cur_completed_frame;
+ isocdesc->cur_completed_frame = cur_comp;
+ isocdesc->total_completed_frames += num_comp; /* 1-based */
+
+#ifdef CONFIG_USB_DEBUG_ISOC
+ printk ("fixup_isoc_desc.2: total_comp_frames = %d, total_length = %d, error_count = %d\n",
+ isocdesc->total_completed_frames, isocdesc->total_length, isocdesc->error_count);
+#endif /* CONFIG_USB_DEBUG_ISOC */
+
+ return 0;
+}
+
static void uhci_interrupt_notify(struct uhci *uhci)
{
struct list_head *tmp, *head = &uhci->interrupt_list;
@@ -1311,57 +1526,43 @@
spin_lock(&irqlist_lock);
tmp = head->next;
while (tmp != head) {
- struct uhci_td *first, *td = list_entry(tmp,
- struct uhci_td, irq_list);
+ struct uhci_td *td = list_entry(tmp, struct uhci_td, irq_list);
+ unsigned long rval;
tmp = tmp->next;
- /* We check the TD which had the IOC bit as well as the */
- /* first TD */
- /* XXX: Shouldn't we check all of the TD's in the chain? */
- if ((td->qh) && (td->qh->element & ~UHCI_PTR_BITS))
- first = uhci_link_to_td(td->qh->element);
- else
- first = NULL;
-
- /* If any of the error bits are set OR the active is NOT set */
- /* then we're interested in this TD */
- status = td->status & 0xF60000;
-
- if ((!(status ^ TD_CTRL_ACTIVE)) && (first) &&
- (!(first->status & TD_CTRL_ACTIVE)))
- status = first->status & 0xF60000;
+ /* We're interested if there was an error or if the chain of */
+ /* TD's completed successfully */
+ status = uhci_td_result(td->dev, td, &rval, 0);
- if (!(status ^ TD_CTRL_ACTIVE))
+ if ((status == USB_ST_NOERROR) && (td->status & TD_CTRL_ACTIVE))
continue;
-
/* remove from IRQ list */
list_del(&td->irq_list);
INIT_LIST_HEAD(&td->irq_list);
- if (td->completed(uhci_map_status(uhci_status_bits(status), uhci_packetout(td->info)),
- bus_to_virt(td->buffer), -1, td->dev_id)) {
+ if (td->completed(status, bus_to_virt(td->buffer), rval,
+ td->dev_id)) {
+ struct usb_device *usb_dev = td->dev->usb;
+
list_add(&td->irq_list, &uhci->interrupt_list);
- /* Isochronous TD's don't need this */
- if (!(td->status & TD_CTRL_IOS)) {
- struct usb_device *usb_dev = td->dev->usb;
-
- usb_dotoggle(usb_dev, uhci_endpoint(td->info), uhci_packetout(td->info));
- td->info &= ~(1 << TD_TOKEN_TOGGLE); /* clear data toggle */
- td->info |= usb_gettoggle(usb_dev, uhci_endpoint(td->info),
- uhci_packetout(td->info)) << TD_TOKEN_TOGGLE; /* toggle between data0 and data1 */
- td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
- /* The HC removes it, so re-add it */
- uhci_insert_td_in_qh(td->qh, td);
- }
+ usb_dotoggle(usb_dev, usb_pipeendpoint(td->info), usb_pipeout(td->info) ^ 1);
+ td->info &= ~(1 << 19); /* clear data toggle */
+ td->info |= usb_gettoggle(usb_dev, usb_pipeendpoint(td->info),
+ usb_pipeout(td->info) ^ 1) << 19; /* toggle between data0 and data1 */
+ td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
+ /* The HC only removes it when it completed */
+ /* successfully, so force remove and readd it */
+ uhci_remove_td(td);
+ uhci_insert_td_in_qh(td->qh, td);
} else if (td->flags & UHCI_TD_REMOVE) {
struct usb_device *usb_dev = td->dev->usb;
/* marked for removal */
td->flags &= ~UHCI_TD_REMOVE;
- usb_dotoggle(usb_dev, uhci_endpoint(td->info), uhci_packetout(td->info));
+ usb_dotoggle(usb_dev, usb_pipeendpoint(td->info), usb_pipeout(td->info) ^ 1);
uhci_remove_qh(td->qh->skel, td->qh);
uhci_qh_free(td->qh);
uhci_td_free(td);
@@ -1406,7 +1607,8 @@
unsigned short status;
/*
- * Read the interrupt status, and write it back to clear the interrupt cause
+ * Read the interrupt status, and write it back to clear the
+ * interrupt cause
*/
status = inw(io_addr + USBSTS);
outw(status, io_addr + USBSTS);
@@ -1511,9 +1713,9 @@
* Queues are dynamically allocated for devices now,
* this code only sets up the skeleton queue
*/
-static struct uhci *alloc_uhci(unsigned int io_addr)
+static struct uhci *alloc_uhci(unsigned int io_addr, unsigned int io_size)
{
- int i;
+ int i, port;
struct uhci *uhci;
struct usb_bus *bus;
struct uhci_device *dev;
@@ -1527,6 +1729,7 @@
uhci->irq = -1;
uhci->io_addr = io_addr;
+ uhci->io_size = io_size;
INIT_LIST_HEAD(&uhci->interrupt_list);
/* We need exactly one page (per UHCI specs), how convenient */
@@ -1544,7 +1747,7 @@
/*
* Allocate the root_hub
*/
- usb = uhci_usb_alloc(NULL);
+ usb = usb_alloc_dev(NULL, bus);
if (!usb)
goto au_free_bus;
@@ -1556,10 +1759,29 @@
uhci->bus->root_hub = uhci_to_usb(dev);
/* Initialize the root hub */
+
/* UHCI specs says devices must have 2 ports, but goes on to say */
/* they may have more but give no way to determine how many they */
/* have, so default to 2 */
- usb->maxchild = 2;
+ /* According to the UHCI spec, Bit 7 is always set to 1. So we try */
+ /* to use this to our advantage */
+ for (port = 0; port < (io_size - 0x10) / 2; port++) {
+ unsigned int portstatus;
+
+ portstatus = inw(io_addr + 0x10 + (port * 2));
+ if (!(portstatus & 0x0080))
+ break;
+ }
+ printk(KERN_DEBUG "Detected %d ports\n", port);
+
+ /* This is experimental so anything less than 2 or greater than 8 is */
+ /* something weird and we'll ignore it */
+ if (port < 2 || port > 8) {
+ printk(KERN_DEBUG "Port count misdetected, forcing to 2 ports\n");
+ port = 2;
+ }
+
+ usb->maxchild = port;
usb_init_root_hub(usb);
/* 8 Interrupt queues */
@@ -1650,7 +1872,7 @@
kfree(uhci);
}
-static int uhci_control_thread(void * __uhci)
+static int uhci_control_thread(void *__uhci)
{
struct uhci *uhci = (struct uhci *)__uhci;
@@ -1693,7 +1915,7 @@
if (signr == SIGUSR1) {
printk(KERN_DEBUG "UHCI queue dump:\n");
- show_queues(uhci);
+ uhci_show_queues(uhci);
} else if (signr == SIGUSR2) {
uhci_debug = !uhci_debug;
printk(KERN_DEBUG "UHCI debug toggle = %x\n",
@@ -1716,19 +1938,19 @@
* If we've successfully found a UHCI, now is the time to increment the
* module usage count, start the control thread, and return success..
*/
-static int found_uhci(int irq, unsigned int io_addr)
+static int found_uhci(int irq, unsigned int io_addr, unsigned int io_size)
{
int retval;
struct uhci *uhci;
- uhci = alloc_uhci(io_addr);
+ uhci = alloc_uhci(io_addr, io_size);
if (!uhci)
return -ENOMEM;
INIT_LIST_HEAD(&uhci->uhci_list);
list_add(&uhci->uhci_list, &uhci_list);
- request_region(uhci->io_addr, 32, "usb-uhci");
+ request_region(uhci->io_addr, io_size, "usb-uhci");
reset_hc(uhci);
@@ -1754,7 +1976,7 @@
}
reset_hc(uhci);
- release_region(uhci->io_addr, 32);
+ release_region(uhci->io_addr, uhci->io_size);
release_uhci(uhci);
return retval;
@@ -1767,18 +1989,18 @@
/* Search for the IO base address.. */
for (i = 0; i < 6; i++) {
unsigned int io_addr = dev->resource[i].start;
+ unsigned int io_size =
+ dev->resource[i].end - dev->resource[i].start;
/* IO address? */
if (!(dev->resource[i].flags & 1))
continue;
-#if 0
/* Is it already in use? */
- if (check_region(io_addr, 32))
+ if (check_region(io_addr, io_size))
break;
-#endif
- return found_uhci(dev->irq, io_addr);
+ return found_uhci(dev->irq, io_addr, io_size);
}
return -1;
}
@@ -1819,30 +2041,15 @@
int retval;
struct pci_dev *dev = NULL;
u8 type;
- char *name;
- /* FIXME: This is lame, but I guess it's better to leak memory than */
- /* crash */
- name = kmalloc(10, GFP_KERNEL);
- if (!name)
- return -ENOMEM;
-
- strcpy(name, "uhci_td");
-
- uhci_td_cachep = kmem_cache_create(name,
+ uhci_td_cachep = kmem_cache_create("uhci_td",
sizeof(struct uhci_td), 0,
SLAB_HWCACHE_ALIGN, NULL, NULL);
if (!uhci_td_cachep)
return -ENOMEM;
- name = kmalloc(10, GFP_KERNEL);
- if (!name)
- return -ENOMEM;
-
- strcpy(name, "uhci_qh");
-
- uhci_qh_cachep = kmem_cache_create(name,
+ uhci_qh_cachep = kmem_cache_create("uhci_qh",
sizeof(struct uhci_qh), 0,
SLAB_HWCACHE_ALIGN, NULL, NULL);
@@ -1854,10 +2061,12 @@
dev = pci_find_class(PCI_CLASS_SERIAL_USB << 8, dev);
if (!dev)
break;
+
/* Is it UHCI */
pci_read_config_byte(dev, PCI_CLASS_PROG, &type);
- if(type != 0)
+ if (type != 0)
continue;
+
/* Ok set it up */
retval = start_uhci(dev);
if (retval < 0)
@@ -1889,7 +2098,8 @@
/* Check if the process is still running */
ret = kill_proc(uhci->control_pid, 0, 1);
if (!ret) {
- int count = 10;
+ /* Try a maximum of 10 seconds */
+ int count = 10 * 100;
uhci->control_continue = 0;
wake_up(&uhci_configure);
@@ -1910,7 +2120,7 @@
usb_deregister_bus(uhci->bus);
reset_hc(uhci);
- release_region(uhci->io_addr, 32);
+ release_region(uhci->io_addr, uhci->io_size);
release_uhci(uhci);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)