xref: /OK3568_Linux_fs/kernel/drivers/isdn/mISDN/hwchannel.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Author	Karsten Keil <kkeil@novell.com>
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Copyright 2008  by Karsten Keil <kkeil@novell.com>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/gfp.h>
10*4882a593Smuzhiyun #include <linux/module.h>
11*4882a593Smuzhiyun #include <linux/mISDNhw.h>
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun static void
dchannel_bh(struct work_struct * ws)14*4882a593Smuzhiyun dchannel_bh(struct work_struct *ws)
15*4882a593Smuzhiyun {
16*4882a593Smuzhiyun 	struct dchannel	*dch  = container_of(ws, struct dchannel, workq);
17*4882a593Smuzhiyun 	struct sk_buff	*skb;
18*4882a593Smuzhiyun 	int		err;
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun 	if (test_and_clear_bit(FLG_RECVQUEUE, &dch->Flags)) {
21*4882a593Smuzhiyun 		while ((skb = skb_dequeue(&dch->rqueue))) {
22*4882a593Smuzhiyun 			if (likely(dch->dev.D.peer)) {
23*4882a593Smuzhiyun 				err = dch->dev.D.recv(dch->dev.D.peer, skb);
24*4882a593Smuzhiyun 				if (err)
25*4882a593Smuzhiyun 					dev_kfree_skb(skb);
26*4882a593Smuzhiyun 			} else
27*4882a593Smuzhiyun 				dev_kfree_skb(skb);
28*4882a593Smuzhiyun 		}
29*4882a593Smuzhiyun 	}
30*4882a593Smuzhiyun 	if (test_and_clear_bit(FLG_PHCHANGE, &dch->Flags)) {
31*4882a593Smuzhiyun 		if (dch->phfunc)
32*4882a593Smuzhiyun 			dch->phfunc(dch);
33*4882a593Smuzhiyun 	}
34*4882a593Smuzhiyun }
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun static void
bchannel_bh(struct work_struct * ws)37*4882a593Smuzhiyun bchannel_bh(struct work_struct *ws)
38*4882a593Smuzhiyun {
39*4882a593Smuzhiyun 	struct bchannel	*bch  = container_of(ws, struct bchannel, workq);
40*4882a593Smuzhiyun 	struct sk_buff	*skb;
41*4882a593Smuzhiyun 	int		err;
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun 	if (test_and_clear_bit(FLG_RECVQUEUE, &bch->Flags)) {
44*4882a593Smuzhiyun 		while ((skb = skb_dequeue(&bch->rqueue))) {
45*4882a593Smuzhiyun 			bch->rcount--;
46*4882a593Smuzhiyun 			if (likely(bch->ch.peer)) {
47*4882a593Smuzhiyun 				err = bch->ch.recv(bch->ch.peer, skb);
48*4882a593Smuzhiyun 				if (err)
49*4882a593Smuzhiyun 					dev_kfree_skb(skb);
50*4882a593Smuzhiyun 			} else
51*4882a593Smuzhiyun 				dev_kfree_skb(skb);
52*4882a593Smuzhiyun 		}
53*4882a593Smuzhiyun 	}
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun int
mISDN_initdchannel(struct dchannel * ch,int maxlen,void * phf)57*4882a593Smuzhiyun mISDN_initdchannel(struct dchannel *ch, int maxlen, void *phf)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun 	test_and_set_bit(FLG_HDLC, &ch->Flags);
60*4882a593Smuzhiyun 	ch->maxlen = maxlen;
61*4882a593Smuzhiyun 	ch->hw = NULL;
62*4882a593Smuzhiyun 	ch->rx_skb = NULL;
63*4882a593Smuzhiyun 	ch->tx_skb = NULL;
64*4882a593Smuzhiyun 	ch->tx_idx = 0;
65*4882a593Smuzhiyun 	ch->phfunc = phf;
66*4882a593Smuzhiyun 	skb_queue_head_init(&ch->squeue);
67*4882a593Smuzhiyun 	skb_queue_head_init(&ch->rqueue);
68*4882a593Smuzhiyun 	INIT_LIST_HEAD(&ch->dev.bchannels);
69*4882a593Smuzhiyun 	INIT_WORK(&ch->workq, dchannel_bh);
70*4882a593Smuzhiyun 	return 0;
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun EXPORT_SYMBOL(mISDN_initdchannel);
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun int
mISDN_initbchannel(struct bchannel * ch,unsigned short maxlen,unsigned short minlen)75*4882a593Smuzhiyun mISDN_initbchannel(struct bchannel *ch, unsigned short maxlen,
76*4882a593Smuzhiyun 		   unsigned short minlen)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun 	ch->Flags = 0;
79*4882a593Smuzhiyun 	ch->minlen = minlen;
80*4882a593Smuzhiyun 	ch->next_minlen = minlen;
81*4882a593Smuzhiyun 	ch->init_minlen = minlen;
82*4882a593Smuzhiyun 	ch->maxlen = maxlen;
83*4882a593Smuzhiyun 	ch->next_maxlen = maxlen;
84*4882a593Smuzhiyun 	ch->init_maxlen = maxlen;
85*4882a593Smuzhiyun 	ch->hw = NULL;
86*4882a593Smuzhiyun 	ch->rx_skb = NULL;
87*4882a593Smuzhiyun 	ch->tx_skb = NULL;
88*4882a593Smuzhiyun 	ch->tx_idx = 0;
89*4882a593Smuzhiyun 	skb_queue_head_init(&ch->rqueue);
90*4882a593Smuzhiyun 	ch->rcount = 0;
91*4882a593Smuzhiyun 	ch->next_skb = NULL;
92*4882a593Smuzhiyun 	INIT_WORK(&ch->workq, bchannel_bh);
93*4882a593Smuzhiyun 	return 0;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun EXPORT_SYMBOL(mISDN_initbchannel);
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun int
mISDN_freedchannel(struct dchannel * ch)98*4882a593Smuzhiyun mISDN_freedchannel(struct dchannel *ch)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun 	if (ch->tx_skb) {
101*4882a593Smuzhiyun 		dev_kfree_skb(ch->tx_skb);
102*4882a593Smuzhiyun 		ch->tx_skb = NULL;
103*4882a593Smuzhiyun 	}
104*4882a593Smuzhiyun 	if (ch->rx_skb) {
105*4882a593Smuzhiyun 		dev_kfree_skb(ch->rx_skb);
106*4882a593Smuzhiyun 		ch->rx_skb = NULL;
107*4882a593Smuzhiyun 	}
108*4882a593Smuzhiyun 	skb_queue_purge(&ch->squeue);
109*4882a593Smuzhiyun 	skb_queue_purge(&ch->rqueue);
110*4882a593Smuzhiyun 	flush_work(&ch->workq);
111*4882a593Smuzhiyun 	return 0;
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun EXPORT_SYMBOL(mISDN_freedchannel);
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun void
mISDN_clear_bchannel(struct bchannel * ch)116*4882a593Smuzhiyun mISDN_clear_bchannel(struct bchannel *ch)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun 	if (ch->tx_skb) {
119*4882a593Smuzhiyun 		dev_kfree_skb(ch->tx_skb);
120*4882a593Smuzhiyun 		ch->tx_skb = NULL;
121*4882a593Smuzhiyun 	}
122*4882a593Smuzhiyun 	ch->tx_idx = 0;
123*4882a593Smuzhiyun 	if (ch->rx_skb) {
124*4882a593Smuzhiyun 		dev_kfree_skb(ch->rx_skb);
125*4882a593Smuzhiyun 		ch->rx_skb = NULL;
126*4882a593Smuzhiyun 	}
127*4882a593Smuzhiyun 	if (ch->next_skb) {
128*4882a593Smuzhiyun 		dev_kfree_skb(ch->next_skb);
129*4882a593Smuzhiyun 		ch->next_skb = NULL;
130*4882a593Smuzhiyun 	}
131*4882a593Smuzhiyun 	test_and_clear_bit(FLG_TX_BUSY, &ch->Flags);
132*4882a593Smuzhiyun 	test_and_clear_bit(FLG_TX_NEXT, &ch->Flags);
133*4882a593Smuzhiyun 	test_and_clear_bit(FLG_ACTIVE, &ch->Flags);
134*4882a593Smuzhiyun 	test_and_clear_bit(FLG_FILLEMPTY, &ch->Flags);
135*4882a593Smuzhiyun 	test_and_clear_bit(FLG_TX_EMPTY, &ch->Flags);
136*4882a593Smuzhiyun 	test_and_clear_bit(FLG_RX_OFF, &ch->Flags);
137*4882a593Smuzhiyun 	ch->dropcnt = 0;
138*4882a593Smuzhiyun 	ch->minlen = ch->init_minlen;
139*4882a593Smuzhiyun 	ch->next_minlen = ch->init_minlen;
140*4882a593Smuzhiyun 	ch->maxlen = ch->init_maxlen;
141*4882a593Smuzhiyun 	ch->next_maxlen = ch->init_maxlen;
142*4882a593Smuzhiyun 	skb_queue_purge(&ch->rqueue);
143*4882a593Smuzhiyun 	ch->rcount = 0;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun EXPORT_SYMBOL(mISDN_clear_bchannel);
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun void
mISDN_freebchannel(struct bchannel * ch)148*4882a593Smuzhiyun mISDN_freebchannel(struct bchannel *ch)
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun 	cancel_work_sync(&ch->workq);
151*4882a593Smuzhiyun 	mISDN_clear_bchannel(ch);
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun EXPORT_SYMBOL(mISDN_freebchannel);
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun int
mISDN_ctrl_bchannel(struct bchannel * bch,struct mISDN_ctrl_req * cq)156*4882a593Smuzhiyun mISDN_ctrl_bchannel(struct bchannel *bch, struct mISDN_ctrl_req *cq)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun 	int ret = 0;
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	switch (cq->op) {
161*4882a593Smuzhiyun 	case MISDN_CTRL_GETOP:
162*4882a593Smuzhiyun 		cq->op = MISDN_CTRL_RX_BUFFER | MISDN_CTRL_FILL_EMPTY |
163*4882a593Smuzhiyun 			 MISDN_CTRL_RX_OFF;
164*4882a593Smuzhiyun 		break;
165*4882a593Smuzhiyun 	case MISDN_CTRL_FILL_EMPTY:
166*4882a593Smuzhiyun 		if (cq->p1) {
167*4882a593Smuzhiyun 			memset(bch->fill, cq->p2 & 0xff, MISDN_BCH_FILL_SIZE);
168*4882a593Smuzhiyun 			test_and_set_bit(FLG_FILLEMPTY, &bch->Flags);
169*4882a593Smuzhiyun 		} else {
170*4882a593Smuzhiyun 			test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
171*4882a593Smuzhiyun 		}
172*4882a593Smuzhiyun 		break;
173*4882a593Smuzhiyun 	case MISDN_CTRL_RX_OFF:
174*4882a593Smuzhiyun 		/* read back dropped byte count */
175*4882a593Smuzhiyun 		cq->p2 = bch->dropcnt;
176*4882a593Smuzhiyun 		if (cq->p1)
177*4882a593Smuzhiyun 			test_and_set_bit(FLG_RX_OFF, &bch->Flags);
178*4882a593Smuzhiyun 		else
179*4882a593Smuzhiyun 			test_and_clear_bit(FLG_RX_OFF, &bch->Flags);
180*4882a593Smuzhiyun 		bch->dropcnt = 0;
181*4882a593Smuzhiyun 		break;
182*4882a593Smuzhiyun 	case MISDN_CTRL_RX_BUFFER:
183*4882a593Smuzhiyun 		if (cq->p2 > MISDN_CTRL_RX_SIZE_IGNORE)
184*4882a593Smuzhiyun 			bch->next_maxlen = cq->p2;
185*4882a593Smuzhiyun 		if (cq->p1 > MISDN_CTRL_RX_SIZE_IGNORE)
186*4882a593Smuzhiyun 			bch->next_minlen = cq->p1;
187*4882a593Smuzhiyun 		/* we return the old values */
188*4882a593Smuzhiyun 		cq->p1 = bch->minlen;
189*4882a593Smuzhiyun 		cq->p2 = bch->maxlen;
190*4882a593Smuzhiyun 		break;
191*4882a593Smuzhiyun 	default:
192*4882a593Smuzhiyun 		pr_info("mISDN unhandled control %x operation\n", cq->op);
193*4882a593Smuzhiyun 		ret = -EINVAL;
194*4882a593Smuzhiyun 		break;
195*4882a593Smuzhiyun 	}
196*4882a593Smuzhiyun 	return ret;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun EXPORT_SYMBOL(mISDN_ctrl_bchannel);
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun static inline u_int
get_sapi_tei(u_char * p)201*4882a593Smuzhiyun get_sapi_tei(u_char *p)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun 	u_int	sapi, tei;
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	sapi = *p >> 2;
206*4882a593Smuzhiyun 	tei = p[1] >> 1;
207*4882a593Smuzhiyun 	return sapi | (tei << 8);
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun void
recv_Dchannel(struct dchannel * dch)211*4882a593Smuzhiyun recv_Dchannel(struct dchannel *dch)
212*4882a593Smuzhiyun {
213*4882a593Smuzhiyun 	struct mISDNhead *hh;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	if (dch->rx_skb->len < 2) { /* at least 2 for sapi / tei */
216*4882a593Smuzhiyun 		dev_kfree_skb(dch->rx_skb);
217*4882a593Smuzhiyun 		dch->rx_skb = NULL;
218*4882a593Smuzhiyun 		return;
219*4882a593Smuzhiyun 	}
220*4882a593Smuzhiyun 	hh = mISDN_HEAD_P(dch->rx_skb);
221*4882a593Smuzhiyun 	hh->prim = PH_DATA_IND;
222*4882a593Smuzhiyun 	hh->id = get_sapi_tei(dch->rx_skb->data);
223*4882a593Smuzhiyun 	skb_queue_tail(&dch->rqueue, dch->rx_skb);
224*4882a593Smuzhiyun 	dch->rx_skb = NULL;
225*4882a593Smuzhiyun 	schedule_event(dch, FLG_RECVQUEUE);
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun EXPORT_SYMBOL(recv_Dchannel);
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun void
recv_Echannel(struct dchannel * ech,struct dchannel * dch)230*4882a593Smuzhiyun recv_Echannel(struct dchannel *ech, struct dchannel *dch)
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun 	struct mISDNhead *hh;
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	if (ech->rx_skb->len < 2) { /* at least 2 for sapi / tei */
235*4882a593Smuzhiyun 		dev_kfree_skb(ech->rx_skb);
236*4882a593Smuzhiyun 		ech->rx_skb = NULL;
237*4882a593Smuzhiyun 		return;
238*4882a593Smuzhiyun 	}
239*4882a593Smuzhiyun 	hh = mISDN_HEAD_P(ech->rx_skb);
240*4882a593Smuzhiyun 	hh->prim = PH_DATA_E_IND;
241*4882a593Smuzhiyun 	hh->id = get_sapi_tei(ech->rx_skb->data);
242*4882a593Smuzhiyun 	skb_queue_tail(&dch->rqueue, ech->rx_skb);
243*4882a593Smuzhiyun 	ech->rx_skb = NULL;
244*4882a593Smuzhiyun 	schedule_event(dch, FLG_RECVQUEUE);
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun EXPORT_SYMBOL(recv_Echannel);
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun void
recv_Bchannel(struct bchannel * bch,unsigned int id,bool force)249*4882a593Smuzhiyun recv_Bchannel(struct bchannel *bch, unsigned int id, bool force)
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun 	struct mISDNhead *hh;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	/* if allocation did fail upper functions still may call us */
254*4882a593Smuzhiyun 	if (unlikely(!bch->rx_skb))
255*4882a593Smuzhiyun 		return;
256*4882a593Smuzhiyun 	if (unlikely(!bch->rx_skb->len)) {
257*4882a593Smuzhiyun 		/* we have no data to send - this may happen after recovery
258*4882a593Smuzhiyun 		 * from overflow or too small allocation.
259*4882a593Smuzhiyun 		 * We need to free the buffer here */
260*4882a593Smuzhiyun 		dev_kfree_skb(bch->rx_skb);
261*4882a593Smuzhiyun 		bch->rx_skb = NULL;
262*4882a593Smuzhiyun 	} else {
263*4882a593Smuzhiyun 		if (test_bit(FLG_TRANSPARENT, &bch->Flags) &&
264*4882a593Smuzhiyun 		    (bch->rx_skb->len < bch->minlen) && !force)
265*4882a593Smuzhiyun 				return;
266*4882a593Smuzhiyun 		hh = mISDN_HEAD_P(bch->rx_skb);
267*4882a593Smuzhiyun 		hh->prim = PH_DATA_IND;
268*4882a593Smuzhiyun 		hh->id = id;
269*4882a593Smuzhiyun 		if (bch->rcount >= 64) {
270*4882a593Smuzhiyun 			printk(KERN_WARNING
271*4882a593Smuzhiyun 			       "B%d receive queue overflow - flushing!\n",
272*4882a593Smuzhiyun 			       bch->nr);
273*4882a593Smuzhiyun 			skb_queue_purge(&bch->rqueue);
274*4882a593Smuzhiyun 		}
275*4882a593Smuzhiyun 		bch->rcount++;
276*4882a593Smuzhiyun 		skb_queue_tail(&bch->rqueue, bch->rx_skb);
277*4882a593Smuzhiyun 		bch->rx_skb = NULL;
278*4882a593Smuzhiyun 		schedule_event(bch, FLG_RECVQUEUE);
279*4882a593Smuzhiyun 	}
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun EXPORT_SYMBOL(recv_Bchannel);
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun void
recv_Dchannel_skb(struct dchannel * dch,struct sk_buff * skb)284*4882a593Smuzhiyun recv_Dchannel_skb(struct dchannel *dch, struct sk_buff *skb)
285*4882a593Smuzhiyun {
286*4882a593Smuzhiyun 	skb_queue_tail(&dch->rqueue, skb);
287*4882a593Smuzhiyun 	schedule_event(dch, FLG_RECVQUEUE);
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun EXPORT_SYMBOL(recv_Dchannel_skb);
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun void
recv_Bchannel_skb(struct bchannel * bch,struct sk_buff * skb)292*4882a593Smuzhiyun recv_Bchannel_skb(struct bchannel *bch, struct sk_buff *skb)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun 	if (bch->rcount >= 64) {
295*4882a593Smuzhiyun 		printk(KERN_WARNING "B-channel %p receive queue overflow, "
296*4882a593Smuzhiyun 		       "flushing!\n", bch);
297*4882a593Smuzhiyun 		skb_queue_purge(&bch->rqueue);
298*4882a593Smuzhiyun 		bch->rcount = 0;
299*4882a593Smuzhiyun 	}
300*4882a593Smuzhiyun 	bch->rcount++;
301*4882a593Smuzhiyun 	skb_queue_tail(&bch->rqueue, skb);
302*4882a593Smuzhiyun 	schedule_event(bch, FLG_RECVQUEUE);
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun EXPORT_SYMBOL(recv_Bchannel_skb);
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun static void
confirm_Dsend(struct dchannel * dch)307*4882a593Smuzhiyun confirm_Dsend(struct dchannel *dch)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun 	struct sk_buff	*skb;
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	skb = _alloc_mISDN_skb(PH_DATA_CNF, mISDN_HEAD_ID(dch->tx_skb),
312*4882a593Smuzhiyun 			       0, NULL, GFP_ATOMIC);
313*4882a593Smuzhiyun 	if (!skb) {
314*4882a593Smuzhiyun 		printk(KERN_ERR "%s: no skb id %x\n", __func__,
315*4882a593Smuzhiyun 		       mISDN_HEAD_ID(dch->tx_skb));
316*4882a593Smuzhiyun 		return;
317*4882a593Smuzhiyun 	}
318*4882a593Smuzhiyun 	skb_queue_tail(&dch->rqueue, skb);
319*4882a593Smuzhiyun 	schedule_event(dch, FLG_RECVQUEUE);
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun int
get_next_dframe(struct dchannel * dch)323*4882a593Smuzhiyun get_next_dframe(struct dchannel *dch)
324*4882a593Smuzhiyun {
325*4882a593Smuzhiyun 	dch->tx_idx = 0;
326*4882a593Smuzhiyun 	dch->tx_skb = skb_dequeue(&dch->squeue);
327*4882a593Smuzhiyun 	if (dch->tx_skb) {
328*4882a593Smuzhiyun 		confirm_Dsend(dch);
329*4882a593Smuzhiyun 		return 1;
330*4882a593Smuzhiyun 	}
331*4882a593Smuzhiyun 	dch->tx_skb = NULL;
332*4882a593Smuzhiyun 	test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
333*4882a593Smuzhiyun 	return 0;
334*4882a593Smuzhiyun }
335*4882a593Smuzhiyun EXPORT_SYMBOL(get_next_dframe);
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun static void
confirm_Bsend(struct bchannel * bch)338*4882a593Smuzhiyun confirm_Bsend(struct bchannel *bch)
339*4882a593Smuzhiyun {
340*4882a593Smuzhiyun 	struct sk_buff	*skb;
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 	if (bch->rcount >= 64) {
343*4882a593Smuzhiyun 		printk(KERN_WARNING "B-channel %p receive queue overflow, "
344*4882a593Smuzhiyun 		       "flushing!\n", bch);
345*4882a593Smuzhiyun 		skb_queue_purge(&bch->rqueue);
346*4882a593Smuzhiyun 		bch->rcount = 0;
347*4882a593Smuzhiyun 	}
348*4882a593Smuzhiyun 	skb = _alloc_mISDN_skb(PH_DATA_CNF, mISDN_HEAD_ID(bch->tx_skb),
349*4882a593Smuzhiyun 			       0, NULL, GFP_ATOMIC);
350*4882a593Smuzhiyun 	if (!skb) {
351*4882a593Smuzhiyun 		printk(KERN_ERR "%s: no skb id %x\n", __func__,
352*4882a593Smuzhiyun 		       mISDN_HEAD_ID(bch->tx_skb));
353*4882a593Smuzhiyun 		return;
354*4882a593Smuzhiyun 	}
355*4882a593Smuzhiyun 	bch->rcount++;
356*4882a593Smuzhiyun 	skb_queue_tail(&bch->rqueue, skb);
357*4882a593Smuzhiyun 	schedule_event(bch, FLG_RECVQUEUE);
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun int
get_next_bframe(struct bchannel * bch)361*4882a593Smuzhiyun get_next_bframe(struct bchannel *bch)
362*4882a593Smuzhiyun {
363*4882a593Smuzhiyun 	bch->tx_idx = 0;
364*4882a593Smuzhiyun 	if (test_bit(FLG_TX_NEXT, &bch->Flags)) {
365*4882a593Smuzhiyun 		bch->tx_skb = bch->next_skb;
366*4882a593Smuzhiyun 		if (bch->tx_skb) {
367*4882a593Smuzhiyun 			bch->next_skb = NULL;
368*4882a593Smuzhiyun 			test_and_clear_bit(FLG_TX_NEXT, &bch->Flags);
369*4882a593Smuzhiyun 			/* confirm imediately to allow next data */
370*4882a593Smuzhiyun 			confirm_Bsend(bch);
371*4882a593Smuzhiyun 			return 1;
372*4882a593Smuzhiyun 		} else {
373*4882a593Smuzhiyun 			test_and_clear_bit(FLG_TX_NEXT, &bch->Flags);
374*4882a593Smuzhiyun 			printk(KERN_WARNING "B TX_NEXT without skb\n");
375*4882a593Smuzhiyun 		}
376*4882a593Smuzhiyun 	}
377*4882a593Smuzhiyun 	bch->tx_skb = NULL;
378*4882a593Smuzhiyun 	test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
379*4882a593Smuzhiyun 	return 0;
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun EXPORT_SYMBOL(get_next_bframe);
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun void
queue_ch_frame(struct mISDNchannel * ch,u_int pr,int id,struct sk_buff * skb)384*4882a593Smuzhiyun queue_ch_frame(struct mISDNchannel *ch, u_int pr, int id, struct sk_buff *skb)
385*4882a593Smuzhiyun {
386*4882a593Smuzhiyun 	struct mISDNhead *hh;
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	if (!skb) {
389*4882a593Smuzhiyun 		_queue_data(ch, pr, id, 0, NULL, GFP_ATOMIC);
390*4882a593Smuzhiyun 	} else {
391*4882a593Smuzhiyun 		if (ch->peer) {
392*4882a593Smuzhiyun 			hh = mISDN_HEAD_P(skb);
393*4882a593Smuzhiyun 			hh->prim = pr;
394*4882a593Smuzhiyun 			hh->id = id;
395*4882a593Smuzhiyun 			if (!ch->recv(ch->peer, skb))
396*4882a593Smuzhiyun 				return;
397*4882a593Smuzhiyun 		}
398*4882a593Smuzhiyun 		dev_kfree_skb(skb);
399*4882a593Smuzhiyun 	}
400*4882a593Smuzhiyun }
401*4882a593Smuzhiyun EXPORT_SYMBOL(queue_ch_frame);
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun int
dchannel_senddata(struct dchannel * ch,struct sk_buff * skb)404*4882a593Smuzhiyun dchannel_senddata(struct dchannel *ch, struct sk_buff *skb)
405*4882a593Smuzhiyun {
406*4882a593Smuzhiyun 	/* check oversize */
407*4882a593Smuzhiyun 	if (skb->len <= 0) {
408*4882a593Smuzhiyun 		printk(KERN_WARNING "%s: skb too small\n", __func__);
409*4882a593Smuzhiyun 		return -EINVAL;
410*4882a593Smuzhiyun 	}
411*4882a593Smuzhiyun 	if (skb->len > ch->maxlen) {
412*4882a593Smuzhiyun 		printk(KERN_WARNING "%s: skb too large(%d/%d)\n",
413*4882a593Smuzhiyun 		       __func__, skb->len, ch->maxlen);
414*4882a593Smuzhiyun 		return -EINVAL;
415*4882a593Smuzhiyun 	}
416*4882a593Smuzhiyun 	/* HW lock must be obtained */
417*4882a593Smuzhiyun 	if (test_and_set_bit(FLG_TX_BUSY, &ch->Flags)) {
418*4882a593Smuzhiyun 		skb_queue_tail(&ch->squeue, skb);
419*4882a593Smuzhiyun 		return 0;
420*4882a593Smuzhiyun 	} else {
421*4882a593Smuzhiyun 		/* write to fifo */
422*4882a593Smuzhiyun 		ch->tx_skb = skb;
423*4882a593Smuzhiyun 		ch->tx_idx = 0;
424*4882a593Smuzhiyun 		return 1;
425*4882a593Smuzhiyun 	}
426*4882a593Smuzhiyun }
427*4882a593Smuzhiyun EXPORT_SYMBOL(dchannel_senddata);
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun int
bchannel_senddata(struct bchannel * ch,struct sk_buff * skb)430*4882a593Smuzhiyun bchannel_senddata(struct bchannel *ch, struct sk_buff *skb)
431*4882a593Smuzhiyun {
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 	/* check oversize */
434*4882a593Smuzhiyun 	if (skb->len <= 0) {
435*4882a593Smuzhiyun 		printk(KERN_WARNING "%s: skb too small\n", __func__);
436*4882a593Smuzhiyun 		return -EINVAL;
437*4882a593Smuzhiyun 	}
438*4882a593Smuzhiyun 	if (skb->len > ch->maxlen) {
439*4882a593Smuzhiyun 		printk(KERN_WARNING "%s: skb too large(%d/%d)\n",
440*4882a593Smuzhiyun 		       __func__, skb->len, ch->maxlen);
441*4882a593Smuzhiyun 		return -EINVAL;
442*4882a593Smuzhiyun 	}
443*4882a593Smuzhiyun 	/* HW lock must be obtained */
444*4882a593Smuzhiyun 	/* check for pending next_skb */
445*4882a593Smuzhiyun 	if (ch->next_skb) {
446*4882a593Smuzhiyun 		printk(KERN_WARNING
447*4882a593Smuzhiyun 		       "%s: next_skb exist ERROR (skb->len=%d next_skb->len=%d)\n",
448*4882a593Smuzhiyun 		       __func__, skb->len, ch->next_skb->len);
449*4882a593Smuzhiyun 		return -EBUSY;
450*4882a593Smuzhiyun 	}
451*4882a593Smuzhiyun 	if (test_and_set_bit(FLG_TX_BUSY, &ch->Flags)) {
452*4882a593Smuzhiyun 		test_and_set_bit(FLG_TX_NEXT, &ch->Flags);
453*4882a593Smuzhiyun 		ch->next_skb = skb;
454*4882a593Smuzhiyun 		return 0;
455*4882a593Smuzhiyun 	} else {
456*4882a593Smuzhiyun 		/* write to fifo */
457*4882a593Smuzhiyun 		ch->tx_skb = skb;
458*4882a593Smuzhiyun 		ch->tx_idx = 0;
459*4882a593Smuzhiyun 		confirm_Bsend(ch);
460*4882a593Smuzhiyun 		return 1;
461*4882a593Smuzhiyun 	}
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun EXPORT_SYMBOL(bchannel_senddata);
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun /* The function allocates a new receive skb on demand with a size for the
466*4882a593Smuzhiyun  * requirements of the current protocol. It returns the tailroom of the
467*4882a593Smuzhiyun  * receive skb or an error.
468*4882a593Smuzhiyun  */
469*4882a593Smuzhiyun int
bchannel_get_rxbuf(struct bchannel * bch,int reqlen)470*4882a593Smuzhiyun bchannel_get_rxbuf(struct bchannel *bch, int reqlen)
471*4882a593Smuzhiyun {
472*4882a593Smuzhiyun 	int len;
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 	if (bch->rx_skb) {
475*4882a593Smuzhiyun 		len = skb_tailroom(bch->rx_skb);
476*4882a593Smuzhiyun 		if (len < reqlen) {
477*4882a593Smuzhiyun 			pr_warn("B%d no space for %d (only %d) bytes\n",
478*4882a593Smuzhiyun 				bch->nr, reqlen, len);
479*4882a593Smuzhiyun 			if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
480*4882a593Smuzhiyun 				/* send what we have now and try a new buffer */
481*4882a593Smuzhiyun 				recv_Bchannel(bch, 0, true);
482*4882a593Smuzhiyun 			} else {
483*4882a593Smuzhiyun 				/* on HDLC we have to drop too big frames */
484*4882a593Smuzhiyun 				return -EMSGSIZE;
485*4882a593Smuzhiyun 			}
486*4882a593Smuzhiyun 		} else {
487*4882a593Smuzhiyun 			return len;
488*4882a593Smuzhiyun 		}
489*4882a593Smuzhiyun 	}
490*4882a593Smuzhiyun 	/* update current min/max length first */
491*4882a593Smuzhiyun 	if (unlikely(bch->maxlen != bch->next_maxlen))
492*4882a593Smuzhiyun 		bch->maxlen = bch->next_maxlen;
493*4882a593Smuzhiyun 	if (unlikely(bch->minlen != bch->next_minlen))
494*4882a593Smuzhiyun 		bch->minlen = bch->next_minlen;
495*4882a593Smuzhiyun 	if (unlikely(reqlen > bch->maxlen))
496*4882a593Smuzhiyun 		return -EMSGSIZE;
497*4882a593Smuzhiyun 	if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
498*4882a593Smuzhiyun 		if (reqlen >= bch->minlen) {
499*4882a593Smuzhiyun 			len = reqlen;
500*4882a593Smuzhiyun 		} else {
501*4882a593Smuzhiyun 			len = 2 * bch->minlen;
502*4882a593Smuzhiyun 			if (len > bch->maxlen)
503*4882a593Smuzhiyun 				len = bch->maxlen;
504*4882a593Smuzhiyun 		}
505*4882a593Smuzhiyun 	} else {
506*4882a593Smuzhiyun 		/* with HDLC we do not know the length yet */
507*4882a593Smuzhiyun 		len = bch->maxlen;
508*4882a593Smuzhiyun 	}
509*4882a593Smuzhiyun 	bch->rx_skb = mI_alloc_skb(len, GFP_ATOMIC);
510*4882a593Smuzhiyun 	if (!bch->rx_skb) {
511*4882a593Smuzhiyun 		pr_warn("B%d receive no memory for %d bytes\n", bch->nr, len);
512*4882a593Smuzhiyun 		len = -ENOMEM;
513*4882a593Smuzhiyun 	}
514*4882a593Smuzhiyun 	return len;
515*4882a593Smuzhiyun }
516*4882a593Smuzhiyun EXPORT_SYMBOL(bchannel_get_rxbuf);
517