📄 hc_simple.c
字号:
if (hci->td_array->len != 0) { DBGERR ("ERROR: schedule, hci->td_array->len = 0x%x, s/b: 0\n", hci->td_array->len); } /* schedule the next available interrupt transfer or the next * stage of the interrupt transfer */ if (hci->td_array->len == 0 && !list_empty (&hci->intr_list)) { units_left = sh_scan_urb_list (hci, &hci->intr_list); } /* schedule the next available control transfer or the next * stage of the control transfer */ if (hci->td_array->len == 0 && !list_empty (&hci->ctrl_list) && units_left > 0) { units_left = sh_scan_urb_list (hci, &hci->ctrl_list); } /* schedule the next available bulk transfer or the next * stage of the bulk transfer */ if (hci->td_array->len == 0 && !list_empty (&hci->bulk_list) && units_left > 0) { sh_scan_urb_list (hci, &hci->bulk_list); /* be fair to each BULK URB (move list head around) * only when the new SOF happens */ lh = hci->bulk_list.next; list_del (&hci->bulk_list); list_add (&hci->bulk_list, lh); } return 0;}/*************************************************************************** * Function Name : sh_add_packet * * This function forms the packet and transmit the packet. This function * will handle all endpoint type: isochoronus, interrupt, control, and * bulk. * * Input: hci = data structure for the host controller * urb = USB request block data structure * * Return: 0 = unsucessful; 1 = successful **************************************************************************/static int sh_add_packet (hci_t * hci, struct urb * urb){ __u8 *data = NULL; int len = 0; int toggle = 0; int maxps = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe)); int endpoint = usb_pipeendpoint (urb->pipe); int address = usb_pipedevice (urb->pipe); int slow = (((urb->pipe) >> 26) & 1); int out = usb_pipeout (urb->pipe); int pid = 0; int ret; int i = 0; int iso = 0; DBGFUNC ("enter sh_add_packet\n"); if (maxps == 0) maxps = 8; /* calculate len, toggle bit and add the transaction */ switch (usb_pipetype (urb->pipe)) { case PIPE_ISOCHRONOUS: pid = out ? PID_OUT : PID_IN; iso = 1; i = hci->frame_number - urb->start_frame; data = urb->transfer_buffer + urb->iso_frame_desc[i].offset; len = urb->iso_frame_desc[i].length; break; case PIPE_BULK: /* BULK and BULK0 */ case PIPE_INTERRUPT: pid = out ? PID_OUT : PID_IN; len = urb->transfer_buffer_length - urb->actual_length; data = urb->transfer_buffer + urb->actual_length; toggle = usb_gettoggle (urb->dev, endpoint, out); break; case PIPE_CONTROL: switch (qu_urbstate (urb)) { case US_CTRL_SETUP: len = 8; pid = PID_SETUP; data = urb->setup_packet; toggle = 0; break; case US_CTRL_DATA: if (!hci->last_packet_nak) { /* The last packet received is not a nak: * reset the nak count */ hci->nakCnt = 0; } if (urb->transfer_buffer_length != 0) { pid = out ? PID_OUT : PID_IN; len = urb->transfer_buffer_length - urb->actual_length; data = urb->transfer_buffer + urb->actual_length; toggle = (urb->actual_length & maxps) ? 0 : 1; usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe), toggle); break; } else { /* correct state and fall through */ qu_seturbstate (urb, US_CTRL_ACK); } case US_CTRL_ACK: len = 0; /* reply in opposite direction */ pid = !out ? PID_OUT : PID_IN; toggle = 1; usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe), toggle); break; } } ret = hc_add_trans (hci, len, data, toggle, maxps, slow, endpoint, address, pid, iso, qu_urbstate (urb)); DBGVERBOSE ("transfer_pa: addr:%d ep:%d pid:%x tog:%x iso:%x sl:%x " "max:%d\n len:%d ret:%d data:%p left:%d\n", address, endpoint, pid, toggle, iso, slow, maxps, len, ret, data, hci->hp.units_left); if (ret >= 0) { hci->td_array->td[hci->td_array->len].urb = urb; hci->td_array->td[hci->td_array->len].len = ret; hci->td_array->td[hci->td_array->len].iso_index = i; hci->td_array->len++; hci->active_trans = 1; return 1; } return 0;}/*************************************************************************** * Function Name : cc_to_error * * This function maps the SL811HS hardware error code to the linux USB error * code. * * Input: cc = hardware error code * * Return: USB error code **************************************************************************/static int cc_to_error (int cc){ int errCode = 0; if (cc & SL11H_STATMASK_ERROR) { errCode |= -EILSEQ; } else if (cc & SL11H_STATMASK_OVF) { errCode |= -EOVERFLOW; } else if (cc & SL11H_STATMASK_STALL) { errCode |= -EPIPE; } return errCode;}/*************************************************************************** * Function Name : sh_done_list * * This function process the packet when it has done finish transfer. * * 1) It handles hardware error * 2) It updates the URB state * 3) If the USB transaction is complete, it start the return stack path. * * Input: hci = data structure for the host controller * isExcessNak = flag tells if there excess NAK condition occurred * * Return: urb_state or -1 if the transaction has complete **************************************************************************/static int sh_done_list (hci_t * hci, int *isExcessNak){ int actbytes = 0; int active = 0; void *data = NULL; int cc; int maxps; int toggle; struct urb *urb; int urb_state = 0; int ret = 1; /* -1 parse abbort, 1 parse ok, 0 last element */ int trans = 0; int len; int iso_index = 0; int out; int pid = 0; int debugLen = 0; *isExcessNak = 0; DBGFUNC ("enter sh_done_list: td_array->len = 0x%x\n", hci->td_array->len); debugLen = hci->td_array->len; if (debugLen > 1) DBGERR ("sh_done_list: td_array->len = 0x%x > 1\n", hci->td_array->len); for (trans = 0; ret && trans < hci->td_array->len && trans < MAX_TRANS; trans++) { urb = hci->td_array->td[trans].urb; /* FIXME: */ /* +++ I'm sorry, can't handle NULL-Pointers 21.11.2002 (hne) */ if (!urb) { DBGERR ("sh_done_list: urb = NULL\n"); continue; } if (!urb->dev || !urb->pipe) { if (!urb->dev) DBGERR ("sh_done_list: urb->dev = NULL\n"); if (!urb->pipe) DBGERR ("sh_done_list: urb->pipe = NULL\n"); continue; } /* --- 21.11.2002 (hne) */ len = hci->td_array->td[trans].len; out = usb_pipeout (urb->pipe); if (usb_pipeisoc (urb->pipe)) { iso_index = hci->td_array->td[trans].iso_index; data = urb->transfer_buffer + urb->iso_frame_desc[iso_index].offset; toggle = 0; } else { data = urb->transfer_buffer + urb->actual_length; /* +++ Crash (hne) urb->dev == NULL !!! */ toggle = usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe)); /* --- Crash (hne) urb->dev == NULL !!! */ } urb_state = qu_urbstate (urb); pid = out ? PID_OUT : PID_IN; ret = hc_parse_trans (hci, &actbytes, data, &cc, &toggle, len, pid, urb_state); maxps = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe)); if (maxps == 0) maxps = 8; active = (urb_state != US_CTRL_SETUP) && (actbytes && !(actbytes & (maxps - 1))); /* If the transfer is not bulk in, then it is necessary to get all * data specify by the urb->transfer_len. */ if (!(usb_pipebulk (urb->pipe) && usb_pipein (urb->pipe))) active = active && (urb->transfer_buffer_length != urb->actual_length + actbytes); if (urb->transfer_buffer_length == urb->actual_length + actbytes) active = 0; if ((cc & (SL11H_STATMASK_ERROR | SL11H_STATMASK_TMOUT | SL11H_STATMASK_OVF | SL11H_STATMASK_STALL)) && !(cc & SL11H_STATMASK_NAK)) { if (++urb->error_count > 3) { DBGERR ("done_list: excessive error: errcount = 0x%x, cc = 0x%x\n", urb->error_count, cc); urb_state = 0; active = 0; } else { DBGERR ("done_list: packet err, cc=0x%x, " " urb->length=0x%x, actual_len=0x%x," " urb_state=0x%x\n", cc, urb->transfer_buffer_length, urb->actual_length, urb_state);// if (cc & SL11H_STATMASK_STALL) { /* The USB function is STALLED on a control pipe (0), * then it needs to send the SETUP command again to * clear the STALL condition */// if (usb_pipeendpoint (urb->pipe) == 0) {// urb_state = 2; // active = 0;// }// } else active = 1; } } else { if (cc & SL11H_STATMASK_NAK) { if (hci->nakCnt < 0x10000) { hci->nakCnt++; hci->last_packet_nak = 1; active = 1; *isExcessNak = 0; } else { DBGERR ("done_list: nak count exceed limit\n"); active = 0; *isExcessNak = 1; hci->nakCnt = 0; } } else { hci->nakCnt = 0; hci->last_packet_nak = 0; } if (urb_state != US_CTRL_SETUP) { /* no error */ urb->actual_length += actbytes; usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe), toggle); } if (usb_pipeisoc (urb->pipe)) { urb->iso_frame_desc[iso_index].actual_length = actbytes; urb->iso_frame_desc[iso_index].status = cc_to_error (cc); active = (iso_index < urb->number_of_packets); } } if (!active) { if (!urb_state) { urb->status = cc_to_error (cc); if (urb->status) { DBGERR ("error on received packet: urb->status = 0x%x\n", urb->status); } hci->td_array->len = 0; qu_return_urb (hci, urb, 1); return -1; } else { /* We do not want to decrement the urb_state if exceeded nak, * because we need to finish the data stage of the control * packet */ if (!(*isExcessNak)) urb_state--; qu_seturbstate (urb, urb_state); } } } if (urb_state < 0) DBGERR ("ERROR: done_list, urb_state = %d, suppose > 0\n", urb_state); if (debugLen != hci->td_array->len) { DBGERR ("ERROR: done_list, debugLen!= td_array->len," "debugLen = 0x%x, hci->td_array->len = 0x%x\n", debugLen, hci->td_array->len); } hci->td_array->len = 0; return urb_state;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -