hscx_irq.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:7k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* $Id: hscx_irq.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
  2.  *
  3.  * low level b-channel stuff for Siemens HSCX
  4.  *
  5.  * Author       Karsten Keil
  6.  * Copyright    by Karsten Keil      <keil@isdn4linux.de>
  7.  * 
  8.  * This software may be used and distributed according to the terms
  9.  * of the GNU General Public License, incorporated herein by reference.
  10.  *
  11.  * This is an include file for fast inline IRQ stuff
  12.  *
  13.  */
  14. static inline void
  15. waitforCEC(struct IsdnCardState *cs, int hscx)
  16. {
  17. int to = 50;
  18. while ((READHSCX(cs, hscx, HSCX_STAR) & 0x04) && to) {
  19. udelay(1);
  20. to--;
  21. }
  22. if (!to)
  23. printk(KERN_WARNING "HiSax: waitforCEC timeoutn");
  24. }
  25. static inline void
  26. waitforXFW(struct IsdnCardState *cs, int hscx)
  27. {
  28. int to = 50;
  29. while ((!(READHSCX(cs, hscx, HSCX_STAR) & 0x44) == 0x40) && to) {
  30. udelay(1);
  31. to--;
  32. }
  33. if (!to)
  34. printk(KERN_WARNING "HiSax: waitforXFW timeoutn");
  35. }
  36. static inline void
  37. WriteHSCXCMDR(struct IsdnCardState *cs, int hscx, u_char data)
  38. {
  39. long flags;
  40. save_flags(flags);
  41. cli();
  42. waitforCEC(cs, hscx);
  43. WRITEHSCX(cs, hscx, HSCX_CMDR, data);
  44. restore_flags(flags);
  45. }
  46. static void
  47. hscx_empty_fifo(struct BCState *bcs, int count)
  48. {
  49. u_char *ptr;
  50. struct IsdnCardState *cs = bcs->cs;
  51. long flags;
  52. if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
  53. debugl1(cs, "hscx_empty_fifo");
  54. if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
  55. if (cs->debug & L1_DEB_WARN)
  56. debugl1(cs, "hscx_empty_fifo: incoming packet too large");
  57. WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);
  58. bcs->hw.hscx.rcvidx = 0;
  59. return;
  60. }
  61. ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
  62. bcs->hw.hscx.rcvidx += count;
  63. save_flags(flags);
  64. cli();
  65. READHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
  66. WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);
  67. restore_flags(flags);
  68. if (cs->debug & L1_DEB_HSCX_FIFO) {
  69. char *t = bcs->blog;
  70. t += sprintf(t, "hscx_empty_fifo %c cnt %d",
  71.      bcs->hw.hscx.hscx ? 'B' : 'A', count);
  72. QuickHex(t, ptr, count);
  73. debugl1(cs, bcs->blog);
  74. }
  75. }
  76. static void
  77. hscx_fill_fifo(struct BCState *bcs)
  78. {
  79. struct IsdnCardState *cs = bcs->cs;
  80. int more, count;
  81. int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32;
  82. u_char *ptr;
  83. long flags;
  84. if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
  85. debugl1(cs, "hscx_fill_fifo");
  86. if (!bcs->tx_skb)
  87. return;
  88. if (bcs->tx_skb->len <= 0)
  89. return;
  90. more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
  91. if (bcs->tx_skb->len > fifo_size) {
  92. more = !0;
  93. count = fifo_size;
  94. } else
  95. count = bcs->tx_skb->len;
  96. waitforXFW(cs, bcs->hw.hscx.hscx);
  97. save_flags(flags);
  98. cli();
  99. ptr = bcs->tx_skb->data;
  100. skb_pull(bcs->tx_skb, count);
  101. bcs->tx_cnt -= count;
  102. bcs->hw.hscx.count += count;
  103. WRITEHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
  104. WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, more ? 0x8 : 0xa);
  105. restore_flags(flags);
  106. if (cs->debug & L1_DEB_HSCX_FIFO) {
  107. char *t = bcs->blog;
  108. t += sprintf(t, "hscx_fill_fifo %c cnt %d",
  109.      bcs->hw.hscx.hscx ? 'B' : 'A', count);
  110. QuickHex(t, ptr, count);
  111. debugl1(cs, bcs->blog);
  112. }
  113. }
  114. static inline void
  115. hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
  116. {
  117. u_char r;
  118. struct BCState *bcs = cs->bcs + hscx;
  119. struct sk_buff *skb;
  120. int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32;
  121. int count;
  122. if (!test_bit(BC_FLG_INIT, &bcs->Flag))
  123. return;
  124. if (val & 0x80) { /* RME */
  125. r = READHSCX(cs, hscx, HSCX_RSTA);
  126. if ((r & 0xf0) != 0xa0) {
  127. if (!(r & 0x80)) {
  128. if (cs->debug & L1_DEB_WARN)
  129. debugl1(cs, "HSCX invalid frame");
  130. #ifdef ERROR_STATISTIC
  131. bcs->err_inv++;
  132. #endif
  133. }
  134. if ((r & 0x40) && bcs->mode) {
  135. if (cs->debug & L1_DEB_WARN)
  136. debugl1(cs, "HSCX RDO mode=%d",
  137. bcs->mode);
  138. #ifdef ERROR_STATISTIC
  139. bcs->err_rdo++;
  140. #endif
  141. }
  142. if (!(r & 0x20)) {
  143. if (cs->debug & L1_DEB_WARN)
  144. debugl1(cs, "HSCX CRC error");
  145. #ifdef ERROR_STATISTIC
  146. bcs->err_crc++;
  147. #endif
  148. }
  149. WriteHSCXCMDR(cs, hscx, 0x80);
  150. } else {
  151. count = READHSCX(cs, hscx, HSCX_RBCL) & (
  152. test_bit(HW_IPAC, &cs->HW_Flags)? 0x3f: 0x1f);
  153. if (count == 0)
  154. count = fifo_size;
  155. hscx_empty_fifo(bcs, count);
  156. if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
  157. if (cs->debug & L1_DEB_HSCX_FIFO)
  158. debugl1(cs, "HX Frame %d", count);
  159. if (!(skb = dev_alloc_skb(count)))
  160. printk(KERN_WARNING "HSCX: receive out of memoryn");
  161. else {
  162. memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count);
  163. skb_queue_tail(&bcs->rqueue, skb);
  164. }
  165. }
  166. }
  167. bcs->hw.hscx.rcvidx = 0;
  168. hscx_sched_event(bcs, B_RCVBUFREADY);
  169. }
  170. if (val & 0x40) { /* RPF */
  171. hscx_empty_fifo(bcs, fifo_size);
  172. if (bcs->mode == L1_MODE_TRANS) {
  173. /* receive audio data */
  174. if (!(skb = dev_alloc_skb(fifo_size)))
  175. printk(KERN_WARNING "HiSax: receive out of memoryn");
  176. else {
  177. memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size);
  178. skb_queue_tail(&bcs->rqueue, skb);
  179. }
  180. bcs->hw.hscx.rcvidx = 0;
  181. hscx_sched_event(bcs, B_RCVBUFREADY);
  182. }
  183. }
  184. if (val & 0x10) { /* XPR */
  185. if (bcs->tx_skb) {
  186. if (bcs->tx_skb->len) {
  187. hscx_fill_fifo(bcs);
  188. return;
  189. } else {
  190. if (bcs->st->lli.l1writewakeup &&
  191. (PACKET_NOACK != bcs->tx_skb->pkt_type))
  192. bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count);
  193. dev_kfree_skb_irq(bcs->tx_skb);
  194. bcs->hw.hscx.count = 0; 
  195. bcs->tx_skb = NULL;
  196. }
  197. }
  198. if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
  199. bcs->hw.hscx.count = 0;
  200. test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
  201. hscx_fill_fifo(bcs);
  202. } else {
  203. test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
  204. hscx_sched_event(bcs, B_XMTBUFREADY);
  205. }
  206. }
  207. }
  208. static inline void
  209. hscx_int_main(struct IsdnCardState *cs, u_char val)
  210. {
  211. u_char exval;
  212. struct BCState *bcs;
  213. if (val & 0x01) {
  214. bcs = cs->bcs + 1;
  215. exval = READHSCX(cs, 1, HSCX_EXIR);
  216. if (exval & 0x40) {
  217. if (bcs->mode == 1)
  218. hscx_fill_fifo(bcs);
  219. else {
  220. #ifdef ERROR_STATISTIC
  221. bcs->err_tx++;
  222. #endif
  223. /* Here we lost an TX interrupt, so
  224.    * restart transmitting the whole frame.
  225.  */
  226. if (bcs->tx_skb) {
  227. skb_push(bcs->tx_skb, bcs->hw.hscx.count);
  228. bcs->tx_cnt += bcs->hw.hscx.count;
  229. bcs->hw.hscx.count = 0;
  230. }
  231. WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
  232. if (cs->debug & L1_DEB_WARN)
  233. debugl1(cs, "HSCX B EXIR %x Lost TX", exval);
  234. }
  235. } else if (cs->debug & L1_DEB_HSCX)
  236. debugl1(cs, "HSCX B EXIR %x", exval);
  237. }
  238. if (val & 0xf8) {
  239. if (cs->debug & L1_DEB_HSCX)
  240. debugl1(cs, "HSCX B interrupt %x", val);
  241. hscx_interrupt(cs, val, 1);
  242. }
  243. if (val & 0x02) {
  244. bcs = cs->bcs;
  245. exval = READHSCX(cs, 0, HSCX_EXIR);
  246. if (exval & 0x40) {
  247. if (bcs->mode == L1_MODE_TRANS)
  248. hscx_fill_fifo(bcs);
  249. else {
  250. /* Here we lost an TX interrupt, so
  251.    * restart transmitting the whole frame.
  252.  */
  253. #ifdef ERROR_STATISTIC
  254. bcs->err_tx++;
  255. #endif
  256. if (bcs->tx_skb) {
  257. skb_push(bcs->tx_skb, bcs->hw.hscx.count);
  258. bcs->tx_cnt += bcs->hw.hscx.count;
  259. bcs->hw.hscx.count = 0;
  260. }
  261. WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
  262. if (cs->debug & L1_DEB_WARN)
  263. debugl1(cs, "HSCX A EXIR %x Lost TX", exval);
  264. }
  265. } else if (cs->debug & L1_DEB_HSCX)
  266. debugl1(cs, "HSCX A EXIR %x", exval);
  267. }
  268. if (val & 0x04) {
  269. exval = READHSCX(cs, 0, HSCX_ISTA);
  270. if (cs->debug & L1_DEB_HSCX)
  271. debugl1(cs, "HSCX A interrupt %x", exval);
  272. hscx_interrupt(cs, exval, 0);
  273. }
  274. }