📄 hc_simple.c
字号:
{
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, urb_t * 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 = usb_pipeslow (urb->pipe);
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 |= USB_ST_CRC;
}
else if (cc & SL11H_STATMASK_OVF)
{
errCode |= USB_ST_DATAOVERRUN;
}
else if (cc & SL11H_STATMASK_STALL)
{
errCode |= USB_ST_STALL;
}
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;
urb_t * 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;
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;
toggle = usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe),
usb_pipeout (urb->pipe));
}
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 + -