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 */
auerbuf_free(struct auerbuf * bp)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 */
auerbuf_free_list(struct list_head * q)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 */
auerbuf_free_buffers(struct auerbufctl * bcp)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 */
auerbuf_init(struct auerbufctl * bcp)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() */
auerbuf_setup(struct auerbufctl * bcp,unsigned int numElements,unsigned int bufsize)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 */
auerbuf_getbuf(struct auerbufctl * bcp)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 */
auerbuf_releasebuf(struct auerbuf * bp)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 }
151