Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
hisax_isac.c
Go to the documentation of this file.
1 /*
2  * Driver for ISAC-S and ISAC-SX
3  * ISDN Subscriber Access Controller for Terminals
4  *
5  * Author Kai Germaschewski
6  * Copyright 2001 by Kai Germaschewski <[email protected]>
7  * 2001 by Karsten Keil <[email protected]>
8  *
9  * based upon Karsten Keil's original isac.c driver
10  *
11  * This software may be used and distributed according to the terms
12  * of the GNU General Public License, incorporated herein by reference.
13  *
14  * Thanks to Wizard Computersysteme GmbH, Bremervoerde and
15  * SoHaNet Technology GmbH, Berlin
16  * for supporting the development of this driver
17  */
18 
19 /* TODO:
20  * specifically handle level vs edge triggered?
21  */
22 
23 #include <linux/module.h>
24 #include <linux/gfp.h>
25 #include <linux/init.h>
26 #include <linux/netdevice.h>
27 #include "hisax_isac.h"
28 
29 // debugging cruft
30 
31 #define __debug_variable debug
32 #include "hisax_debug.h"
33 
34 #ifdef CONFIG_HISAX_DEBUG
35 static int debug = 1;
36 module_param(debug, int, 0);
37 
38 static char *ISACVer[] = {
39  "2086/2186 V1.1",
40  "2085 B1",
41  "2085 B2",
42  "2085 V2.3"
43 };
44 #endif
45 
46 MODULE_AUTHOR("Kai Germaschewski <[email protected]>/Karsten Keil <[email protected]>");
47 MODULE_DESCRIPTION("ISAC/ISAC-SX driver");
48 MODULE_LICENSE("GPL");
49 
50 #define DBG_WARN 0x0001
51 #define DBG_IRQ 0x0002
52 #define DBG_L1M 0x0004
53 #define DBG_PR 0x0008
54 #define DBG_RFIFO 0x0100
55 #define DBG_RPACKET 0x0200
56 #define DBG_XFIFO 0x1000
57 #define DBG_XPACKET 0x2000
58 
59 // we need to distinguish ISAC-S and ISAC-SX
60 #define TYPE_ISAC 0x00
61 #define TYPE_ISACSX 0x01
62 
63 // registers etc.
64 #define ISAC_MASK 0x20
65 #define ISAC_ISTA 0x20
66 #define ISAC_ISTA_EXI 0x01
67 #define ISAC_ISTA_SIN 0x02
68 #define ISAC_ISTA_CISQ 0x04
69 #define ISAC_ISTA_XPR 0x10
70 #define ISAC_ISTA_RSC 0x20
71 #define ISAC_ISTA_RPF 0x40
72 #define ISAC_ISTA_RME 0x80
73 
74 #define ISAC_STAR 0x21
75 #define ISAC_CMDR 0x21
76 #define ISAC_CMDR_XRES 0x01
77 #define ISAC_CMDR_XME 0x02
78 #define ISAC_CMDR_XTF 0x08
79 #define ISAC_CMDR_RRES 0x40
80 #define ISAC_CMDR_RMC 0x80
81 
82 #define ISAC_EXIR 0x24
83 #define ISAC_EXIR_MOS 0x04
84 #define ISAC_EXIR_XDU 0x40
85 #define ISAC_EXIR_XMR 0x80
86 
87 #define ISAC_ADF2 0x39
88 #define ISAC_SPCR 0x30
89 #define ISAC_ADF1 0x38
90 
91 #define ISAC_CIR0 0x31
92 #define ISAC_CIX0 0x31
93 #define ISAC_CIR0_CIC0 0x02
94 #define ISAC_CIR0_CIC1 0x01
95 
96 #define ISAC_CIR1 0x33
97 #define ISAC_CIX1 0x33
98 #define ISAC_STCR 0x37
99 #define ISAC_MODE 0x22
100 
101 #define ISAC_RSTA 0x27
102 #define ISAC_RSTA_RDO 0x40
103 #define ISAC_RSTA_CRC 0x20
104 #define ISAC_RSTA_RAB 0x10
105 
106 #define ISAC_RBCL 0x25
107 #define ISAC_RBCH 0x2A
108 #define ISAC_TIMR 0x23
109 #define ISAC_SQXR 0x3b
110 #define ISAC_MOSR 0x3a
111 #define ISAC_MOCR 0x3a
112 #define ISAC_MOR0 0x32
113 #define ISAC_MOX0 0x32
114 #define ISAC_MOR1 0x34
115 #define ISAC_MOX1 0x34
116 
117 #define ISAC_RBCH_XAC 0x80
118 
119 #define ISAC_CMD_TIM 0x0
120 #define ISAC_CMD_RES 0x1
121 #define ISAC_CMD_SSP 0x2
122 #define ISAC_CMD_SCP 0x3
123 #define ISAC_CMD_AR8 0x8
124 #define ISAC_CMD_AR10 0x9
125 #define ISAC_CMD_ARL 0xa
126 #define ISAC_CMD_DI 0xf
127 
128 #define ISACSX_MASK 0x60
129 #define ISACSX_ISTA 0x60
130 #define ISACSX_ISTA_ICD 0x01
131 #define ISACSX_ISTA_CIC 0x10
132 
133 #define ISACSX_MASKD 0x20
134 #define ISACSX_ISTAD 0x20
135 #define ISACSX_ISTAD_XDU 0x04
136 #define ISACSX_ISTAD_XMR 0x08
137 #define ISACSX_ISTAD_XPR 0x10
138 #define ISACSX_ISTAD_RFO 0x20
139 #define ISACSX_ISTAD_RPF 0x40
140 #define ISACSX_ISTAD_RME 0x80
141 
142 #define ISACSX_CMDRD 0x21
143 #define ISACSX_CMDRD_XRES 0x01
144 #define ISACSX_CMDRD_XME 0x02
145 #define ISACSX_CMDRD_XTF 0x08
146 #define ISACSX_CMDRD_RRES 0x40
147 #define ISACSX_CMDRD_RMC 0x80
148 
149 #define ISACSX_MODED 0x22
150 
151 #define ISACSX_RBCLD 0x26
152 
153 #define ISACSX_RSTAD 0x28
154 #define ISACSX_RSTAD_RAB 0x10
155 #define ISACSX_RSTAD_CRC 0x20
156 #define ISACSX_RSTAD_RDO 0x40
157 #define ISACSX_RSTAD_VFR 0x80
158 
159 #define ISACSX_CIR0 0x2e
160 #define ISACSX_CIR0_CIC0 0x08
161 #define ISACSX_CIX0 0x2e
162 
163 #define ISACSX_TR_CONF0 0x30
164 
165 #define ISACSX_TR_CONF2 0x32
166 
167 static struct Fsm l1fsm;
168 
169 enum {
179 };
180 
181 #define L1_STATE_COUNT (ST_L1_F8 + 1)
182 
183 static char *strL1State[] =
184 {
185  "ST_L1_RESET",
186  "ST_L1_F3_PDOWN",
187  "ST_L1_F3_PUP",
188  "ST_L1_F3_PEND_DEACT",
189  "ST_L1_F4",
190  "ST_L1_F5",
191  "ST_L1_F6",
192  "ST_L1_F7",
193  "ST_L1_F8",
194 };
195 
196 enum {
197  EV_PH_DR, // 0000
198  EV_PH_RES, // 0001
199  EV_PH_TMA, // 0010
200  EV_PH_SLD, // 0011
201  EV_PH_RSY, // 0100
202  EV_PH_DR6, // 0101
203  EV_PH_EI, // 0110
204  EV_PH_PU, // 0111
205  EV_PH_AR, // 1000
206  EV_PH_9, // 1001
207  EV_PH_ARL, // 1010
208  EV_PH_CVR, // 1011
209  EV_PH_AI8, // 1100
210  EV_PH_AI10, // 1101
211  EV_PH_AIL, // 1110
212  EV_PH_DC, // 1111
216 };
217 
218 #define L1_EVENT_COUNT (EV_TIMER3 + 1)
219 
220 static char *strL1Event[] =
221 {
222  "EV_PH_DR", // 0000
223  "EV_PH_RES", // 0001
224  "EV_PH_TMA", // 0010
225  "EV_PH_SLD", // 0011
226  "EV_PH_RSY", // 0100
227  "EV_PH_DR6", // 0101
228  "EV_PH_EI", // 0110
229  "EV_PH_PU", // 0111
230  "EV_PH_AR", // 1000
231  "EV_PH_9", // 1001
232  "EV_PH_ARL", // 1010
233  "EV_PH_CVR", // 1011
234  "EV_PH_AI8", // 1100
235  "EV_PH_AI10", // 1101
236  "EV_PH_AIL", // 1110
237  "EV_PH_DC", // 1111
238  "EV_PH_ACTIVATE_REQ",
239  "EV_PH_DEACTIVATE_REQ",
240  "EV_TIMER3",
241 };
242 
243 static inline void D_L1L2(struct isac *isac, int pr, void *arg)
244 {
245  struct hisax_if *ifc = (struct hisax_if *) &isac->hisax_d_if;
246 
247  DBG(DBG_PR, "pr %#x", pr);
248  ifc->l1l2(ifc, pr, arg);
249 }
250 
251 static void ph_command(struct isac *isac, unsigned int command)
252 {
253  DBG(DBG_L1M, "ph_command %#x", command);
254  switch (isac->type) {
255  case TYPE_ISAC:
256  isac->write_isac(isac, ISAC_CIX0, (command << 2) | 3);
257  break;
258  case TYPE_ISACSX:
259  isac->write_isac(isac, ISACSX_CIX0, (command << 4) | (7 << 1));
260  break;
261  }
262 }
263 
264 // ----------------------------------------------------------------------
265 
266 static void l1_di(struct FsmInst *fi, int event, void *arg)
267 {
268  struct isac *isac = fi->userdata;
269 
271  ph_command(isac, ISAC_CMD_DI);
272 }
273 
274 static void l1_di_deact_ind(struct FsmInst *fi, int event, void *arg)
275 {
276  struct isac *isac = fi->userdata;
277 
279  D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
280  ph_command(isac, ISAC_CMD_DI);
281 }
282 
283 static void l1_go_f3pdown(struct FsmInst *fi, int event, void *arg)
284 {
286 }
287 
288 static void l1_go_f3pend_deact_ind(struct FsmInst *fi, int event, void *arg)
289 {
290  struct isac *isac = fi->userdata;
291 
293  D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
294  ph_command(isac, ISAC_CMD_DI);
295 }
296 
297 static void l1_go_f3pend(struct FsmInst *fi, int event, void *arg)
298 {
299  struct isac *isac = fi->userdata;
300 
302  ph_command(isac, ISAC_CMD_DI);
303 }
304 
305 static void l1_go_f4(struct FsmInst *fi, int event, void *arg)
306 {
308 }
309 
310 static void l1_go_f5(struct FsmInst *fi, int event, void *arg)
311 {
313 }
314 
315 static void l1_go_f6(struct FsmInst *fi, int event, void *arg)
316 {
318 }
319 
320 static void l1_go_f6_deact_ind(struct FsmInst *fi, int event, void *arg)
321 {
322  struct isac *isac = fi->userdata;
323 
325  D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
326 }
327 
328 static void l1_go_f7_act_ind(struct FsmInst *fi, int event, void *arg)
329 {
330  struct isac *isac = fi->userdata;
331 
332  FsmDelTimer(&isac->timer, 0);
334  ph_command(isac, ISAC_CMD_AR8);
335  D_L1L2(isac, PH_ACTIVATE | INDICATION, NULL);
336 }
337 
338 static void l1_go_f8(struct FsmInst *fi, int event, void *arg)
339 {
341 }
342 
343 static void l1_go_f8_deact_ind(struct FsmInst *fi, int event, void *arg)
344 {
345  struct isac *isac = fi->userdata;
346 
348  D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
349 }
350 
351 static void l1_ar8(struct FsmInst *fi, int event, void *arg)
352 {
353  struct isac *isac = fi->userdata;
354 
356  ph_command(isac, ISAC_CMD_AR8);
357 }
358 
359 static void l1_timer3(struct FsmInst *fi, int event, void *arg)
360 {
361  struct isac *isac = fi->userdata;
362 
363  ph_command(isac, ISAC_CMD_DI);
364  D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
365 }
366 
367 // state machines according to data sheet PSB 2186 / 3186
368 
369 static struct FsmNode L1FnList[] __initdata =
370 {
371  {ST_L1_RESET, EV_PH_RES, l1_di},
372  {ST_L1_RESET, EV_PH_EI, l1_di},
373  {ST_L1_RESET, EV_PH_DC, l1_go_f3pdown},
374  {ST_L1_RESET, EV_PH_AR, l1_go_f6},
375  {ST_L1_RESET, EV_PH_AI8, l1_go_f7_act_ind},
376 
377  {ST_L1_F3_PDOWN, EV_PH_RES, l1_di},
378  {ST_L1_F3_PDOWN, EV_PH_EI, l1_di},
379  {ST_L1_F3_PDOWN, EV_PH_AR, l1_go_f6},
380  {ST_L1_F3_PDOWN, EV_PH_RSY, l1_go_f5},
381  {ST_L1_F3_PDOWN, EV_PH_PU, l1_go_f4},
382  {ST_L1_F3_PDOWN, EV_PH_AI8, l1_go_f7_act_ind},
384  {ST_L1_F3_PDOWN, EV_TIMER3, l1_timer3},
385 
386  {ST_L1_F3_PEND_DEACT, EV_PH_RES, l1_di},
387  {ST_L1_F3_PEND_DEACT, EV_PH_EI, l1_di},
388  {ST_L1_F3_PEND_DEACT, EV_PH_DC, l1_go_f3pdown},
389  {ST_L1_F3_PEND_DEACT, EV_PH_RSY, l1_go_f5},
390  {ST_L1_F3_PEND_DEACT, EV_PH_AR, l1_go_f6},
391  {ST_L1_F3_PEND_DEACT, EV_PH_AI8, l1_go_f7_act_ind},
392 
393  {ST_L1_F4, EV_PH_RES, l1_di},
394  {ST_L1_F4, EV_PH_EI, l1_di},
395  {ST_L1_F4, EV_PH_RSY, l1_go_f5},
396  {ST_L1_F4, EV_PH_AI8, l1_go_f7_act_ind},
397  {ST_L1_F4, EV_TIMER3, l1_timer3},
398  {ST_L1_F4, EV_PH_DC, l1_go_f3pdown},
399 
400  {ST_L1_F5, EV_PH_RES, l1_di},
401  {ST_L1_F5, EV_PH_EI, l1_di},
402  {ST_L1_F5, EV_PH_AR, l1_go_f6},
403  {ST_L1_F5, EV_PH_AI8, l1_go_f7_act_ind},
404  {ST_L1_F5, EV_TIMER3, l1_timer3},
405  {ST_L1_F5, EV_PH_DR, l1_go_f3pend},
406  {ST_L1_F5, EV_PH_DC, l1_go_f3pdown},
407 
408  {ST_L1_F6, EV_PH_RES, l1_di},
409  {ST_L1_F6, EV_PH_EI, l1_di},
410  {ST_L1_F6, EV_PH_RSY, l1_go_f8},
411  {ST_L1_F6, EV_PH_AI8, l1_go_f7_act_ind},
412  {ST_L1_F6, EV_PH_DR6, l1_go_f3pend},
413  {ST_L1_F6, EV_TIMER3, l1_timer3},
414  {ST_L1_F6, EV_PH_DC, l1_go_f3pdown},
415 
416  {ST_L1_F7, EV_PH_RES, l1_di_deact_ind},
417  {ST_L1_F7, EV_PH_EI, l1_di_deact_ind},
418  {ST_L1_F7, EV_PH_AR, l1_go_f6_deact_ind},
419  {ST_L1_F7, EV_PH_RSY, l1_go_f8_deact_ind},
420  {ST_L1_F7, EV_PH_DR, l1_go_f3pend_deact_ind},
421 
422  {ST_L1_F8, EV_PH_RES, l1_di},
423  {ST_L1_F8, EV_PH_EI, l1_di},
424  {ST_L1_F8, EV_PH_AR, l1_go_f6},
425  {ST_L1_F8, EV_PH_DR, l1_go_f3pend},
426  {ST_L1_F8, EV_PH_AI8, l1_go_f7_act_ind},
427  {ST_L1_F8, EV_TIMER3, l1_timer3},
428  {ST_L1_F8, EV_PH_DC, l1_go_f3pdown},
429 };
430 
431 static void l1m_debug(struct FsmInst *fi, char *fmt, ...)
432 {
433  va_list args;
434  char buf[256];
435 
436  va_start(args, fmt);
437  vsnprintf(buf, sizeof(buf), fmt, args);
438  DBG(DBG_L1M, "%s", buf);
439  va_end(args);
440 }
441 
442 static void isac_version(struct isac *cs)
443 {
444  int val;
445 
446  val = cs->read_isac(cs, ISAC_RBCH);
447  DBG(1, "ISAC version (%x): %s", val, ISACVer[(val >> 5) & 3]);
448 }
449 
450 static void isac_empty_fifo(struct isac *isac, int count)
451 {
452  // this also works for isacsx, since
453  // CMDR(D) register works the same
454  u_char *ptr;
455 
456  DBG(DBG_IRQ, "count %d", count);
457 
458  if ((isac->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
459  DBG(DBG_WARN, "overrun %d", isac->rcvidx + count);
460  isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
461  isac->rcvidx = 0;
462  return;
463  }
464  ptr = isac->rcvbuf + isac->rcvidx;
465  isac->rcvidx += count;
466  isac->read_isac_fifo(isac, ptr, count);
467  isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
468  DBG_PACKET(DBG_RFIFO, ptr, count);
469 }
470 
471 static void isac_fill_fifo(struct isac *isac)
472 {
473  // this also works for isacsx, since
474  // CMDR(D) register works the same
475 
476  int count;
477  unsigned char cmd;
478  u_char *ptr;
479 
480  BUG_ON(!isac->tx_skb);
481 
482  count = isac->tx_skb->len;
483  BUG_ON(count <= 0);
484 
485  DBG(DBG_IRQ, "count %d", count);
486 
487  if (count > 0x20) {
488  count = 0x20;
489  cmd = ISAC_CMDR_XTF;
490  } else {
492  }
493 
494  ptr = isac->tx_skb->data;
495  skb_pull(isac->tx_skb, count);
496  isac->tx_cnt += count;
497  DBG_PACKET(DBG_XFIFO, ptr, count);
498  isac->write_isac_fifo(isac, ptr, count);
499  isac->write_isac(isac, ISAC_CMDR, cmd);
500 }
501 
502 static void isac_retransmit(struct isac *isac)
503 {
504  if (!isac->tx_skb) {
505  DBG(DBG_WARN, "no skb");
506  return;
507  }
508  skb_push(isac->tx_skb, isac->tx_cnt);
509  isac->tx_cnt = 0;
510 }
511 
512 
513 static inline void isac_cisq_interrupt(struct isac *isac)
514 {
515  unsigned char val;
516 
517  val = isac->read_isac(isac, ISAC_CIR0);
518  DBG(DBG_IRQ, "CIR0 %#x", val);
519  if (val & ISAC_CIR0_CIC0) {
520  DBG(DBG_IRQ, "CODR0 %#x", (val >> 2) & 0xf);
521  FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL);
522  }
523  if (val & ISAC_CIR0_CIC1) {
524  val = isac->read_isac(isac, ISAC_CIR1);
525  DBG(DBG_WARN, "ISAC CIR1 %#x", val);
526  }
527 }
528 
529 static inline void isac_rme_interrupt(struct isac *isac)
530 {
531  unsigned char val;
532  int count;
533  struct sk_buff *skb;
534 
535  val = isac->read_isac(isac, ISAC_RSTA);
536  if ((val & (ISAC_RSTA_RDO | ISAC_RSTA_CRC | ISAC_RSTA_RAB))
537  != ISAC_RSTA_CRC) {
538  DBG(DBG_WARN, "RSTA %#x, dropped", val);
539  isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
540  goto out;
541  }
542 
543  count = isac->read_isac(isac, ISAC_RBCL) & 0x1f;
544  DBG(DBG_IRQ, "RBCL %#x", count);
545  if (count == 0)
546  count = 0x20;
547 
548  isac_empty_fifo(isac, count);
549  count = isac->rcvidx;
550  if (count < 1) {
551  DBG(DBG_WARN, "count %d < 1", count);
552  goto out;
553  }
554 
555  skb = alloc_skb(count, GFP_ATOMIC);
556  if (!skb) {
557  DBG(DBG_WARN, "no memory, dropping\n");
558  goto out;
559  }
560  memcpy(skb_put(skb, count), isac->rcvbuf, count);
561  DBG_SKB(DBG_RPACKET, skb);
562  D_L1L2(isac, PH_DATA | INDICATION, skb);
563 out:
564  isac->rcvidx = 0;
565 }
566 
567 static inline void isac_xpr_interrupt(struct isac *isac)
568 {
569  if (!isac->tx_skb)
570  return;
571 
572  if (isac->tx_skb->len > 0) {
573  isac_fill_fifo(isac);
574  return;
575  }
576  dev_kfree_skb_irq(isac->tx_skb);
577  isac->tx_cnt = 0;
578  isac->tx_skb = NULL;
579  D_L1L2(isac, PH_DATA | CONFIRM, NULL);
580 }
581 
582 static inline void isac_exi_interrupt(struct isac *isac)
583 {
584  unsigned char val;
585 
586  val = isac->read_isac(isac, ISAC_EXIR);
587  DBG(2, "EXIR %#x", val);
588 
589  if (val & ISAC_EXIR_XMR) {
590  DBG(DBG_WARN, "ISAC XMR");
591  isac_retransmit(isac);
592  }
593  if (val & ISAC_EXIR_XDU) {
594  DBG(DBG_WARN, "ISAC XDU");
595  isac_retransmit(isac);
596  }
597  if (val & ISAC_EXIR_MOS) { /* MOS */
598  DBG(DBG_WARN, "MOS");
599  val = isac->read_isac(isac, ISAC_MOSR);
600  DBG(2, "ISAC MOSR %#x", val);
601  }
602 }
603 
604 void isac_irq(struct isac *isac)
605 {
606  unsigned char val;
607 
608  val = isac->read_isac(isac, ISAC_ISTA);
609  DBG(DBG_IRQ, "ISTA %#x", val);
610 
611  if (val & ISAC_ISTA_EXI) {
612  DBG(DBG_IRQ, "EXI");
613  isac_exi_interrupt(isac);
614  }
615  if (val & ISAC_ISTA_XPR) {
616  DBG(DBG_IRQ, "XPR");
617  isac_xpr_interrupt(isac);
618  }
619  if (val & ISAC_ISTA_RME) {
620  DBG(DBG_IRQ, "RME");
621  isac_rme_interrupt(isac);
622  }
623  if (val & ISAC_ISTA_RPF) {
624  DBG(DBG_IRQ, "RPF");
625  isac_empty_fifo(isac, 0x20);
626  }
627  if (val & ISAC_ISTA_CISQ) {
628  DBG(DBG_IRQ, "CISQ");
629  isac_cisq_interrupt(isac);
630  }
631  if (val & ISAC_ISTA_RSC) {
632  DBG(DBG_WARN, "RSC");
633  }
634  if (val & ISAC_ISTA_SIN) {
635  DBG(DBG_WARN, "SIN");
636  }
637  isac->write_isac(isac, ISAC_MASK, 0xff);
638  isac->write_isac(isac, ISAC_MASK, 0x00);
639 }
640 
641 // ======================================================================
642 
643 static inline void isacsx_cic_interrupt(struct isac *isac)
644 {
645  unsigned char val;
646 
647  val = isac->read_isac(isac, ISACSX_CIR0);
648  DBG(DBG_IRQ, "CIR0 %#x", val);
649  if (val & ISACSX_CIR0_CIC0) {
650  DBG(DBG_IRQ, "CODR0 %#x", val >> 4);
651  FsmEvent(&isac->l1m, val >> 4, NULL);
652  }
653 }
654 
655 static inline void isacsx_rme_interrupt(struct isac *isac)
656 {
657  int count;
658  struct sk_buff *skb;
659  unsigned char val;
660 
661  val = isac->read_isac(isac, ISACSX_RSTAD);
662  if ((val & (ISACSX_RSTAD_VFR |
667  DBG(DBG_WARN, "RSTAD %#x, dropped", val);
669  goto out;
670  }
671 
672  count = isac->read_isac(isac, ISACSX_RBCLD) & 0x1f;
673  DBG(DBG_IRQ, "RBCLD %#x", count);
674  if (count == 0)
675  count = 0x20;
676 
677  isac_empty_fifo(isac, count);
678  // strip trailing status byte
679  count = isac->rcvidx - 1;
680  if (count < 1) {
681  DBG(DBG_WARN, "count %d < 1", count);
682  goto out;
683  }
684 
685  skb = dev_alloc_skb(count);
686  if (!skb) {
687  DBG(DBG_WARN, "no memory, dropping");
688  goto out;
689  }
690  memcpy(skb_put(skb, count), isac->rcvbuf, count);
691  DBG_SKB(DBG_RPACKET, skb);
692  D_L1L2(isac, PH_DATA | INDICATION, skb);
693 out:
694  isac->rcvidx = 0;
695 }
696 
697 static inline void isacsx_xpr_interrupt(struct isac *isac)
698 {
699  if (!isac->tx_skb)
700  return;
701 
702  if (isac->tx_skb->len > 0) {
703  isac_fill_fifo(isac);
704  return;
705  }
706  dev_kfree_skb_irq(isac->tx_skb);
707  isac->tx_skb = NULL;
708  isac->tx_cnt = 0;
709  D_L1L2(isac, PH_DATA | CONFIRM, NULL);
710 }
711 
712 static inline void isacsx_icd_interrupt(struct isac *isac)
713 {
714  unsigned char val;
715 
716  val = isac->read_isac(isac, ISACSX_ISTAD);
717  DBG(DBG_IRQ, "ISTAD %#x", val);
718  if (val & ISACSX_ISTAD_XDU) {
719  DBG(DBG_WARN, "ISTAD XDU");
720  isac_retransmit(isac);
721  }
722  if (val & ISACSX_ISTAD_XMR) {
723  DBG(DBG_WARN, "ISTAD XMR");
724  isac_retransmit(isac);
725  }
726  if (val & ISACSX_ISTAD_XPR) {
727  DBG(DBG_IRQ, "ISTAD XPR");
728  isacsx_xpr_interrupt(isac);
729  }
730  if (val & ISACSX_ISTAD_RFO) {
731  DBG(DBG_WARN, "ISTAD RFO");
733  }
734  if (val & ISACSX_ISTAD_RME) {
735  DBG(DBG_IRQ, "ISTAD RME");
736  isacsx_rme_interrupt(isac);
737  }
738  if (val & ISACSX_ISTAD_RPF) {
739  DBG(DBG_IRQ, "ISTAD RPF");
740  isac_empty_fifo(isac, 0x20);
741  }
742 }
743 
744 void isacsx_irq(struct isac *isac)
745 {
746  unsigned char val;
747 
748  val = isac->read_isac(isac, ISACSX_ISTA);
749  DBG(DBG_IRQ, "ISTA %#x", val);
750 
751  if (val & ISACSX_ISTA_ICD)
752  isacsx_icd_interrupt(isac);
753  if (val & ISACSX_ISTA_CIC)
754  isacsx_cic_interrupt(isac);
755 }
756 
757 void isac_init(struct isac *isac)
758 {
759  isac->tx_skb = NULL;
760  isac->l1m.fsm = &l1fsm;
761  isac->l1m.state = ST_L1_RESET;
762 #ifdef CONFIG_HISAX_DEBUG
763  isac->l1m.debug = 1;
764 #else
765  isac->l1m.debug = 0;
766 #endif
767  isac->l1m.userdata = isac;
768  isac->l1m.printdebug = l1m_debug;
769  FsmInitTimer(&isac->l1m, &isac->timer);
770 }
771 
772 void isac_setup(struct isac *isac)
773 {
774  int val, eval;
775 
776  isac->type = TYPE_ISAC;
777  isac_version(isac);
778 
779  ph_command(isac, ISAC_CMD_RES);
780 
781  isac->write_isac(isac, ISAC_MASK, 0xff);
782  isac->mocr = 0xaa;
783  if (test_bit(ISAC_IOM1, &isac->flags)) {
784  /* IOM 1 Mode */
785  isac->write_isac(isac, ISAC_ADF2, 0x0);
786  isac->write_isac(isac, ISAC_SPCR, 0xa);
787  isac->write_isac(isac, ISAC_ADF1, 0x2);
788  isac->write_isac(isac, ISAC_STCR, 0x70);
789  isac->write_isac(isac, ISAC_MODE, 0xc9);
790  } else {
791  /* IOM 2 Mode */
792  if (!isac->adf2)
793  isac->adf2 = 0x80;
794  isac->write_isac(isac, ISAC_ADF2, isac->adf2);
795  isac->write_isac(isac, ISAC_SQXR, 0x2f);
796  isac->write_isac(isac, ISAC_SPCR, 0x00);
797  isac->write_isac(isac, ISAC_STCR, 0x70);
798  isac->write_isac(isac, ISAC_MODE, 0xc9);
799  isac->write_isac(isac, ISAC_TIMR, 0x00);
800  isac->write_isac(isac, ISAC_ADF1, 0x00);
801  }
802  val = isac->read_isac(isac, ISAC_STAR);
803  DBG(2, "ISAC STAR %x", val);
804  val = isac->read_isac(isac, ISAC_MODE);
805  DBG(2, "ISAC MODE %x", val);
806  val = isac->read_isac(isac, ISAC_ADF2);
807  DBG(2, "ISAC ADF2 %x", val);
808  val = isac->read_isac(isac, ISAC_ISTA);
809  DBG(2, "ISAC ISTA %x", val);
810  if (val & 0x01) {
811  eval = isac->read_isac(isac, ISAC_EXIR);
812  DBG(2, "ISAC EXIR %x", eval);
813  }
814  val = isac->read_isac(isac, ISAC_CIR0);
815  DBG(2, "ISAC CIR0 %x", val);
816  FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL);
817 
818  isac->write_isac(isac, ISAC_MASK, 0x0);
819  // RESET Receiver and Transmitter
821 }
822 
823 void isacsx_setup(struct isac *isac)
824 {
825  isac->type = TYPE_ISACSX;
826  // clear LDD
827  isac->write_isac(isac, ISACSX_TR_CONF0, 0x00);
828  // enable transmitter
829  isac->write_isac(isac, ISACSX_TR_CONF2, 0x00);
830  // transparent mode 0, RAC, stop/go
831  isac->write_isac(isac, ISACSX_MODED, 0xc9);
832  // all HDLC IRQ unmasked
833  isac->write_isac(isac, ISACSX_MASKD, 0x03);
834  // unmask ICD, CID IRQs
835  isac->write_isac(isac, ISACSX_MASK,
837 }
838 
839 void isac_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg)
840 {
841  struct isac *isac = hisax_d_if->priv;
842  struct sk_buff *skb = arg;
843 
844  DBG(DBG_PR, "pr %#x", pr);
845 
846  switch (pr) {
847  case PH_ACTIVATE | REQUEST:
849  break;
850  case PH_DEACTIVATE | REQUEST:
852  break;
853  case PH_DATA | REQUEST:
854  DBG(DBG_PR, "PH_DATA REQUEST len %d", skb->len);
855  DBG_SKB(DBG_XPACKET, skb);
856  if (isac->l1m.state != ST_L1_F7) {
857  DBG(1, "L1 wrong state %d\n", isac->l1m.state);
858  dev_kfree_skb(skb);
859  break;
860  }
861  BUG_ON(isac->tx_skb);
862 
863  isac->tx_skb = skb;
864  isac_fill_fifo(isac);
865  break;
866  }
867 }
868 
869 static int __init hisax_isac_init(void)
870 {
871  printk(KERN_INFO "hisax_isac: ISAC-S/ISAC-SX ISDN driver v0.1.0\n");
872 
873  l1fsm.state_count = L1_STATE_COUNT;
874  l1fsm.event_count = L1_EVENT_COUNT;
875  l1fsm.strState = strL1State;
876  l1fsm.strEvent = strL1Event;
877  return FsmNew(&l1fsm, L1FnList, ARRAY_SIZE(L1FnList));
878 }
879 
880 static void __exit hisax_isac_exit(void)
881 {
882  FsmFree(&l1fsm);
883 }
884 
885 EXPORT_SYMBOL(isac_init);
887 
890 
893 
894 module_init(hisax_isac_init);
895 module_exit(hisax_isac_exit);