📄 m8xxhci.c
字号:
static intendpoint_hung(struct m8xxhci_qe *qe){ struct m8xxhci_device *dev; int io, ep; dev = qe->dev ? usb_to_m8xxhci(qe->dev) : NULL; if (dev) { io = usb_pipein(qe->pipe) ? 0 : 1; ep = usb_pipeendpoint(qe->pipe); if (dev->busy[io][ep] && dev->busy_count[io][ep] > MAX_EP_BUSYS) { return 1; } } return 0;}static voidmark_endpoint_busy(struct m8xxhci_qe *qe){ struct m8xxhci_device *dev; int io, ep; dev = qe->dev ? usb_to_m8xxhci(qe->dev) : NULL; if (dev) { io = usb_pipein(qe->pipe) ? 0 : 1; ep = usb_pipeendpoint(qe->pipe); if (1) { log_event(3, "mark dev busy dev", (int)dev); log_event(3, "mark dev busy io", io); } dev->busy[io][ep]++; }}static voidmark_endpoint_idle(struct m8xxhci_qe *qe){ struct m8xxhci_device *dev; int io, ep; dev = qe->dev ? usb_to_m8xxhci(qe->dev) : NULL; if (dev) { io = usb_pipein(qe->pipe) ? 0 : 1; ep = usb_pipeendpoint(qe->pipe); if (1) { log_event(3, "mark dev idle dev", (int)dev); log_event(3, "mark dev idle io", io); } dev->busy[io][ep]--; if (dev->busy[io][ep] == 0) dev->busy_count[io][ep] = 0; }}/* * scan the pending work list, looking for qe's for idle endpoints * add them to the current frame's qe list and mark the device endpoint busy */static voidrun_queues(void){ struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr; struct list_head *head, *l, *next; struct m8xxhci_qe *qe; int i, j, prev_classes; /* if we can't lock, exit */ if (lock_queues(hp)) return; for (i = 0; i < MAX_Q_TYPES; i++) { /* calculate bytes in higher priority classes */ prev_classes = 0; for (j = 0; j <= i; j++) prev_classes += hp->current_frame->bytes[i]; if (0) printk("run_queues() [%d] next %p, head %p\n", i, hp->qe_list[i].next, &hp->qe_list[i]); head = &hp->qe_list[i]; /* scan pending qe's */ for (l = head->next; l != head; l = next) { qe = list_entry(l, struct m8xxhci_qe, qe_list); next = l->next; if (0) printk("top: head %p, l %p, qe %p\n", &hp->qe_list[i], l, qe); log_event(3, "run_queues qe", (int)qe); /* find ones for device endpoints which are not busy */ if (endpoint_busy(qe)) { log_event(3, "dev ep busy qe", (int)qe); log_event(3, "qstate", qe->qstate); /* if endpoint is hung, abort this qe */ if (endpoint_hung(qe)) { list_del(&qe->qe_list); INIT_LIST_HEAD(&qe->qe_list); abort_qe(qe, USB_ST_NORESPONSE); } continue; } /* don't exceed a single frame */ if (hp->current_frame->total_bytes + qe->data_len > 1400) { log_event(2, "frame full qe", (int)qe); goto done; } /* * keep iso and interrupt from exceeding 90%, * give remaining 10% to control and anything left * to bulk. * * pretty simplistic but it's a start... */ if ((prev_classes + qe->data_len) > frame_cumul_class_quota[qe->qtype]) { log_event(2, "type over quota qe", (int)qe); break; } /* ok, commit. mark ep busy and remove from list */ mark_endpoint_busy(qe); list_del(&qe->qe_list); INIT_LIST_HEAD(&qe->qe_list); if (0) log_event(3, "adding qe", (int)qe); /* and start the qe */ add_to_current_frame(qe); } } done: unlock_queues(hp);}static voiddump_delay_qe_list(void){ struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr; struct m8xxhci_qe *qe; printk("active_qe %p\n", hp->active_qe); printk("delay_qe_list %p\n", delay_qe_list); for (qe = delay_qe_list; qe; qe = qe->next) { printk("qe %p, delta %d\n", qe, qe->delta); }}/* put current qe on next frame and reset active to nil */static voidpace_qe(struct m8xxhci_qe *qe){ log_event(3, "pace qe", (int)qe); /* turn off active but don't mark ep idle - we're still using it */ make_inactive_qe(qe); add_to_next_frame(qe);}static intservice_delay_qe_list(void){ struct m8xxhci_qe *qe; /* while top one is ready, add to frame's work */ while ((qe = delay_qe_list) && qe->delta <= 0) { /* if endpoint is busy in this frame, don't */ if (endpoint_busy(qe)) { /* if endpoint is hung, abort this qe */ if (endpoint_hung(qe)) { abort_qe(qe, USB_ST_NORESPONSE); continue; } break; } /* mark endpoint busy and remove from list */ mark_endpoint_busy(qe); /* take off list */ delay_qe_list = qe->next; qe->next = 0; log_event(3, "put delay on current qe", (int)qe); /* ok, we assume this is an interrupt transaction... */ qe->qstate = QS_INTR; add_to_current_frame(qe); } return 0;}/* put qe on delay list and reset active to nil keep a time ordered list of qe's, sorted by their period (in ms) the 'delta' is the period from the last qe to the next one*/static voidreschedule_qe(struct m8xxhci_qe *qe){ struct m8xxhci_qe *qe2, *prev; int odelta, cum; struct urb *urb = qe->urb; int period = urb->interval; log_event(1, "reschedule qe", (int)qe); log_event(4, "delay ms", period); if (qdbg) printk("reschedule qe %p\n", qe); qe->busys = 0; /* if list is empty, start the list */ if (delay_qe_list == NULL){ if (qdbg) printk("first\n"); if (0) log_event(1, "first", period); delay_qe_list = qe; qe->next = 0; qe->delta = period; } else { /* find where to put this in time order */ for (qe2 = delay_qe_list, prev = 0, cum = 0; qe2; qe2 = qe2->next) { cum += qe2->delta; if (cum > period) break; prev = qe2; } if (qdbg) printk("after qe2 %p, prev %p\n", qe2, prev); /* link in front of qe2 (if there is one) */ if (qe2) { if (prev) prev->next = qe; else delay_qe_list = qe; qe->next = qe2; odelta = qe2->delta; qe2->delta = cum - period; qe->delta = odelta - qe2->delta; if (0) log_event(1, "after, delta", qe->delta); } else { prev->next = qe; qe->next = 0; qe->delta = period - cum; if (0) log_event(1, "end, delta", qe->delta); } }}static voidnak_qe(struct m8xxhci_qe *qe){ switch (qe->qtype) { case Q_INTR: /* an interrupt transaction got a NAK, reset xmit machine */ /* and try again next time */ make_inactive_qe_idle_endpoint(qe); reschedule_qe(qe); return; case Q_ISO: /* nak an iso IN; retry IN at next frame */ pace_qe(qe); break; default: /* effectively reschedule for next frame */ log_event(1, "nak, delay qe", (int)qe);#if 0 /* pace slow devices, one IN per 1ms frame */ if (usb_pipeslow(qe->pipe)) { pace_qe(qe); return; }#else pace_qe(qe);#endif break; }}/* start the next pending qe, in transaction priority order */static voidpick_next_thing_to_send(void){ struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr; struct m8xxhci_qe *qe; int i; /* if tx bd list is locked, bail out */ if (txbd_list_busy) return; /* if actively working on qe, bail out */ if (hp->active_qe != 0) {// log_event(3, "run_frame active_qe", (int)hp->active_qe); return; } /* minimalist scheduler */ for (i = 0; i < 4; i++) { /* if we're in progress, wait */ if (hp->xmit_state[i] != XS_IDLE) { log_event(3, "run_frame not idle", i); continue; } while ((qe = take_from_current_frame(i))) { log_event(3, "run_frame qe", (int)qe); switch (send_qe(qe)) { case -1: /* can't ever send this - free & exit */ abort_qe(qe, -1); goto done; break; case 1: /* send in progress, stop adding bd's */ goto done; break; case 2: /* can't send this time - retry later */ add_to_next_frame(qe); goto done; break; } } } done: ;}static voidswitch_frames(void){ struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr; struct m8xxhci_frame *tmp; if (hp->current_frame == 0) { hp->current_frame = &hp->frames[0]; hp->next_frame = &hp->frames[1]; return; }#ifdef DEBUG_CHECKS if (hp->active_qe) { log_event(3, "switch_frames; active_qe", (int)hp->active_qe); log_event(3, "active_qe->qstate", hp->active_qe->qstate); if (hp->active_qe->qstate == 0) { log_event(1, "active_qe->qstate == 0; qe", (int)hp->active_qe);// m8xxhci_dump(); } }#endif tmp = hp->current_frame; hp->current_frame = hp->next_frame; hp->next_frame = tmp;}static voidschedule_current_frame(void){ /* add any ready interrupt transactions */ service_delay_qe_list(); /* add pending who transactions */ run_queues();}#if 0/* see if we need to retransmit a failed setup */static voidretransmit_setup(void){ struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr; struct m8xxhci_qe *qe; if ((qe = hp->active_qe)) { qe->frames++; if (qe->frames > 2 && (qe->qstate == QS_SETUP || qe->qstate == QS_SETUP2)) { log_event(3, "retransmit setup", (int)qe); hp->stats.retransmit++; if (++(qe->retries) > MAX_QE_RETRIES) { abort_qe(qe, USB_ST_NORESPONSE); } else { continue_xmit(); } } return; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -