[lantiq] move files/ -> files-3.3/
[openwrt.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