[lantiq] cleanup basefiles
[openwrt/svn-archive/archive.git] / target / linux / lantiq / files-3.3 / drivers / usb / ifxhcd / ifxhcd_queue.c
1 /*****************************************************************************
2 ** FILE NAME : ifxhcd_queue.c
3 ** PROJECT : IFX USB sub-system V3
4 ** MODULES : IFX USB sub-system Host and Device driver
5 ** SRC VERSION : 1.0
6 ** DATE : 1/Jan/2009
7 ** AUTHOR : Chen, Howard
8 ** DESCRIPTION : This file contains the functions to manage Queue Heads and Queue
9 ** Transfer Descriptors.
10 *****************************************************************************/
11
12 /*!
13 \file ifxhcd_queue.c
14 \ingroup IFXUSB_DRIVER_V3
15 \brief This file contains the functions to manage Queue Heads and Queue
16 Transfer Descriptors.
17 */
18 #include <linux/version.h>
19 #include "ifxusb_version.h"
20
21 #include <linux/kernel.h>
22 #include <linux/module.h>
23 #include <linux/moduleparam.h>
24 #include <linux/init.h>
25 #include <linux/device.h>
26 #include <linux/errno.h>
27 #include <linux/list.h>
28 #include <linux/interrupt.h>
29 #include <linux/string.h>
30
31 #include "ifxusb_plat.h"
32 #include "ifxusb_regs.h"
33 #include "ifxusb_cif.h"
34 #include "ifxhcd.h"
35
36 #ifdef __EPQD_DESTROY_TIMEOUT__
37 #define epqh_self_destroy_timeout 5
38 static void eqph_destroy_func(unsigned long _ptr)
39 {
40 ifxhcd_epqh_t *epqh=(ifxhcd_epqh_t *)_ptr;
41 if(epqh)
42 {
43 ifxhcd_epqh_free (epqh);
44 }
45 }
46 #endif
47
48 #define SCHEDULE_SLOP 10
49
50 /*!
51 \brief This function allocates and initializes a EPQH.
52
53 \param _ifxhcd The HCD state structure for the USB Host controller.
54 \param[in] _urb Holds the information about the device/endpoint that we need
55 to initialize the EPQH.
56
57 \return Returns pointer to the newly allocated EPQH, or NULL on error.
58 */
59 ifxhcd_epqh_t *ifxhcd_epqh_create (ifxhcd_hcd_t *_ifxhcd, struct urb *_urb)
60 {
61 ifxhcd_epqh_t *epqh;
62
63 hprt0_data_t hprt0;
64 struct usb_host_endpoint *sysep = ifxhcd_urb_to_endpoint(_urb);
65
66 /* Allocate memory */
67 // epqh=(ifxhcd_epqh_t *) kmalloc (sizeof(ifxhcd_epqh_t), GFP_KERNEL);
68 epqh=(ifxhcd_epqh_t *) kmalloc (sizeof(ifxhcd_epqh_t), GFP_ATOMIC);
69
70 if(epqh == NULL)
71 return NULL;
72
73 memset (epqh, 0, sizeof (ifxhcd_epqh_t));
74
75 epqh->sysep=sysep;
76
77 /* Initialize EPQH */
78 switch (usb_pipetype(_urb->pipe))
79 {
80 case PIPE_CONTROL : epqh->ep_type = IFXUSB_EP_TYPE_CTRL; break;
81 case PIPE_BULK : epqh->ep_type = IFXUSB_EP_TYPE_BULK; break;
82 case PIPE_ISOCHRONOUS: epqh->ep_type = IFXUSB_EP_TYPE_ISOC; break;
83 case PIPE_INTERRUPT : epqh->ep_type = IFXUSB_EP_TYPE_INTR; break;
84 }
85
86 //epqh->data_toggle = IFXUSB_HC_PID_DATA0;
87
88 epqh->mps = usb_maxpacket(_urb->dev, _urb->pipe, !(usb_pipein(_urb->pipe)));
89
90 hprt0.d32 = ifxusb_read_hprt0 (&_ifxhcd->core_if);
91
92 INIT_LIST_HEAD(&epqh->urbd_list);
93 INIT_LIST_HEAD(&epqh->epqh_list_entry);
94 epqh->hc = NULL;
95
96 epqh->dump_buf = ifxusb_alloc_buf(epqh->mps, 0);
97
98 /* FS/LS Enpoint on HS Hub
99 * NOT virtual root hub */
100 epqh->need_split = 0;
101 epqh->pkt_count_limit=0;
102 if(epqh->ep_type == IFXUSB_EP_TYPE_BULK && !(usb_pipein(_urb->pipe)) )
103 epqh->pkt_count_limit=4;
104 if (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_HIGH_SPEED &&
105 ((_urb->dev->speed == USB_SPEED_LOW) ||
106 (_urb->dev->speed == USB_SPEED_FULL)) &&
107 (_urb->dev->tt) && (_urb->dev->tt->hub->devnum != 1))
108 {
109 IFX_DEBUGPL(DBG_HCD, "QH init: EP %d: TT found at hub addr %d, for port %d\n",
110 usb_pipeendpoint(_urb->pipe), _urb->dev->tt->hub->devnum,
111 _urb->dev->ttport);
112 epqh->need_split = 1;
113 epqh->pkt_count_limit=1;
114 }
115
116 if (epqh->ep_type == IFXUSB_EP_TYPE_INTR ||
117 epqh->ep_type == IFXUSB_EP_TYPE_ISOC)
118 {
119 /* Compute scheduling parameters once and save them. */
120 epqh->interval = _urb->interval;
121 if(epqh->need_split)
122 epqh->interval *= 8;
123 }
124
125 epqh->period_counter=0;
126 epqh->is_active=0;
127
128 #ifdef __EPQD_DESTROY_TIMEOUT__
129 /* Start a timer for this transfer. */
130 init_timer(&epqh->destroy_timer);
131 epqh->destroy_timer.function = eqph_destroy_func;
132 epqh->destroy_timer.data = (unsigned long)(epqh);
133 #endif
134
135 #ifdef __DEBUG__
136 IFX_DEBUGPL(DBG_HCD , "IFXUSB HCD EPQH Initialized\n");
137 IFX_DEBUGPL(DBG_HCDV, "IFXUSB HCD EPQH - epqh = %p\n", epqh);
138 IFX_DEBUGPL(DBG_HCDV, "IFXUSB HCD EPQH - Device Address = %d EP %d, %s\n",
139 _urb->dev->devnum,
140 usb_pipeendpoint(_urb->pipe),
141 usb_pipein(_urb->pipe) == USB_DIR_IN ? "IN" : "OUT");
142 IFX_DEBUGPL(DBG_HCDV, "IFXUSB HCD EPQH - Speed = %s\n",
143 ({ char *speed; switch (_urb->dev->speed) {
144 case USB_SPEED_LOW: speed = "low" ; break;
145 case USB_SPEED_FULL: speed = "full"; break;
146 case USB_SPEED_HIGH: speed = "high"; break;
147 default: speed = "?"; break;
148 }; speed;}));
149 IFX_DEBUGPL(DBG_HCDV, "IFXUSB HCD EPQH - Type = %s\n",
150 ({
151 char *type; switch (epqh->ep_type)
152 {
153 case IFXUSB_EP_TYPE_ISOC: type = "isochronous"; break;
154 case IFXUSB_EP_TYPE_INTR: type = "interrupt" ; break;
155 case IFXUSB_EP_TYPE_CTRL: type = "control" ; break;
156 case IFXUSB_EP_TYPE_BULK: type = "bulk" ; break;
157 default: type = "?"; break;
158 };
159 type;
160 }));
161 if (epqh->ep_type == IFXUSB_EP_TYPE_INTR)
162 IFX_DEBUGPL(DBG_HCDV, "IFXUSB HCD EPQH - interval = %d\n", epqh->interval);
163 #endif
164
165 return epqh;
166 }
167
168
169
170
171
172
173 /*!
174 \brief Free the EPQH. EPQH should already be removed from a list.
175 URBD list should already be empty if called from URB Dequeue.
176
177 \param[in] _epqh The EPQH to free.
178 */
179 void ifxhcd_epqh_free (ifxhcd_epqh_t *_epqh)
180 {
181 unsigned long flags;
182
183 if(_epqh->sysep) _epqh->sysep->hcpriv=NULL;
184 _epqh->sysep=NULL;
185
186 if(!_epqh)
187 return;
188
189 /* Free each QTD in the QTD list */
190 local_irq_save (flags);
191 if (!list_empty(&_epqh->urbd_list))
192 IFX_WARN("%s() invalid epqh state\n",__func__);
193
194 #if defined(__UNALIGNED_BUFFER_ADJ__)
195 if(_epqh->aligned_buf)
196 ifxusb_free_buf(_epqh->aligned_buf);
197 if(_epqh->aligned_setup)
198 ifxusb_free_buf(_epqh->aligned_setup);
199 #endif
200
201 if (!list_empty(&_epqh->epqh_list_entry))
202 list_del_init(&_epqh->epqh_list_entry);
203
204 #ifdef __EPQD_DESTROY_TIMEOUT__
205 del_timer(&_epqh->destroy_timer);
206 #endif
207 if(_epqh->dump_buf)
208 ifxusb_free_buf(_epqh->dump_buf);
209 _epqh->dump_buf=0;
210
211
212 kfree (_epqh);
213 local_irq_restore (flags);
214 }
215
216 /*!
217 \brief This function adds a EPQH to
218
219 \return 0 if successful, negative error code otherwise.
220 */
221 void ifxhcd_epqh_ready(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh)
222 {
223 unsigned long flags;
224 local_irq_save(flags);
225 if (list_empty(&_epqh->epqh_list_entry))
226 {
227 #ifdef __EN_ISOC__
228 if (_epqh->ep_type == IFXUSB_EP_TYPE_ISOC)
229 list_add_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_isoc_ready);
230 else
231 #endif
232 if(_epqh->ep_type == IFXUSB_EP_TYPE_INTR)
233 list_add_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_intr_ready);
234 else
235 list_add_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_np_ready);
236 _epqh->is_active=0;
237 }
238 else if(!_epqh->is_active)
239 {
240 #ifdef __EN_ISOC__
241 if (_epqh->ep_type == IFXUSB_EP_TYPE_ISOC)
242 list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_isoc_ready);
243 else
244 #endif
245 if(_epqh->ep_type == IFXUSB_EP_TYPE_INTR)
246 list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_intr_ready);
247 else
248 list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_np_ready);
249 }
250 #ifdef __EPQD_DESTROY_TIMEOUT__
251 del_timer(&_epqh->destroy_timer);
252 #endif
253 local_irq_restore(flags);
254 }
255
256 void ifxhcd_epqh_active(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh)
257 {
258 unsigned long flags;
259 local_irq_save(flags);
260 if (list_empty(&_epqh->epqh_list_entry))
261 IFX_WARN("%s() invalid epqh state\n",__func__);
262 #ifdef __EN_ISOC__
263 if (_epqh->ep_type == IFXUSB_EP_TYPE_ISOC)
264 list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_isoc_active);
265 else
266 #endif
267 if(_epqh->ep_type == IFXUSB_EP_TYPE_INTR)
268 list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_intr_active);
269 else
270 list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_np_active);
271 _epqh->is_active=1;
272 #ifdef __EPQD_DESTROY_TIMEOUT__
273 del_timer(&_epqh->destroy_timer);
274 #endif
275 local_irq_restore(flags);
276 }
277
278 void ifxhcd_epqh_idle(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh)
279 {
280 unsigned long flags;
281 local_irq_save(flags);
282
283 if (list_empty(&_epqh->urbd_list))
284 {
285 if(_epqh->ep_type == IFXUSB_EP_TYPE_ISOC || _epqh->ep_type == IFXUSB_EP_TYPE_INTR)
286 {
287 list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_stdby);
288 }
289 else
290 {
291 list_del_init(&_epqh->epqh_list_entry);
292 #ifdef __EPQD_DESTROY_TIMEOUT__
293 del_timer(&_epqh->destroy_timer);
294 _epqh->destroy_timer.expires = jiffies + (HZ*epqh_self_destroy_timeout);
295 add_timer(&_epqh->destroy_timer );
296 #endif
297 }
298 }
299 else
300 {
301 #ifdef __EN_ISOC__
302 if (_epqh->ep_type == IFXUSB_EP_TYPE_ISOC)
303 list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_isoc_ready);
304 else
305 #endif
306 if(_epqh->ep_type == IFXUSB_EP_TYPE_INTR)
307 list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_intr_ready);
308 else
309 list_move_tail(&_epqh->epqh_list_entry, &_ifxhcd->epqh_np_ready);
310 }
311 _epqh->is_active=0;
312 local_irq_restore(flags);
313 }
314
315
316 void ifxhcd_epqh_idle_periodic(ifxhcd_epqh_t *_epqh)
317 {
318 unsigned long flags;
319 if(_epqh->ep_type != IFXUSB_EP_TYPE_ISOC && _epqh->ep_type != IFXUSB_EP_TYPE_INTR)
320 return;
321
322 local_irq_save(flags);
323
324 if (list_empty(&_epqh->epqh_list_entry))
325 IFX_WARN("%s() invalid epqh state\n",__func__);
326 if (!list_empty(&_epqh->urbd_list))
327 IFX_WARN("%s() invalid epqh state(not empty)\n",__func__);
328
329 _epqh->is_active=0;
330 list_del_init(&_epqh->epqh_list_entry);
331 #ifdef __EPQD_DESTROY_TIMEOUT__
332 del_timer(&_epqh->destroy_timer);
333 _epqh->destroy_timer.expires = jiffies + (HZ*epqh_self_destroy_timeout);
334 add_timer(&_epqh->destroy_timer );
335 #endif
336
337 local_irq_restore(flags);
338 }
339
340
341 int ifxhcd_urbd_create (ifxhcd_hcd_t *_ifxhcd,struct urb *_urb)
342 {
343 ifxhcd_urbd_t *urbd;
344 struct usb_host_endpoint *sysep;
345 ifxhcd_epqh_t *epqh;
346 unsigned long flags;
347 /* == AVM/WK 20100714 retval correctly initialized ==*/
348 int retval = -ENOMEM;
349
350 /*== AVM/BC 20100630 - Spinlock ==*/
351 //local_irq_save(flags);
352 SPIN_LOCK_IRQSAVE(&_ifxhcd->lock, flags);
353
354 // urbd = (ifxhcd_urbd_t *) kmalloc (sizeof(ifxhcd_urbd_t), GFP_KERNEL);
355 urbd = (ifxhcd_urbd_t *) kmalloc (sizeof(ifxhcd_urbd_t), GFP_ATOMIC);
356 if (urbd != NULL) /* Initializes a QTD structure.*/
357 {
358 retval = 0;
359 memset (urbd, 0, sizeof (ifxhcd_urbd_t));
360
361 sysep = ifxhcd_urb_to_endpoint(_urb);
362 epqh = (ifxhcd_epqh_t *)sysep->hcpriv;
363 if (epqh == NULL)
364 {
365 epqh = ifxhcd_epqh_create (_ifxhcd, _urb);
366 if (epqh == NULL)
367 {
368 retval = -ENOSPC;
369 kfree(urbd);
370 //local_irq_restore (flags);
371 SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags);
372 return retval;
373 }
374 sysep->hcpriv = epqh;
375 }
376
377 INIT_LIST_HEAD(&urbd->urbd_list_entry);
378
379 /*== AVM/BC 20100630 - 2.6.28 needs HCD link/unlink URBs ==*/
380 retval = usb_hcd_link_urb_to_ep(ifxhcd_to_syshcd(_ifxhcd), _urb);
381
382 if (unlikely(retval)){
383 kfree(urbd);
384 kfree(epqh);
385 SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags);
386 return retval;
387 }
388
389 list_add_tail(&urbd->urbd_list_entry, &epqh->urbd_list);
390 urbd->urb = _urb;
391 _urb->hcpriv = urbd;
392
393 urbd->epqh=epqh;
394 urbd->is_in=usb_pipein(_urb->pipe) ? 1 : 0;;
395
396 urbd->xfer_len=_urb->transfer_buffer_length;
397 #define URB_NO_SETUP_DMA_MAP 0
398
399 if(urbd->xfer_len>0)
400 {
401 if(_urb->transfer_flags && URB_NO_TRANSFER_DMA_MAP)
402 urbd->xfer_buff = (uint8_t *) (KSEG1ADDR((uint32_t *)_urb->transfer_dma));
403 else
404 urbd->xfer_buff = (uint8_t *) _urb->transfer_buffer;
405 }
406 if(epqh->ep_type == IFXUSB_EP_TYPE_CTRL)
407 {
408 if(_urb->transfer_flags && URB_NO_SETUP_DMA_MAP)
409 urbd->setup_buff = (uint8_t *) (KSEG1ADDR((uint32_t *)_urb->setup_dma));
410 else
411 urbd->setup_buff = (uint8_t *) _urb->setup_packet;
412 }
413 }
414 //local_irq_restore (flags);
415 SPIN_UNLOCK_IRQRESTORE(&_ifxhcd->lock, flags);
416 return retval;
417 }
418