OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [usb/] [auerchain.c] - Blame information for rev 1780

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*****************************************************************************/
2
/*
3
 *      auerchain.c  --  Auerswald PBX/System Telephone chained urb support.
4
 *
5
 *      Copyright (C) 2002  Wolfgang Mües (wolfgang@iksw-muees.de)
6
 *
7
 *      This program is free software; you can redistribute it and/or modify
8
 *      it under the terms of the GNU General Public License as published by
9
 *      the Free Software Foundation; either version 2 of the License, or
10
 *      (at your option) any later version.
11
 *
12
 *      This program is distributed in the hope that it will be useful,
13
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 *      GNU General Public License for more details.
16
 *
17
 *      You should have received a copy of the GNU General Public License
18
 *      along with this program; if not, write to the Free Software
19
 *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
 */
21
 /*****************************************************************************/
22
 
23
#undef DEBUG                    /* include debug macros until it's done */
24
#include <linux/usb.h>
25
#include "auerchain.h"
26
#include <linux/slab.h>
27
 
28
/* completion function for chained urbs */
29
static void auerchain_complete(struct urb *urb)
30
{
31
        unsigned long flags;
32
        int result;
33
 
34
        /* get pointer to element and to chain */
35
        struct auerchainelement *acep =
36
            (struct auerchainelement *) urb->context;
37
        struct auerchain *acp = acep->chain;
38
 
39
        /* restore original entries in urb */
40
        urb->context = acep->context;
41
        urb->complete = acep->complete;
42
 
43
        dbg("auerchain_complete called");
44
 
45
        /* call original completion function
46
           NOTE: this function may lead to more urbs submitted into the chain.
47
           (no chain lock at calling complete()!)
48
           acp->active != NULL is protecting us against recursion. */
49
        urb->complete(urb);
50
 
51
        /* detach element from chain data structure */
52
        spin_lock_irqsave(&acp->lock, flags);
53
        if (acp->active != acep)        /* paranoia debug check */
54
                dbg("auerchain_complete: completion on non-active element called!");
55
        else
56
                acp->active = NULL;
57
 
58
        /* add the used chain element to the list of free elements */
59
        list_add_tail(&acep->list, &acp->free_list);
60
        acep = NULL;
61
 
62
        /* is there a new element waiting in the chain? */
63
        if (!acp->active && !list_empty(&acp->waiting_list)) {
64
                /* yes: get the entry */
65
                struct list_head *tmp = acp->waiting_list.next;
66
                list_del(tmp);
67
                acep = list_entry(tmp, struct auerchainelement, list);
68
                acp->active = acep;
69
        }
70
        spin_unlock_irqrestore(&acp->lock, flags);
71
 
72
        /* submit the new urb */
73
        if (acep) {
74
                urb = acep->urbp;
75
                dbg("auerchain_complete: submitting next urb from chain");
76
                urb->status = 0; /* needed! */
77
                result = usb_submit_urb(urb);
78
 
79
                /* check for submit errors */
80
                if (result) {
81
                        urb->status = result;
82
                        dbg("auerchain_complete: usb_submit_urb with error code %d", result);
83
                        /* and do error handling via *this* completion function (recursive) */
84
                        auerchain_complete(urb);
85
                }
86
        } else {
87
                /* simple return without submitting a new urb.
88
                   The empty chain is detected with acp->active == NULL. */
89
        };
90
}
91
 
92
/* submit function for chained urbs
93
   this function may be called from completion context or from user space!
94
   early = 1 -> submit in front of chain
95
*/
96
int auerchain_submit_urb_list(struct auerchain *acp, struct urb *urb,
97
                              int early)
98
{
99
        int result;
100
        unsigned long flags;
101
        struct auerchainelement *acep = NULL;
102
 
103
        dbg("auerchain_submit_urb called");
104
 
105
        /* try to get a chain element */
106
        spin_lock_irqsave(&acp->lock, flags);
107
        if (!list_empty(&acp->free_list)) {
108
                /* yes: get the entry */
109
                struct list_head *tmp = acp->free_list.next;
110
                list_del(tmp);
111
                acep = list_entry(tmp, struct auerchainelement, list);
112
        }
113
        spin_unlock_irqrestore(&acp->lock, flags);
114
 
115
        /* if no chain element available: return with error */
116
        if (!acep) {
117
                return -ENOMEM;
118
        }
119
 
120
        /* fill in the new chain element values */
121
        acep->chain = acp;
122
        acep->context = urb->context;
123
        acep->complete = urb->complete;
124
        acep->urbp = urb;
125
        INIT_LIST_HEAD(&acep->list);
126
 
127
        /* modify urb */
128
        urb->context = acep;
129
        urb->complete = auerchain_complete;
130
        urb->status = -EINPROGRESS;     /* usb_submit_urb does this, too */
131
 
132
        /* add element to chain - or start it immediately */
133
        spin_lock_irqsave(&acp->lock, flags);
134
        if (acp->active) {
135
                /* there is traffic in the chain, simple add element to chain */
136
                if (early) {
137
                        dbg("adding new urb to head of chain");
138
                        list_add(&acep->list, &acp->waiting_list);
139
                } else {
140
                        dbg("adding new urb to end of chain");
141
                        list_add_tail(&acep->list, &acp->waiting_list);
142
                }
143
                acep = NULL;
144
        } else {
145
                /* the chain is empty. Prepare restart */
146
                acp->active = acep;
147
        }
148
        /* Spin has to be removed before usb_submit_urb! */
149
        spin_unlock_irqrestore(&acp->lock, flags);
150
 
151
        /* Submit urb if immediate restart */
152
        if (acep) {
153
                dbg("submitting urb immediate");
154
                urb->status = 0; /* needed! */
155
                result = usb_submit_urb(urb);
156
                /* check for submit errors */
157
                if (result) {
158
                        urb->status = result;
159
                        dbg("auerchain_submit_urb: usb_submit_urb with error code %d", result);
160
                        /* and do error handling via completion function */
161
                        auerchain_complete(urb);
162
                }
163
        }
164
 
165
        return 0;
166
}
167
 
168
/* submit function for chained urbs
169
   this function may be called from completion context or from user space!
170
*/
171
int auerchain_submit_urb(struct auerchain *acp, struct urb *urb)
172
{
173
        return auerchain_submit_urb_list(acp, urb, 0);
174
}
175
 
176
/* cancel an urb which is submitted to the chain
177
   the result is 0 if the urb is cancelled, or -EINPROGRESS if
178
   USB_ASYNC_UNLINK is set and the function is successfully started.
179
*/
180
int auerchain_unlink_urb(struct auerchain *acp, struct urb *urb)
181
{
182
        unsigned long flags;
183
        struct urb *urbp;
184
        struct auerchainelement *acep;
185
        struct list_head *tmp;
186
 
187
        dbg("auerchain_unlink_urb called");
188
 
189
        /* search the chain of waiting elements */
190
        spin_lock_irqsave(&acp->lock, flags);
191
        list_for_each(tmp, &acp->waiting_list) {
192
                acep = list_entry(tmp, struct auerchainelement, list);
193
                if (acep->urbp == urb) {
194
                        list_del(tmp);
195
                        urb->context = acep->context;
196
                        urb->complete = acep->complete;
197
                        list_add_tail(&acep->list, &acp->free_list);
198
                        spin_unlock_irqrestore(&acp->lock, flags);
199
                        dbg("unlink waiting urb");
200
                        urb->status = -ENOENT;
201
                        urb->complete(urb);
202
                        return 0;
203
                }
204
        }
205
        /* not found. */
206
        spin_unlock_irqrestore(&acp->lock, flags);
207
 
208
        /* get the active urb */
209
        acep = acp->active;
210
        if (acep) {
211
                urbp = acep->urbp;
212
 
213
                /* check if we have to cancel the active urb */
214
                if (urbp == urb) {
215
                        /* note that there is a race condition between the check above
216
                           and the unlink() call because of no lock. This race is harmless,
217
                           because the usb module will detect the unlink() after completion.
218
                           We can't use the acp->lock here because the completion function
219
                           wants to grab it.
220
                         */
221
                        dbg("unlink active urb");
222
                        return usb_unlink_urb(urbp);
223
                }
224
        }
225
 
226
        /* not found anyway
227
           ... is some kind of success
228
         */
229
        dbg("urb to unlink not found in chain");
230
        return 0;
231
}
232
 
233
/* cancel all urbs which are in the chain.
234
   this function must not be called from interrupt or completion handler.
235
*/
236
void auerchain_unlink_all(struct auerchain *acp)
237
{
238
        unsigned long flags;
239
        struct urb *urbp;
240
        struct auerchainelement *acep;
241
 
242
        dbg("auerchain_unlink_all called");
243
 
244
        /* clear the chain of waiting elements */
245
        spin_lock_irqsave(&acp->lock, flags);
246
        while (!list_empty(&acp->waiting_list)) {
247
                /* get the next entry */
248
                struct list_head *tmp = acp->waiting_list.next;
249
                list_del(tmp);
250
                acep = list_entry(tmp, struct auerchainelement, list);
251
                urbp = acep->urbp;
252
                urbp->context = acep->context;
253
                urbp->complete = acep->complete;
254
                list_add_tail(&acep->list, &acp->free_list);
255
                spin_unlock_irqrestore(&acp->lock, flags);
256
                dbg("unlink waiting urb");
257
                urbp->status = -ENOENT;
258
                urbp->complete(urbp);
259
                spin_lock_irqsave(&acp->lock, flags);
260
        }
261
        spin_unlock_irqrestore(&acp->lock, flags);
262
 
263
        /* clear the active urb */
264
        acep = acp->active;
265
        if (acep) {
266
                urbp = acep->urbp;
267
                urbp->transfer_flags &= ~USB_ASYNC_UNLINK;
268
                dbg("unlink active urb");
269
                usb_unlink_urb(urbp);
270
        }
271
}
272
 
273
 
274
/* free the chain.
275
   this function must not be called from interrupt or completion handler.
276
*/
277
void auerchain_free(struct auerchain *acp)
278
{
279
        unsigned long flags;
280
        struct auerchainelement *acep;
281
 
282
        dbg("auerchain_free called");
283
 
284
        /* first, cancel all pending urbs */
285
        auerchain_unlink_all(acp);
286
 
287
        /* free the elements */
288
        spin_lock_irqsave(&acp->lock, flags);
289
        while (!list_empty(&acp->free_list)) {
290
                /* get the next entry */
291
                struct list_head *tmp = acp->free_list.next;
292
                list_del(tmp);
293
                spin_unlock_irqrestore(&acp->lock, flags);
294
                acep = list_entry(tmp, struct auerchainelement, list);
295
                kfree(acep);
296
                spin_lock_irqsave(&acp->lock, flags);
297
        }
298
        spin_unlock_irqrestore(&acp->lock, flags);
299
}
300
 
301
 
302
/* Init the chain control structure */
303
void auerchain_init(struct auerchain *acp)
304
{
305
        /* init the chain data structure */
306
        acp->active = NULL;
307
        spin_lock_init(&acp->lock);
308
        INIT_LIST_HEAD(&acp->waiting_list);
309
        INIT_LIST_HEAD(&acp->free_list);
310
}
311
 
312
/* setup a chain.
313
   It is assumed that there is no concurrency while setting up the chain
314
   requirement: auerchain_init()
315
*/
316
int auerchain_setup(struct auerchain *acp, unsigned int numElements)
317
{
318
        struct auerchainelement *acep;
319
 
320
        dbg("auerchain_setup called with %d elements", numElements);
321
 
322
        /* fill the list of free elements */
323
        for (; numElements; numElements--) {
324
                acep =
325
                    (struct auerchainelement *)
326
                    kmalloc(sizeof(struct auerchainelement), GFP_KERNEL);
327
                if (!acep)
328
                        goto ac_fail;
329
                memset(acep, 0, sizeof(struct auerchainelement));
330
                INIT_LIST_HEAD(&acep->list);
331
                list_add_tail(&acep->list, &acp->free_list);
332
        }
333
        return 0;
334
 
335
      ac_fail:  /* free the elements */
336
        while (!list_empty(&acp->free_list)) {
337
                /* get the next entry */
338
                struct list_head *tmp = acp->free_list.next;
339
                list_del(tmp);
340
                acep = list_entry(tmp, struct auerchainelement, list);
341
                kfree(acep);
342
        }
343
        return -ENOMEM;
344
}
345
 
346
 
347
/* completion handler for synchronous chained URBs */
348
static void auerchain_blocking_completion(struct urb *urb)
349
{
350
        struct auerchain_chs *pchs = (struct auerchain_chs *) urb->context;
351
        pchs->done = 1;
352
        wmb();
353
        wake_up(&pchs->wqh);
354
}
355
 
356
 
357
/* Starts chained urb and waits for completion or timeout */
358
static int auerchain_start_wait_urb(struct auerchain *acp, struct urb *urb,
359
                                    int timeout, int *actual_length)
360
{
361
        DECLARE_WAITQUEUE(wait, current);
362
        struct auerchain_chs chs;
363
        int status;
364
 
365
        dbg("auerchain_start_wait_urb called");
366
        init_waitqueue_head(&chs.wqh);
367
        chs.done = 0;
368
 
369
        set_current_state(TASK_UNINTERRUPTIBLE);
370
        add_wait_queue(&chs.wqh, &wait);
371
        urb->context = &chs;
372
        status = auerchain_submit_urb(acp, urb);
373
        if (status) {
374
                /* something went wrong */
375
                set_current_state(TASK_RUNNING);
376
                remove_wait_queue(&chs.wqh, &wait);
377
                return status;
378
        }
379
 
380
        while (timeout && !chs.done) {
381
                timeout = schedule_timeout(timeout);
382
                set_current_state(TASK_UNINTERRUPTIBLE);
383
                rmb();
384
        }
385
 
386
        set_current_state(TASK_RUNNING);
387
        remove_wait_queue(&chs.wqh, &wait);
388
 
389
        if (!timeout && !chs.done) {
390
                if (urb->status != -EINPROGRESS) {      /* No callback?!! */
391
                        dbg("auerchain_start_wait_urb: raced timeout");
392
                        status = urb->status;
393
                } else {
394
                        dbg("auerchain_start_wait_urb: timeout");
395
                        auerchain_unlink_urb(acp, urb); /* remove urb safely */
396
                        status = -ETIMEDOUT;
397
                }
398
        } else
399
                status = urb->status;
400
 
401
        if (actual_length)
402
                *actual_length = urb->actual_length;
403
 
404
        return status;
405
}
406
 
407
 
408
/* auerchain_control_msg - Builds a control urb, sends it off and waits for completion
409
   acp: pointer to the auerchain
410
   dev: pointer to the usb device to send the message to
411
   pipe: endpoint "pipe" to send the message to
412
   request: USB message request value
413
   requesttype: USB message request type value
414
   value: USB message value
415
   index: USB message index value
416
   data: pointer to the data to send
417
   size: length in bytes of the data to send
418
   timeout: time to wait for the message to complete before timing out (if 0 the wait is forever)
419
 
420
   This function sends a simple control message to a specified endpoint
421
   and waits for the message to complete, or timeout.
422
 
423
   If successful, it returns the transfered length, othwise a negative error number.
424
 
425
   Don't use this function from within an interrupt context, like a
426
   bottom half handler.  If you need a asyncronous message, or need to send
427
   a message from within interrupt context, use auerchain_submit_urb()
428
*/
429
int auerchain_control_msg(struct auerchain *acp, struct usb_device *dev,
430
                          unsigned int pipe, __u8 request,
431
                          __u8 requesttype, __u16 value, __u16 index,
432
                          void *data, __u16 size, int timeout)
433
{
434
        int ret;
435
        struct usb_ctrlrequest *dr;
436
        struct urb *urb;
437
        int length;
438
 
439
        dbg("auerchain_control_msg");
440
        dr = (struct usb_ctrlrequest *)
441
            kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
442
        if (!dr)
443
                return -ENOMEM;
444
        urb = usb_alloc_urb(0);
445
        if (!urb) {
446
                kfree(dr);
447
                return -ENOMEM;
448
        }
449
 
450
        dr->bRequestType = requesttype;
451
        dr->bRequest = request;
452
        dr->wValue = cpu_to_le16(value);
453
        dr->wIndex = cpu_to_le16(index);
454
        dr->wLength = cpu_to_le16(size);
455
 
456
        FILL_CONTROL_URB(urb, dev, pipe, (unsigned char *) dr, data, size,      /* build urb */
457
                         (usb_complete_t) auerchain_blocking_completion,
458
                         0);
459
        ret = auerchain_start_wait_urb(acp, urb, timeout, &length);
460
 
461
        usb_free_urb(urb);
462
        kfree(dr);
463
 
464
        if (ret < 0)
465
                return ret;
466
        else
467
                return length;
468
}

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.