3 * Author Karsten Keil <kkeil@novell.com>
5 * Copyright 2008 by Karsten Keil <kkeil@novell.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
18 #include <linux/module.h>
19 #include <linux/mISDNhw.h>
22 dchannel_bh(struct work_struct
*ws
)
24 struct dchannel
*dch
= container_of(ws
, struct dchannel
, workq
);
28 if (test_and_clear_bit(FLG_RECVQUEUE
, &dch
->Flags
)) {
29 while ((skb
= skb_dequeue(&dch
->rqueue
))) {
30 if (likely(dch
->dev
.D
.peer
)) {
31 err
= dch
->dev
.D
.recv(dch
->dev
.D
.peer
, skb
);
38 if (test_and_clear_bit(FLG_PHCHANGE
, &dch
->Flags
)) {
45 bchannel_bh(struct work_struct
*ws
)
47 struct bchannel
*bch
= container_of(ws
, struct bchannel
, workq
);
51 if (test_and_clear_bit(FLG_RECVQUEUE
, &bch
->Flags
)) {
52 while ((skb
= skb_dequeue(&bch
->rqueue
))) {
53 if (bch
->rcount
>= 64)
54 printk(KERN_WARNING
"B-channel %p receive "
55 "queue if full, but empties...\n", bch
);
57 if (likely(bch
->ch
.peer
)) {
58 err
= bch
->ch
.recv(bch
->ch
.peer
, skb
);
68 mISDN_initdchannel(struct dchannel
*ch
, int maxlen
, void *phf
)
70 test_and_set_bit(FLG_HDLC
, &ch
->Flags
);
77 skb_queue_head_init(&ch
->squeue
);
78 skb_queue_head_init(&ch
->rqueue
);
79 INIT_LIST_HEAD(&ch
->dev
.bchannels
);
80 INIT_WORK(&ch
->workq
, dchannel_bh
);
83 EXPORT_SYMBOL(mISDN_initdchannel
);
86 mISDN_initbchannel(struct bchannel
*ch
, int maxlen
)
94 skb_queue_head_init(&ch
->rqueue
);
97 INIT_WORK(&ch
->workq
, bchannel_bh
);
100 EXPORT_SYMBOL(mISDN_initbchannel
);
103 mISDN_freedchannel(struct dchannel
*ch
)
106 dev_kfree_skb(ch
->tx_skb
);
110 dev_kfree_skb(ch
->rx_skb
);
113 skb_queue_purge(&ch
->squeue
);
114 skb_queue_purge(&ch
->rqueue
);
115 flush_scheduled_work();
118 EXPORT_SYMBOL(mISDN_freedchannel
);
121 mISDN_freebchannel(struct bchannel
*ch
)
124 dev_kfree_skb(ch
->tx_skb
);
128 dev_kfree_skb(ch
->rx_skb
);
132 dev_kfree_skb(ch
->next_skb
);
135 skb_queue_purge(&ch
->rqueue
);
137 flush_scheduled_work();
140 EXPORT_SYMBOL(mISDN_freebchannel
);
143 get_sapi_tei(u_char
*p
)
149 return sapi
| (tei
<< 8);
153 recv_Dchannel(struct dchannel
*dch
)
155 struct mISDNhead
*hh
;
157 if (dch
->rx_skb
->len
< 2) { /* at least 2 for sapi / tei */
158 dev_kfree_skb(dch
->rx_skb
);
162 hh
= mISDN_HEAD_P(dch
->rx_skb
);
163 hh
->prim
= PH_DATA_IND
;
164 hh
->id
= get_sapi_tei(dch
->rx_skb
->data
);
165 skb_queue_tail(&dch
->rqueue
, dch
->rx_skb
);
167 schedule_event(dch
, FLG_RECVQUEUE
);
169 EXPORT_SYMBOL(recv_Dchannel
);
172 recv_Bchannel(struct bchannel
*bch
)
174 struct mISDNhead
*hh
;
176 hh
= mISDN_HEAD_P(bch
->rx_skb
);
177 hh
->prim
= PH_DATA_IND
;
178 hh
->id
= MISDN_ID_ANY
;
179 if (bch
->rcount
>= 64) {
180 dev_kfree_skb(bch
->rx_skb
);
185 skb_queue_tail(&bch
->rqueue
, bch
->rx_skb
);
187 schedule_event(bch
, FLG_RECVQUEUE
);
189 EXPORT_SYMBOL(recv_Bchannel
);
192 recv_Dchannel_skb(struct dchannel
*dch
, struct sk_buff
*skb
)
194 skb_queue_tail(&dch
->rqueue
, skb
);
195 schedule_event(dch
, FLG_RECVQUEUE
);
197 EXPORT_SYMBOL(recv_Dchannel_skb
);
200 recv_Bchannel_skb(struct bchannel
*bch
, struct sk_buff
*skb
)
202 if (bch
->rcount
>= 64) {
207 skb_queue_tail(&bch
->rqueue
, skb
);
208 schedule_event(bch
, FLG_RECVQUEUE
);
210 EXPORT_SYMBOL(recv_Bchannel_skb
);
213 confirm_Dsend(struct dchannel
*dch
)
217 skb
= _alloc_mISDN_skb(PH_DATA_CNF
, mISDN_HEAD_ID(dch
->tx_skb
),
218 0, NULL
, GFP_ATOMIC
);
220 printk(KERN_ERR
"%s: no skb id %x\n", __func__
,
221 mISDN_HEAD_ID(dch
->tx_skb
));
224 skb_queue_tail(&dch
->rqueue
, skb
);
225 schedule_event(dch
, FLG_RECVQUEUE
);
229 get_next_dframe(struct dchannel
*dch
)
232 dch
->tx_skb
= skb_dequeue(&dch
->squeue
);
238 test_and_clear_bit(FLG_TX_BUSY
, &dch
->Flags
);
241 EXPORT_SYMBOL(get_next_dframe
);
244 confirm_Bsend(struct bchannel
*bch
)
248 if (bch
->rcount
>= 64)
250 skb
= _alloc_mISDN_skb(PH_DATA_CNF
, mISDN_HEAD_ID(bch
->tx_skb
),
251 0, NULL
, GFP_ATOMIC
);
253 printk(KERN_ERR
"%s: no skb id %x\n", __func__
,
254 mISDN_HEAD_ID(bch
->tx_skb
));
258 skb_queue_tail(&bch
->rqueue
, skb
);
259 schedule_event(bch
, FLG_RECVQUEUE
);
261 EXPORT_SYMBOL(confirm_Bsend
);
264 get_next_bframe(struct bchannel
*bch
)
267 if (test_bit(FLG_TX_NEXT
, &bch
->Flags
)) {
268 bch
->tx_skb
= bch
->next_skb
;
270 bch
->next_skb
= NULL
;
271 test_and_clear_bit(FLG_TX_NEXT
, &bch
->Flags
);
272 if (!test_bit(FLG_TRANSPARENT
, &bch
->Flags
))
273 confirm_Bsend(bch
); /* not for transparent */
276 test_and_clear_bit(FLG_TX_NEXT
, &bch
->Flags
);
277 printk(KERN_WARNING
"B TX_NEXT without skb\n");
281 test_and_clear_bit(FLG_TX_BUSY
, &bch
->Flags
);
284 EXPORT_SYMBOL(get_next_bframe
);
287 queue_ch_frame(struct mISDNchannel
*ch
, u_int pr
, int id
, struct sk_buff
*skb
)
289 struct mISDNhead
*hh
;
292 _queue_data(ch
, pr
, id
, 0, NULL
, GFP_ATOMIC
);
295 hh
= mISDN_HEAD_P(skb
);
298 if (!ch
->recv(ch
->peer
, skb
))
304 EXPORT_SYMBOL(queue_ch_frame
);
307 dchannel_senddata(struct dchannel
*ch
, struct sk_buff
*skb
)
311 printk(KERN_WARNING
"%s: skb too small\n", __func__
);
314 if (skb
->len
> ch
->maxlen
) {
315 printk(KERN_WARNING
"%s: skb too large(%d/%d)\n",
316 __func__
, skb
->len
, ch
->maxlen
);
319 /* HW lock must be obtained */
320 if (test_and_set_bit(FLG_TX_BUSY
, &ch
->Flags
)) {
321 skb_queue_tail(&ch
->squeue
, skb
);
330 EXPORT_SYMBOL(dchannel_senddata
);
333 bchannel_senddata(struct bchannel
*ch
, struct sk_buff
*skb
)
338 printk(KERN_WARNING
"%s: skb too small\n", __func__
);
341 if (skb
->len
> ch
->maxlen
) {
342 printk(KERN_WARNING
"%s: skb too large(%d/%d)\n",
343 __func__
, skb
->len
, ch
->maxlen
);
346 /* HW lock must be obtained */
347 /* check for pending next_skb */
350 "%s: next_skb exist ERROR (skb->len=%d next_skb->len=%d)\n",
351 __func__
, skb
->len
, ch
->next_skb
->len
);
354 if (test_and_set_bit(FLG_TX_BUSY
, &ch
->Flags
)) {
355 test_and_set_bit(FLG_TX_NEXT
, &ch
->Flags
);
365 EXPORT_SYMBOL(bchannel_senddata
);