📄 patch-2.4.4-sl811hs
字号:
+ * 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)
+ {
+ 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -