1 /* 2 * 3 * Author Karsten Keil <kkeil@novell.com> 4 * 5 * Copyright 2008 by Karsten Keil <kkeil@novell.com> 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 version 2 as 9 * published by the Free Software Foundation. 10 * 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. 15 * 16 */ 17 18 #include <linux/module.h> 19 #include <linux/mISDNhw.h> 20 21 static void 22 dchannel_bh(struct work_struct *ws) 23 { 24 struct dchannel *dch = container_of(ws, struct dchannel, workq); 25 struct sk_buff *skb; 26 int err; 27 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); 32 if (err) 33 dev_kfree_skb(skb); 34 } else 35 dev_kfree_skb(skb); 36 } 37 } 38 if (test_and_clear_bit(FLG_PHCHANGE, &dch->Flags)) { 39 if (dch->phfunc) 40 dch->phfunc(dch); 41 } 42 } 43 44 static void 45 bchannel_bh(struct work_struct *ws) 46 { 47 struct bchannel *bch = container_of(ws, struct bchannel, workq); 48 struct sk_buff *skb; 49 int err; 50 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); 56 bch->rcount--; 57 if (likely(bch->ch.peer)) { 58 err = bch->ch.recv(bch->ch.peer, skb); 59 if (err) 60 dev_kfree_skb(skb); 61 } else 62 dev_kfree_skb(skb); 63 } 64 } 65 } 66 67 int 68 mISDN_initdchannel(struct dchannel *ch, int maxlen, void *phf) 69 { 70 test_and_set_bit(FLG_HDLC, &ch->Flags); 71 ch->maxlen = maxlen; 72 ch->hw = NULL; 73 ch->rx_skb = NULL; 74 ch->tx_skb = NULL; 75 ch->tx_idx = 0; 76 ch->phfunc = phf; 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); 81 return 0; 82 } 83 EXPORT_SYMBOL(mISDN_initdchannel); 84 85 int 86 mISDN_initbchannel(struct bchannel *ch, int maxlen) 87 { 88 ch->Flags = 0; 89 ch->maxlen = maxlen; 90 ch->hw = NULL; 91 ch->rx_skb = NULL; 92 ch->tx_skb = NULL; 93 ch->tx_idx = 0; 94 skb_queue_head_init(&ch->rqueue); 95 ch->rcount = 0; 96 ch->next_skb = NULL; 97 INIT_WORK(&ch->workq, bchannel_bh); 98 return 0; 99 } 100 EXPORT_SYMBOL(mISDN_initbchannel); 101 102 int 103 mISDN_freedchannel(struct dchannel *ch) 104 { 105 if (ch->tx_skb) { 106 dev_kfree_skb(ch->tx_skb); 107 ch->tx_skb = NULL; 108 } 109 if (ch->rx_skb) { 110 dev_kfree_skb(ch->rx_skb); 111 ch->rx_skb = NULL; 112 } 113 skb_queue_purge(&ch->squeue); 114 skb_queue_purge(&ch->rqueue); 115 flush_scheduled_work(); 116 return 0; 117 } 118 EXPORT_SYMBOL(mISDN_freedchannel); 119 120 int 121 mISDN_freebchannel(struct bchannel *ch) 122 { 123 if (ch->tx_skb) { 124 dev_kfree_skb(ch->tx_skb); 125 ch->tx_skb = NULL; 126 } 127 if (ch->rx_skb) { 128 dev_kfree_skb(ch->rx_skb); 129 ch->rx_skb = NULL; 130 } 131 if (ch->next_skb) { 132 dev_kfree_skb(ch->next_skb); 133 ch->next_skb = NULL; 134 } 135 skb_queue_purge(&ch->rqueue); 136 ch->rcount = 0; 137 flush_scheduled_work(); 138 return 0; 139 } 140 EXPORT_SYMBOL(mISDN_freebchannel); 141 142 static inline u_int 143 get_sapi_tei(u_char *p) 144 { 145 u_int sapi, tei; 146 147 sapi = *p >> 2; 148 tei = p[1] >> 1; 149 return sapi | (tei << 8); 150 } 151 152 void 153 recv_Dchannel(struct dchannel *dch) 154 { 155 struct mISDNhead *hh; 156 157 if (dch->rx_skb->len < 2) { /* at least 2 for sapi / tei */ 158 dev_kfree_skb(dch->rx_skb); 159 dch->rx_skb = NULL; 160 return; 161 } 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); 166 dch->rx_skb = NULL; 167 schedule_event(dch, FLG_RECVQUEUE); 168 } 169 EXPORT_SYMBOL(recv_Dchannel); 170 171 void 172 recv_Bchannel(struct bchannel *bch) 173 { 174 struct mISDNhead *hh; 175 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); 181 bch->rx_skb = NULL; 182 return; 183 } 184 bch->rcount++; 185 skb_queue_tail(&bch->rqueue, bch->rx_skb); 186 bch->rx_skb = NULL; 187 schedule_event(bch, FLG_RECVQUEUE); 188 } 189 EXPORT_SYMBOL(recv_Bchannel); 190 191 void 192 recv_Dchannel_skb(struct dchannel *dch, struct sk_buff *skb) 193 { 194 skb_queue_tail(&dch->rqueue, skb); 195 schedule_event(dch, FLG_RECVQUEUE); 196 } 197 EXPORT_SYMBOL(recv_Dchannel_skb); 198 199 void 200 recv_Bchannel_skb(struct bchannel *bch, struct sk_buff *skb) 201 { 202 if (bch->rcount >= 64) { 203 dev_kfree_skb(skb); 204 return; 205 } 206 bch->rcount++; 207 skb_queue_tail(&bch->rqueue, skb); 208 schedule_event(bch, FLG_RECVQUEUE); 209 } 210 EXPORT_SYMBOL(recv_Bchannel_skb); 211 212 static void 213 confirm_Dsend(struct dchannel *dch) 214 { 215 struct sk_buff *skb; 216 217 skb = _alloc_mISDN_skb(PH_DATA_CNF, mISDN_HEAD_ID(dch->tx_skb), 218 0, NULL, GFP_ATOMIC); 219 if (!skb) { 220 printk(KERN_ERR "%s: no skb id %x\n", __func__, 221 mISDN_HEAD_ID(dch->tx_skb)); 222 return; 223 } 224 skb_queue_tail(&dch->rqueue, skb); 225 schedule_event(dch, FLG_RECVQUEUE); 226 } 227 228 int 229 get_next_dframe(struct dchannel *dch) 230 { 231 dch->tx_idx = 0; 232 dch->tx_skb = skb_dequeue(&dch->squeue); 233 if (dch->tx_skb) { 234 confirm_Dsend(dch); 235 return 1; 236 } 237 dch->tx_skb = NULL; 238 test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); 239 return 0; 240 } 241 EXPORT_SYMBOL(get_next_dframe); 242 243 void 244 confirm_Bsend(struct bchannel *bch) 245 { 246 struct sk_buff *skb; 247 248 if (bch->rcount >= 64) 249 return; 250 skb = _alloc_mISDN_skb(PH_DATA_CNF, mISDN_HEAD_ID(bch->tx_skb), 251 0, NULL, GFP_ATOMIC); 252 if (!skb) { 253 printk(KERN_ERR "%s: no skb id %x\n", __func__, 254 mISDN_HEAD_ID(bch->tx_skb)); 255 return; 256 } 257 bch->rcount++; 258 skb_queue_tail(&bch->rqueue, skb); 259 schedule_event(bch, FLG_RECVQUEUE); 260 } 261 EXPORT_SYMBOL(confirm_Bsend); 262 263 int 264 get_next_bframe(struct bchannel *bch) 265 { 266 bch->tx_idx = 0; 267 if (test_bit(FLG_TX_NEXT, &bch->Flags)) { 268 bch->tx_skb = bch->next_skb; 269 if (bch->tx_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 */ 274 return 1; 275 } else { 276 test_and_clear_bit(FLG_TX_NEXT, &bch->Flags); 277 printk(KERN_WARNING "B TX_NEXT without skb\n"); 278 } 279 } 280 bch->tx_skb = NULL; 281 test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); 282 return 0; 283 } 284 EXPORT_SYMBOL(get_next_bframe); 285 286 void 287 queue_ch_frame(struct mISDNchannel *ch, u_int pr, int id, struct sk_buff *skb) 288 { 289 struct mISDNhead *hh; 290 291 if (!skb) { 292 _queue_data(ch, pr, id, 0, NULL, GFP_ATOMIC); 293 } else { 294 if (ch->peer) { 295 hh = mISDN_HEAD_P(skb); 296 hh->prim = pr; 297 hh->id = id; 298 if (!ch->recv(ch->peer, skb)) 299 return; 300 } 301 dev_kfree_skb(skb); 302 } 303 } 304 EXPORT_SYMBOL(queue_ch_frame); 305 306 int 307 dchannel_senddata(struct dchannel *ch, struct sk_buff *skb) 308 { 309 /* check oversize */ 310 if (skb->len <= 0) { 311 printk(KERN_WARNING "%s: skb too small\n", __func__); 312 return -EINVAL; 313 } 314 if (skb->len > ch->maxlen) { 315 printk(KERN_WARNING "%s: skb too large(%d/%d)\n", 316 __func__, skb->len, ch->maxlen); 317 return -EINVAL; 318 } 319 /* HW lock must be obtained */ 320 if (test_and_set_bit(FLG_TX_BUSY, &ch->Flags)) { 321 skb_queue_tail(&ch->squeue, skb); 322 return 0; 323 } else { 324 /* write to fifo */ 325 ch->tx_skb = skb; 326 ch->tx_idx = 0; 327 return 1; 328 } 329 } 330 EXPORT_SYMBOL(dchannel_senddata); 331 332 int 333 bchannel_senddata(struct bchannel *ch, struct sk_buff *skb) 334 { 335 336 /* check oversize */ 337 if (skb->len <= 0) { 338 printk(KERN_WARNING "%s: skb too small\n", __func__); 339 return -EINVAL; 340 } 341 if (skb->len > ch->maxlen) { 342 printk(KERN_WARNING "%s: skb too large(%d/%d)\n", 343 __func__, skb->len, ch->maxlen); 344 return -EINVAL; 345 } 346 /* HW lock must be obtained */ 347 /* check for pending next_skb */ 348 if (ch->next_skb) { 349 printk(KERN_WARNING 350 "%s: next_skb exist ERROR (skb->len=%d next_skb->len=%d)\n", 351 __func__, skb->len, ch->next_skb->len); 352 return -EBUSY; 353 } 354 if (test_and_set_bit(FLG_TX_BUSY, &ch->Flags)) { 355 test_and_set_bit(FLG_TX_NEXT, &ch->Flags); 356 ch->next_skb = skb; 357 return 0; 358 } else { 359 /* write to fifo */ 360 ch->tx_skb = skb; 361 ch->tx_idx = 0; 362 return 1; 363 } 364 } 365 EXPORT_SYMBOL(bchannel_senddata); 366