📄 sl811.c
字号:
PDEBUG(4, "enter, urb = %p", urb); if (usb_pipeslow(urb->pipe) && !(hc->rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED)) ctrl |= SL811_USB_CTRL_PREAMBLE; /* Build SETUP TD */ pidep = PIDEP(USB_PID_SETUP, usb_pipeendpoint(urb->pipe)); ctrl |= SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE | SL811_USB_CTRL_DIR_OUT; td = sl811_alloc_td(urb); if (!td) return -ENOMEM; sl811_fill_td(td, ctrl, SL811_DATA_START, 8, pidep, dev, urb->setup_packet); sl811_calc_td_time(td); urbp->cur_td = urbp->first_td = td; /* * If direction is "send", change the frame from SETUP (0x2D) * to OUT (0xE1). Else change it from SETUP to IN (0x69). */ pidep = PIDEP(usb_packetid(urb->pipe), usb_pipeendpoint(urb->pipe)); if (usb_pipeout(urb->pipe)) ctrl |= SL811_USB_CTRL_DIR_OUT; else ctrl &= ~SL811_USB_CTRL_DIR_OUT; /* Build the DATA TD's */ while (len > 0) { int pktsze = len; if (pktsze > maxsze) pktsze = maxsze; /* Alternate Data0/1 (start with Data1) */ ctrl ^= SL811_USB_CTRL_TOGGLE_1; td = sl811_alloc_td(urb); if (!td) return -ENOMEM; sl811_fill_td(td, ctrl, SL811_DATA_START, pktsze, pidep, dev, data); sl811_calc_td_time(td); data += pktsze; len -= pktsze; } /* Build the final TD for control status */ td = sl811_alloc_td(urb); if (!td) return -ENOMEM; /* It's IN if the pipe is an output pipe or we're not expecting data back */ if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length) { pidep = PIDEP(USB_PID_IN, usb_pipeendpoint(urb->pipe)); ctrl &= ~SL811_USB_CTRL_DIR_OUT; } else { pidep = PIDEP(USB_PID_OUT, usb_pipeendpoint(urb->pipe)); ctrl |= SL811_USB_CTRL_DIR_OUT; } /* End in Data1 */ ctrl |= SL811_USB_CTRL_TOGGLE_1; sl811_fill_td(td, ctrl, SL811_DATA_START, 0, pidep, dev, 0); sl811_calc_td_time(td); urbp->last_td = td;/* // for debug { struct list_head *head, *tmp; struct sl811_td *td; int i = 0; head = &urbp->td_list; tmp = head->next; if (list_empty(&urbp->td_list)) { PDEBUG(1, "bug!!! td list is empty!"); return -ENODEV; } while (tmp != head) { ++i; td = list_entry(tmp, struct sl811_td, td_list);// PDEBUG(3, "td = %p, i = %d", td, i); PDEBUG(1, "td = %p, i = %d", td, i); tmp = tmp->next; } }*/ PDEBUG(4, "leave success"); return 0;}/* * Result the control urb. */static void sl811_result_control(struct urb *urb){ struct list_head *tmp, *head; struct sl811_urb_priv *urbp = urb->hcpriv; struct sl811_td *td; PDEBUG(4, "enter, urb = %p", urb); if (list_empty(&urbp->td_list)) { PDEBUG(1, "td list is empty"); return ; } head = &urbp->td_list; tmp = head->next; td = list_entry(tmp, struct sl811_td, td_list); /* The first TD is the SETUP phase, check the status, but skip the count */ if (!td->done) { PDEBUG(3, "setup phase error, td = %p, done = %d", td, td->done);// printk("setup phase error, td = %p, addr = %d, dev = %d\n", td, td->addr, td->dev); goto err_done; } if (td->td_status) { PDEBUG(3, "setup phase error, td = %p, td status = %d", td, td->td_status); goto err_status; } 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 sl811_td, td_list); tmp = tmp->next; if (!td->done) { PDEBUG(3, "data phase error, td = %p, done = %d", td, td->done); goto err_done; } if (td->td_status) { PDEBUG(3, "data phase error, td = %p, td status = %d", td, td->td_status); goto err_status; } urb->actual_length += td->len - td->left; // short packet. if (td->left) { PDEBUG(3, "data phase short packet, td = %p, count = %d", td, td->len - td->left); break; } } /* The last td is status phase */ td = urbp->last_td; if (!td->done) { PDEBUG(3, "status phase error, td = %p, done = %d", td, td->done); goto err_done; } if (td->td_status) { PDEBUG(3, "status phase error, td = %p, td status = %d", td, td->td_status); goto err_status; } PDEBUG(4, "leave success"); urb->status = 0; return ;err_done: if (urbp->unlink) urb->status = -ENOENT; else { PDEBUG(1, "we should not get here! td = %p", td); urb->status = -EPIPE; } return ; err_status: urb->status = td->td_status; return ;}/* * Bulk transfers */static int sl811_submit_bulk(struct urb *urb){ int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); int len = urb->transfer_buffer_length; __u8 *data = urb->transfer_buffer; __u8 dev = usb_pipedevice(urb->pipe); __u8 pidep = PIDEP(usb_packetid(urb->pipe), usb_pipeendpoint(urb->pipe)); __u8 ctrl = 0; struct sl811_urb_priv *urbp = urb->hcpriv; struct sl811_td *td = NULL; PDEBUG(4, "enter, urb = %p", urb); if (len < 0) { PDEBUG(1, "error, urb = %p, len = %d", urb, len); return -EINVAL; } /* Can't have low speed bulk transfers */ if (usb_pipeslow(urb->pipe)) { PDEBUG(1, "error, urb = %p, low speed device", urb); return -EINVAL; } if (usb_pipeout(urb->pipe)) ctrl |= SL811_USB_CTRL_DIR_OUT; ctrl |= SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE; /* Build the DATA TD's */ do { /* Allow zero length packets */ int pktsze = len; if (pktsze > maxsze) pktsze = maxsze; td = sl811_alloc_td(urb); if (!td) return -ENOMEM; /* Alternate Data0/1 (start with Data1) */ ctrl &= ~SL811_USB_CTRL_TOGGLE_1; if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe))) ctrl |= SL811_USB_CTRL_TOGGLE_1; usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); sl811_fill_td(td, ctrl, SL811_DATA_START, pktsze, pidep, dev, data); sl811_calc_td_time(td); if (urbp->cur_td == NULL) urbp->cur_td = urbp->first_td = td; data += pktsze; len -= maxsze; } while (len > 0); /* * USB_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 & USB_ZERO_PACKET) && !len && urb->transfer_buffer_length) { td = sl811_alloc_td(urb); if (!td) return -ENOMEM; /* Alternate Data0/1 (start with Data1) */ ctrl &= ~SL811_USB_CTRL_TOGGLE_1; if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe))) ctrl |= SL811_USB_CTRL_TOGGLE_1; usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); sl811_fill_td(td, ctrl, SL811_DATA_START, 0, pidep, dev, 0); sl811_calc_td_time(td); } urbp->last_td = td; PDEBUG(4, "leave success"); return 0;}/* * Reset bulk transfers */static int sl811_reset_bulk(struct urb *urb){ struct sl811_urb_priv *urbp = urb->hcpriv; struct sl811_td *td; struct list_head *head, *tmp; PDEBUG(4, "enter, urb = %p", urb); head = &urbp->td_list; tmp = head->next; while (tmp != head) { td = list_entry(tmp, struct sl811_td, td_list); /* Alternate Data0/1 (start with Data1) */ td->ctrl &= ~SL811_USB_CTRL_TOGGLE_1; if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe))) td->ctrl |= SL811_USB_CTRL_TOGGLE_1; usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); sl811_reset_td(td); } urb->status = -EINPROGRESS; urb->actual_length = 0; urbp->cur_td = urbp->first_td; PDEBUG(4, "leave success"); return 0;}/* * Result the bulk urb. */static void sl811_result_bulk(struct urb *urb){ struct list_head *tmp, *head; struct sl811_urb_priv *urbp = urb->hcpriv; struct sl811_td *td = NULL; int toggle; PDEBUG(4, "enter, urb = %p", urb); urb->actual_length = 0; head = &urbp->td_list; tmp = head->next; while (tmp != head) { td = list_entry(tmp, struct sl811_td, td_list); tmp = tmp->next; // success. if (td->done && td->td_status == 0) { urb->actual_length += td->len - td->left; // short packet if (td->left) { urb->status = 0; PDEBUG(3, "short packet, td = %p, count = %d", td, td->len - td->left); goto reset_toggle; } } // tranfer is done but fail, reset the toggle. else if (td->done && td->td_status) { urb->status = td->td_status; PDEBUG(3, "error: td = %p, td status = %d", td, td->td_status); goto reset_toggle; } // unlink, and not do transfer yet else if (td->done == 0 && urbp->unlink && td->td_status == 0) { urb->status = -ENOENT; PDEBUG(3, "unlink and not transfer!"); return ; } // unlink, and transfer not complete yet. else if (td->done == 0 && urbp->unlink && td->td_status) { PDEBUG(3, "unlink and not complete!"); urb->status = -ENOENT; goto reset_toggle; } // must be bug!!! else {// (td->done == 0 && urbp->unlink == 0) urb->status = -EPIPE; PDEBUG(1, "we should not get here!"); return ; } } PDEBUG(4, "leave success"); urb->status = 0; return ;reset_toggle: toggle = (td->ctrl & SL811_USB_CTRL_TOGGLE_1) ? 1 : 0; usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), toggle);}/* * Find the first urb have the same dev and endpoint. */static inline int sl811_find_same_urb(struct list_head *head, struct urb *urb){ struct list_head *tmp; struct urb *u; if (!head || !urb) return 0; tmp = head->next; while (tmp != head) { u = list_entry(tmp, struct urb, urb_list); if (u == urb) return 1; tmp = tmp->next; } return 0;}/* * Find the first urb have the same dev and endpoint. */static inline struct urb* sl811_find_same_devep(struct list_head *head, struct urb *urb){ struct list_head *tmp; struct urb *u; if (!head || !urb) return NULL; tmp = head->next; while (tmp != head) { u = list_entry(tmp, struct urb, urb_list); if ((usb_pipe_endpdev(u->pipe)) == (usb_pipe_endpdev(urb->pipe))) return u; tmp = tmp->next; } return NULL;}/* * This function is called by the USB core API when an URB is available to * process. */static int sl811_submit_urb(struct urb *urb){ struct sl811_hc *hc = urb->dev->bus->hcpriv; unsigned int pipe = urb->pipe; struct list_head *head = NULL; unsigned long flags; int bustime; int ret = 0; if (!urb) { PDEBUG(1, "urb is null"); return -EINVAL; } if (urb->hcpriv) { PDEBUG(1, "urbp is not null, urb = %p, urbp = %p", urb, urb->hcpriv); return -EINVAL; } if (!urb->dev || !urb->dev->bus || !hc) { PDEBUG(1, "dev or bus or hc is null"); return -ENODEV; } if (usb_endpoint_halted(urb->dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) { PDEBUG(2, "sl811_submit_urb: endpoint_halted"); return -EPIPE; } if (usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)) > SL811_DATA_LIMIT) { printk(KERN_ERR "Packet size is big for SL811, should < %d!\n", SL811_DATA_LIMIT); return -EINVAL; } /* a request to the virtual root hub */ if (usb_pipedevice(pipe) == hc->rh.devnum) return sl811_rh_submit_urb(urb); spin_lock_irqsave(&hc->hc_lock, flags); spin_lock(&urb->lock); switch (usb_pipetype(urb->pipe)) { case PIPE_ISOCHRONOUS: head = &hc->iso_list; break; case PIPE_INTERRUPT: head = &hc->intr_list; break; case PIPE_CONTROL: head = &hc->ctrl_list; break; case PIPE_BULK: head = &hc->bulk_list; break; } if (sl811_find_same_devep(head, urb)) { list_add(&urb->urb_list, &hc->wait_list); PDEBUG(4, "add to wait list"); goto out_unlock; } if (!sl811_alloc_urb_priv(urb)) { ret = -ENOMEM; goto out_unlock; } switch (usb_pipetype(urb->pipe)) { case PIPE_ISOCHRONOUS: if (urb->number_of_packets <= 0) { ret = -EINVAL; break; } bustime = usb_check_bandwidth(urb->dev, urb); if (bustime < 0) { ret = bustime; break; } if (!(ret = sl811_submit_isochronous(urb))) usb_claim_bandwidth(urb->dev, urb, bustime, 1); break; case PIPE_INTERRUPT: bustime = usb_check_bandwidth(urb->dev, urb); if (bustime < 0) ret = bustime; else if (!(ret = sl811_submit_interrupt(urb))) usb_claim_bandwidth(urb->dev, urb, bustime, 0); break; case PIPE_CONTROL: ret = sl811_submit_control(urb); break; case PIPE_BULK: ret = sl811_submit_bulk(urb); break; } if (!ret) { ((struct sl811_urb_priv *)urb->hcpriv)->inserttime = jiffies; list_add(&urb->urb_list, head); PDEBUG(4, "add to type list"); urb->status = -EINPROGRESS; if (++hc->active_urbs == 1) sl811_enable_interrupt(hc); goto out_unlock; } else { PDEBUG(2, "submit urb fail! error = %d", ret); sl811_free_urb_priv(urb); } out_unlock: spin_unlock(&urb->lock); spin_unlock_irqrestore(&hc->hc_lock, flags); return ret;}/* * Submit the urb the wait list. */static int sl811_submit_urb_with_lock(struct urb *urb){ struct sl811_hc *hc = urb->dev->bus->hcpriv; struct list_head *head = NULL; int bustime; int ret = 0; spin_lock(&urb->lock); switch (usb_pipetype(urb->pipe)) { case PIPE_ISOCHRONOUS: head = &hc->iso_list; break; case PIPE_INTERRUPT:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -