📄 sl811.c
字号:
case RH_GET_DESCRIPTOR | USB_TYPE_CLASS: len = sizeof(sl811_rh_hub_des); bufp = sl811_rh_hub_des; OK(len); case RH_GET_CONFIGURATION: bufp[0] = 0x01; OK(1); case RH_SET_CONFIGURATION: OK(0); default: PDEBUG(1, "unsupported root hub command"); status = -EPIPE; } len = min(len, buf_len); if (data != bufp) memcpy(data, bufp, len); urb->actual_length = len; urb->status = status; PDEBUG(5, "len = %d, status = %d", len, status); urb->hcpriv = NULL; urb->dev = NULL; if (urb->complete) urb->complete(urb); return 0;}/* * This function unlinks the URB */static int sl811_rh_unlink_urb(struct urb *urb){ struct sl811_hc *hc = urb->dev->bus->hcpriv; PDEBUG(5, "enter"); if (hc->rh.urb == urb) { hc->rh.send = 0; del_timer(&hc->rh.rh_int_timer); hc->rh.urb = NULL; urb->hcpriv = NULL; usb_dec_dev_use(urb->dev); urb->dev = NULL; if (urb->transfer_flags & USB_ASYNC_UNLINK) { urb->status = -ECONNRESET; if (urb->complete) urb->complete(urb); } else urb->status = -ENOENT; } return 0;}/* * This function connect the virtual root hub to the USB stack */static int sl811_connect_rh(struct sl811_hc * hc){ struct usb_device *usb_dev; hc->rh.devnum = 0; usb_dev = usb_alloc_dev(NULL, hc->bus); if (!usb_dev) return -ENOMEM; hc->bus->root_hub = usb_dev; usb_connect(usb_dev); if (usb_new_device(usb_dev)) { usb_free_dev(usb_dev); return -ENODEV; } PDEBUG(5, "leave success"); return 0;}/* * This function allocates private data space for the usb device */static int sl811_alloc_dev_priv(struct usb_device *usb_dev){ return 0;}/* * This function de-allocates private data space for the usb devic */static int sl811_free_dev_priv (struct usb_device *usb_dev){ return 0;}/* * This function allocates private data space for the urb */static struct sl811_urb_priv* sl811_alloc_urb_priv(struct urb *urb){ struct sl811_urb_priv *urbp; urbp = kmalloc(sizeof(*urbp), GFP_KERNEL); if (!urbp) return NULL; memset(urbp, 0, sizeof(*urbp)); INIT_LIST_HEAD(&urbp->td_list); urbp->urb = urb; urb->hcpriv = urbp; return urbp;}/* * This function free private data space for the urb */static void sl811_free_urb_priv(struct urb *urb){ struct sl811_urb_priv *urbp = urb->hcpriv; struct sl811_td *td; struct list_head *head, *tmp; if (!urbp) return ; head = &urbp->td_list; tmp = head->next; while (tmp != head) { td = list_entry(tmp, struct sl811_td, td_list); tmp = tmp->next; kfree(td); } kfree(urbp); urb->hcpriv = NULL; return ;}/* * This function calculate the bus time need by this td. * Fix me! Can this use usb_calc_bus_time()? */static void sl811_calc_td_time(struct sl811_td *td){#if 1 int time; int len = td->len; struct sl811_hc *hc = td->urb->dev->bus->hcpriv; if (hc->rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED) time = 8*8*len + 1024; else { if (td->ctrl & SL811_USB_CTRL_PREAMBLE) time = 8*8*len + 2048; else time = 8*len + 256; } time += 2*10 * len; td->bustime = time; #else unsigned long tmp; int time; int low_speed = usb_pipeslow(td->urb->pipe); int input_dir = usb_pipein(td->urb->pipe); int bytecount = td->len; int isoc = usb_pipeisoc(td->urb->pipe); if (low_speed) { /* no isoc. here */ if (input_dir) { tmp = (67667L * (31L + 10L * BitTime (bytecount))) / 1000L; time = (64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp); } else { tmp = (66700L * (31L + 10L * BitTime (bytecount))) / 1000L; time = (64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp); } } else if (!isoc){ /* for full-speed: */ tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L; time = (9107L + BW_HOST_DELAY + tmp); } else { /* for isoc: */ tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L; time = (((input_dir) ? 7268L : 6265L) + BW_HOST_DELAY + tmp); } td->bustime = time / 84;#endif }/* * This function calculate the remainder bus time in current frame. */static inline int sl811_calc_bus_remainder(struct sl811_hc *hc){ return (sl811_read(hc, SL811_SOFCNTDIV) * 64);}/* * This function allocates td for the urb */static struct sl811_td* sl811_alloc_td(struct urb *urb){ struct sl811_urb_priv *urbp = urb->hcpriv; struct sl811_td *td; td = kmalloc(sizeof (*td), GFP_KERNEL); if (!td) return NULL; memset(td, 0, sizeof(*td)); INIT_LIST_HEAD(&td->td_list); td->urb = urb; list_add_tail(&td->td_list, &urbp->td_list); return td;}/* * Fill the td. */static inline void sl811_fill_td(struct sl811_td *td, __u8 ctrl, __u8 addr, __u8 len, __u8 pidep, __u8 dev, __u8 *buf){ td->ctrl = ctrl; td->addr = addr; td->len = len; td->pidep = pidep; td->dev = dev; td->buf = buf; td->left = len; td->errcnt = 3;}/* * Fill the td. */static inline void sl811_reset_td(struct sl811_td *td){ td->status = 0; td->left = td->len; td->done = 0; td->errcnt = 3; td->nakcnt = 0; td->td_status = 0;}static void sl811_print_td(int level, struct sl811_td *td){ PDEBUG(level, "td = %p, ctrl = %x, addr = %x, len = %x, pidep = %x\n " "dev = %x, status = %x, left = %x, errcnt = %x, done = %x\n " "buf = %p, bustime = %d, td_status = %d\n", td, td->ctrl, td->addr, td->len, td->pidep, td->dev, td->status, td->left, td->errcnt, td->done, td->buf, td->bustime, td->td_status);}/* * Isochronous transfers */static int sl811_submit_isochronous(struct urb *urb){ __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; int i; PDEBUG(4, "enter, urb = %p, urbp = %p", urb, urbp); /* 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 | SL811_USB_CTRL_ISO; for (i = 0; i < urb->number_of_packets; i++) { urb->iso_frame_desc[i].actual_length = 0; urb->iso_frame_desc[i].status = -EXDEV; td = sl811_alloc_td(urb); if (!td) return -ENOMEM; sl811_fill_td(td, ctrl, SL811_DATA_START, urb->iso_frame_desc[i].length, pidep, dev, urb->transfer_buffer + urb->iso_frame_desc[i].offset); sl811_calc_td_time(td); if (urbp->cur_td == NULL) urbp->cur_td = urbp->first_td = td; } urbp->last_td = td; PDEBUG(4, "leave success");/* // 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(2, "td = %p, i = %d", td, i); tmp = tmp->next; } }*/ return 0;}/* * Reset isochronous transfers */static void sl811_reset_isochronous(struct urb *urb){ struct sl811_urb_priv *urbp = urb->hcpriv; struct sl811_td *td = NULL; struct list_head *head, *tmp; int i; PDEBUG(4, "enter, urb = %p", urb); for (i = 0; i < urb->number_of_packets; i++) { urb->iso_frame_desc[i].actual_length = 0; urb->iso_frame_desc[i].status = -EXDEV; } head = &urbp->td_list; tmp = head->next; while (tmp != head) { td = list_entry(tmp, struct sl811_td, td_list); tmp = tmp->next; sl811_reset_td(td); } urbp->cur_td = urbp->first_td; urb->status = -EINPROGRESS; urb->actual_length = 0; urb->error_count = 0;}/* * Result the iso urb. */static void sl811_result_isochronous(struct urb *urb){ struct list_head *tmp, *head; struct sl811_urb_priv *urbp = urb->hcpriv; int status = 0; struct sl811_td *td; int i; PDEBUG(4, "enter, urb = %p", urb); urb->actual_length = 0; i = 0; head = &urbp->td_list; tmp = head->next; while (tmp != head) { td = list_entry(tmp, struct sl811_td, td_list); tmp = tmp->next; if (!td->done) { if (urbp->unlink) urb->status = -ENOENT; else { PDEBUG(1, "we should not get here!"); urb->status = -EXDEV; } return ; } if (td->td_status) { status = td->td_status; urb->error_count++; PDEBUG(1, "error: td = %p, td status = %d", td, td->td_status); } urb->iso_frame_desc[i].actual_length = td->len - td->left; urb->actual_length += td->len - td->left; urb->iso_frame_desc[i].status = td->td_status; ++i; if (td->left) PDEBUG(3, "short packet, td = %p, len = %d, left = %d", td, td->len, td->left); } urb->status = status;/*// for debug PDEBUG(2, "iso urb complete, len = %d, status =%d ", urb->actual_length, urb->status); */ PDEBUG(4, "leave success");}/* * Interrupt transfers */static int sl811_submit_interrupt(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_hc *hc = urb->dev->bus->hcpriv; struct sl811_urb_priv *urbp = urb->hcpriv; struct sl811_td *td = NULL; PDEBUG(4, "enter, urb = %p", urb); if (len > maxsze) { PDEBUG(1, "length is big than max packet size, len = %d, max packet = %d", len, maxsze); return -EINVAL; } if (usb_pipeslow(urb->pipe) && !(hc->rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED)) ctrl |= SL811_USB_CTRL_PREAMBLE; ctrl |= SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE; 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)); td = sl811_alloc_td(urb); if (!td) return -ENOMEM; sl811_fill_td(td, ctrl, SL811_DATA_START, len, pidep, dev, data); sl811_calc_td_time(td); urbp->cur_td = urbp->first_td = urbp->last_td = td; urbp->interval = 0; PDEBUG(4, "leave success"); return 0;}/* * Reset interrupt transfers */static void sl811_reset_interrupt(struct urb *urb){ struct sl811_urb_priv *urbp = urb->hcpriv; struct sl811_td *td = urbp->cur_td; PDEBUG(4, "enter, interval = %d", urb->interval); 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); urbp->interval = urb->interval; urb->status = -EINPROGRESS; urb->actual_length = 0;}/* * Result the interrupt urb. */static void sl811_result_interrupt(struct urb *urb){ struct list_head *tmp; struct sl811_urb_priv *urbp = urb->hcpriv; struct sl811_td *td; int toggle; PDEBUG(4, "enter, urb = %p", urb); urb->actual_length = 0; tmp = &urbp->td_list; tmp = tmp->next; td = list_entry(tmp, struct sl811_td, td_list); // success. if (td->done && td->td_status == 0) { urb->actual_length += td->len - td->left; urb->status = 0; return ; } // tranfer is done but fail, reset the toggle. else if (td->done && td->td_status) { urb->status = td->td_status;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); PDEBUG(3, "error: td = %p, td status = %d", td, td->td_status); return ; } // 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) { urb->status = -ENOENT; PDEBUG(3, "unlink and not complete!"); goto reset_toggle; } // must be bug!!! else {// (td->done == 0 && urbp->unlink == 0) PDEBUG(1, "we should not get here!"); urb->status = -EPIPE; return ; }}/* * Control transfers */static int sl811_submit_control(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 = 0; __u8 ctrl = 0; struct sl811_hc *hc = urb->dev->bus->hcpriv; struct sl811_urb_priv *urbp = urb->hcpriv; struct sl811_td *td = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -