📄 m8xxhci.c
字号:
dump_frame_list("current", hp->current_frame); dump_frame_list("next", hp->next_frame);}/* ----- */static spinlock_t queue_lock = SPIN_LOCK_UNLOCKED;static int queues_busy;static spinlock_t txbd_list_lock = SPIN_LOCK_UNLOCKED;static int txbd_list_busy;static struct m8xxhci_qe *delay_qe_list;static int qdbg = 0;static intmap_pipe_to_qtype(int pipe){ switch (usb_pipetype(pipe)) { case PIPE_CONTROL: return Q_CTRL; case PIPE_INTERRUPT: return Q_INTR; case PIPE_BULK: return Q_BULK; case PIPE_ISOCHRONOUS: return Q_ISO; }#ifdef DEBUG_CHECKS printk("map_pipe_to_qtype(%x) -> unknown pipe type!\n", pipe);#endif return 0;}/* allocate an internal queue entry for sending frames */static struct m8xxhci_qe *allocate_qe(struct m8xxhci_device *dev, int qtype){ struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr; struct m8xxhci_qe *qe; int inuse; if (0) printk("allocate_qe(dev=%p,qtype=%d)\n", dev, qtype); qe = hp->queues[qtype]; while ((inuse = test_and_set_bit(0, &qe->inuse)) != 0 && qe < &hp->queues[qtype][M8XXHCI_MAXQE]) { qe++; }#ifdef DEBUG_CHECKS if (qe == &hp->queues[qtype][M8XXHCI_MAXQE]) inuse = 1;#endif if (!inuse) { qe->qtype = qtype; qe->qstate = 0; qe->retries = 0; qe->busys = 0; qe->recv_len = 0; qe->send_len = 0; qe->reschedule = 0; qe->shortread = 0; qe->dev = 0; qe->urb = 0; qe->iso_ptr = 0; qe->frames = 0; qe->on_frame_list = 0; INIT_LIST_HEAD(&qe->frame_list); INIT_LIST_HEAD(&qe->qe_list); init_waitqueue_head(&qe->wakeup); if (0) printk("allocate_qe(dev=%p,qtype=%d) -> %p\n", dev, qtype, qe); return(qe); } printk("m8xxhci: out of qe's for dev %p\n", dev); return(NULL);}static voiddeallocate_qe(struct m8xxhci_qe *qe){ if (0) printk("deallocate_qe(qe=%p)\n", qe); log_event(2, "deallocate_qe qe", (int)qe); clear_bit(0, &qe->inuse);}/* remove qe from pending list */static voiddequeue_qe(struct m8xxhci_qe *qe){ if (!list_empty(&qe->qe_list)) { list_del(&qe->qe_list); INIT_LIST_HEAD(&qe->qe_list); }}/* place internal queue entry at end of queue */static voidenqueue_qe(struct m8xxhci_qe *qe, int qtype){ struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr; if (0) printk("enqueue_qe(qe=%p,qtype=%d)\n", qe, qtype); INIT_LIST_HEAD(&qe->qe_list); list_add_tail(&qe->qe_list, &hp->qe_list[qtype]);}static voiddump_pending_qe_list(void){ struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr; struct list_head *head, *l; struct m8xxhci_qe *qe; unsigned long flags; int i; spin_lock_irqsave(&queue_lock, flags); for (i = 0; i < MAX_Q_TYPES; i++) { printk("qtype %d:\n", i); head = &hp->qe_list[i]; if (list_empty(head)) continue; for (l = head->next; l != head; l = l->next) { qe = list_entry(l, struct m8xxhci_qe, qe_list); printk("qe %p, next %p, urb %p, delta %d, next %p\n", qe, list_entry(&qe->qe_list.next, struct m8xxhci_qe, qe_list), qe->urb, qe->delta, qe->next); printk(" devnum %d, state %d, reschedule %d\n", qe->devnum, qe->qstate, qe->reschedule); } } spin_unlock_irqrestore(&queue_lock, flags);}/* remove qe from any list it might be on and reset qe & driver state */static voiddeactivate_qe(struct m8xxhci_qe *qe){ struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr; unsigned long flags; struct m8xxhci_qe *q = NULL; struct m8xxhci_frame *frame; spin_lock_irqsave(&queue_lock, flags); qe->qstate = 0; /* if active, reset state */ if (hp->active_qe == qe) { make_inactive_qe_idle_endpoint(qe); } /* if on current/next frame list, remove */ if (!list_empty(&qe->frame_list)) { list_del(&qe->frame_list); INIT_LIST_HEAD(&qe->frame_list); frame = qe->on_frame_list; qe->on_frame_list = 0; /* fix frame accounting */ if (frame) { frame->total_bytes -= qe->data_len; frame->bytes[qe->qtype] -= qe->data_len; /* if on a frame list, ep was marked busy */ mark_endpoint_idle(qe); } } /* if on delay list, remove */ if (delay_qe_list == qe) { delay_qe_list = qe->next; q = delay_qe_list; } else { for (q = delay_qe_list; q; q = q->next) { if (q->next == qe) { q->next = qe->next; break; } } } if (q) { q->delta += qe->delta; } spin_unlock_irqrestore(&queue_lock, flags);}static voidmake_active_qe(struct m8xxhci_qe *qe){ struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr; hp->active_qe = qe;}static voidmake_inactive_qe(struct m8xxhci_qe *qe){ struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr; hp->active_qe = 0; hp->xmit_state[qe->qtype] = XS_IDLE;}static voidmake_inactive_qe_idle_endpoint(struct m8xxhci_qe *qe){ make_inactive_qe(qe); mark_endpoint_idle(qe);}static intcomplete_qe(struct m8xxhci_qe *qe, int status){ struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr; struct urb *urb = qe->urb; log_event(1, "complete_qe qe", (int)qe); log_event(3, "complete_qe status", status); log_event(3, "complete_qe urb", (int)urb); log_event(3, "qe->qtype", qe->qtype); if (urb) log_event(3, "complete_qe urb->complete", (int)urb->complete); qe->status = status;#if 0 /*def DEBUG_CHECKS*/ if (status != 0) { if (m8xxhci_verbose > 1 || status != -1) printk("complete_qe(qe=%p,status=%d)\n", qe, status); }#endif if (urb) { urb->actual_length = usb_pipein(urb->pipe) ? qe->recv_len : qe->send_len; log_event(3, "complete_qe set status", urb->status); if (status == -1) status = USB_ST_TIMEOUT; urb->status = status; log_event(3, "complete_qe after set status", urb->status);#if 0 /* debug; turn off logging to catch last error */ if (status != 0) { logging_off(); }#endif#if 0 if (m8xxhci_verbose && status != 0) { printk("complete urb %p, " "actual_length %d, status %d\n", urb, urb->actual_length, status);// m8xxhci_dump(); }#endif /* interrupt urbs restart themselves */ switch (qe->qtype) { case Q_INTR: if (urb->interval) { qe->recv_len = 0; qe->send_len = 0; qe->retries = 0; qe->busys = 0; qe->reschedule = 1; if (urb->complete) { urb->complete(urb); hp->stats.completes[1]++; } break; } /* fall through */ default: unlink_urb(urb, qe->qtype); log_event(3, "complete_qe after unlink", (int)urb->complete);// not sure we should do this// urb->dev = NULL; if (urb->complete) { urb->complete(urb); hp->stats.completes[qe->qtype]++; } } } if (waitqueue_active(&qe->wakeup)) wake_up(&qe->wakeup); return 0;}/* abort a qe; only works if it's active or just dequeued */static voidabort_qe(struct m8xxhci_qe *qe, int status){ log_event(1, "abort_qe qe", (int)qe); deactivate_qe(qe); complete_qe(qe, status);}static voidwait_for_qe(struct m8xxhci_qe *qe){ DECLARE_WAITQUEUE (wait, current); log_event(3, "wait_for_qe qe", (int)qe); if (0) printk("wait_for_qe(qe=%p) urb=%p\n", qe, qe->urb); set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&qe->wakeup, &wait);// schedule_timeout(HZ/10); schedule_timeout(HZ); remove_wait_queue(&qe->wakeup, &wait); set_current_state(TASK_RUNNING); if (qe->status > 0) { log_event(1, "wait_for_qe timeout qe", (int)qe); if (qe->urb) printk("wait_for_qe(qe=%p) timeout; urb %p\n", qe, qe->urb); abort_qe(qe, USB_ST_NORESPONSE); } log_event(3, "wait_for_qe done qe", (int)qe); if (qe->status != 0) { if (m8xxhci_verbose > 1 || qe->status != -1) printk("wait_for_qe(qe=%p) done; urb %p, status %d\n", qe, qe->urb, qe->status); }}static intlock_queues(struct m8xxhci_private *hp){ unsigned long flags; spin_lock_irqsave(&queue_lock, flags); if (queues_busy) { spin_unlock_irqrestore(&queue_lock, flags); return -1; } queues_busy++; spin_unlock_irqrestore(&queue_lock, flags); return 0;}static voidunlock_queues(struct m8xxhci_private *hp){ unsigned long flags; spin_lock_irqsave(&queue_lock, flags); queues_busy--; spin_unlock_irqrestore(&queue_lock, flags);}static intendpoint_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 (dev->busy[io][ep]) { /* if iso, don't timeout for busy */ if (qe->qstate == QS_ISO) { return 1; } if (1) { log_event(3, "dev is busy dev", (int)dev); log_event(3, "dev is busy qe", (int)qe); log_event(3, "dev is busy io", io); } dev->busy_count[io][ep]++; if (dev->busy_count[io][ep] > MAX_EP_BUSYS) { int devnum; devnum = dev ? dev->usb->devnum : 0; if (m8xxhci_verbose) printk("m8xxhci: EXCESSIVE BUSYS " "on device %d, ep %d!\n", devnum, ep); log_event(1, "excessive busys; dnum", devnum); log_event(1, "excessive busys; ep", ep);#ifdef DEBUG_CHECKS if (0) dump_events();#endif } return 1; } } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -