hwchannel.c 7.9 KB

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