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