📄 hc_simple.c
字号:
* The state of an intr and iso URB is 0.
* For ctrl URBs the states are US_CTRL_SETUP, US_CTRL_DATA, US_CTRL_ACK
* Bulk URBs states are US_BULK and US_BULK0 (with 0-len packet)
*
**************************************************************************/
/***************************************************************************
* Function Name : qu_urb_timeout
*
* This function is called when the URB timeout. The function unlinks the
* URB.
*
* Input: lurb: URB
*
* Return: none
**************************************************************************/
#ifdef HC_URB_TIMEOUT
static void qu_urb_timeout (unsigned long lurb)
{
urb_t * urb = (urb_t *) lurb;
DBGFUNC ("enter qu_urb_timeout\n");
urb->transfer_flags |= USB_TIMEOUT_KILLED;
hci_unlink_urb (urb);
}
#endif
/***************************************************************************
* Function Name : qu_pipeindex
*
* This function gets the index of the pipe.
*
* Input: pipe: the urb pipe
*
* Return: index
**************************************************************************/
static inline int qu_pipeindex (__u32 pipe)
{
DBGFUNC ("enter qu_pipeindex\n");
return (usb_pipeendpoint (pipe) << 1) | (usb_pipecontrol (pipe) ?
0 : usb_pipeout (pipe));
}
/***************************************************************************
* Function Name : qu_seturbstate
*
* This function set the state of the URB.
*
* control pipe: 3 states -- Setup, data, status
* interrupt and bulk pipe: 1 state -- data
*
* Input: urb = USB request block data structure
* state = the urb state
*
* Return: none
**************************************************************************/
static inline void qu_seturbstate (urb_t * urb, int state)
{
DBGFUNC ("enter qu_seturbstate\n");
urb->pipe &= ~0x1f;
urb->pipe |= state & 0x1f;
}
/***************************************************************************
* Function Name : qu_urbstate
*
* This function get the current state of the URB.
*
* Input: urb = USB request block data structure
*
* Return: none
**************************************************************************/
static inline int qu_urbstate (urb_t * urb)
{
DBGFUNC ("enter qu_urbstate\n");
return urb->pipe & 0x1f;
}
/***************************************************************************
* Function Name : qu_queue_active_urb
*
* This function adds the urb to the appropriate active urb list and set
* the urb state.
*
* There are four active lists: isochoronous list, interrupt list,
* control list, and bulk list.
*
* Input: hci = data structure for the host controller
* urb = USB request block data structure
* ed = endpoint descriptor
*
* Return: none
**************************************************************************/
static inline void qu_queue_active_urb (hci_t * hci, urb_t * urb, epd_t * ed)
{
int urb_state = 0;
DBGFUNC ("enter qu_queue_active_urb\n");
switch (usb_pipetype (urb->pipe))
{
case PIPE_CONTROL:
list_add (&urb->urb_list, &hci->ctrl_list);
urb_state = US_CTRL_SETUP;
break;
case PIPE_BULK:
list_add (&urb->urb_list, &hci->bulk_list);
if ((urb->transfer_flags & USB_ZERO_PACKET) &&
urb->transfer_buffer_length > 0 &&
((urb->transfer_buffer_length %
usb_maxpacket (urb->dev, urb->pipe,
usb_pipeout (urb->pipe))) == 0))
{
urb_state = US_BULK0;
}
break;
case PIPE_INTERRUPT:
urb->start_frame = hci->frame_number;
list_add (&urb->urb_list, &hci->intr_list);
break;
case PIPE_ISOCHRONOUS:
list_add (&urb->urb_list, &hci->iso_list);
break;
}
#ifdef HC_URB_TIMEOUT
if (urb->timeout)
{
ed->timeout.data = (unsigned long) urb;
ed->timeout.expires = urb->timeout + jiffies;
ed->timeout.function = qu_urb_timeout;
add_timer (&ed->timeout);
}
#endif
qu_seturbstate (urb, urb_state);
}
/***************************************************************************
* Function Name : qu_queue_urb
*
* This function adds the urb to the endpoint descriptor list
*
* Input: hci = data structure for the host controller
* urb = USB request block data structure
*
* Return: none
**************************************************************************/
static int qu_queue_urb (hci_t * hci, urb_t * urb)
{
struct hci_device * hci_dev = usb_to_hci (urb->dev);
epd_t * ed = &hci_dev->ed [qu_pipeindex (urb->pipe)];
DBGFUNC ("Enter qu_queue_urb\n");
/* for ISOC transfers calculate start frame index */
if (usb_pipeisoc (urb->pipe) && urb->transfer_flags & USB_ISO_ASAP)
{
urb->start_frame = ((ed->pipe_head)? (ed->last_iso + 1):
hci_get_current_frame_number (urb->dev) + 1) & 0xffff;
}
if (ed->pipe_head)
{
__list_add (&urb->urb_list, ed->urb_queue.prev, &(ed->urb_queue));
}
else
{
ed->pipe_head = urb;
qu_queue_active_urb (hci, urb, ed);
if (++hci->active_urbs == 1)
hc_start_int (hci);
}
return 0;
}
/***************************************************************************
* Function Name : qu_next_urb
*
* This function removes the URB from the queue and add the next URB to
* active list.
*
* Input: hci = data structure for the host controller
* urb = USB request block data structure
* resub_ok = resubmit flag
*
* Return: pointer to the next urb
**************************************************************************/
static urb_t * qu_next_urb (hci_t * hci, urb_t * urb, int resub_ok)
{
struct hci_device * hci_dev = usb_to_hci (urb->dev);
epd_t * ed = &hci_dev->ed [qu_pipeindex (urb->pipe)];
DBGFUNC ("enter qu_next_urb\n");
list_del (&urb->urb_list);
INIT_LIST_HEAD (&urb->urb_list);
if (ed->pipe_head == urb)
{
#ifdef HC_URB_TIMEOUT
if (urb->timeout)
del_timer (&ed->timeout);
#endif
if (!--hci->active_urbs)
hc_stop_int (hci);
if (!list_empty (&ed->urb_queue))
{
urb = list_entry (ed->urb_queue.next, urb_t, urb_list);
list_del (&urb->urb_list);
INIT_LIST_HEAD (&urb->urb_list);
ed->pipe_head = urb;
qu_queue_active_urb (hci, urb, ed);
}
else
{
ed->pipe_head = NULL;
urb = NULL;
}
}
return urb;
}
/***************************************************************************
* Function Name : qu_return_urb
*
* This function is part of the return path.
*
* Input: hci = data structure for the host controller
* urb = USB request block data structure
* resub_ok = resubmit flag
*
* Return: pointer to the next urb
**************************************************************************/
static urb_t * qu_return_urb (hci_t * hci, urb_t * urb, int resub_ok)
{
urb_t * next_urb;
DBGFUNC ("enter qu_return_rub\n");
next_urb = qu_next_urb (hci, urb, resub_ok);
hcs_return_urb (hci, urb, resub_ok);
return next_urb;
}
/***************************************************************************
* Function Name : sh_scan_iso_urb_list
*
* This function goes throught the isochronous urb list and schedule the
* the transfer.
*
* Note: This function has not tested yet
*
* Input: hci = data structure for the host controller
* list_lh = pointer to the isochronous list
* frame_number = the frame number
*
* Return: 0 = unsuccessful; 1 = successful
**************************************************************************/
static int sh_scan_iso_urb_list (hci_t * hci, struct list_head * list_lh, int frame_number)
{
struct list_head * lh = list_lh->next;
urb_t * urb;
DBGFUNC ("enter sh_scan_iso_urb_list\n");
hci->td_array->len = 0;
while (lh != list_lh)
{
urb = list_entry (lh, urb_t, urb_list);
lh = lh->next;
if (((frame_number - urb->start_frame) & 0x7ff) <
urb->number_of_packets)
{
if (!sh_add_packet (hci, urb))
{
return 0;
}
else
{
if (((frame_number - urb->start_frame) & 0x7ff) > 0x400)
{
if (qu_urbstate(urb) > 0)
urb = qu_return_urb (hci, urb, 1);
else
urb = qu_next_urb (hci, urb, 1);
if (lh == list_lh && urb)
lh = &urb->urb_list;
}
}
}
}
return 1;
}
/***************************************************************************
* Function Name : sh_scan_urb_list
*
* This function goes through the urb list and schedule the
* the transaction.
*
* Input: hci = data structure for the host controller
* list_lh = pointer to the isochronous list
*
* Return: 0 = unsuccessful; 1 = successful
**************************************************************************/
static int sh_scan_urb_list (hci_t * hci, struct list_head * list_lh)
{
struct list_head * lh = NULL;
urb_t * urb;
if (list_lh == NULL)
{
DBGERR ("sh_scan_urb_list: error, list_lh == NULL\n");
}
DBGFUNC ("enter sh_scan_urb_list: frame# \n");
list_for_each (lh, list_lh)
{
urb = list_entry (lh, urb_t, urb_list);
if (urb == NULL)
return 1;
if (!usb_pipeint (urb->pipe) ||(((hci->frame_number - urb->start_frame)
& 0x7ff) >= urb->interval))
{
DBGVERBOSE("sh_scan_urb_list !INT: %d fr_no: %d int: %d pint: %d\n",
urb->start_frame, hci->frame_number, urb->interval,
usb_pipeint (urb->pipe));
if (!sh_add_packet (hci, urb))
{
return 0;
}
else
{
DBGVERBOSE("INT: start: %d fr_no: %d int: %d pint: %d\n",
urb->start_frame, hci->frame_number, urb->interval,
usb_pipeint (urb->pipe));
urb->start_frame = hci->frame_number;
return 0;
}
}
}
return 1;
}
/***************************************************************************
* Function Name : sh_shedule_trans
*
* This function schedule the USB transaction.
* This function will process the endpoint in the following order:
* interrupt, control, and bulk.
*
* Input: hci = data structure for the host controller
* isSOF = flag indicate if Start Of Frame has occurred
*
* Return: 0
**************************************************************************/
static int sh_schedule_trans (hci_t * hci, int isSOF)
{
int units_left = 1;
struct list_head * lh;
if (hci == NULL)
{
DBGERR ("sh_schedule_trans: hci == NULL\n");
return 0;
}
if (hci->td_array == NULL)
{
DBGERR ("sh_schedule_trans: hci->td_array == NULL\n");
return 0;
}
if (hci->td_array->len != 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -