1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <linux/kernel.h>
19#include <linux/types.h>
20#include <linux/spinlock.h>
21#include <linux/errno.h>
22#include <linux/list.h>
23#include <linux/usb.h>
24#include "../core/hcd.h"
25#include "fhci.h"
26
27
28static int status_to_error(u32 status)
29{
30 if (status == USB_TD_OK)
31 return 0;
32 else if (status & USB_TD_RX_ER_CRC)
33 return -EILSEQ;
34 else if (status & USB_TD_RX_ER_NONOCT)
35 return -EPROTO;
36 else if (status & USB_TD_RX_ER_OVERUN)
37 return -ECOMM;
38 else if (status & USB_TD_RX_ER_BITSTUFF)
39 return -EPROTO;
40 else if (status & USB_TD_RX_ER_PID)
41 return -EILSEQ;
42 else if (status & (USB_TD_TX_ER_NAK | USB_TD_TX_ER_TIMEOUT))
43 return -ETIMEDOUT;
44 else if (status & USB_TD_TX_ER_STALL)
45 return -EPIPE;
46 else if (status & USB_TD_TX_ER_UNDERUN)
47 return -ENOSR;
48 else if (status & USB_TD_RX_DATA_UNDERUN)
49 return -EREMOTEIO;
50 else if (status & USB_TD_RX_DATA_OVERUN)
51 return -EOVERFLOW;
52 else
53 return -EINVAL;
54}
55
56void fhci_add_td_to_frame(struct fhci_time_frame *frame, struct td *td)
57{
58 list_add_tail(&td->frame_lh, &frame->tds_list);
59}
60
61void fhci_add_tds_to_ed(struct ed *ed, struct td **td_list, int number)
62{
63 int i;
64
65 for (i = 0; i < number; i++) {
66 struct td *td = td_list[i];
67 list_add_tail(&td->node, &ed->td_list);
68 }
69 if (ed->td_head == NULL)
70 ed->td_head = td_list[0];
71}
72
73static struct td *peek_td_from_ed(struct ed *ed)
74{
75 struct td *td;
76
77 if (!list_empty(&ed->td_list))
78 td = list_entry(ed->td_list.next, struct td, node);
79 else
80 td = NULL;
81
82 return td;
83}
84
85struct td *fhci_remove_td_from_frame(struct fhci_time_frame *frame)
86{
87 struct td *td;
88
89 if (!list_empty(&frame->tds_list)) {
90 td = list_entry(frame->tds_list.next, struct td, frame_lh);
91 list_del_init(frame->tds_list.next);
92 } else
93 td = NULL;
94
95 return td;
96}
97
98struct td *fhci_peek_td_from_frame(struct fhci_time_frame *frame)
99{
100 struct td *td;
101
102 if (!list_empty(&frame->tds_list))
103 td = list_entry(frame->tds_list.next, struct td, frame_lh);
104 else
105 td = NULL;
106
107 return td;
108}
109
110struct td *fhci_remove_td_from_ed(struct ed *ed)
111{
112 struct td *td;
113
114 if (!list_empty(&ed->td_list)) {
115 td = list_entry(ed->td_list.next, struct td, node);
116 list_del_init(ed->td_list.next);
117
118
119 if (!list_empty(&ed->td_list))
120 ed->td_head = list_entry(ed->td_list.next, struct td,
121 node);
122 else
123 ed->td_head = NULL;
124 } else
125 td = NULL;
126
127 return td;
128}
129
130struct td *fhci_remove_td_from_done_list(struct fhci_controller_list *p_list)
131{
132 struct td *td;
133
134 if (!list_empty(&p_list->done_list)) {
135 td = list_entry(p_list->done_list.next, struct td, node);
136 list_del_init(p_list->done_list.next);
137 } else
138 td = NULL;
139
140 return td;
141}
142
143void fhci_move_td_from_ed_to_done_list(struct fhci_usb *usb, struct ed *ed)
144{
145 struct td *td;
146
147 td = ed->td_head;
148 list_del_init(&td->node);
149
150
151 if (!list_empty(&ed->td_list))
152 ed->td_head = list_entry(ed->td_list.next, struct td, node);
153 else {
154 ed->td_head = NULL;
155 ed->state = FHCI_ED_SKIP;
156 }
157 ed->toggle_carry = td->toggle;
158 list_add_tail(&td->node, &usb->hc_list->done_list);
159 if (td->ioc)
160 usb->transfer_confirm(usb->fhci);
161}
162
163
164static void free_urb_priv(struct fhci_hcd *fhci, struct urb *urb)
165{
166 int i;
167 struct urb_priv *urb_priv = urb->hcpriv;
168 struct ed *ed = urb_priv->ed;
169
170 for (i = 0; i < urb_priv->num_of_tds; i++) {
171 list_del_init(&urb_priv->tds[i]->node);
172 fhci_recycle_empty_td(fhci, urb_priv->tds[i]);
173 }
174
175
176 if (!list_empty(&ed->td_list))
177 ed->td_head = list_entry(ed->td_list.next, struct td, node);
178 else
179 ed->td_head = NULL;
180
181 kfree(urb_priv->tds);
182 kfree(urb_priv);
183 urb->hcpriv = NULL;
184
185
186 if (ed->td_head == NULL)
187 list_del_init(&ed->node);
188 fhci->active_urbs--;
189}
190
191
192void fhci_urb_complete_free(struct fhci_hcd *fhci, struct urb *urb)
193{
194 free_urb_priv(fhci, urb);
195
196 if (urb->status == -EINPROGRESS) {
197 if (urb->actual_length != urb->transfer_buffer_length &&
198 urb->transfer_flags & URB_SHORT_NOT_OK)
199 urb->status = -EREMOTEIO;
200 else
201 urb->status = 0;
202 }
203
204 usb_hcd_unlink_urb_from_ep(fhci_to_hcd(fhci), urb);
205
206 spin_unlock(&fhci->lock);
207
208 usb_hcd_giveback_urb(fhci_to_hcd(fhci), urb, urb->status);
209
210 spin_lock(&fhci->lock);
211}
212
213
214
215
216
217void fhci_done_td(struct urb *urb, struct td *td)
218{
219 struct ed *ed = td->ed;
220 u32 cc = td->status;
221
222
223 if (ed->mode == FHCI_TF_ISO) {
224 u32 len;
225 if (!(urb->transfer_flags & URB_SHORT_NOT_OK &&
226 cc == USB_TD_RX_DATA_UNDERUN))
227 cc = USB_TD_OK;
228
229 if (usb_pipeout(urb->pipe))
230 len = urb->iso_frame_desc[td->iso_index].length;
231 else
232 len = td->actual_len;
233
234 urb->actual_length += len;
235 urb->iso_frame_desc[td->iso_index].actual_length = len;
236 urb->iso_frame_desc[td->iso_index].status =
237 status_to_error(cc);
238 }
239
240
241
242
243
244 else {
245 if (td->error_cnt >= 3)
246 urb->error_count = 3;
247
248
249
250
251 if (!(urb->transfer_flags & URB_SHORT_NOT_OK) &&
252 cc == USB_TD_RX_DATA_UNDERUN) {
253 ed->state = FHCI_ED_OPER;
254 cc = USB_TD_OK;
255 }
256 if (cc != USB_TD_OK) {
257 if (urb->status == -EINPROGRESS)
258 urb->status = status_to_error(cc);
259 }
260
261
262 if (td->type != FHCI_TA_SETUP || td->iso_index != 0)
263 urb->actual_length += td->actual_len;
264 }
265}
266
267
268void fhci_del_ed_list(struct fhci_hcd *fhci, struct ed *ed)
269{
270 struct td *td = peek_td_from_ed(ed);
271 struct urb *urb = td->urb;
272 struct urb_priv *urb_priv = urb->hcpriv;
273
274 if (urb_priv->state == URB_DEL) {
275 td = fhci_remove_td_from_ed(ed);
276
277 if (td->status != USB_TD_INPROGRESS)
278 fhci_done_td(urb, td);
279
280
281 if (++(urb_priv->tds_cnt) == urb_priv->num_of_tds)
282 fhci_urb_complete_free(fhci, urb);
283 }
284}
285