X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;ds=sidebyside;f=drivers%2Fusb%2Fhost%2Fuhci-hcd.c;h=1e82aa7dc01ed6d22b408dcc8ad7ff2106ca6bc6;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=20a42f914684b351337324f35f678006b14bcdba;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 20a42f914..1e82aa7dc 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -46,13 +46,13 @@ #include #include #include -#include +#include #include #include #include #include +#include -#include #include #include #include @@ -74,7 +74,7 @@ Alan Stern" * debug = 0, no debugging messages * debug = 1, dump failed URB's except for stalls * debug = 2, dump all failed URB's (including stalls) - * show all queues in /proc/driver/uhci/[pci_addr] + * show all queues in /debug/uhci/[pci_addr] * debug = 3, show all TD's in URB's when dumping */ #ifdef DEBUG @@ -92,7 +92,7 @@ static char *errbuf; static kmem_cache_t *uhci_up_cachep; /* urb_priv */ -static int uhci_get_current_frame_number(struct uhci_hcd *uhci); +static unsigned int uhci_get_current_frame_number(struct uhci_hcd *uhci); static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb); static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb); static void uhci_remove_pending_urbps(struct uhci_hcd *uhci); @@ -174,7 +174,7 @@ static inline void uhci_fill_td(struct uhci_td *td, u32 status, */ static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td, unsigned framenum) { - framenum %= UHCI_NUMFRAMES; + framenum &= (UHCI_NUMFRAMES - 1); td->frame = framenum; @@ -230,42 +230,22 @@ static void uhci_remove_td(struct uhci_hcd *uhci, struct uhci_td *td) } /* - * Inserts a td into qh list at the top. + * Inserts a td list into qh. */ static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, __le32 breadth) { - struct list_head *tmp, *head; struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - struct uhci_td *td, *ptd; - - if (list_empty(&urbp->td_list)) - return; - - head = &urbp->td_list; - tmp = head->next; + struct uhci_td *td; + __le32 *plink; /* Ordering isn't important here yet since the QH hasn't been */ - /* inserted into the schedule yet */ - td = list_entry(tmp, struct uhci_td, list); - - /* Add the first TD to the QH element pointer */ - qh->element = cpu_to_le32(td->dma_handle) | breadth; - - ptd = td; - - /* Then link the rest of the TD's */ - tmp = tmp->next; - while (tmp != head) { - td = list_entry(tmp, struct uhci_td, list); - - tmp = tmp->next; - - ptd->link = cpu_to_le32(td->dma_handle) | breadth; - - ptd = td; + /* inserted into the schedule yet */ + plink = &qh->element; + list_for_each_entry(td, &urbp->td_list, list) { + *plink = cpu_to_le32(td->dma_handle) | breadth; + plink = &td->link; } - - ptd->link = UHCI_PTR_TERM; + *plink = UHCI_PTR_TERM; } static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td) @@ -330,7 +310,7 @@ static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) static void uhci_insert_qh(struct uhci_hcd *uhci, struct uhci_qh *skelqh, struct urb *urb) { struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - struct list_head *tmp; + struct urb_priv *turbp; struct uhci_qh *lqh; /* Grab the last QH */ @@ -358,12 +338,8 @@ static void uhci_insert_qh(struct uhci_hcd *uhci, struct uhci_qh *skelqh, struct */ lqh->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH; if (lqh->urbp) { - list_for_each (tmp, &lqh->urbp->queue_list) { - struct urb_priv *turbp = - list_entry(tmp, struct urb_priv, queue_list); - + list_for_each_entry(turbp, &lqh->urbp->queue_list, queue_list) turbp->qh->link = lqh->link; - } } list_add_tail(&urbp->qh->list, &skelqh->list); @@ -405,18 +381,11 @@ static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) pqh = list_entry(qh->list.prev, struct uhci_qh, list); pqh->link = newlink; if (pqh->urbp) { - struct list_head *head, *tmp; - - head = &pqh->urbp->queue_list; - tmp = head->next; - while (head != tmp) { - struct urb_priv *turbp = - list_entry(tmp, struct urb_priv, queue_list); - - tmp = tmp->next; + struct urb_priv *turbp; + list_for_each_entry(turbp, &pqh->urbp->queue_list, + queue_list) turbp->qh->link = newlink; - } } wmb(); @@ -447,21 +416,14 @@ static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) static int uhci_fixup_toggle(struct urb *urb, unsigned int toggle) { struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - struct list_head *head, *tmp; - - head = &urbp->td_list; - tmp = head->next; - while (head != tmp) { - struct uhci_td *td = list_entry(tmp, struct uhci_td, list); - - tmp = tmp->next; + struct uhci_td *td; + list_for_each_entry(td, &urbp->td_list, list) { if (toggle) td->token |= cpu_to_le32(TD_TOKEN_TOGGLE); else td->token &= ~cpu_to_le32(TD_TOKEN_TOGGLE); - toggle ^= 1; } @@ -473,30 +435,19 @@ static int uhci_fixup_toggle(struct urb *urb, unsigned int toggle) static void uhci_append_queued_urb(struct uhci_hcd *uhci, struct urb *eurb, struct urb *urb) { struct urb_priv *eurbp, *urbp, *furbp, *lurbp; - struct list_head *tmp; struct uhci_td *lltd; eurbp = eurb->hcpriv; urbp = urb->hcpriv; /* Find the first URB in the queue */ + furbp = eurbp; if (eurbp->queued) { - struct list_head *head = &eurbp->queue_list; - - tmp = head->next; - while (tmp != head) { - struct urb_priv *turbp = - list_entry(tmp, struct urb_priv, queue_list); - - if (!turbp->queued) + list_for_each_entry(furbp, &eurbp->queue_list, queue_list) + if (!furbp->queued) break; + } - tmp = tmp->next; - } - } else - tmp = &eurbp->queue_list; - - furbp = list_entry(tmp, struct urb_priv, queue_list); lurbp = list_entry(furbp->queue_list.prev, struct urb_priv, queue_list); lltd = list_entry(lurbp->td_list.prev, struct uhci_td, list); @@ -522,9 +473,7 @@ static void uhci_append_queued_urb(struct uhci_hcd *uhci, struct urb *eurb, stru static void uhci_delete_queued_urb(struct uhci_hcd *uhci, struct urb *urb) { - struct urb_priv *urbp, *nurbp; - struct list_head *head, *tmp; - struct urb_priv *purbp; + struct urb_priv *urbp, *nurbp, *purbp, *turbp; struct uhci_td *pltd; unsigned int toggle; @@ -556,14 +505,7 @@ static void uhci_delete_queued_urb(struct uhci_hcd *uhci, struct urb *urb) toggle = uhci_toggle(td_token(pltd)) ^ 1; } - head = &urbp->queue_list; - tmp = head->next; - while (head != tmp) { - struct urb_priv *turbp; - - turbp = list_entry(tmp, struct urb_priv, queue_list); - tmp = tmp->next; - + list_for_each_entry(turbp, &urbp->queue_list, queue_list) { if (!turbp->queued) break; toggle = uhci_fixup_toggle(turbp->urb, toggle); @@ -637,7 +579,7 @@ static void uhci_remove_td_from_urb(struct uhci_td *td) static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) { - struct list_head *head, *tmp; + struct uhci_td *td, *tmp; struct urb_priv *urbp; unsigned int age; @@ -660,13 +602,7 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) if (list_empty(&uhci->td_remove_list)) uhci_set_next_interrupt(uhci); - head = &urbp->td_list; - tmp = head->next; - while (tmp != head) { - struct uhci_td *td = list_entry(tmp, struct uhci_td, list); - - tmp = tmp->next; - + list_for_each_entry_safe(td, tmp, &urbp->td_list, list) { uhci_remove_td_from_urb(td); uhci_remove_td(uhci, td); list_add(&td->remove_list, &uhci->td_remove_list); @@ -701,8 +637,9 @@ static void uhci_dec_fsbr(struct uhci_hcd *uhci, struct urb *urb) /* * Map status to standard result codes * - * is (td->status & 0xF60000) [a.k.a. uhci_status_bits(td->status)] - * Note: status does not include the TD_CTRL_NAK bit. + * is (td_status(td) & 0xF60000), a.k.a. + * uhci_status_bits(td_status(td)). + * Note: does not include the TD_CTRL_NAK bit. * is True for output TDs and False for input TDs. */ static int uhci_map_status(int status, int dir_out) @@ -829,8 +766,12 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH); - /* Low-speed transfers get a different queue, and won't hog the bus */ - if (urb->dev->speed == USB_SPEED_LOW) + /* Low-speed transfers get a different queue, and won't hog the bus. + * Also, some devices enumerate better without FSBR; the easiest way + * to do that is to put URBs on the low-speed queue while the device + * is in the DEFAULT state. */ + if (urb->dev->speed == USB_SPEED_LOW || + urb->dev->state == USB_STATE_DEFAULT) skelqh = uhci->skel_ls_control_qh; else { skelqh = uhci->skel_fs_control_qh; @@ -903,21 +844,24 @@ static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb) /* The rest of the TD's (but the last) are data */ tmp = tmp->next; while (tmp != head && tmp->next != head) { - td = list_entry(tmp, struct uhci_td, list); + unsigned int ctrlstat; + td = list_entry(tmp, struct uhci_td, list); tmp = tmp->next; - status = uhci_status_bits(td_status(td)); + ctrlstat = td_status(td); + status = uhci_status_bits(ctrlstat); if (status & TD_CTRL_ACTIVE) return -EINPROGRESS; - urb->actual_length += uhci_actual_length(td_status(td)); + urb->actual_length += uhci_actual_length(ctrlstat); if (status) goto td_error; /* Check to see if we received a short packet */ - if (uhci_actual_length(td_status(td)) < uhci_expected_length(td_token(td))) { + if (uhci_actual_length(ctrlstat) < + uhci_expected_length(td_token(td))) { if (urb->transfer_flags & URB_SHORT_NOT_OK) { ret = -EREMOTEIO; goto err; @@ -1083,7 +1027,6 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb */ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb) { - struct list_head *tmp, *head; struct urb_priv *urbp = urb->hcpriv; struct uhci_td *td; unsigned int status = 0; @@ -1091,23 +1034,20 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb) urb->actual_length = 0; - head = &urbp->td_list; - tmp = head->next; - while (tmp != head) { - td = list_entry(tmp, struct uhci_td, list); - - tmp = tmp->next; + list_for_each_entry(td, &urbp->td_list, list) { + unsigned int ctrlstat = td_status(td); - status = uhci_status_bits(td_status(td)); + status = uhci_status_bits(ctrlstat); if (status & TD_CTRL_ACTIVE) return -EINPROGRESS; - urb->actual_length += uhci_actual_length(td_status(td)); + urb->actual_length += uhci_actual_length(ctrlstat); if (status) goto td_error; - if (uhci_actual_length(td_status(td)) < uhci_expected_length(td_token(td))) { + if (uhci_actual_length(ctrlstat) < + uhci_expected_length(td_token(td))) { if (urb->transfer_flags & URB_SHORT_NOT_OK) { ret = -EREMOTEIO; goto err; @@ -1176,17 +1116,12 @@ static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb, static int isochronous_find_limits(struct uhci_hcd *uhci, struct urb *urb, unsigned int *start, unsigned int *end) { struct urb *last_urb = NULL; - struct list_head *tmp, *head; + struct urb_priv *up; int ret = 0; - head = &uhci->urb_list; - tmp = head->next; - while (tmp != head) { - struct urb_priv *up = list_entry(tmp, struct urb_priv, urb_list); + list_for_each_entry(up, &uhci->urb_list, urb_list) { struct urb *u = up->urb; - tmp = tmp->next; - /* look for pending URB's with identical pipe handle */ if ((urb->pipe == u->pipe) && (urb->dev == u->dev) && (u->status == -EINPROGRESS) && (u != urb)) { @@ -1217,15 +1152,14 @@ static int isochronous_find_start(struct uhci_hcd *uhci, struct urb *urb) limits = isochronous_find_limits(uhci, urb, &start, &end); if (urb->transfer_flags & URB_ISO_ASAP) { - if (limits) { - int curframe; - - curframe = uhci_get_current_frame_number(uhci) % UHCI_NUMFRAMES; - urb->start_frame = (curframe + 10) % UHCI_NUMFRAMES; - } else + if (limits) + urb->start_frame = + (uhci_get_current_frame_number(uhci) + + 10) & (UHCI_NUMFRAMES - 1); + else urb->start_frame = end; } else { - urb->start_frame %= UHCI_NUMFRAMES; + urb->start_frame &= (UHCI_NUMFRAMES - 1); /* FIXME: Sanity check */ } @@ -1272,7 +1206,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb) static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) { - struct list_head *tmp, *head; + struct uhci_td *td; struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; int status; int i, ret = 0; @@ -1280,22 +1214,18 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) urb->actual_length = 0; i = 0; - head = &urbp->td_list; - tmp = head->next; - while (tmp != head) { - struct uhci_td *td = list_entry(tmp, struct uhci_td, list); + list_for_each_entry(td, &urbp->td_list, list) { int actlength; + unsigned int ctrlstat = td_status(td); - tmp = tmp->next; - - if (td_status(td) & TD_CTRL_ACTIVE) + if (ctrlstat & TD_CTRL_ACTIVE) return -EINPROGRESS; - actlength = uhci_actual_length(td_status(td)); + actlength = uhci_actual_length(ctrlstat); urb->iso_frame_desc[i].actual_length = actlength; urb->actual_length += actlength; - status = uhci_map_status(uhci_status_bits(td_status(td)), + status = uhci_map_status(uhci_status_bits(ctrlstat), usb_pipeout(urb->pipe)); urb->iso_frame_desc[i].status = status; if (status) { @@ -1311,20 +1241,15 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) static struct urb *uhci_find_urb_ep(struct uhci_hcd *uhci, struct urb *urb) { - struct list_head *tmp, *head; + struct urb_priv *up; /* We don't match Isoc transfers since they are special */ if (usb_pipeisoc(urb->pipe)) return NULL; - head = &uhci->urb_list; - tmp = head->next; - while (tmp != head) { - struct urb_priv *up = list_entry(tmp, struct urb_priv, urb_list); + list_for_each_entry(up, &uhci->urb_list, urb_list) { struct urb *u = up->urb; - tmp = tmp->next; - if (u->dev == urb->dev && u->status == -EINPROGRESS) { /* For control, ignore the direction */ if (usb_pipecontrol(urb->pipe) && @@ -1338,7 +1263,9 @@ static struct urb *uhci_find_urb_ep(struct uhci_hcd *uhci, struct urb *urb) return NULL; } -static int uhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, int mem_flags) +static int uhci_urb_enqueue(struct usb_hcd *hcd, + struct usb_host_endpoint *ep, + struct urb *urb, int mem_flags) { int ret; struct uhci_hcd *uhci = hcd_to_uhci(hcd); @@ -1475,9 +1402,10 @@ out: static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb) { - struct list_head *head, *tmp; + struct list_head *head; + struct uhci_td *td; struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - int prevactive = 1; + int prevactive = 0; uhci_dec_fsbr(uhci, urb); /* Safe since it checks */ @@ -1485,34 +1413,39 @@ static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb) * Now we need to find out what the last successful toggle was * so we can update the local data toggle for the next transfer * - * There's 3 way's the last successful completed TD is found: + * There are 2 ways the last successful completed TD is found: * * 1) The TD is NOT active and the actual length < expected length * 2) The TD is NOT active and it's the last TD in the chain + * + * and a third way the first uncompleted TD is found: + * * 3) The TD is active and the previous TD is NOT active * * Control and Isochronous ignore the toggle, so this is safe * for all types + * + * FIXME: The toggle fixups won't be 100% reliable until we + * change over to using a single queue for each endpoint and + * stop the queue before unlinking. */ head = &urbp->td_list; - tmp = head->next; - while (tmp != head) { - struct uhci_td *td = list_entry(tmp, struct uhci_td, list); + list_for_each_entry(td, head, list) { + unsigned int ctrlstat = td_status(td); - tmp = tmp->next; - - if (!(td_status(td) & TD_CTRL_ACTIVE) && - (uhci_actual_length(td_status(td)) < uhci_expected_length(td_token(td)) || - tmp == head)) + if (!(ctrlstat & TD_CTRL_ACTIVE) && + (uhci_actual_length(ctrlstat) < + uhci_expected_length(td_token(td)) || + td->list.next == head)) usb_settoggle(urb->dev, uhci_endpoint(td_token(td)), uhci_packetout(td_token(td)), uhci_toggle(td_token(td)) ^ 1); - else if ((td_status(td) & TD_CTRL_ACTIVE) && !prevactive) + else if ((ctrlstat & TD_CTRL_ACTIVE) && !prevactive) usb_settoggle(urb->dev, uhci_endpoint(td_token(td)), uhci_packetout(td_token(td)), uhci_toggle(td_token(td))); - prevactive = td_status(td) & TD_CTRL_ACTIVE; + prevactive = ctrlstat & TD_CTRL_ACTIVE; } uhci_delete_queued_urb(uhci, urb); @@ -1556,7 +1489,8 @@ done: static int uhci_fsbr_timeout(struct uhci_hcd *uhci, struct urb *urb) { struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - struct list_head *head, *tmp; + struct list_head *head; + struct uhci_td *td; int count = 0; uhci_dec_fsbr(uhci, urb); @@ -1570,18 +1504,14 @@ static int uhci_fsbr_timeout(struct uhci_hcd *uhci, struct urb *urb) */ head = &urbp->td_list; - tmp = head->next; - while (tmp != head) { - struct uhci_td *td = list_entry(tmp, struct uhci_td, list); - - tmp = tmp->next; - + list_for_each_entry(td, head, list) { /* * Make sure we don't do the last one (since it'll have the * TERM bit set) as well as we skip every so many TD's to * make sure it doesn't hog the bandwidth */ - if (tmp != head && (count % DEPTH_INTERVAL) == (DEPTH_INTERVAL - 1)) + if (td->list.next != head && (count % DEPTH_INTERVAL) == + (DEPTH_INTERVAL - 1)) td->link |= UHCI_PTR_DEPTH; count++; @@ -1595,7 +1525,7 @@ static int uhci_fsbr_timeout(struct uhci_hcd *uhci, struct urb *urb) * * returns the current frame number for a USB bus/controller. */ -static int uhci_get_current_frame_number(struct uhci_hcd *uhci) +static unsigned int uhci_get_current_frame_number(struct uhci_hcd *uhci) { return inw(uhci->io_addr + USBFRNUM); } @@ -1606,12 +1536,10 @@ static void stall_callback(unsigned long ptr) { struct usb_hcd *hcd = (struct usb_hcd *)ptr; struct uhci_hcd *uhci = hcd_to_uhci(hcd); - struct list_head list, *tmp, *head; + struct urb_priv *up; unsigned long flags; int called_uhci_finish_completion = 0; - INIT_LIST_HEAD(&list); - spin_lock_irqsave(&uhci->schedule_lock, flags); if (!list_empty(&uhci->urb_remove_list) && uhci_get_current_frame_number(uhci) != uhci->urb_remove_age) { @@ -1620,14 +1548,9 @@ static void stall_callback(unsigned long ptr) called_uhci_finish_completion = 1; } - head = &uhci->urb_list; - tmp = head->next; - while (tmp != head) { - struct urb_priv *up = list_entry(tmp, struct urb_priv, urb_list); + list_for_each_entry(up, &uhci->urb_list, urb_list) { struct urb *u = up->urb; - tmp = tmp->next; - spin_lock(&u->lock); /* Check if the FSBR timed out */ @@ -1642,17 +1565,6 @@ static void stall_callback(unsigned long ptr) if (called_uhci_finish_completion) wake_up_all(&uhci->waitqh); - head = &list; - tmp = head->next; - while (tmp != head) { - struct urb_priv *up = list_entry(tmp, struct urb_priv, urb_list); - struct urb *u = up->urb; - - tmp = tmp->next; - - uhci_urb_dequeue(hcd, u); - } - /* Really disable FSBR */ if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) { uhci->fsbrtimeout = 0; @@ -1661,6 +1573,8 @@ static void stall_callback(unsigned long ptr) /* Poll for and perform state transitions */ hc_state_transitions(uhci); + if (unlikely(uhci->suspended_ports && uhci->state != UHCI_SUSPENDED)) + uhci_check_resume(uhci); init_stall_timer(hcd); } @@ -1680,15 +1594,9 @@ static int init_stall_timer(struct usb_hcd *hcd) static void uhci_free_pending_qhs(struct uhci_hcd *uhci) { - struct list_head *tmp, *head; - - head = &uhci->qh_remove_list; - tmp = head->next; - while (tmp != head) { - struct uhci_qh *qh = list_entry(tmp, struct uhci_qh, remove_list); - - tmp = tmp->next; + struct uhci_qh *qh, *tmp; + list_for_each_entry_safe(qh, tmp, &uhci->qh_remove_list, remove_list) { list_del_init(&qh->remove_list); uhci_free_qh(uhci, qh); @@ -1697,22 +1605,19 @@ static void uhci_free_pending_qhs(struct uhci_hcd *uhci) static void uhci_free_pending_tds(struct uhci_hcd *uhci) { - struct list_head *tmp, *head; - - head = &uhci->td_remove_list; - tmp = head->next; - while (tmp != head) { - struct uhci_td *td = list_entry(tmp, struct uhci_td, remove_list); - - tmp = tmp->next; + struct uhci_td *td, *tmp; + list_for_each_entry_safe(td, tmp, &uhci->td_remove_list, remove_list) { list_del_init(&td->remove_list); uhci_free_td(uhci, td); } } -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) +__releases(uhci->schedule_lock) +__acquires(uhci->schedule_lock) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); @@ -1726,19 +1631,13 @@ static void uhci_finish_urb(struct usb_hcd *hcd, struct urb *urb, struct pt_regs static void uhci_finish_completion(struct usb_hcd *hcd, struct pt_regs *regs) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); - struct list_head *tmp, *head; + struct urb_priv *urbp, *tmp; - head = &uhci->complete_list; - tmp = head->next; - while (tmp != head) { - struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list); + list_for_each_entry_safe(urbp, tmp, &uhci->complete_list, urb_list) { struct urb *urb = urbp->urb; list_del_init(&urbp->urb_list); uhci_finish_urb(hcd, urb, regs); - - head = &uhci->complete_list; - tmp = head->next; } } @@ -1754,7 +1653,7 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) struct uhci_hcd *uhci = hcd_to_uhci(hcd); unsigned long io_addr = uhci->io_addr; unsigned short status; - struct list_head *tmp, *head; + struct urb_priv *urbp, *tmp; unsigned int age; /* @@ -1801,15 +1700,11 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) else uhci_set_next_interrupt(uhci); - /* Walk the list of pending URB's to see which ones completed */ - head = &uhci->urb_list; - tmp = head->next; - while (tmp != head) { - struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list); + /* Walk the list of pending URBs to see which ones completed + * (must be _safe because uhci_transfer_result() dequeues URBs) */ + list_for_each_entry_safe(urbp, tmp, &uhci->urb_list, urb_list) { struct urb *urb = urbp->urb; - tmp = tmp->next; - /* Checks the status and does all of the magic necessary */ uhci_transfer_result(uhci, urb); } @@ -1971,10 +1866,10 @@ static void hc_state_transitions(struct uhci_hcd *uhci) } } -static void start_hc(struct uhci_hcd *uhci) +static int start_hc(struct uhci_hcd *uhci) { unsigned long io_addr = uhci->io_addr; - int timeout = 1000; + int timeout = 10; /* * Reset the HC - this will force us to get a @@ -1984,10 +1879,11 @@ static void start_hc(struct uhci_hcd *uhci) */ outw(USBCMD_HCRESET, io_addr + USBCMD); while (inw(io_addr + USBCMD) & USBCMD_HCRESET) { - if (!--timeout) { + if (--timeout < 0) { dev_err(uhci_dev(uhci), "USBCMD_HCRESET timed out!\n"); - break; + return -ETIMEDOUT; } + msleep(1); } /* Turn on PIRQ and all interrupts */ @@ -2005,7 +1901,8 @@ static void start_hc(struct uhci_hcd *uhci) uhci->state_end = jiffies + HZ; outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD); - uhci->hcd.state = USB_STATE_RUNNING; + uhci_to_hcd(uhci)->state = USB_STATE_RUNNING; + return 0; } /* @@ -2042,12 +1939,10 @@ static void release_uhci(struct uhci_hcd *uhci) uhci->fl = NULL; } -#ifdef CONFIG_PROC_FS - if (uhci->proc_entry) { - remove_proc_entry(uhci->hcd.self.bus_name, uhci_proc_root); - uhci->proc_entry = NULL; + if (uhci->dentry) { + debugfs_remove(uhci->dentry); + uhci->dentry = NULL; } -#endif } static int uhci_reset(struct usb_hcd *hcd) @@ -2087,25 +1982,17 @@ static int uhci_start(struct usb_hcd *hcd) unsigned io_size; dma_addr_t dma_handle; struct usb_device *udev; -#ifdef CONFIG_PROC_FS - struct proc_dir_entry *ent; -#endif + struct dentry *dentry; io_size = pci_resource_len(to_pci_dev(uhci_dev(uhci)), hcd->region); -#ifdef CONFIG_PROC_FS - ent = create_proc_entry(hcd->self.bus_name, S_IFREG|S_IRUGO|S_IWUSR, uhci_proc_root); - if (!ent) { - dev_err(uhci_dev(uhci), "couldn't create uhci proc entry\n"); + dentry = debugfs_create_file(hcd->self.bus_name, S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root, uhci, &uhci_debug_operations); + if (!dentry) { + dev_err(uhci_dev(uhci), "couldn't create uhci debugfs entry\n"); retval = -ENOMEM; - goto err_create_proc_entry; + goto err_create_debug_entry; } - - ent->data = uhci; - ent->proc_fops = &uhci_proc_operations; - ent->size = 0; - uhci->proc_entry = ent; -#endif + uhci->dentry = dentry; uhci->fsbr = 0; uhci->fsbrtimeout = 0; @@ -2257,13 +2144,14 @@ static int uhci_start(struct usb_hcd *hcd) * the memory writes above before the I/O transfers in start_hc(). */ mb(); - start_hc(uhci); + if ((retval = start_hc(uhci)) != 0) + goto err_alloc_skelqh; init_stall_timer(hcd); udev->speed = USB_SPEED_FULL; - if (hcd_register_root(udev, &uhci->hcd) != 0) { + if (hcd_register_root(udev, hcd) != 0) { dev_err(uhci_dev(uhci), "unable to start root hub\n"); retval = -ENOMEM; goto err_start_root_hub; @@ -2306,13 +2194,10 @@ err_create_td_pool: uhci->fl = NULL; err_alloc_fl: -#ifdef CONFIG_PROC_FS - remove_proc_entry(hcd->self.bus_name, uhci_proc_root); - uhci->proc_entry = NULL; - -err_create_proc_entry: -#endif + debugfs_remove(uhci->dentry); + uhci->dentry = NULL; +err_create_debug_entry: return retval; } @@ -2363,6 +2248,7 @@ static int uhci_suspend(struct usb_hcd *hcd, u32 state) static int uhci_resume(struct usb_hcd *hcd) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); + int rc; pci_set_master(to_pci_dev(uhci_dev(uhci))); @@ -2385,69 +2271,21 @@ static int uhci_resume(struct usb_hcd *hcd) USBLEGSUP_DEFAULT); } else { reset_hc(uhci); - start_hc(uhci); + if ((rc = start_hc(uhci)) != 0) + return rc; } - uhci->hcd.state = USB_STATE_RUNNING; + hcd->state = USB_STATE_RUNNING; return 0; } #endif -static struct usb_hcd *uhci_hcd_alloc(void) -{ - struct uhci_hcd *uhci; - - uhci = (struct uhci_hcd *)kmalloc(sizeof(*uhci), GFP_KERNEL); - if (!uhci) - return NULL; - - memset(uhci, 0, sizeof(*uhci)); - uhci->hcd.product_desc = "UHCI Host Controller"; - return &uhci->hcd; -} - -static void uhci_hcd_free(struct usb_hcd *hcd) -{ - kfree(hcd_to_uhci(hcd)); -} - -/* Are there any URBs for a particular device/endpoint on a given list? */ -static int urbs_for_ep_list(struct list_head *head, - struct hcd_dev *hdev, int ep) -{ - struct urb_priv *urbp; - - list_for_each_entry(urbp, head, urb_list) { - struct urb *urb = urbp->urb; - - if (hdev == urb->dev->hcpriv && ep == - (usb_pipeendpoint(urb->pipe) | - usb_pipein(urb->pipe))) - return 1; - } - return 0; -} - -/* Are there any URBs for a particular device/endpoint? */ -static int urbs_for_ep(struct uhci_hcd *uhci, struct hcd_dev *hdev, int ep) -{ - int rc; - - spin_lock_irq(&uhci->schedule_lock); - rc = (urbs_for_ep_list(&uhci->urb_list, hdev, ep) || - urbs_for_ep_list(&uhci->complete_list, hdev, ep) || - urbs_for_ep_list(&uhci->urb_remove_list, hdev, ep)); - spin_unlock_irq(&uhci->schedule_lock); - return rc; -} - /* Wait until all the URBs for a particular device/endpoint are gone */ static void uhci_hcd_endpoint_disable(struct usb_hcd *hcd, - struct hcd_dev *hdev, int endpoint) + struct usb_host_endpoint *ep) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); - wait_event_interruptible(uhci->waitqh, - !urbs_for_ep(uhci, hdev, endpoint)); + wait_event_interruptible(uhci->waitqh, list_empty(&ep->urb_list)); } static int uhci_hcd_get_frame_number(struct usb_hcd *hcd) @@ -2459,6 +2297,8 @@ static const char hcd_name[] = "uhci_hcd"; static const struct hc_driver uhci_driver = { .description = hcd_name, + .product_desc = "UHCI Host Controller", + .hcd_priv_size = sizeof(struct uhci_hcd), /* Generic hardware linkage */ .irq = uhci_irq, @@ -2473,9 +2313,6 @@ static const struct hc_driver uhci_driver = { #endif .stop = uhci_stop, - .hcd_alloc = uhci_hcd_alloc, - .hcd_free = uhci_hcd_free, - .urb_enqueue = uhci_urb_enqueue, .urb_dequeue = uhci_urb_dequeue, @@ -2523,18 +2360,16 @@ static int __init uhci_hcd_init(void) goto errbuf_failed; } -#ifdef CONFIG_PROC_FS - uhci_proc_root = create_proc_entry("driver/uhci", S_IFDIR, NULL); - if (!uhci_proc_root) - goto proc_failed; -#endif + uhci_debugfs_root = debugfs_create_dir("uhci", NULL); + if (!uhci_debugfs_root) + goto debug_failed; uhci_up_cachep = kmem_cache_create("uhci_urb_priv", sizeof(struct urb_priv), 0, 0, NULL, NULL); if (!uhci_up_cachep) goto up_failed; - retval = pci_module_init(&uhci_pci_driver); + retval = pci_register_driver(&uhci_pci_driver); if (retval) goto init_failed; @@ -2545,12 +2380,9 @@ init_failed: warn("not all urb_priv's were freed!"); up_failed: + debugfs_remove(uhci_debugfs_root); -#ifdef CONFIG_PROC_FS - remove_proc_entry("driver/uhci", NULL); - -proc_failed: -#endif +debug_failed: if (errbuf) kfree(errbuf); @@ -2566,9 +2398,7 @@ static void __exit uhci_hcd_cleanup(void) if (kmem_cache_destroy(uhci_up_cachep)) warn("not all urb_priv's were freed!"); -#ifdef CONFIG_PROC_FS - remove_proc_entry("driver/uhci", NULL); -#endif + debugfs_remove(uhci_debugfs_root); if (errbuf) kfree(errbuf);