special usb hub handling, IDE disks, and retries all over the place
[linux-2.4.git] / drivers / usb / auerbuf.c
1 /*****************************************************************************/
2 /*
3  *      auerbuf.c  --  Auerswald PBX/System Telephone urb list storage.
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 "auerbuf.h"
26 #include <linux/slab.h>
27
28 /* free a single auerbuf */
29 void auerbuf_free(struct auerbuf *bp)
30 {
31         if (!bp) return;
32         kfree(bp->bufp);
33         kfree(bp->dr);
34         if (bp->urbp) {
35                 usb_free_urb(bp->urbp);
36         }
37         kfree(bp);
38 }
39
40 /* free the buffers from an auerbuf list */
41 void auerbuf_free_list(struct list_head *q)
42 {
43         struct list_head *tmp;
44         struct list_head *p;
45         struct auerbuf *bp;
46
47         dbg("auerbuf_free_list");
48         for (p = q->next; p != q;) {
49                 bp = list_entry(p, struct auerbuf, buff_list);
50                 tmp = p->next;
51                 list_del(p);
52                 p = tmp;
53                 auerbuf_free(bp);
54         }
55 }
56
57 /* free all buffers from an auerbuf chain */
58 void auerbuf_free_buffers(struct auerbufctl *bcp)
59 {
60         unsigned long flags;
61         dbg("auerbuf_free_buffers");
62
63         spin_lock_irqsave(&bcp->lock, flags);
64
65         auerbuf_free_list(&bcp->free_buff_list);
66         auerbuf_free_list(&bcp->rec_buff_list);
67
68         spin_unlock_irqrestore(&bcp->lock, flags);
69 }
70
71 /* init the members of a list control block */
72 void auerbuf_init(struct auerbufctl *bcp)
73 {
74         dbg("auerbuf_init");
75         spin_lock_init(&bcp->lock);
76         INIT_LIST_HEAD(&bcp->free_buff_list);
77         INIT_LIST_HEAD(&bcp->rec_buff_list);
78 }
79
80 /* setup a list of buffers */
81 /* requirement: auerbuf_init() */
82 int auerbuf_setup(struct auerbufctl *bcp, unsigned int numElements,
83                   unsigned int bufsize)
84 {
85         struct auerbuf *bep = NULL;
86
87         dbg("auerbuf_setup called with %d elements of %d bytes",
88             numElements, bufsize);
89
90         /* fill the list of free elements */
91         for (; numElements; numElements--) {
92                 bep =
93                     (struct auerbuf *) kmalloc(sizeof(struct auerbuf),
94                                                GFP_KERNEL);
95                 if (!bep)
96                         goto bl_fail;
97                 memset(bep, 0, sizeof(struct auerbuf));
98                 bep->list = bcp;
99                 INIT_LIST_HEAD(&bep->buff_list);
100                 bep->bufp = (char *) kmalloc(bufsize, GFP_KERNEL);
101                 if (!bep->bufp)
102                         goto bl_fail;
103                 bep->dr =
104                     (struct usb_ctrlrequest *)
105                     kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
106                 if (!bep->dr)
107                         goto bl_fail;
108                 bep->urbp = usb_alloc_urb(0);
109                 if (!bep->urbp)
110                         goto bl_fail;
111                 list_add_tail(&bep->buff_list, &bcp->free_buff_list);
112         }
113         return 0;
114
115       bl_fail:                  /* not enought memory. Free allocated elements */
116         dbg("auerbuf_setup: no more memory");
117         auerbuf_free (bep);
118         auerbuf_free_buffers(bcp);
119         return -ENOMEM;
120 }
121
122 /* alloc a free buffer from the list. Returns NULL if no buffer available */
123 struct auerbuf *auerbuf_getbuf(struct auerbufctl *bcp)
124 {
125         unsigned long flags;
126         struct auerbuf *bp = NULL;
127
128         spin_lock_irqsave(&bcp->lock, flags);
129         if (!list_empty(&bcp->free_buff_list)) {
130                 /* yes: get the entry */
131                 struct list_head *tmp = bcp->free_buff_list.next;
132                 list_del(tmp);
133                 bp = list_entry(tmp, struct auerbuf, buff_list);
134         }
135         spin_unlock_irqrestore(&bcp->lock, flags);
136         return bp;
137 }
138
139 /* insert a used buffer into the free list */
140 void auerbuf_releasebuf(struct auerbuf *bp)
141 {
142         unsigned long flags;
143         struct auerbufctl *bcp = bp->list;
144         bp->retries = 0;
145
146         dbg("auerbuf_releasebuf called");
147         spin_lock_irqsave(&bcp->lock, flags);
148         list_add_tail(&bp->buff_list, &bcp->free_buff_list);
149         spin_unlock_irqrestore(&bcp->lock, flags);
150 }