- * Control transfers
- */
-static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
-{
- struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
- struct uhci_td *td;
- struct uhci_qh *qh, *skelqh;
- unsigned long destination, status;
- int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
- int len = urb->transfer_buffer_length;
- dma_addr_t data = urb->transfer_dma;
-
- /* The "pipe" thing contains the destination in bits 8--18 */
- destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
-
- /* 3 errors */
- status = TD_CTRL_ACTIVE | uhci_maxerr(3);
- if (urb->dev->speed == USB_SPEED_LOW)
- status |= TD_CTRL_LS;
-
- /*
- * Build the TD for the control request setup packet
- */
- td = uhci_alloc_td(uhci, urb->dev);
- if (!td)
- return -ENOMEM;
-
- uhci_add_td_to_urb(urb, td);
- uhci_fill_td(td, status, destination | uhci_explen(7),
- urb->setup_dma);
-
- /*
- * If direction is "send", change the packet ID from SETUP (0x2D)
- * to OUT (0xE1). Else change it from SETUP to IN (0x69) and
- * set Short Packet Detect (SPD) for all data packets.
- */
- if (usb_pipeout(urb->pipe))
- destination ^= (USB_PID_SETUP ^ USB_PID_OUT);
- else {
- destination ^= (USB_PID_SETUP ^ USB_PID_IN);
- status |= TD_CTRL_SPD;
- }
-
- /*
- * Build the DATA TD's
- */
- while (len > 0) {
- int pktsze = len;
-
- if (pktsze > maxsze)
- pktsze = maxsze;
-
- td = uhci_alloc_td(uhci, urb->dev);
- if (!td)
- return -ENOMEM;
-
- /* Alternate Data0/1 (start with Data1) */
- destination ^= TD_TOKEN_TOGGLE;
-
- uhci_add_td_to_urb(urb, td);
- uhci_fill_td(td, status, destination | uhci_explen(pktsze - 1),
- data);
-
- data += pktsze;
- len -= pktsze;
- }
-
- /*
- * Build the final TD for control status
- */
- td = uhci_alloc_td(uhci, urb->dev);
- if (!td)
- return -ENOMEM;
-
- /*
- * It's IN if the pipe is an output pipe or we're not expecting
- * data back.
- */
- destination &= ~TD_TOKEN_PID_MASK;
- if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length)
- destination |= USB_PID_IN;
- else
- destination |= USB_PID_OUT;
-
- destination |= TD_TOKEN_TOGGLE; /* End in Data1 */
-
- status &= ~TD_CTRL_SPD;
-
- uhci_add_td_to_urb(urb, td);
- uhci_fill_td(td, status | TD_CTRL_IOC,
- destination | uhci_explen(UHCI_NULL_DATA_SIZE), 0);
-
- qh = uhci_alloc_qh(uhci, urb->dev);
- if (!qh)
- return -ENOMEM;
-
- urbp->qh = qh;
- qh->urbp = urbp;
-
- 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)
- skelqh = uhci->skel_ls_control_qh;
- else {
- skelqh = uhci->skel_fs_control_qh;
- uhci_inc_fsbr(uhci, urb);
- }
-
- if (eurb)
- uhci_append_queued_urb(uhci, eurb, urb);
- else
- uhci_insert_qh(uhci, skelqh, urb);
-
- return -EINPROGRESS;
-}
-
-/*
- * If control-IN transfer was short, the status packet wasn't sent.
- * This routine changes the element pointer in the QH to point at the
- * status TD. It's safe to do this even while the QH is live, because
- * the hardware only updates the element pointer following a successful
- * transfer. The inactive TD for the short packet won't cause an update,
- * so the pointer won't get overwritten. The next time the controller
- * sees this QH, it will send the status packet.
- */
-static int usb_control_retrigger_status(struct uhci_hcd *uhci, struct urb *urb)
-{
- struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
- struct uhci_td *td;
-
- urbp->short_control_packet = 1;
-
- td = list_entry(urbp->td_list.prev, struct uhci_td, list);
- urbp->qh->element = td->dma_handle;
-
- return -EINPROGRESS;
-}
-
-
-static int uhci_result_control(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;
- int ret = 0;
-
- if (list_empty(&urbp->td_list))
- return -EINVAL;
-
- head = &urbp->td_list;
-
- if (urbp->short_control_packet) {
- tmp = head->prev;
- goto status_stage;
- }
-
- tmp = head->next;
- td = list_entry(tmp, struct uhci_td, list);
-
- /* The first TD is the SETUP stage, check the status, but skip */
- /* the count */
- status = uhci_status_bits(td_status(td));
- if (status & TD_CTRL_ACTIVE)
- return -EINPROGRESS;
-
- if (status)
- goto td_error;
-
- urb->actual_length = 0;
-
- /* 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);
-
- tmp = tmp->next;
-
- status = uhci_status_bits(td_status(td));
- if (status & TD_CTRL_ACTIVE)
- return -EINPROGRESS;
-
- urb->actual_length += uhci_actual_length(td_status(td));
-
- 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 (urb->transfer_flags & URB_SHORT_NOT_OK) {
- ret = -EREMOTEIO;
- goto err;
- }
-
- if (uhci_packetid(td_token(td)) == USB_PID_IN)
- return usb_control_retrigger_status(uhci, urb);
- else
- return 0;
- }
- }
-
-status_stage:
- td = list_entry(tmp, struct uhci_td, list);
-
- /* Control status stage */
- status = td_status(td);
-
-#ifdef I_HAVE_BUGGY_APC_BACKUPS
- /* APC BackUPS Pro kludge */
- /* It tries to send all of the descriptor instead of the amount */
- /* we requested */
- if (status & TD_CTRL_IOC && /* IOC is masked out by uhci_status_bits */
- status & TD_CTRL_ACTIVE &&
- status & TD_CTRL_NAK)
- return 0;
-#endif
-
- status = uhci_status_bits(status);
- if (status & TD_CTRL_ACTIVE)
- return -EINPROGRESS;
-
- if (status)
- goto td_error;
-
- return 0;
-
-td_error:
- ret = uhci_map_status(status, uhci_packetout(td_token(td)));
-
-err:
- if ((debug == 1 && ret != -EPIPE) || debug > 1) {
- /* Some debugging code */
- dev_dbg(uhci_dev(uhci), "%s: failed with status %x\n",
- __FUNCTION__, status);
-
- if (errbuf) {
- /* Print the chain for debugging purposes */
- uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
-
- lprintk(errbuf);
- }
- }
-
- return ret;
-}
-
-/*
- * Common submit for bulk and interrupt
- */
-static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb, struct uhci_qh *skelqh)
-{
- struct uhci_td *td;
- struct uhci_qh *qh;
- unsigned long destination, status;
- int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
- int len = urb->transfer_buffer_length;
- struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
- dma_addr_t data = urb->transfer_dma;
-
- if (len < 0)
- return -EINVAL;
-
- /* The "pipe" thing contains the destination in bits 8--18 */
- destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
-
- status = uhci_maxerr(3) | TD_CTRL_ACTIVE;
- if (urb->dev->speed == USB_SPEED_LOW)
- status |= TD_CTRL_LS;
- if (usb_pipein(urb->pipe))
- status |= TD_CTRL_SPD;
-
- /*
- * Build the DATA TD's
- */
- do { /* Allow zero length packets */
- int pktsze = maxsze;
-
- if (pktsze >= len) {
- pktsze = len;
- if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
- status &= ~TD_CTRL_SPD;
- }
-
- td = uhci_alloc_td(uhci, urb->dev);
- if (!td)
- return -ENOMEM;
-
- uhci_add_td_to_urb(urb, td);
- uhci_fill_td(td, status, destination | uhci_explen(pktsze - 1) |
- (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
- usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
- data);
-
- data += pktsze;
- len -= maxsze;
-
- usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
- usb_pipeout(urb->pipe));
- } while (len > 0);
-
- /*
- * URB_ZERO_PACKET means adding a 0-length packet, if direction
- * is OUT and the transfer_length was an exact multiple of maxsze,
- * hence (len = transfer_length - N * maxsze) == 0
- * however, if transfer_length == 0, the zero packet was already
- * prepared above.
- */
- if (usb_pipeout(urb->pipe) && (urb->transfer_flags & URB_ZERO_PACKET) &&
- !len && urb->transfer_buffer_length) {
- td = uhci_alloc_td(uhci, urb->dev);
- if (!td)
- return -ENOMEM;
-
- uhci_add_td_to_urb(urb, td);
- uhci_fill_td(td, status, destination | uhci_explen(UHCI_NULL_DATA_SIZE) |
- (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
- usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
- data);
-
- usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
- usb_pipeout(urb->pipe));
- }
-
- /* Set the flag on the last packet */
- if (!(urb->transfer_flags & URB_NO_INTERRUPT))
- td->status |= cpu_to_le32(TD_CTRL_IOC);
-
- qh = uhci_alloc_qh(uhci, urb->dev);
- if (!qh)
- return -ENOMEM;
-
- urbp->qh = qh;
- qh->urbp = urbp;
-
- /* Always breadth first */
- uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH);
-
- if (eurb)
- uhci_append_queued_urb(uhci, eurb, urb);
- else
- uhci_insert_qh(uhci, skelqh, urb);
-
- return -EINPROGRESS;
-}
-
-/*
- * Common result for bulk and interrupt
- */
-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;
- int ret = 0;
-
- 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;
-
- status = uhci_status_bits(td_status(td));
- if (status & TD_CTRL_ACTIVE)
- return -EINPROGRESS;
-
- urb->actual_length += uhci_actual_length(td_status(td));
-
- if (status)
- goto td_error;
-
- if (uhci_actual_length(td_status(td)) < uhci_expected_length(td_token(td))) {
- if (urb->transfer_flags & URB_SHORT_NOT_OK) {
- ret = -EREMOTEIO;
- goto err;
- } else
- return 0;
- }
- }
-
- return 0;
-
-td_error:
- ret = uhci_map_status(status, uhci_packetout(td_token(td)));
- if (ret == -EPIPE)
- /* endpoint has stalled - mark it halted */
- usb_endpoint_halt(urb->dev, uhci_endpoint(td_token(td)),
- uhci_packetout(td_token(td)));
-
-err:
- /*
- * Enable this chunk of code if you want to see some more debugging.
- * But be careful, it has the tendancy to starve out khubd and prevent
- * disconnects from happening successfully if you have a slow debug
- * log interface (like a serial console.
- */
-#if 0
- if ((debug == 1 && ret != -EPIPE) || debug > 1) {
- /* Some debugging code */
- dev_dbg(uhci_dev(uhci), "%s: failed with status %x\n",
- __FUNCTION__, status);
-
- if (errbuf) {
- /* Print the chain for debugging purposes */
- uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
-
- lprintk(errbuf);
- }
- }
-#endif
- return ret;
-}
-
-static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
-{
- int ret;
-
- /* Can't have low-speed bulk transfers */
- if (urb->dev->speed == USB_SPEED_LOW)
- return -EINVAL;
-
- ret = uhci_submit_common(uhci, urb, eurb, uhci->skel_bulk_qh);
- if (ret == -EINPROGRESS)
- uhci_inc_fsbr(uhci, urb);
-
- return ret;
-}
-
-static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
-{
- /* USB 1.1 interrupt transfers only involve one packet per interval;
- * that's the uhci_submit_common() "breadth first" policy. Drivers
- * can submit urbs of any length, but longer ones might need many
- * intervals to complete.
- */
- return uhci_submit_common(uhci, urb, eurb, uhci->skelqh[__interval_to_skel(urb->interval)]);
-}
-
-/*
- * Isochronous transfers
- */
-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;
- 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);
- 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)) {
- if (!last_urb)
- *start = u->start_frame;
- last_urb = u;
- }
- }
-
- if (last_urb) {
- *end = (last_urb->start_frame + last_urb->number_of_packets *
- last_urb->interval) & (UHCI_NUMFRAMES-1);
- ret = 0;
- } else
- ret = -1; /* no previous urb found */
-
- return ret;
-}
-
-static int isochronous_find_start(struct uhci_hcd *uhci, struct urb *urb)
-{
- int limits;
- unsigned int start = 0, end = 0;
-
- if (urb->number_of_packets > 900) /* 900? Why? */
- return -EFBIG;
-
- 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
- urb->start_frame = end;
- } else {
- urb->start_frame %= UHCI_NUMFRAMES;
- /* FIXME: Sanity check */
- }
-
- return 0;
-}
-
-/*
- * Isochronous transfers
- */
-static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb)
-{
- struct uhci_td *td;
- int i, ret, frame;
- int status, destination;
-
- status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
- destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
-
- ret = isochronous_find_start(uhci, urb);
- if (ret)
- return ret;
-
- frame = urb->start_frame;
- for (i = 0; i < urb->number_of_packets; i++, frame += urb->interval) {
- if (!urb->iso_frame_desc[i].length)
- continue;
-
- td = uhci_alloc_td(uhci, urb->dev);
- if (!td)
- return -ENOMEM;
-
- uhci_add_td_to_urb(urb, td);
- uhci_fill_td(td, status, destination | uhci_explen(urb->iso_frame_desc[i].length - 1),
- urb->transfer_dma + urb->iso_frame_desc[i].offset);
-
- if (i + 1 >= urb->number_of_packets)
- td->status |= cpu_to_le32(TD_CTRL_IOC);
-
- uhci_insert_td_frame_list(uhci, td, frame);
- }
-
- return -EINPROGRESS;
-}
-
-static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
-{
- struct list_head *tmp, *head;
- struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
- int status;
- int i, ret = 0;
-
- 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);
- int actlength;
-
- tmp = tmp->next;
-
- if (td_status(td) & TD_CTRL_ACTIVE)
- return -EINPROGRESS;
-
- actlength = uhci_actual_length(td_status(td));
- urb->iso_frame_desc[i].actual_length = actlength;
- urb->actual_length += actlength;
-
- status = uhci_map_status(uhci_status_bits(td_status(td)),
- usb_pipeout(urb->pipe));
- urb->iso_frame_desc[i].status = status;
- if (status) {
- urb->error_count++;
- ret = status;
- }
-
- i++;
- }
-
- return ret;
-}
-
-static struct urb *uhci_find_urb_ep(struct uhci_hcd *uhci, struct urb *urb)
-{
- struct list_head *tmp, *head;
-
- /* 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);
- 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) &&
- (u->pipe & ~USB_DIR_IN) == (urb->pipe & ~USB_DIR_IN))
- return u;
- else if (u->pipe == urb->pipe)
- return u;
- }
- }
-
- return NULL;
-}
-
-static int uhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, int mem_flags)
-{
- int ret = -EINVAL;
- struct uhci_hcd *uhci = hcd_to_uhci(hcd);
- unsigned long flags;
- struct urb *eurb;
- int bustime;
-
- spin_lock_irqsave(&uhci->schedule_lock, flags);
-
- if (urb->status != -EINPROGRESS) /* URB already unlinked! */
- goto out;
-
- eurb = uhci_find_urb_ep(uhci, urb);
-
- if (!uhci_alloc_urb_priv(uhci, urb)) {
- ret = -ENOMEM;
- goto out;
- }
-
- switch (usb_pipetype(urb->pipe)) {
- case PIPE_CONTROL:
- ret = uhci_submit_control(uhci, urb, eurb);
- break;
- case PIPE_INTERRUPT:
- if (!eurb) {
- bustime = usb_check_bandwidth(urb->dev, urb);
- if (bustime < 0)
- ret = bustime;
- else {
- ret = uhci_submit_interrupt(uhci, urb, eurb);
- if (ret == -EINPROGRESS)
- usb_claim_bandwidth(urb->dev, urb, bustime, 0);
- }
- } else { /* inherit from parent */
- urb->bandwidth = eurb->bandwidth;
- ret = uhci_submit_interrupt(uhci, urb, eurb);
- }
- break;
- case PIPE_BULK:
- ret = uhci_submit_bulk(uhci, urb, eurb);
- break;
- case PIPE_ISOCHRONOUS:
- bustime = usb_check_bandwidth(urb->dev, urb);
- if (bustime < 0) {
- ret = bustime;
- break;
- }
-
- ret = uhci_submit_isochronous(uhci, urb);
- if (ret == -EINPROGRESS)
- usb_claim_bandwidth(urb->dev, urb, bustime, 1);
- break;
- }
-
- if (ret != -EINPROGRESS) {
- /* Submit failed, so delete it from the urb_list */
- struct urb_priv *urbp = urb->hcpriv;
-
- list_del_init(&urbp->urb_list);
- uhci_destroy_urb_priv(uhci, urb);
- } else
- ret = 0;
-
-out:
- spin_unlock_irqrestore(&uhci->schedule_lock, flags);
- return ret;
-}
-
-/*
- * Return the result of a transfer
- */
-static void uhci_transfer_result(struct uhci_hcd *uhci, struct urb *urb)
-{
- int ret = -EINPROGRESS;
- struct urb_priv *urbp;
-
- spin_lock(&urb->lock);
-
- urbp = (struct urb_priv *)urb->hcpriv;
-
- if (urb->status != -EINPROGRESS) /* URB already dequeued */
- goto out;
-
- switch (usb_pipetype(urb->pipe)) {
- case PIPE_CONTROL:
- ret = uhci_result_control(uhci, urb);
- break;
- case PIPE_BULK:
- case PIPE_INTERRUPT:
- ret = uhci_result_common(uhci, urb);
- break;
- case PIPE_ISOCHRONOUS:
- ret = uhci_result_isochronous(uhci, urb);
- break;
- }
-
- if (ret == -EINPROGRESS)
- goto out;
- urb->status = ret;
-
- switch (usb_pipetype(urb->pipe)) {
- case PIPE_CONTROL:
- case PIPE_BULK:
- case PIPE_ISOCHRONOUS:
- /* Release bandwidth for Interrupt or Isoc. transfers */
- if (urb->bandwidth)
- usb_release_bandwidth(urb->dev, urb, 1);
- uhci_unlink_generic(uhci, urb);
- break;
- case PIPE_INTERRUPT:
- /* Release bandwidth for Interrupt or Isoc. transfers */
- /* Make sure we don't release if we have a queued URB */
- if (list_empty(&urbp->queue_list) && urb->bandwidth)
- usb_release_bandwidth(urb->dev, urb, 0);
- else
- /* bandwidth was passed on to queued URB, */
- /* so don't let usb_unlink_urb() release it */
- urb->bandwidth = 0;
- uhci_unlink_generic(uhci, urb);
- break;
- default:
- dev_info(uhci_dev(uhci), "%s: unknown pipe type %d "
- "for urb %p\n",
- __FUNCTION__, usb_pipetype(urb->pipe), urb);
- }
-
- /* Move it from uhci->urb_list to uhci->complete_list */
- uhci_moveto_complete(uhci, urbp);
-
-out:
- spin_unlock(&urb->lock);
-}
-
-static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb)
-{
- struct list_head *head, *tmp;
- struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
- int prevactive = 1;
-
- uhci_dec_fsbr(uhci, urb); /* Safe since it checks */
-
- /*
- * 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:
- *
- * 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
- * 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
- */
- head = &urbp->td_list;
- tmp = head->next;
- while (tmp != head) {
- struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
-
- tmp = tmp->next;
-
- if (!(td_status(td) & TD_CTRL_ACTIVE) &&
- (uhci_actual_length(td_status(td)) < uhci_expected_length(td_token(td)) ||
- tmp == 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)
- 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;
- }
-
- uhci_delete_queued_urb(uhci, urb);
-
- /* The interrupt loop will reclaim the QH's */
- uhci_remove_qh(uhci, urbp->qh);
- urbp->qh = NULL;
-}
-
-static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
-{
- struct uhci_hcd *uhci = hcd_to_uhci(hcd);
- unsigned long flags;
- struct urb_priv *urbp;
-
- spin_lock_irqsave(&uhci->schedule_lock, flags);
- urbp = urb->hcpriv;
- if (!urbp) /* URB was never linked! */
- goto done;
- list_del_init(&urbp->urb_list);
-
- uhci_unlink_generic(uhci, urb);
-
- /* If we're the first, set the next interrupt bit */
- if (list_empty(&uhci->urb_remove_list))
- uhci_set_next_interrupt(uhci);
- list_add_tail(&urbp->urb_list, &uhci->urb_remove_list);
-
-done:
- spin_unlock_irqrestore(&uhci->schedule_lock, flags);
- return 0;
-}
-
-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;
- int count = 0;
-
- uhci_dec_fsbr(uhci, urb);
-
- urbp->fsbr_timeout = 1;
-
- /*
- * Ideally we would want to fix qh->element as well, but it's
- * read/write by the HC, so that can introduce a race. It's not
- * really worth the hassle
- */
-
- head = &urbp->td_list;
- tmp = head->next;
- while (tmp != head) {
- struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
-
- tmp = tmp->next;
-
- /*
- * 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))
- td->link |= UHCI_PTR_DEPTH;
-
- count++;
- }
-
- return 0;
-}
-
-/*
- * uhci_get_current_frame_number()
- *
- * returns the current frame number for a USB bus/controller.
- */
-static int uhci_get_current_frame_number(struct uhci_hcd *uhci)
-{
- return inw(uhci->io_addr + USBFRNUM);
-}
-
-static int init_stall_timer(struct usb_hcd *hcd);
-
-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;
- unsigned long flags;
-
- INIT_LIST_HEAD(&list);
-
- spin_lock_irqsave(&uhci->schedule_lock, flags);
- head = &uhci->urb_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;
-
- spin_lock(&u->lock);
-
- /* Check if the FSBR timed out */
- if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT))
- uhci_fsbr_timeout(uhci, u);
-
- /* Check if the URB timed out */
- if (u->timeout && u->status == -EINPROGRESS &&
- time_after_eq(jiffies, up->inserttime + u->timeout)) {
- u->status = -ETIMEDOUT;
- list_move_tail(&up->urb_list, &list);
- }
-
- spin_unlock(&u->lock);
- }
- spin_unlock_irqrestore(&uhci->schedule_lock, flags);
-
- 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;
- uhci->skel_term_qh->link = UHCI_PTR_TERM;
- }
-
- /* Poll for and perform state transitions */
- hc_state_transitions(uhci);
-
- init_stall_timer(hcd);