123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964 |
- #include <linux/irq.h>
- #include <linux/slab.h>
- static void
- finish_urb(struct admhcd *ahcd, struct urb *urb, int status)
- __releases(ahcd->lock)
- __acquires(ahcd->lock)
- {
- urb_priv_free(ahcd, urb->hcpriv);
- if (likely(status == -EINPROGRESS))
- status = 0;
- switch (usb_pipetype(urb->pipe)) {
- case PIPE_ISOCHRONOUS:
- admhcd_to_hcd(ahcd)->self.bandwidth_isoc_reqs--;
- break;
- case PIPE_INTERRUPT:
- admhcd_to_hcd(ahcd)->self.bandwidth_int_reqs--;
- break;
- }
- #ifdef ADMHC_VERBOSE_DEBUG
- urb_print(ahcd, urb, "RET", usb_pipeout(urb->pipe), status);
- #endif
-
- usb_hcd_unlink_urb_from_ep(admhcd_to_hcd(ahcd), urb);
- spin_unlock(&ahcd->lock);
- usb_hcd_giveback_urb(admhcd_to_hcd(ahcd), urb, status);
- spin_lock(&ahcd->lock);
- }
- #if 0
- static int balance(struct admhcd *ahcd, int interval, int load)
- {
- int i, branch = -ENOSPC;
-
- if (interval > NUM_INTS)
- interval = NUM_INTS;
-
- for (i = 0; i < interval ; i++) {
- if (branch < 0 || ahcd->load[branch] > ahcd->load[i]) {
- int j;
-
- for (j = i; j < NUM_INTS; j += interval) {
- if ((ahcd->load[j] + load) > 900)
- break;
- }
- if (j < NUM_INTS)
- continue;
- branch = i;
- }
- }
- return branch;
- }
- #endif
- #if 0
- static void periodic_link(struct admhcd *ahcd, struct ed *ed)
- {
- unsigned i;
- admhc_vdbg(ahcd, "link %sed %p branch %d [%dus.], interval %d\n",
- (ed->hwINFO & cpu_to_hc32(ahcd, ED_ISO)) ? "iso " : "",
- ed, ed->branch, ed->load, ed->interval);
- for (i = ed->branch; i < NUM_INTS; i += ed->interval) {
- struct ed **prev = &ahcd->periodic[i];
- __hc32 *prev_p = &ahcd->hcca->int_table[i];
- struct ed *here = *prev;
-
- while (here && ed != here) {
- if (ed->interval > here->interval)
- break;
- prev = &here->ed_next;
- prev_p = &here->hwNextED;
- here = *prev;
- }
- if (ed != here) {
- ed->ed_next = here;
- if (here)
- ed->hwNextED = *prev_p;
- wmb();
- *prev = ed;
- *prev_p = cpu_to_hc32(ahcd, ed->dma);
- wmb();
- }
- ahcd->load[i] += ed->load;
- }
- admhcd_to_hcd(ahcd)->self.bandwidth_allocated += ed->load / ed->interval;
- }
- #endif
- static int ed_schedule(struct admhcd *ahcd, struct ed *ed)
- {
- struct ed *old_tail;
- if (admhcd_to_hcd(ahcd)->state == HC_STATE_QUIESCING)
- return -EAGAIN;
- ed->state = ED_OPER;
- old_tail = ahcd->ed_tails[ed->type];
- ed->ed_next = old_tail->ed_next;
- if (ed->ed_next) {
- ed->ed_next->ed_prev = ed;
- ed->hwNextED = cpu_to_hc32(ahcd, ed->ed_next->dma);
- }
- ed->ed_prev = old_tail;
- old_tail->ed_next = ed;
- old_tail->hwNextED = cpu_to_hc32(ahcd, ed->dma);
- ahcd->ed_tails[ed->type] = ed;
- admhc_dma_enable(ahcd);
- return 0;
- }
- #if 0
- static void periodic_unlink(struct admhcd *ahcd, struct ed *ed)
- {
- int i;
- for (i = ed->branch; i < NUM_INTS; i += ed->interval) {
- struct ed *temp;
- struct ed **prev = &ahcd->periodic[i];
- __hc32 *prev_p = &ahcd->hcca->int_table[i];
- while (*prev && (temp = *prev) != ed) {
- prev_p = &temp->hwNextED;
- prev = &temp->ed_next;
- }
- if (*prev) {
- *prev_p = ed->hwNextED;
- *prev = ed->ed_next;
- }
- ahcd->load[i] -= ed->load;
- }
- admhcd_to_hcd(ahcd)->self.bandwidth_allocated -= ed->load / ed->interval;
- admhc_vdbg(ahcd, "unlink %sed %p branch %d [%dus.], interval %d\n",
- (ed->hwINFO & cpu_to_hc32(ahcd, ED_ISO)) ? "iso " : "",
- ed, ed->branch, ed->load, ed->interval);
- }
- #endif
- static void ed_deschedule(struct admhcd *ahcd, struct ed *ed)
- {
- #ifdef ADMHC_VERBOSE_DEBUG
- admhc_dump_ed(ahcd, "ED-DESCHED", ed, 1);
- #endif
- ed->hwINFO |= cpu_to_hc32(ahcd, ED_SKIP);
- wmb();
- ed->state = ED_UNLINK;
-
- ed->ed_prev->hwNextED = ed->hwNextED;
-
- ed->ed_prev->ed_next = ed->ed_next;
- if (ed->ed_next)
- ed->ed_next->ed_prev = ed->ed_prev;
- if (ahcd->ed_tails[ed->type] == ed)
- ahcd->ed_tails[ed->type] = ed->ed_prev;
- }
- static struct ed *ed_create(struct admhcd *ahcd, unsigned int type, u32 info)
- {
- struct ed *ed;
- struct td *td;
- ed = ed_alloc(ahcd, GFP_ATOMIC);
- if (!ed)
- goto err;
-
- td = td_alloc(ahcd, GFP_ATOMIC);
- if (!td)
- goto err_free_ed;
- switch (type) {
- case PIPE_INTERRUPT:
- info |= ED_INT;
- break;
- case PIPE_ISOCHRONOUS:
- info |= ED_ISO;
- break;
- }
- ed->dummy = td;
- ed->state = ED_IDLE;
- ed->type = type;
- ed->hwINFO = cpu_to_hc32(ahcd, info);
- ed->hwTailP = cpu_to_hc32(ahcd, td->td_dma);
- ed->hwHeadP = ed->hwTailP;
- return ed;
- err_free_ed:
- ed_free(ahcd, ed);
- err:
- return NULL;
- }
- static struct ed *ed_get(struct admhcd *ahcd, struct usb_host_endpoint *ep,
- struct usb_device *udev, unsigned int pipe, int interval)
- {
- struct ed *ed;
- unsigned long flags;
- spin_lock_irqsave(&ahcd->lock, flags);
- ed = ep->hcpriv;
- if (!ed) {
- u32 info;
-
- info = usb_pipedevice(pipe);
- info |= (ep->desc.bEndpointAddress & ~USB_DIR_IN) << ED_EN_SHIFT;
- info |= le16_to_cpu(ep->desc.wMaxPacketSize) << ED_MPS_SHIFT;
- if (udev->speed == USB_SPEED_FULL)
- info |= ED_SPEED_FULL;
- ed = ed_create(ahcd, usb_pipetype(pipe), info);
- if (ed)
- ep->hcpriv = ed;
- }
- spin_unlock_irqrestore(&ahcd->lock, flags);
- return ed;
- }
- static void start_ed_unlink(struct admhcd *ahcd, struct ed *ed)
- {
- #ifdef ADMHC_VERBOSE_DEBUG
- admhc_dump_ed(ahcd, "ED-UNLINK", ed, 1);
- #endif
- ed->hwINFO |= cpu_to_hc32(ahcd, ED_DEQUEUE);
- ed_deschedule(ahcd, ed);
-
- ed->ed_rm_next = ahcd->ed_rm_list;
- ahcd->ed_rm_list = ed;
-
- admhc_intr_ack(ahcd, ADMHC_INTR_SOFI);
- admhc_intr_enable(ahcd, ADMHC_INTR_SOFI);
-
- admhc_writel_flush(ahcd);
-
- ed->tick = admhc_frame_no(ahcd) + 1;
- }
- static void
- td_fill(struct admhcd *ahcd, u32 info, dma_addr_t data, int len,
- struct urb *urb, int index)
- {
- struct td *td, *td_pt;
- struct urb_priv *urb_priv = urb->hcpriv;
- int hash;
- u32 cbl = 0;
- #if 1
- if (index == (urb_priv->td_cnt - 1) &&
- ((urb->transfer_flags & URB_NO_INTERRUPT) == 0))
- cbl |= TD_IE;
- #else
- if (index == (urb_priv->td_cnt - 1))
- cbl |= TD_IE;
- #endif
-
- td_pt = urb_priv->td[index];
-
- td = urb_priv->td[index] = urb_priv->ed->dummy;
- urb_priv->ed->dummy = td_pt;
- td->ed = urb_priv->ed;
- td->next_dl_td = NULL;
- td->index = index;
- td->urb = urb;
- td->data_dma = data;
- if (!len)
- data = 0;
- if (data)
- cbl |= (len & TD_BL_MASK);
- info |= TD_OWN;
-
- td->hwINFO = cpu_to_hc32(ahcd, info);
- td->hwDBP = cpu_to_hc32(ahcd, data);
- td->hwCBL = cpu_to_hc32(ahcd, cbl);
- td->hwNextTD = cpu_to_hc32(ahcd, td_pt->td_dma);
-
- list_add_tail(&td->td_list, &td->ed->td_list);
-
- hash = TD_HASH_FUNC(td->td_dma);
- td->td_hash = ahcd->td_hash[hash];
- ahcd->td_hash[hash] = td;
-
- wmb();
- td->ed->hwTailP = td->hwNextTD;
- }
- static void td_submit_urb(struct admhcd *ahcd, struct urb *urb)
- {
- struct urb_priv *urb_priv = urb->hcpriv;
- dma_addr_t data;
- int data_len = urb->transfer_buffer_length;
- int cnt = 0;
- u32 info = 0;
- int is_out = usb_pipeout(urb->pipe);
- u32 toggle = 0;
-
- if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), is_out)) {
- toggle = TD_T_CARRY;
- } else {
- toggle = TD_T_DATA0;
- usb_settoggle(urb->dev, usb_pipeendpoint (urb->pipe),
- is_out, 1);
- }
- urb_priv->td_idx = 0;
- list_add(&urb_priv->pending, &ahcd->pending);
- if (data_len)
- data = urb->transfer_dma;
- else
- data = 0;
-
- switch (urb_priv->ed->type) {
- case PIPE_INTERRUPT:
- info = is_out
- ? TD_T_CARRY | TD_SCC_NOTACCESSED | TD_DP_OUT
- : TD_T_CARRY | TD_SCC_NOTACCESSED | TD_DP_IN;
-
- info |= (urb->start_frame & TD_FN_MASK);
- info |= (urb->interval & TD_ISI_MASK) << TD_ISI_SHIFT;
- td_fill(ahcd, info, data, data_len, urb, cnt);
- cnt++;
- admhcd_to_hcd(ahcd)->self.bandwidth_int_reqs++;
- break;
- case PIPE_BULK:
- info = is_out
- ? TD_SCC_NOTACCESSED | TD_DP_OUT
- : TD_SCC_NOTACCESSED | TD_DP_IN;
-
- while (data_len > TD_DATALEN_MAX) {
- td_fill(ahcd, info | ((cnt) ? TD_T_CARRY : toggle),
- data, TD_DATALEN_MAX, urb, cnt);
- data += TD_DATALEN_MAX;
- data_len -= TD_DATALEN_MAX;
- cnt++;
- }
- td_fill(ahcd, info | ((cnt) ? TD_T_CARRY : toggle), data,
- data_len, urb, cnt);
- cnt++;
- if ((urb->transfer_flags & URB_ZERO_PACKET)
- && (cnt < urb_priv->td_cnt)) {
- td_fill(ahcd, info | ((cnt) ? TD_T_CARRY : toggle),
- 0, 0, urb, cnt);
- cnt++;
- }
- break;
-
- case PIPE_CONTROL:
-
- info = TD_SCC_NOTACCESSED | TD_DP_SETUP | TD_T_DATA0;
- td_fill(ahcd, info, urb->setup_dma, 8, urb, cnt++);
- if (data_len > 0) {
-
- info = TD_SCC_NOTACCESSED | TD_T_DATA1;
- info |= is_out ? TD_DP_OUT : TD_DP_IN;
-
- td_fill(ahcd, info, data, data_len, urb, cnt++);
- }
-
- info = (is_out || data_len == 0)
- ? TD_SCC_NOTACCESSED | TD_DP_IN | TD_T_DATA1
- : TD_SCC_NOTACCESSED | TD_DP_OUT | TD_T_DATA1;
- td_fill(ahcd, info, data, 0, urb, cnt++);
- break;
-
- case PIPE_ISOCHRONOUS:
- info = is_out
- ? TD_T_CARRY | TD_SCC_NOTACCESSED | TD_DP_OUT
- : TD_T_CARRY | TD_SCC_NOTACCESSED | TD_DP_IN;
- for (cnt = 0; cnt < urb->number_of_packets; cnt++) {
- int frame = urb->start_frame;
- frame += cnt * urb->interval;
- frame &= TD_FN_MASK;
- td_fill(ahcd, info | frame,
- data + urb->iso_frame_desc[cnt].offset,
- urb->iso_frame_desc[cnt].length, urb, cnt);
- }
- admhcd_to_hcd(ahcd)->self.bandwidth_isoc_reqs++;
- break;
- }
- if (urb_priv->td_cnt != cnt)
- admhc_err(ahcd, "bad number of tds created for urb %p\n", urb);
- }
- static int td_done(struct admhcd *ahcd, struct urb *urb, struct td *td)
- {
- struct urb_priv *urb_priv = urb->hcpriv;
- u32 info;
- u32 bl;
- u32 tdDBP;
- int type = usb_pipetype(urb->pipe);
- int cc;
- int status = -EINPROGRESS;
- info = hc32_to_cpup(ahcd, &td->hwINFO);
- tdDBP = hc32_to_cpup(ahcd, &td->hwDBP);
- bl = TD_BL_GET(hc32_to_cpup(ahcd, &td->hwCBL));
- cc = TD_CC_GET(info);
-
- if (type == PIPE_ISOCHRONOUS) {
-
- int dlen = 0;
-
- if (info & TD_CC)
- return status;
- if (usb_pipeout(urb->pipe))
- dlen = urb->iso_frame_desc[td->index].length;
- else {
-
- if (cc == TD_CC_DATAUNDERRUN)
- cc = TD_CC_NOERROR;
- dlen = tdDBP - td->data_dma + bl;
- }
- urb->actual_length += dlen;
- urb->iso_frame_desc[td->index].actual_length = dlen;
- urb->iso_frame_desc[td->index].status = cc_to_error[cc];
- if (cc != TD_CC_NOERROR)
- admhc_vdbg(ahcd,
- "urb %p iso td %p (%d) len %d cc %d\n",
- urb, td, 1 + td->index, dlen, cc);
-
- } else {
-
- if (cc == TD_CC_DATAUNDERRUN
- && !(urb->transfer_flags & URB_SHORT_NOT_OK))
- cc = TD_CC_NOERROR;
- if (cc != TD_CC_NOERROR && cc < TD_CC_HCD0)
- status = cc_to_error[cc];
-
- if ((type != PIPE_CONTROL || td->index != 0) && tdDBP != 0)
- urb->actual_length += tdDBP - td->data_dma + bl;
- if (cc != TD_CC_NOERROR && cc < TD_CC_HCD0)
- admhc_vdbg(ahcd,
- "urb %p td %p (%d) cc %d, len=%d/%d\n",
- urb, td, td->index, cc,
- urb->actual_length,
- urb->transfer_buffer_length);
- }
- list_del(&td->td_list);
- urb_priv->td_idx++;
- return status;
- }
- static void ed_halted(struct admhcd *ahcd, struct td *td, int cc)
- {
- struct urb *urb = td->urb;
- struct urb_priv *urb_priv = urb->hcpriv;
- struct ed *ed = td->ed;
- struct list_head *tmp = td->td_list.next;
- __hc32 toggle = ed->hwHeadP & cpu_to_hc32(ahcd, ED_C);
- admhc_dump_ed(ahcd, "ed halted", td->ed, 1);
-
- ed->hwINFO |= cpu_to_hc32(ahcd, ED_SKIP);
- wmb();
- ed->hwHeadP &= ~cpu_to_hc32(ahcd, ED_H);
-
- while (tmp != &ed->td_list) {
- struct td *next;
- next = list_entry(tmp, struct td, td_list);
- tmp = next->td_list.next;
- if (next->urb != urb)
- break;
-
- list_del(&next->td_list);
- urb_priv->td_cnt++;
- ed->hwHeadP = next->hwNextTD | toggle;
- }
-
- switch (cc) {
- case TD_CC_DATAUNDERRUN:
- if ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)
- break;
-
- case TD_CC_STALL:
- if (usb_pipecontrol(urb->pipe))
- break;
-
- default:
- admhc_dbg(ahcd,
- "urb %p path %s ep%d%s %08x cc %d --> status %d\n",
- urb, urb->dev->devpath,
- usb_pipeendpoint (urb->pipe),
- usb_pipein(urb->pipe) ? "in" : "out",
- hc32_to_cpu(ahcd, td->hwINFO),
- cc, cc_to_error[cc]);
- }
- }
- static void
- finish_unlinks(struct admhcd *ahcd, u16 tick)
- {
- struct ed *ed, **last;
- rescan_all:
- for (last = &ahcd->ed_rm_list, ed = *last; ed != NULL; ed = *last) {
- struct list_head *entry, *tmp;
- int completed, modified;
- __hc32 *prev;
-
- if (likely(HC_IS_RUNNING(admhcd_to_hcd(ahcd)->state))) {
- if (tick_before(tick, ed->tick)) {
- skip_ed:
- last = &ed->ed_rm_next;
- continue;
- }
- #if 0
- if (!list_empty(&ed->td_list)) {
- struct td *td;
- u32 head;
- td = list_entry(ed->td_list.next, struct td,
- td_list);
- head = hc32_to_cpu(ahcd, ed->hwHeadP) &
- TD_MASK;
-
- if (td->td_dma != head)
- goto skip_ed;
- }
- #endif
- }
-
- *last = ed->ed_rm_next;
- ed->ed_rm_next = NULL;
- modified = 0;
-
- rescan_this:
- completed = 0;
- prev = &ed->hwHeadP;
- list_for_each_safe(entry, tmp, &ed->td_list) {
- struct td *td;
- struct urb *urb;
- struct urb_priv *urb_priv;
- __hc32 savebits;
- u32 tdINFO;
- int status;
- td = list_entry(entry, struct td, td_list);
- urb = td->urb;
- urb_priv = td->urb->hcpriv;
- if (!urb->unlinked) {
- prev = &td->hwNextTD;
- continue;
- }
- if ((urb_priv) == NULL)
- continue;
-
- savebits = *prev & ~cpu_to_hc32(ahcd, TD_MASK);
- *prev = td->hwNextTD | savebits;
-
- tdINFO = hc32_to_cpup(ahcd, &td->hwINFO);
- if ((tdINFO & TD_T) == TD_T_DATA0)
- ed->hwHeadP &= ~cpu_to_hc32(ahcd, ED_C);
- else if ((tdINFO & TD_T) == TD_T_DATA1)
- ed->hwHeadP |= cpu_to_hc32(ahcd, ED_C);
-
- #ifdef ADMHC_VERBOSE_DEBUG
- urb_print(ahcd, urb, "PARTIAL", 0);
- #endif
- status = td_done(ahcd, urb, td);
-
- if (urb_priv->td_idx == urb_priv->td_cnt) {
- modified = completed = 1;
- finish_urb(ahcd, urb, status);
- }
- }
- if (completed && !list_empty(&ed->td_list))
- goto rescan_this;
-
- ed->state = ED_IDLE;
- ed->hwHeadP &= ~cpu_to_hc32(ahcd, ED_H);
- ed->hwNextED = 0;
- wmb();
- ed->hwINFO &= ~cpu_to_hc32(ahcd, ED_SKIP | ED_DEQUEUE);
-
- if (!list_empty(&ed->td_list)) {
- if (HC_IS_RUNNING(admhcd_to_hcd(ahcd)->state))
- ed_schedule(ahcd, ed);
- }
- if (modified)
- goto rescan_all;
- }
- }
- static void ed_unhalt(struct admhcd *ahcd, struct ed *ed, struct urb *urb)
- {
- struct list_head *entry, *tmp;
- __hc32 toggle = ed->hwHeadP & cpu_to_hc32(ahcd, ED_C);
- #ifdef ADMHC_VERBOSE_DEBUG
- admhc_dump_ed(ahcd, "UNHALT", ed, 0);
- #endif
-
- ed->hwINFO |= cpu_to_hc32(ahcd, ED_SKIP);
- wmb();
- ed->hwHeadP &= ~cpu_to_hc32(ahcd, ED_H);
- list_for_each_safe(entry, tmp, &ed->td_list) {
- struct td *td = list_entry(entry, struct td, td_list);
- __hc32 info;
- if (td->urb != urb)
- break;
- info = td->hwINFO;
- info &= ~cpu_to_hc32(ahcd, TD_CC | TD_OWN);
- td->hwINFO = info;
- ed->hwHeadP = td->hwNextTD | toggle;
- wmb();
- }
- }
- static void ed_intr_refill(struct admhcd *ahcd, struct ed *ed)
- {
- __hc32 toggle = ed->hwHeadP & cpu_to_hc32(ahcd, ED_C);
- ed->hwHeadP = ed->hwTailP | toggle;
- }
- static inline int is_ed_halted(struct admhcd *ahcd, struct ed *ed)
- {
- return ((hc32_to_cpup(ahcd, &ed->hwHeadP) & ED_H) == ED_H);
- }
- static inline int is_td_halted(struct admhcd *ahcd, struct ed *ed,
- struct td *td)
- {
- return ((hc32_to_cpup(ahcd, &ed->hwHeadP) & TD_MASK) ==
- (hc32_to_cpup(ahcd, &td->hwNextTD) & TD_MASK));
- }
- static void ed_update(struct admhcd *ahcd, struct ed *ed)
- {
- struct list_head *entry, *tmp;
- #ifdef ADMHC_VERBOSE_DEBUG
- admhc_dump_ed(ahcd, "UPDATE", ed, 1);
- #endif
- list_for_each_safe(entry, tmp, &ed->td_list) {
- struct td *td = list_entry(entry, struct td, td_list);
- struct urb *urb = td->urb;
- struct urb_priv *urb_priv = urb->hcpriv;
- int status;
- if (hc32_to_cpup(ahcd, &td->hwINFO) & TD_OWN)
- break;
-
- status = td_done(ahcd, urb, td);
- if (is_ed_halted(ahcd, ed) && is_td_halted(ahcd, ed, td))
- ed_unhalt(ahcd, ed, urb);
- if (ed->type == PIPE_INTERRUPT)
- ed_intr_refill(ahcd, ed);
-
- if (urb_priv->td_idx == urb_priv->td_cnt)
- finish_urb(ahcd, urb, status);
-
- if (list_empty(&ed->td_list)) {
- if (ed->state == ED_OPER)
- start_ed_unlink(ahcd, ed);
-
- } else if ((ed->hwINFO & cpu_to_hc32(ahcd,
- ED_SKIP | ED_DEQUEUE))
- == cpu_to_hc32(ahcd, ED_SKIP)) {
- td = list_entry(ed->td_list.next, struct td, td_list);
- #if 0
- if (!(td->hwINFO & cpu_to_hc32(ahcd, TD_DONE))) {
- ed->hwINFO &= ~cpu_to_hc32(ahcd, ED_SKIP);
-
- switch (ed->type) {
- case PIPE_CONTROL:
- admhc_writel(ahcd, OHCI_CLF,
- &ahcd->regs->cmdstatus);
- break;
- case PIPE_BULK:
- admhc_writel(ahcd, OHCI_BLF,
- &ahcd->regs->cmdstatus);
- break;
- }
- }
- #else
- if ((td->hwINFO & cpu_to_hc32(ahcd, TD_OWN)))
- ed->hwINFO &= ~cpu_to_hc32(ahcd, ED_SKIP);
- #endif
- }
- }
- }
- static void admhc_td_complete(struct admhcd *ahcd)
- {
- struct ed *ed;
- for (ed = ahcd->ed_head; ed; ed = ed->ed_next) {
- if (ed->state != ED_OPER)
- continue;
- ed_update(ahcd, ed);
- }
- }
|