aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/isdn/capi/capi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/isdn/capi/capi.c')
-rw-r--r--drivers/isdn/capi/capi.c54
1 files changed, 32 insertions, 22 deletions
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 173c899a1fb4..2e541fa02024 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -87,6 +87,11 @@ struct capincci;
87#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE 87#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
88struct capiminor; 88struct capiminor;
89 89
90struct datahandle_queue {
91 struct list_head list;
92 u16 datahandle;
93};
94
90struct capiminor { 95struct capiminor {
91 struct list_head list; 96 struct list_head list;
92 struct capincci *nccip; 97 struct capincci *nccip;
@@ -109,12 +114,9 @@ struct capiminor {
109 int outbytes; 114 int outbytes;
110 115
111 /* transmit path */ 116 /* transmit path */
112 struct datahandle_queue { 117 struct list_head ackqueue;
113 struct datahandle_queue *next;
114 u16 datahandle;
115 } *ackqueue;
116 int nack; 118 int nack;
117 119 spinlock_t ackqlock;
118}; 120};
119#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ 121#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
120 122
@@ -156,48 +158,54 @@ static LIST_HEAD(capiminor_list);
156 158
157static int capincci_add_ack(struct capiminor *mp, u16 datahandle) 159static int capincci_add_ack(struct capiminor *mp, u16 datahandle)
158{ 160{
159 struct datahandle_queue *n, **pp; 161 struct datahandle_queue *n;
162 unsigned long flags;
160 163
161 n = kmalloc(sizeof(*n), GFP_ATOMIC); 164 n = kmalloc(sizeof(*n), GFP_ATOMIC);
162 if (!n) { 165 if (unlikely(!n)) {
163 printk(KERN_ERR "capi: alloc datahandle failed\n"); 166 printk(KERN_ERR "capi: alloc datahandle failed\n");
164 return -1; 167 return -1;
165 } 168 }
166 n->next = NULL;
167 n->datahandle = datahandle; 169 n->datahandle = datahandle;
168 for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) ; 170 INIT_LIST_HEAD(&n->list);
169 *pp = n; 171 spin_lock_irqsave(&mp->ackqlock, flags);
172 list_add_tail(&n->list, &mp->ackqueue);
170 mp->nack++; 173 mp->nack++;
174 spin_unlock_irqrestore(&mp->ackqlock, flags);
171 return 0; 175 return 0;
172} 176}
173 177
174static int capiminor_del_ack(struct capiminor *mp, u16 datahandle) 178static int capiminor_del_ack(struct capiminor *mp, u16 datahandle)
175{ 179{
176 struct datahandle_queue **pp, *p; 180 struct datahandle_queue *p, *tmp;
181 unsigned long flags;
177 182
178 for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) { 183 spin_lock_irqsave(&mp->ackqlock, flags);
179 if ((*pp)->datahandle == datahandle) { 184 list_for_each_entry_safe(p, tmp, &mp->ackqueue, list) {
180 p = *pp; 185 if (p->datahandle == datahandle) {
181 *pp = (*pp)->next; 186 list_del(&p->list);
182 kfree(p); 187 kfree(p);
183 mp->nack--; 188 mp->nack--;
189 spin_unlock_irqrestore(&mp->ackqlock, flags);
184 return 0; 190 return 0;
185 } 191 }
186 } 192 }
193 spin_unlock_irqrestore(&mp->ackqlock, flags);
187 return -1; 194 return -1;
188} 195}
189 196
190static void capiminor_del_all_ack(struct capiminor *mp) 197static void capiminor_del_all_ack(struct capiminor *mp)
191{ 198{
192 struct datahandle_queue **pp, *p; 199 struct datahandle_queue *p, *tmp;
200 unsigned long flags;
193 201
194 pp = &mp->ackqueue; 202 spin_lock_irqsave(&mp->ackqlock, flags);
195 while (*pp) { 203 list_for_each_entry_safe(p, tmp, &mp->ackqueue, list) {
196 p = *pp; 204 list_del(&p->list);
197 *pp = (*pp)->next;
198 kfree(p); 205 kfree(p);
199 mp->nack--; 206 mp->nack--;
200 } 207 }
208 spin_unlock_irqrestore(&mp->ackqlock, flags);
201} 209}
202 210
203 211
@@ -220,6 +228,8 @@ static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci)
220 mp->ncci = ncci; 228 mp->ncci = ncci;
221 mp->msgid = 0; 229 mp->msgid = 0;
222 atomic_set(&mp->ttyopencount,0); 230 atomic_set(&mp->ttyopencount,0);
231 INIT_LIST_HEAD(&mp->ackqueue);
232 spin_lock_init(&mp->ackqlock);
223 233
224 skb_queue_head_init(&mp->inqueue); 234 skb_queue_head_init(&mp->inqueue);
225 skb_queue_head_init(&mp->outqueue); 235 skb_queue_head_init(&mp->outqueue);