Root/target/linux/lantiq/files/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 */
59ifxhcd_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 */
179void 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 */
221void 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
256void 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
278void 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
316void 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
341int 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
419

Archive Download this file



interactive