aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/isdn/act2000
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/isdn/act2000
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/isdn/act2000')
-rw-r--r--drivers/isdn/act2000/Kconfig13
-rw-r--r--drivers/isdn/act2000/Makefile9
-rw-r--r--drivers/isdn/act2000/act2000.h202
-rw-r--r--drivers/isdn/act2000/act2000_isa.c449
-rw-r--r--drivers/isdn/act2000/act2000_isa.h136
-rw-r--r--drivers/isdn/act2000/capi.c1177
-rw-r--r--drivers/isdn/act2000/capi.h366
-rw-r--r--drivers/isdn/act2000/module.c808
8 files changed, 3160 insertions, 0 deletions
diff --git a/drivers/isdn/act2000/Kconfig b/drivers/isdn/act2000/Kconfig
new file mode 100644
index 000000000000..78e6ad8d57c5
--- /dev/null
+++ b/drivers/isdn/act2000/Kconfig
@@ -0,0 +1,13 @@
1#
2# Config.in for IBM Active 2000 ISDN driver
3#
4config ISDN_DRV_ACT2000
5 tristate "IBM Active 2000 support"
6 depends on ISDN_I4L && ISA
7 help
8 Say Y here if you have an IBM Active 2000 ISDN card. In order to use
9 this card, additional firmware is necessary, which has to be loaded
10 into the card using a utility which is part of the latest
11 isdn4k-utils package. Please read the file
12 <file:Documentation/isdn/README.act2000> for more information.
13
diff --git a/drivers/isdn/act2000/Makefile b/drivers/isdn/act2000/Makefile
new file mode 100644
index 000000000000..05e582fb5c00
--- /dev/null
+++ b/drivers/isdn/act2000/Makefile
@@ -0,0 +1,9 @@
1# Makefile for the act2000 ISDN device driver
2
3# Each configuration option enables a list of files.
4
5obj-$(CONFIG_ISDN_DRV_ACT2000) += act2000.o
6
7# Multipart objects.
8
9act2000-y := module.o capi.o act2000_isa.o
diff --git a/drivers/isdn/act2000/act2000.h b/drivers/isdn/act2000/act2000.h
new file mode 100644
index 000000000000..b091d1a54125
--- /dev/null
+++ b/drivers/isdn/act2000/act2000.h
@@ -0,0 +1,202 @@
1/* $Id: act2000.h,v 1.8.6.3 2001/09/23 22:24:32 kai Exp $
2 *
3 * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
4 *
5 * Author Fritz Elfert
6 * Copyright by Fritz Elfert <fritz@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 * Thanks to Friedemann Baitinger and IBM Germany
12 *
13 */
14
15#ifndef act2000_h
16#define act2000_h
17
18#include <linux/compiler.h>
19
20#define ACT2000_IOCTL_SETPORT 1
21#define ACT2000_IOCTL_GETPORT 2
22#define ACT2000_IOCTL_SETIRQ 3
23#define ACT2000_IOCTL_GETIRQ 4
24#define ACT2000_IOCTL_SETBUS 5
25#define ACT2000_IOCTL_GETBUS 6
26#define ACT2000_IOCTL_SETPROTO 7
27#define ACT2000_IOCTL_GETPROTO 8
28#define ACT2000_IOCTL_SETMSN 9
29#define ACT2000_IOCTL_GETMSN 10
30#define ACT2000_IOCTL_LOADBOOT 11
31#define ACT2000_IOCTL_ADDCARD 12
32
33#define ACT2000_IOCTL_TEST 98
34#define ACT2000_IOCTL_DEBUGVAR 99
35
36#define ACT2000_BUS_ISA 1
37#define ACT2000_BUS_MCA 2
38#define ACT2000_BUS_PCMCIA 3
39
40/* Struct for adding new cards */
41typedef struct act2000_cdef {
42 int bus;
43 int port;
44 int irq;
45 char id[10];
46} act2000_cdef;
47
48/* Struct for downloading firmware */
49typedef struct act2000_ddef {
50 int length; /* Length of code */
51 char __user *buffer; /* Ptr. to code */
52} act2000_ddef;
53
54typedef struct act2000_fwid {
55 char isdn[4];
56 char revlen[2];
57 char revision[504];
58} act2000_fwid;
59
60#if defined(__KERNEL__) || defined(__DEBUGVAR__)
61
62#ifdef __KERNEL__
63/* Kernel includes */
64
65#include <linux/sched.h>
66#include <linux/string.h>
67#include <linux/workqueue.h>
68#include <linux/interrupt.h>
69#include <linux/skbuff.h>
70#include <linux/errno.h>
71#include <linux/fs.h>
72#include <linux/major.h>
73#include <asm/io.h>
74#include <linux/kernel.h>
75#include <linux/signal.h>
76#include <linux/slab.h>
77#include <linux/mm.h>
78#include <linux/mman.h>
79#include <linux/ioport.h>
80#include <linux/timer.h>
81#include <linux/wait.h>
82#include <linux/delay.h>
83#include <linux/ctype.h>
84#include <linux/isdnif.h>
85
86#endif /* __KERNEL__ */
87
88#define ACT2000_PORTLEN 8
89
90#define ACT2000_FLAGS_RUNNING 1 /* Cards driver activated */
91#define ACT2000_FLAGS_PVALID 2 /* Cards port is valid */
92#define ACT2000_FLAGS_IVALID 4 /* Cards irq is valid */
93#define ACT2000_FLAGS_LOADED 8 /* Firmware loaded */
94
95#define ACT2000_BCH 2 /* # of channels per card */
96
97/* D-Channel states */
98#define ACT2000_STATE_NULL 0
99#define ACT2000_STATE_ICALL 1
100#define ACT2000_STATE_OCALL 2
101#define ACT2000_STATE_IWAIT 3
102#define ACT2000_STATE_OWAIT 4
103#define ACT2000_STATE_IBWAIT 5
104#define ACT2000_STATE_OBWAIT 6
105#define ACT2000_STATE_BWAIT 7
106#define ACT2000_STATE_BHWAIT 8
107#define ACT2000_STATE_BHWAIT2 9
108#define ACT2000_STATE_DHWAIT 10
109#define ACT2000_STATE_DHWAIT2 11
110#define ACT2000_STATE_BSETUP 12
111#define ACT2000_STATE_ACTIVE 13
112
113#define ACT2000_MAX_QUEUED 8000 /* 2 * maxbuff */
114
115#define ACT2000_LOCK_TX 0
116#define ACT2000_LOCK_RX 1
117
118typedef struct act2000_chan {
119 unsigned short callref; /* Call Reference */
120 unsigned short fsm_state; /* Current D-Channel state */
121 unsigned short eazmask; /* EAZ-Mask for this Channel */
122 short queued; /* User-Data Bytes in TX queue */
123 unsigned short plci;
124 unsigned short ncci;
125 unsigned char l2prot; /* Layer 2 protocol */
126 unsigned char l3prot; /* Layer 3 protocol */
127} act2000_chan;
128
129typedef struct msn_entry {
130 char eaz;
131 char msn[16];
132 struct msn_entry * next;
133} msn_entry;
134
135typedef struct irq_data_isa {
136 __u8 *rcvptr;
137 __u16 rcvidx;
138 __u16 rcvlen;
139 struct sk_buff *rcvskb;
140 __u8 rcvignore;
141 __u8 rcvhdr[8];
142} irq_data_isa;
143
144typedef union irq_data {
145 irq_data_isa isa;
146} irq_data;
147
148/*
149 * Per card driver data
150 */
151typedef struct act2000_card {
152 unsigned short port; /* Base-port-address */
153 unsigned short irq; /* Interrupt */
154 u_char ptype; /* Protocol type (1TR6 or Euro) */
155 u_char bus; /* Cardtype (ISA, MCA, PCMCIA) */
156 struct act2000_card *next; /* Pointer to next device struct */
157 spinlock_t lock; /* protect critical operations */
158 int myid; /* Driver-Nr. assigned by linklevel */
159 unsigned long flags; /* Statusflags */
160 unsigned long ilock; /* Semaphores for IRQ-Routines */
161 struct sk_buff_head rcvq; /* Receive-Message queue */
162 struct sk_buff_head sndq; /* Send-Message queue */
163 struct sk_buff_head ackq; /* Data-Ack-Message queue */
164 u_char *ack_msg; /* Ptr to User Data in User skb */
165 __u16 need_b3ack; /* Flag: Need ACK for current skb */
166 struct sk_buff *sbuf; /* skb which is currently sent */
167 struct timer_list ptimer; /* Poll timer */
168 struct work_struct snd_tq; /* Task struct for xmit bh */
169 struct work_struct rcv_tq; /* Task struct for rcv bh */
170 struct work_struct poll_tq; /* Task struct for polled rcv bh */
171 msn_entry *msn_list;
172 unsigned short msgnum; /* Message number for sending */
173 spinlock_t mnlock; /* lock for msgnum */
174 act2000_chan bch[ACT2000_BCH]; /* B-Channel status/control */
175 char status_buf[256]; /* Buffer for status messages */
176 char *status_buf_read;
177 char *status_buf_write;
178 char *status_buf_end;
179 irq_data idat; /* Data used for IRQ handler */
180 isdn_if interface; /* Interface to upper layer */
181 char regname[35]; /* Name used for request_region */
182} act2000_card;
183
184extern __inline__ void act2000_schedule_tx(act2000_card *card)
185{
186 schedule_work(&card->snd_tq);
187}
188
189extern __inline__ void act2000_schedule_rx(act2000_card *card)
190{
191 schedule_work(&card->rcv_tq);
192}
193
194extern __inline__ void act2000_schedule_poll(act2000_card *card)
195{
196 schedule_work(&card->poll_tq);
197}
198
199extern char *act2000_find_eaz(act2000_card *, char);
200
201#endif /* defined(__KERNEL__) || defined(__DEBUGVAR__) */
202#endif /* act2000_h */
diff --git a/drivers/isdn/act2000/act2000_isa.c b/drivers/isdn/act2000/act2000_isa.c
new file mode 100644
index 000000000000..bc98d77c5ecd
--- /dev/null
+++ b/drivers/isdn/act2000/act2000_isa.c
@@ -0,0 +1,449 @@
1/* $Id: act2000_isa.c,v 1.11.6.3 2001/09/23 22:24:32 kai Exp $
2 *
3 * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
4 *
5 * Author Fritz Elfert
6 * Copyright by Fritz Elfert <fritz@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 * Thanks to Friedemann Baitinger and IBM Germany
12 *
13 */
14
15#include "act2000.h"
16#include "act2000_isa.h"
17#include "capi.h"
18
19static act2000_card *irq2card_map[16];
20
21/*
22 * Reset Controller, then try to read the Card's signature.
23 + Return:
24 * 1 = Signature found.
25 * 0 = Signature not found.
26 */
27static int
28act2000_isa_reset(unsigned short portbase)
29{
30 unsigned char reg;
31 int i;
32 int found;
33 int serial = 0;
34
35 found = 0;
36 if ((reg = inb(portbase + ISA_COR)) != 0xff) {
37 outb(reg | ISA_COR_RESET, portbase + ISA_COR);
38 mdelay(10);
39 outb(reg, portbase + ISA_COR);
40 mdelay(10);
41
42 for (i = 0; i < 16; i++) {
43 if (inb(portbase + ISA_ISR) & ISA_ISR_SERIAL)
44 serial |= 0x10000;
45 serial >>= 1;
46 }
47 if (serial == ISA_SER_ID)
48 found++;
49 }
50 return found;
51}
52
53int
54act2000_isa_detect(unsigned short portbase)
55{
56 int ret = 0;
57
58 if (request_region(portbase, ACT2000_PORTLEN, "act2000isa")) {
59 ret = act2000_isa_reset(portbase);
60 release_region(portbase, ISA_REGION);
61 }
62 return ret;
63}
64
65static irqreturn_t
66act2000_isa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
67{
68 act2000_card *card = irq2card_map[irq];
69 u_char istatus;
70
71 if (!card) {
72 printk(KERN_WARNING
73 "act2000: Spurious interrupt!\n");
74 return IRQ_NONE;
75 }
76 istatus = (inb(ISA_PORT_ISR) & 0x07);
77 if (istatus & ISA_ISR_OUT) {
78 /* RX fifo has data */
79 istatus &= ISA_ISR_OUT_MASK;
80 outb(0, ISA_PORT_SIS);
81 act2000_isa_receive(card);
82 outb(ISA_SIS_INT, ISA_PORT_SIS);
83 }
84 if (istatus & ISA_ISR_ERR) {
85 /* Error Interrupt */
86 istatus &= ISA_ISR_ERR_MASK;
87 printk(KERN_WARNING "act2000: errIRQ\n");
88 }
89 if (istatus)
90 printk(KERN_DEBUG "act2000: ?IRQ %d %02x\n", irq, istatus);
91 return IRQ_HANDLED;
92}
93
94static void
95act2000_isa_select_irq(act2000_card * card)
96{
97 unsigned char reg;
98
99 reg = (inb(ISA_PORT_COR) & ~ISA_COR_IRQOFF) | ISA_COR_PERR;
100 switch (card->irq) {
101 case 3:
102 reg = ISA_COR_IRQ03;
103 break;
104 case 5:
105 reg = ISA_COR_IRQ05;
106 break;
107 case 7:
108 reg = ISA_COR_IRQ07;
109 break;
110 case 10:
111 reg = ISA_COR_IRQ10;
112 break;
113 case 11:
114 reg = ISA_COR_IRQ11;
115 break;
116 case 12:
117 reg = ISA_COR_IRQ12;
118 break;
119 case 15:
120 reg = ISA_COR_IRQ15;
121 break;
122 }
123 outb(reg, ISA_PORT_COR);
124}
125
126static void
127act2000_isa_enable_irq(act2000_card * card)
128{
129 act2000_isa_select_irq(card);
130 /* Enable READ irq */
131 outb(ISA_SIS_INT, ISA_PORT_SIS);
132}
133
134/*
135 * Install interrupt handler, enable irq on card.
136 * If irq is -1, choose next free irq, else irq is given explicitely.
137 */
138int
139act2000_isa_config_irq(act2000_card * card, short irq)
140{
141 if (card->flags & ACT2000_FLAGS_IVALID) {
142 free_irq(card->irq, NULL);
143 irq2card_map[card->irq] = NULL;
144 }
145 card->flags &= ~ACT2000_FLAGS_IVALID;
146 outb(ISA_COR_IRQOFF, ISA_PORT_COR);
147 if (!irq)
148 return 0;
149
150 if (!request_irq(irq, &act2000_isa_interrupt, 0, card->regname, NULL)) {
151 card->irq = irq;
152 irq2card_map[card->irq] = card;
153 card->flags |= ACT2000_FLAGS_IVALID;
154 printk(KERN_WARNING
155 "act2000: Could not request irq %d\n",irq);
156 return -EBUSY;
157 } else {
158 act2000_isa_select_irq(card);
159 /* Disable READ and WRITE irq */
160 outb(0, ISA_PORT_SIS);
161 outb(0, ISA_PORT_SOS);
162 }
163 return 0;
164}
165
166int
167act2000_isa_config_port(act2000_card * card, unsigned short portbase)
168{
169 if (card->flags & ACT2000_FLAGS_PVALID) {
170 release_region(card->port, ISA_REGION);
171 card->flags &= ~ACT2000_FLAGS_PVALID;
172 }
173 if (request_region(portbase, ACT2000_PORTLEN, card->regname) == NULL)
174 return -EBUSY;
175 else {
176 card->port = portbase;
177 card->flags |= ACT2000_FLAGS_PVALID;
178 return 0;
179 }
180}
181
182/*
183 * Release ressources, used by an adaptor.
184 */
185void
186act2000_isa_release(act2000_card * card)
187{
188 unsigned long flags;
189
190 spin_lock_irqsave(&card->lock, flags);
191 if (card->flags & ACT2000_FLAGS_IVALID) {
192 free_irq(card->irq, NULL);
193 irq2card_map[card->irq] = NULL;
194 }
195 card->flags &= ~ACT2000_FLAGS_IVALID;
196 if (card->flags & ACT2000_FLAGS_PVALID)
197 release_region(card->port, ISA_REGION);
198 card->flags &= ~ACT2000_FLAGS_PVALID;
199 spin_unlock_irqrestore(&card->lock, flags);
200}
201
202static int
203act2000_isa_writeb(act2000_card * card, u_char data)
204{
205 u_char timeout = 40;
206
207 while (timeout) {
208 if (inb(ISA_PORT_SOS) & ISA_SOS_READY) {
209 outb(data, ISA_PORT_SDO);
210 return 0;
211 } else {
212 timeout--;
213 udelay(10);
214 }
215 }
216 return 1;
217}
218
219static int
220act2000_isa_readb(act2000_card * card, u_char * data)
221{
222 u_char timeout = 40;
223
224 while (timeout) {
225 if (inb(ISA_PORT_SIS) & ISA_SIS_READY) {
226 *data = inb(ISA_PORT_SDI);
227 return 0;
228 } else {
229 timeout--;
230 udelay(10);
231 }
232 }
233 return 1;
234}
235
236void
237act2000_isa_receive(act2000_card *card)
238{
239 u_char c;
240
241 if (test_and_set_bit(ACT2000_LOCK_RX, (void *) &card->ilock) != 0)
242 return;
243 while (!act2000_isa_readb(card, &c)) {
244 if (card->idat.isa.rcvidx < 8) {
245 card->idat.isa.rcvhdr[card->idat.isa.rcvidx++] = c;
246 if (card->idat.isa.rcvidx == 8) {
247 int valid = actcapi_chkhdr(card, (actcapi_msghdr *)&card->idat.isa.rcvhdr);
248
249 if (valid) {
250 card->idat.isa.rcvlen = ((actcapi_msghdr *)&card->idat.isa.rcvhdr)->len;
251 card->idat.isa.rcvskb = dev_alloc_skb(card->idat.isa.rcvlen);
252 if (card->idat.isa.rcvskb == NULL) {
253 card->idat.isa.rcvignore = 1;
254 printk(KERN_WARNING
255 "act2000_isa_receive: no memory\n");
256 test_and_clear_bit(ACT2000_LOCK_RX, (void *) &card->ilock);
257 return;
258 }
259 memcpy(skb_put(card->idat.isa.rcvskb, 8), card->idat.isa.rcvhdr, 8);
260 card->idat.isa.rcvptr = skb_put(card->idat.isa.rcvskb, card->idat.isa.rcvlen - 8);
261 } else {
262 card->idat.isa.rcvidx = 0;
263 printk(KERN_WARNING
264 "act2000_isa_receive: Invalid CAPI msg\n");
265 {
266 int i; __u8 *p; __u8 *c; __u8 tmp[30];
267 for (i = 0, p = (__u8 *)&card->idat.isa.rcvhdr, c = tmp; i < 8; i++)
268 c += sprintf(c, "%02x ", *(p++));
269 printk(KERN_WARNING "act2000_isa_receive: %s\n", tmp);
270 }
271 }
272 }
273 } else {
274 if (!card->idat.isa.rcvignore)
275 *card->idat.isa.rcvptr++ = c;
276 if (++card->idat.isa.rcvidx >= card->idat.isa.rcvlen) {
277 if (!card->idat.isa.rcvignore) {
278 skb_queue_tail(&card->rcvq, card->idat.isa.rcvskb);
279 act2000_schedule_rx(card);
280 }
281 card->idat.isa.rcvidx = 0;
282 card->idat.isa.rcvlen = 8;
283 card->idat.isa.rcvignore = 0;
284 card->idat.isa.rcvskb = NULL;
285 card->idat.isa.rcvptr = card->idat.isa.rcvhdr;
286 }
287 }
288 }
289 if (!(card->flags & ACT2000_FLAGS_IVALID)) {
290 /* In polling mode, schedule myself */
291 if ((card->idat.isa.rcvidx) &&
292 (card->idat.isa.rcvignore ||
293 (card->idat.isa.rcvidx < card->idat.isa.rcvlen)))
294 act2000_schedule_poll(card);
295 }
296 test_and_clear_bit(ACT2000_LOCK_RX, (void *) &card->ilock);
297}
298
299void
300act2000_isa_send(act2000_card * card)
301{
302 unsigned long flags;
303 struct sk_buff *skb;
304 actcapi_msg *msg;
305 int l;
306
307 if (test_and_set_bit(ACT2000_LOCK_TX, (void *) &card->ilock) != 0)
308 return;
309 while (1) {
310 spin_lock_irqsave(&card->lock, flags);
311 if (!(card->sbuf)) {
312 if ((card->sbuf = skb_dequeue(&card->sndq))) {
313 card->ack_msg = card->sbuf->data;
314 msg = (actcapi_msg *)card->sbuf->data;
315 if ((msg->hdr.cmd.cmd == 0x86) &&
316 (msg->hdr.cmd.subcmd == 0) ) {
317 /* Save flags in message */
318 card->need_b3ack = msg->msg.data_b3_req.flags;
319 msg->msg.data_b3_req.flags = 0;
320 }
321 }
322 }
323 spin_unlock_irqrestore(&card->lock, flags);
324 if (!(card->sbuf)) {
325 /* No more data to send */
326 test_and_clear_bit(ACT2000_LOCK_TX, (void *) &card->ilock);
327 return;
328 }
329 skb = card->sbuf;
330 l = 0;
331 while (skb->len) {
332 if (act2000_isa_writeb(card, *(skb->data))) {
333 /* Fifo is full, but more data to send */
334 test_and_clear_bit(ACT2000_LOCK_TX, (void *) &card->ilock);
335 /* Schedule myself */
336 act2000_schedule_tx(card);
337 return;
338 }
339 skb_pull(skb, 1);
340 l++;
341 }
342 msg = (actcapi_msg *)card->ack_msg;
343 if ((msg->hdr.cmd.cmd == 0x86) &&
344 (msg->hdr.cmd.subcmd == 0) ) {
345 /*
346 * If it's user data, reset data-ptr
347 * and put skb into ackq.
348 */
349 skb->data = card->ack_msg;
350 /* Restore flags in message */
351 msg->msg.data_b3_req.flags = card->need_b3ack;
352 skb_queue_tail(&card->ackq, skb);
353 } else
354 dev_kfree_skb(skb);
355 card->sbuf = NULL;
356 }
357}
358
359/*
360 * Get firmware ID, check for 'ISDN' signature.
361 */
362static int
363act2000_isa_getid(act2000_card * card)
364{
365
366 act2000_fwid fid;
367 u_char *p = (u_char *) & fid;
368 int count = 0;
369
370 while (1) {
371 if (count > 510)
372 return -EPROTO;
373 if (act2000_isa_readb(card, p++))
374 break;
375 count++;
376 }
377 if (count <= 20) {
378 printk(KERN_WARNING "act2000: No Firmware-ID!\n");
379 return -ETIME;
380 }
381 *p = '\0';
382 fid.revlen[0] = '\0';
383 if (strcmp(fid.isdn, "ISDN")) {
384 printk(KERN_WARNING "act2000: Wrong Firmware-ID!\n");
385 return -EPROTO;
386 }
387 if ((p = strchr(fid.revision, '\n')))
388 *p = '\0';
389 printk(KERN_INFO "act2000: Firmware-ID: %s\n", fid.revision);
390 if (card->flags & ACT2000_FLAGS_IVALID) {
391 printk(KERN_DEBUG "Enabling Interrupts ...\n");
392 act2000_isa_enable_irq(card);
393 }
394 return 0;
395}
396
397/*
398 * Download microcode into card, check Firmware signature.
399 */
400int
401act2000_isa_download(act2000_card * card, act2000_ddef __user * cb)
402{
403 unsigned int length;
404 int l;
405 int c;
406 long timeout;
407 u_char *b;
408 u_char __user *p;
409 u_char *buf;
410 act2000_ddef cblock;
411
412 if (!act2000_isa_reset(card->port))
413 return -ENXIO;
414 msleep_interruptible(500);
415 if (copy_from_user(&cblock, cb, sizeof(cblock)))
416 return -EFAULT;
417 length = cblock.length;
418 p = cblock.buffer;
419 if (!access_ok(VERIFY_READ, p, length))
420 return -EFAULT;
421 buf = (u_char *) kmalloc(1024, GFP_KERNEL);
422 if (!buf)
423 return -ENOMEM;
424 timeout = 0;
425 while (length) {
426 l = (length > 1024) ? 1024 : length;
427 c = 0;
428 b = buf;
429 if (copy_from_user(buf, p, l)) {
430 kfree(buf);
431 return -EFAULT;
432 }
433 while (c < l) {
434 if (act2000_isa_writeb(card, *b++)) {
435 printk(KERN_WARNING
436 "act2000: loader timed out"
437 " len=%d c=%d\n", length, c);
438 kfree(buf);
439 return -ETIME;
440 }
441 c++;
442 }
443 length -= l;
444 p += l;
445 }
446 kfree(buf);
447 msleep_interruptible(500);
448 return (act2000_isa_getid(card));
449}
diff --git a/drivers/isdn/act2000/act2000_isa.h b/drivers/isdn/act2000/act2000_isa.h
new file mode 100644
index 000000000000..ad86c5ed9aad
--- /dev/null
+++ b/drivers/isdn/act2000/act2000_isa.h
@@ -0,0 +1,136 @@
1/* $Id: act2000_isa.h,v 1.4.6.1 2001/09/23 22:24:32 kai Exp $
2 *
3 * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
4 *
5 * Author Fritz Elfert
6 * Copyright by Fritz Elfert <fritz@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 * Thanks to Friedemann Baitinger and IBM Germany
12 *
13 */
14
15#ifndef act2000_isa_h
16#define act2000_isa_h
17
18#define ISA_POLL_LOOP 40 /* Try to read-write before give up */
19
20typedef enum {
21 INT_NO_CHANGE = 0, /* Do not change the Mask */
22 INT_ON = 1, /* Set to Enable */
23 INT_OFF = 2, /* Set to Disable */
24} ISA_INT_T;
25
26/**************************************************************************/
27/* Configuration Register COR (RW) */
28/**************************************************************************/
29/* 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 */
30/* Soft Res| IRQM | IRQ Select | N/A | WAIT |Proc err */
31/**************************************************************************/
32#define ISA_COR 0 /* Offset for ISA config register */
33#define ISA_COR_PERR 0x01 /* Processor Error Enabled */
34#define ISA_COR_WS 0x02 /* Insert Wait State if 1 */
35#define ISA_COR_IRQOFF 0x38 /* No Interrupt */
36#define ISA_COR_IRQ07 0x30 /* IRQ 7 Enable */
37#define ISA_COR_IRQ05 0x28 /* IRQ 5 Enable */
38#define ISA_COR_IRQ03 0x20 /* IRQ 3 Enable */
39#define ISA_COR_IRQ10 0x18 /* IRQ 10 Enable */
40#define ISA_COR_IRQ11 0x10 /* IRQ 11 Enable */
41#define ISA_COR_IRQ12 0x08 /* IRQ 12 Enable */
42#define ISA_COR_IRQ15 0x00 /* IRQ 15 Enable */
43#define ISA_COR_IRQPULSE 0x40 /* 0 = Level 1 = Pulse Interrupt */
44#define ISA_COR_RESET 0x80 /* Soft Reset for Transputer */
45
46/**************************************************************************/
47/* Interrupt Source Register ISR (RO) */
48/**************************************************************************/
49/* 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 */
50/* N/A | N/A | N/A |Err sig |Ser ID |IN Intr |Out Intr| Error */
51/**************************************************************************/
52#define ISA_ISR 1 /* Offset for Interrupt Register */
53#define ISA_ISR_ERR 0x01 /* Error Interrupt */
54#define ISA_ISR_OUT 0x02 /* Output Interrupt */
55#define ISA_ISR_INP 0x04 /* Input Interrupt */
56#define ISA_ISR_SERIAL 0x08 /* Read out Serial ID after Reset */
57#define ISA_ISR_ERRSIG 0x10 /* Error Signal Input */
58#define ISA_ISR_ERR_MASK 0xfe /* Mask Error Interrupt */
59#define ISA_ISR_OUT_MASK 0xfd /* Mask Output Interrupt */
60#define ISA_ISR_INP_MASK 0xfb /* Mask Input Interrupt */
61
62/* Signature delivered after Reset at ISA_ISR_SERIAL (LSB first) */
63#define ISA_SER_ID 0x0201 /* ID for ISA Card */
64
65/**************************************************************************/
66/* EEPROM Register EPR (RW) */
67/**************************************************************************/
68/* 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 */
69/* N/A | N/A | N/A |ROM Hold| ROM CS |ROM CLK | ROM IN |ROM Out */
70/**************************************************************************/
71#define ISA_EPR 2 /* Offset for this Register */
72#define ISA_EPR_OUT 0x01 /* Rome Register Out (RO) */
73#define ISA_EPR_IN 0x02 /* Rom Register In (WR) */
74#define ISA_EPR_CLK 0x04 /* Rom Clock (WR) */
75#define ISA_EPR_CS 0x08 /* Rom Cip Select (WR) */
76#define ISA_EPR_HOLD 0x10 /* Rom Hold Signal (WR) */
77
78/**************************************************************************/
79/* EEPROM enable Register EER (unused) */
80/**************************************************************************/
81#define ISA_EER 3 /* Offset for this Register */
82
83/**************************************************************************/
84/* SLC Data Input SDI (RO) */
85/**************************************************************************/
86#define ISA_SDI 4 /* Offset for this Register */
87
88/**************************************************************************/
89/* SLC Data Output SDO (WO) */
90/**************************************************************************/
91#define ISA_SDO 5 /* Offset for this Register */
92
93/**************************************************************************/
94/* IMS C011 Mode 2 Input Status Register for INMOS CPU SIS (RW) */
95/**************************************************************************/
96/* 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 */
97/* N/A | N/A | N/A | N/A | N/A | N/A |Int Ena |Data Pre */
98/**************************************************************************/
99#define ISA_SIS 6 /* Offset for this Register */
100#define ISA_SIS_READY 0x01 /* If 1 : data is available */
101#define ISA_SIS_INT 0x02 /* Enable Interrupt for READ */
102
103/**************************************************************************/
104/* IMS C011 Mode 2 Output Status Register from INMOS CPU SOS (RW) */
105/**************************************************************************/
106/* 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 */
107/* N/A | N/A | N/A | N/A | N/A | N/A |Int Ena |Out Rdy */
108/**************************************************************************/
109#define ISA_SOS 7 /* Offset for this Register */
110#define ISA_SOS_READY 0x01 /* If 1 : we can write Data */
111#define ISA_SOS_INT 0x02 /* Enable Interrupt for WRITE */
112
113#define ISA_REGION 8 /* Number of Registers */
114
115
116/* Macros for accessing ports */
117#define ISA_PORT_COR (card->port+ISA_COR)
118#define ISA_PORT_ISR (card->port+ISA_ISR)
119#define ISA_PORT_EPR (card->port+ISA_EPR)
120#define ISA_PORT_EER (card->port+ISA_EER)
121#define ISA_PORT_SDI (card->port+ISA_SDI)
122#define ISA_PORT_SDO (card->port+ISA_SDO)
123#define ISA_PORT_SIS (card->port+ISA_SIS)
124#define ISA_PORT_SOS (card->port+ISA_SOS)
125
126/* Prototypes */
127
128extern int act2000_isa_detect(unsigned short portbase);
129extern int act2000_isa_config_irq(act2000_card * card, short irq);
130extern int act2000_isa_config_port(act2000_card * card, unsigned short portbase);
131extern int act2000_isa_download(act2000_card * card, act2000_ddef __user * cb);
132extern void act2000_isa_release(act2000_card * card);
133extern void act2000_isa_receive(act2000_card *card);
134extern void act2000_isa_send(act2000_card *card);
135
136#endif /* act2000_isa_h */
diff --git a/drivers/isdn/act2000/capi.c b/drivers/isdn/act2000/capi.c
new file mode 100644
index 000000000000..40395f567231
--- /dev/null
+++ b/drivers/isdn/act2000/capi.c
@@ -0,0 +1,1177 @@
1/* $Id: capi.c,v 1.9.6.2 2001/09/23 22:24:32 kai Exp $
2 *
3 * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
4 * CAPI encoder/decoder
5 *
6 * Author Fritz Elfert
7 * Copyright by Fritz Elfert <fritz@isdn4linux.de>
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 *
12 * Thanks to Friedemann Baitinger and IBM Germany
13 *
14 */
15
16#include "act2000.h"
17#include "capi.h"
18
19static actcapi_msgdsc valid_msg[] = {
20 {{ 0x86, 0x02}, "DATA_B3_IND"}, /* DATA_B3_IND/CONF must be first because of speed!!! */
21 {{ 0x86, 0x01}, "DATA_B3_CONF"},
22 {{ 0x02, 0x01}, "CONNECT_CONF"},
23 {{ 0x02, 0x02}, "CONNECT_IND"},
24 {{ 0x09, 0x01}, "CONNECT_INFO_CONF"},
25 {{ 0x03, 0x02}, "CONNECT_ACTIVE_IND"},
26 {{ 0x04, 0x01}, "DISCONNECT_CONF"},
27 {{ 0x04, 0x02}, "DISCONNECT_IND"},
28 {{ 0x05, 0x01}, "LISTEN_CONF"},
29 {{ 0x06, 0x01}, "GET_PARAMS_CONF"},
30 {{ 0x07, 0x01}, "INFO_CONF"},
31 {{ 0x07, 0x02}, "INFO_IND"},
32 {{ 0x08, 0x01}, "DATA_CONF"},
33 {{ 0x08, 0x02}, "DATA_IND"},
34 {{ 0x40, 0x01}, "SELECT_B2_PROTOCOL_CONF"},
35 {{ 0x80, 0x01}, "SELECT_B3_PROTOCOL_CONF"},
36 {{ 0x81, 0x01}, "LISTEN_B3_CONF"},
37 {{ 0x82, 0x01}, "CONNECT_B3_CONF"},
38 {{ 0x82, 0x02}, "CONNECT_B3_IND"},
39 {{ 0x83, 0x02}, "CONNECT_B3_ACTIVE_IND"},
40 {{ 0x84, 0x01}, "DISCONNECT_B3_CONF"},
41 {{ 0x84, 0x02}, "DISCONNECT_B3_IND"},
42 {{ 0x85, 0x01}, "GET_B3_PARAMS_CONF"},
43 {{ 0x01, 0x01}, "RESET_B3_CONF"},
44 {{ 0x01, 0x02}, "RESET_B3_IND"},
45 /* {{ 0x87, 0x02, "HANDSET_IND"}, not implemented */
46 {{ 0xff, 0x01}, "MANUFACTURER_CONF"},
47 {{ 0xff, 0x02}, "MANUFACTURER_IND"},
48#ifdef DEBUG_MSG
49 /* Requests */
50 {{ 0x01, 0x00}, "RESET_B3_REQ"},
51 {{ 0x02, 0x00}, "CONNECT_REQ"},
52 {{ 0x04, 0x00}, "DISCONNECT_REQ"},
53 {{ 0x05, 0x00}, "LISTEN_REQ"},
54 {{ 0x06, 0x00}, "GET_PARAMS_REQ"},
55 {{ 0x07, 0x00}, "INFO_REQ"},
56 {{ 0x08, 0x00}, "DATA_REQ"},
57 {{ 0x09, 0x00}, "CONNECT_INFO_REQ"},
58 {{ 0x40, 0x00}, "SELECT_B2_PROTOCOL_REQ"},
59 {{ 0x80, 0x00}, "SELECT_B3_PROTOCOL_REQ"},
60 {{ 0x81, 0x00}, "LISTEN_B3_REQ"},
61 {{ 0x82, 0x00}, "CONNECT_B3_REQ"},
62 {{ 0x84, 0x00}, "DISCONNECT_B3_REQ"},
63 {{ 0x85, 0x00}, "GET_B3_PARAMS_REQ"},
64 {{ 0x86, 0x00}, "DATA_B3_REQ"},
65 {{ 0xff, 0x00}, "MANUFACTURER_REQ"},
66 /* Responses */
67 {{ 0x01, 0x03}, "RESET_B3_RESP"},
68 {{ 0x02, 0x03}, "CONNECT_RESP"},
69 {{ 0x03, 0x03}, "CONNECT_ACTIVE_RESP"},
70 {{ 0x04, 0x03}, "DISCONNECT_RESP"},
71 {{ 0x07, 0x03}, "INFO_RESP"},
72 {{ 0x08, 0x03}, "DATA_RESP"},
73 {{ 0x82, 0x03}, "CONNECT_B3_RESP"},
74 {{ 0x83, 0x03}, "CONNECT_B3_ACTIVE_RESP"},
75 {{ 0x84, 0x03}, "DISCONNECT_B3_RESP"},
76 {{ 0x86, 0x03}, "DATA_B3_RESP"},
77 {{ 0xff, 0x03}, "MANUFACTURER_RESP"},
78#endif
79 {{ 0x00, 0x00}, NULL},
80};
81#define num_valid_msg (sizeof(valid_msg)/sizeof(actcapi_msgdsc))
82#define num_valid_imsg 27 /* MANUFACTURER_IND */
83
84/*
85 * Check for a valid incoming CAPI message.
86 * Return:
87 * 0 = Invalid message
88 * 1 = Valid message, no B-Channel-data
89 * 2 = Valid message, B-Channel-data
90 */
91int
92actcapi_chkhdr(act2000_card * card, actcapi_msghdr *hdr)
93{
94 int i;
95
96 if (hdr->applicationID != 1)
97 return 0;
98 if (hdr->len < 9)
99 return 0;
100 for (i = 0; i < num_valid_imsg; i++)
101 if ((hdr->cmd.cmd == valid_msg[i].cmd.cmd) &&
102 (hdr->cmd.subcmd == valid_msg[i].cmd.subcmd)) {
103 return (i?1:2);
104 }
105 return 0;
106}
107
108#define ACTCAPI_MKHDR(l, c, s) { \
109 skb = alloc_skb(l + 8, GFP_ATOMIC); \
110 if (skb) { \
111 m = (actcapi_msg *)skb_put(skb, l + 8); \
112 m->hdr.len = l + 8; \
113 m->hdr.applicationID = 1; \
114 m->hdr.cmd.cmd = c; \
115 m->hdr.cmd.subcmd = s; \
116 m->hdr.msgnum = actcapi_nextsmsg(card); \
117 } else m = NULL;\
118}
119
120#define ACTCAPI_CHKSKB if (!skb) { \
121 printk(KERN_WARNING "actcapi: alloc_skb failed\n"); \
122 return; \
123}
124
125#define ACTCAPI_QUEUE_TX { \
126 actcapi_debug_msg(skb, 1); \
127 skb_queue_tail(&card->sndq, skb); \
128 act2000_schedule_tx(card); \
129}
130
131int
132actcapi_listen_req(act2000_card *card)
133{
134 __u16 eazmask = 0;
135 int i;
136 actcapi_msg *m;
137 struct sk_buff *skb;
138
139 for (i = 0; i < ACT2000_BCH; i++)
140 eazmask |= card->bch[i].eazmask;
141 ACTCAPI_MKHDR(9, 0x05, 0x00);
142 if (!skb) {
143 printk(KERN_WARNING "actcapi: alloc_skb failed\n");
144 return -ENOMEM;
145 }
146 m->msg.listen_req.controller = 0;
147 m->msg.listen_req.infomask = 0x3f; /* All information */
148 m->msg.listen_req.eazmask = eazmask;
149 m->msg.listen_req.simask = (eazmask)?0x86:0; /* All SI's */
150 ACTCAPI_QUEUE_TX;
151 return 0;
152}
153
154int
155actcapi_connect_req(act2000_card *card, act2000_chan *chan, char *phone,
156 char eaz, int si1, int si2)
157{
158 actcapi_msg *m;
159 struct sk_buff *skb;
160
161 ACTCAPI_MKHDR((11 + strlen(phone)), 0x02, 0x00);
162 if (!skb) {
163 printk(KERN_WARNING "actcapi: alloc_skb failed\n");
164 chan->fsm_state = ACT2000_STATE_NULL;
165 return -ENOMEM;
166 }
167 m->msg.connect_req.controller = 0;
168 m->msg.connect_req.bchan = 0x83;
169 m->msg.connect_req.infomask = 0x3f;
170 m->msg.connect_req.si1 = si1;
171 m->msg.connect_req.si2 = si2;
172 m->msg.connect_req.eaz = eaz?eaz:'0';
173 m->msg.connect_req.addr.len = strlen(phone) + 1;
174 m->msg.connect_req.addr.tnp = 0x81;
175 memcpy(m->msg.connect_req.addr.num, phone, strlen(phone));
176 chan->callref = m->hdr.msgnum;
177 ACTCAPI_QUEUE_TX;
178 return 0;
179}
180
181static void
182actcapi_connect_b3_req(act2000_card *card, act2000_chan *chan)
183{
184 actcapi_msg *m;
185 struct sk_buff *skb;
186
187 ACTCAPI_MKHDR(17, 0x82, 0x00);
188 ACTCAPI_CHKSKB;
189 m->msg.connect_b3_req.plci = chan->plci;
190 memset(&m->msg.connect_b3_req.ncpi, 0,
191 sizeof(m->msg.connect_b3_req.ncpi));
192 m->msg.connect_b3_req.ncpi.len = 13;
193 m->msg.connect_b3_req.ncpi.modulo = 8;
194 ACTCAPI_QUEUE_TX;
195}
196
197/*
198 * Set net type (1TR6) or (EDSS1)
199 */
200int
201actcapi_manufacturer_req_net(act2000_card *card)
202{
203 actcapi_msg *m;
204 struct sk_buff *skb;
205
206 ACTCAPI_MKHDR(5, 0xff, 0x00);
207 if (!skb) {
208 printk(KERN_WARNING "actcapi: alloc_skb failed\n");
209 return -ENOMEM;
210 }
211 m->msg.manufacturer_req_net.manuf_msg = 0x11;
212 m->msg.manufacturer_req_net.controller = 1;
213 m->msg.manufacturer_req_net.nettype = (card->ptype == ISDN_PTYPE_EURO)?1:0;
214 ACTCAPI_QUEUE_TX;
215 printk(KERN_INFO "act2000 %s: D-channel protocol now %s\n",
216 card->interface.id, (card->ptype == ISDN_PTYPE_EURO)?"euro":"1tr6");
217 card->interface.features &=
218 ~(ISDN_FEATURE_P_UNKNOWN | ISDN_FEATURE_P_EURO | ISDN_FEATURE_P_1TR6);
219 card->interface.features |=
220 ((card->ptype == ISDN_PTYPE_EURO)?ISDN_FEATURE_P_EURO:ISDN_FEATURE_P_1TR6);
221 return 0;
222}
223
224/*
225 * Switch V.42 on or off
226 */
227int
228actcapi_manufacturer_req_v42(act2000_card *card, ulong arg)
229{
230 actcapi_msg *m;
231 struct sk_buff *skb;
232
233 ACTCAPI_MKHDR(8, 0xff, 0x00);
234 if (!skb) {
235
236 printk(KERN_WARNING "actcapi: alloc_skb failed\n");
237 return -ENOMEM;
238 }
239 m->msg.manufacturer_req_v42.manuf_msg = 0x10;
240 m->msg.manufacturer_req_v42.controller = 0;
241 m->msg.manufacturer_req_v42.v42control = (arg?1:0);
242 ACTCAPI_QUEUE_TX;
243 return 0;
244}
245
246/*
247 * Set error-handler
248 */
249int
250actcapi_manufacturer_req_errh(act2000_card *card)
251{
252 actcapi_msg *m;
253 struct sk_buff *skb;
254
255 ACTCAPI_MKHDR(4, 0xff, 0x00);
256 if (!skb) {
257
258 printk(KERN_WARNING "actcapi: alloc_skb failed\n");
259 return -ENOMEM;
260 }
261 m->msg.manufacturer_req_err.manuf_msg = 0x03;
262 m->msg.manufacturer_req_err.controller = 0;
263 ACTCAPI_QUEUE_TX;
264 return 0;
265}
266
267/*
268 * Set MSN-Mapping.
269 */
270int
271actcapi_manufacturer_req_msn(act2000_card *card)
272{
273 msn_entry *p = card->msn_list;
274 actcapi_msg *m;
275 struct sk_buff *skb;
276 int len;
277
278 while (p) {
279 int i;
280
281 len = strlen(p->msn);
282 for (i = 0; i < 2; i++) {
283 ACTCAPI_MKHDR(6 + len, 0xff, 0x00);
284 if (!skb) {
285 printk(KERN_WARNING "actcapi: alloc_skb failed\n");
286 return -ENOMEM;
287 }
288 m->msg.manufacturer_req_msn.manuf_msg = 0x13 + i;
289 m->msg.manufacturer_req_msn.controller = 0;
290 m->msg.manufacturer_req_msn.msnmap.eaz = p->eaz;
291 m->msg.manufacturer_req_msn.msnmap.len = len;
292 memcpy(m->msg.manufacturer_req_msn.msnmap.msn, p->msn, len);
293 ACTCAPI_QUEUE_TX;
294 }
295 p = p->next;
296 }
297 return 0;
298}
299
300void
301actcapi_select_b2_protocol_req(act2000_card *card, act2000_chan *chan)
302{
303 actcapi_msg *m;
304 struct sk_buff *skb;
305
306 ACTCAPI_MKHDR(10, 0x40, 0x00);
307 ACTCAPI_CHKSKB;
308 m->msg.select_b2_protocol_req.plci = chan->plci;
309 memset(&m->msg.select_b2_protocol_req.dlpd, 0,
310 sizeof(m->msg.select_b2_protocol_req.dlpd));
311 m->msg.select_b2_protocol_req.dlpd.len = 6;
312 switch (chan->l2prot) {
313 case ISDN_PROTO_L2_TRANS:
314 m->msg.select_b2_protocol_req.protocol = 0x03;
315 m->msg.select_b2_protocol_req.dlpd.dlen = 4000;
316 break;
317 case ISDN_PROTO_L2_HDLC:
318 m->msg.select_b2_protocol_req.protocol = 0x02;
319 m->msg.select_b2_protocol_req.dlpd.dlen = 4000;
320 break;
321 case ISDN_PROTO_L2_X75I:
322 case ISDN_PROTO_L2_X75UI:
323 case ISDN_PROTO_L2_X75BUI:
324 m->msg.select_b2_protocol_req.protocol = 0x01;
325 m->msg.select_b2_protocol_req.dlpd.dlen = 4000;
326 m->msg.select_b2_protocol_req.dlpd.laa = 3;
327 m->msg.select_b2_protocol_req.dlpd.lab = 1;
328 m->msg.select_b2_protocol_req.dlpd.win = 7;
329 m->msg.select_b2_protocol_req.dlpd.modulo = 8;
330 break;
331 }
332 ACTCAPI_QUEUE_TX;
333}
334
335static void
336actcapi_select_b3_protocol_req(act2000_card *card, act2000_chan *chan)
337{
338 actcapi_msg *m;
339 struct sk_buff *skb;
340
341 ACTCAPI_MKHDR(17, 0x80, 0x00);
342 ACTCAPI_CHKSKB;
343 m->msg.select_b3_protocol_req.plci = chan->plci;
344 memset(&m->msg.select_b3_protocol_req.ncpd, 0,
345 sizeof(m->msg.select_b3_protocol_req.ncpd));
346 switch (chan->l3prot) {
347 case ISDN_PROTO_L3_TRANS:
348 m->msg.select_b3_protocol_req.protocol = 0x04;
349 m->msg.select_b3_protocol_req.ncpd.len = 13;
350 m->msg.select_b3_protocol_req.ncpd.modulo = 8;
351 break;
352 }
353 ACTCAPI_QUEUE_TX;
354}
355
356static void
357actcapi_listen_b3_req(act2000_card *card, act2000_chan *chan)
358{
359 actcapi_msg *m;
360 struct sk_buff *skb;
361
362 ACTCAPI_MKHDR(2, 0x81, 0x00);
363 ACTCAPI_CHKSKB;
364 m->msg.listen_b3_req.plci = chan->plci;
365 ACTCAPI_QUEUE_TX;
366}
367
368static void
369actcapi_disconnect_req(act2000_card *card, act2000_chan *chan)
370{
371 actcapi_msg *m;
372 struct sk_buff *skb;
373
374 ACTCAPI_MKHDR(3, 0x04, 0x00);
375 ACTCAPI_CHKSKB;
376 m->msg.disconnect_req.plci = chan->plci;
377 m->msg.disconnect_req.cause = 0;
378 ACTCAPI_QUEUE_TX;
379}
380
381void
382actcapi_disconnect_b3_req(act2000_card *card, act2000_chan *chan)
383{
384 actcapi_msg *m;
385 struct sk_buff *skb;
386
387 ACTCAPI_MKHDR(17, 0x84, 0x00);
388 ACTCAPI_CHKSKB;
389 m->msg.disconnect_b3_req.ncci = chan->ncci;
390 memset(&m->msg.disconnect_b3_req.ncpi, 0,
391 sizeof(m->msg.disconnect_b3_req.ncpi));
392 m->msg.disconnect_b3_req.ncpi.len = 13;
393 m->msg.disconnect_b3_req.ncpi.modulo = 8;
394 chan->fsm_state = ACT2000_STATE_BHWAIT;
395 ACTCAPI_QUEUE_TX;
396}
397
398void
399actcapi_connect_resp(act2000_card *card, act2000_chan *chan, __u8 cause)
400{
401 actcapi_msg *m;
402 struct sk_buff *skb;
403
404 ACTCAPI_MKHDR(3, 0x02, 0x03);
405 ACTCAPI_CHKSKB;
406 m->msg.connect_resp.plci = chan->plci;
407 m->msg.connect_resp.rejectcause = cause;
408 if (cause) {
409 chan->fsm_state = ACT2000_STATE_NULL;
410 chan->plci = 0x8000;
411 } else
412 chan->fsm_state = ACT2000_STATE_IWAIT;
413 ACTCAPI_QUEUE_TX;
414}
415
416static void
417actcapi_connect_active_resp(act2000_card *card, act2000_chan *chan)
418{
419 actcapi_msg *m;
420 struct sk_buff *skb;
421
422 ACTCAPI_MKHDR(2, 0x03, 0x03);
423 ACTCAPI_CHKSKB;
424 m->msg.connect_resp.plci = chan->plci;
425 if (chan->fsm_state == ACT2000_STATE_IWAIT)
426 chan->fsm_state = ACT2000_STATE_IBWAIT;
427 ACTCAPI_QUEUE_TX;
428}
429
430static void
431actcapi_connect_b3_resp(act2000_card *card, act2000_chan *chan, __u8 rejectcause)
432{
433 actcapi_msg *m;
434 struct sk_buff *skb;
435
436 ACTCAPI_MKHDR((rejectcause?3:17), 0x82, 0x03);
437 ACTCAPI_CHKSKB;
438 m->msg.connect_b3_resp.ncci = chan->ncci;
439 m->msg.connect_b3_resp.rejectcause = rejectcause;
440 if (!rejectcause) {
441 memset(&m->msg.connect_b3_resp.ncpi, 0,
442 sizeof(m->msg.connect_b3_resp.ncpi));
443 m->msg.connect_b3_resp.ncpi.len = 13;
444 m->msg.connect_b3_resp.ncpi.modulo = 8;
445 chan->fsm_state = ACT2000_STATE_BWAIT;
446 }
447 ACTCAPI_QUEUE_TX;
448}
449
450static void
451actcapi_connect_b3_active_resp(act2000_card *card, act2000_chan *chan)
452{
453 actcapi_msg *m;
454 struct sk_buff *skb;
455
456 ACTCAPI_MKHDR(2, 0x83, 0x03);
457 ACTCAPI_CHKSKB;
458 m->msg.connect_b3_active_resp.ncci = chan->ncci;
459 chan->fsm_state = ACT2000_STATE_ACTIVE;
460 ACTCAPI_QUEUE_TX;
461}
462
463static void
464actcapi_info_resp(act2000_card *card, act2000_chan *chan)
465{
466 actcapi_msg *m;
467 struct sk_buff *skb;
468
469 ACTCAPI_MKHDR(2, 0x07, 0x03);
470 ACTCAPI_CHKSKB;
471 m->msg.info_resp.plci = chan->plci;
472 ACTCAPI_QUEUE_TX;
473}
474
475static void
476actcapi_disconnect_b3_resp(act2000_card *card, act2000_chan *chan)
477{
478 actcapi_msg *m;
479 struct sk_buff *skb;
480
481 ACTCAPI_MKHDR(2, 0x84, 0x03);
482 ACTCAPI_CHKSKB;
483 m->msg.disconnect_b3_resp.ncci = chan->ncci;
484 chan->ncci = 0x8000;
485 chan->queued = 0;
486 ACTCAPI_QUEUE_TX;
487}
488
489static void
490actcapi_disconnect_resp(act2000_card *card, act2000_chan *chan)
491{
492 actcapi_msg *m;
493 struct sk_buff *skb;
494
495 ACTCAPI_MKHDR(2, 0x04, 0x03);
496 ACTCAPI_CHKSKB;
497 m->msg.disconnect_resp.plci = chan->plci;
498 chan->plci = 0x8000;
499 ACTCAPI_QUEUE_TX;
500}
501
502static int
503new_plci(act2000_card *card, __u16 plci)
504{
505 int i;
506 for (i = 0; i < ACT2000_BCH; i++)
507 if (card->bch[i].plci == 0x8000) {
508 card->bch[i].plci = plci;
509 return i;
510 }
511 return -1;
512}
513
514static int
515find_plci(act2000_card *card, __u16 plci)
516{
517 int i;
518 for (i = 0; i < ACT2000_BCH; i++)
519 if (card->bch[i].plci == plci)
520 return i;
521 return -1;
522}
523
524static int
525find_ncci(act2000_card *card, __u16 ncci)
526{
527 int i;
528 for (i = 0; i < ACT2000_BCH; i++)
529 if (card->bch[i].ncci == ncci)
530 return i;
531 return -1;
532}
533
534static int
535find_dialing(act2000_card *card, __u16 callref)
536{
537 int i;
538 for (i = 0; i < ACT2000_BCH; i++)
539 if ((card->bch[i].callref == callref) &&
540 (card->bch[i].fsm_state == ACT2000_STATE_OCALL))
541 return i;
542 return -1;
543}
544
545static int
546actcapi_data_b3_ind(act2000_card *card, struct sk_buff *skb) {
547 __u16 plci;
548 __u16 ncci;
549 __u16 controller;
550 __u8 blocknr;
551 int chan;
552 actcapi_msg *msg = (actcapi_msg *)skb->data;
553
554 EVAL_NCCI(msg->msg.data_b3_ind.fakencci, plci, controller, ncci);
555 chan = find_ncci(card, ncci);
556 if (chan < 0)
557 return 0;
558 if (card->bch[chan].fsm_state != ACT2000_STATE_ACTIVE)
559 return 0;
560 if (card->bch[chan].plci != plci)
561 return 0;
562 blocknr = msg->msg.data_b3_ind.blocknr;
563 skb_pull(skb, 19);
564 card->interface.rcvcallb_skb(card->myid, chan, skb);
565 if (!(skb = alloc_skb(11, GFP_ATOMIC))) {
566 printk(KERN_WARNING "actcapi: alloc_skb failed\n");
567 return 1;
568 }
569 msg = (actcapi_msg *)skb_put(skb, 11);
570 msg->hdr.len = 11;
571 msg->hdr.applicationID = 1;
572 msg->hdr.cmd.cmd = 0x86;
573 msg->hdr.cmd.subcmd = 0x03;
574 msg->hdr.msgnum = actcapi_nextsmsg(card);
575 msg->msg.data_b3_resp.ncci = ncci;
576 msg->msg.data_b3_resp.blocknr = blocknr;
577 ACTCAPI_QUEUE_TX;
578 return 1;
579}
580
581/*
582 * Walk over ackq, unlink DATA_B3_REQ from it, if
583 * ncci and blocknr are matching.
584 * Decrement queued-bytes counter.
585 */
586static int
587handle_ack(act2000_card *card, act2000_chan *chan, __u8 blocknr) {
588 unsigned long flags;
589 struct sk_buff *skb;
590 struct sk_buff *tmp;
591 struct actcapi_msg *m;
592 int ret = 0;
593
594 spin_lock_irqsave(&card->lock, flags);
595 skb = skb_peek(&card->ackq);
596 spin_unlock_irqrestore(&card->lock, flags);
597 if (!skb) {
598 printk(KERN_WARNING "act2000: handle_ack nothing found!\n");
599 return 0;
600 }
601 tmp = skb;
602 while (1) {
603 m = (actcapi_msg *)tmp->data;
604 if ((((m->msg.data_b3_req.fakencci >> 8) & 0xff) == chan->ncci) &&
605 (m->msg.data_b3_req.blocknr == blocknr)) {
606 /* found corresponding DATA_B3_REQ */
607 skb_unlink(tmp);
608 chan->queued -= m->msg.data_b3_req.datalen;
609 if (m->msg.data_b3_req.flags)
610 ret = m->msg.data_b3_req.datalen;
611 dev_kfree_skb(tmp);
612 if (chan->queued < 0)
613 chan->queued = 0;
614 return ret;
615 }
616 spin_lock_irqsave(&card->lock, flags);
617 tmp = skb_peek((struct sk_buff_head *)tmp);
618 spin_unlock_irqrestore(&card->lock, flags);
619 if ((tmp == skb) || (tmp == NULL)) {
620 /* reached end of queue */
621 printk(KERN_WARNING "act2000: handle_ack nothing found!\n");
622 return 0;
623 }
624 }
625}
626
627void
628actcapi_dispatch(act2000_card *card)
629{
630 struct sk_buff *skb;
631 actcapi_msg *msg;
632 __u16 ccmd;
633 int chan;
634 int len;
635 act2000_chan *ctmp;
636 isdn_ctrl cmd;
637 char tmp[170];
638
639 while ((skb = skb_dequeue(&card->rcvq))) {
640 actcapi_debug_msg(skb, 0);
641 msg = (actcapi_msg *)skb->data;
642 ccmd = ((msg->hdr.cmd.cmd << 8) | msg->hdr.cmd.subcmd);
643 switch (ccmd) {
644 case 0x8602:
645 /* DATA_B3_IND */
646 if (actcapi_data_b3_ind(card, skb))
647 return;
648 break;
649 case 0x8601:
650 /* DATA_B3_CONF */
651 chan = find_ncci(card, msg->msg.data_b3_conf.ncci);
652 if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_ACTIVE)) {
653 if (msg->msg.data_b3_conf.info != 0)
654 printk(KERN_WARNING "act2000: DATA_B3_CONF: %04x\n",
655 msg->msg.data_b3_conf.info);
656 len = handle_ack(card, &card->bch[chan],
657 msg->msg.data_b3_conf.blocknr);
658 if (len) {
659 cmd.driver = card->myid;
660 cmd.command = ISDN_STAT_BSENT;
661 cmd.arg = chan;
662 cmd.parm.length = len;
663 card->interface.statcallb(&cmd);
664 }
665 }
666 break;
667 case 0x0201:
668 /* CONNECT_CONF */
669 chan = find_dialing(card, msg->hdr.msgnum);
670 if (chan >= 0) {
671 if (msg->msg.connect_conf.info) {
672 card->bch[chan].fsm_state = ACT2000_STATE_NULL;
673 cmd.driver = card->myid;
674 cmd.command = ISDN_STAT_DHUP;
675 cmd.arg = chan;
676 card->interface.statcallb(&cmd);
677 } else {
678 card->bch[chan].fsm_state = ACT2000_STATE_OWAIT;
679 card->bch[chan].plci = msg->msg.connect_conf.plci;
680 }
681 }
682 break;
683 case 0x0202:
684 /* CONNECT_IND */
685 chan = new_plci(card, msg->msg.connect_ind.plci);
686 if (chan < 0) {
687 ctmp = (act2000_chan *)tmp;
688 ctmp->plci = msg->msg.connect_ind.plci;
689 actcapi_connect_resp(card, ctmp, 0x11); /* All Card-Cannels busy */
690 } else {
691 card->bch[chan].fsm_state = ACT2000_STATE_ICALL;
692 cmd.driver = card->myid;
693 cmd.command = ISDN_STAT_ICALL;
694 cmd.arg = chan;
695 cmd.parm.setup.si1 = msg->msg.connect_ind.si1;
696 cmd.parm.setup.si2 = msg->msg.connect_ind.si2;
697 if (card->ptype == ISDN_PTYPE_EURO)
698 strcpy(cmd.parm.setup.eazmsn,
699 act2000_find_eaz(card, msg->msg.connect_ind.eaz));
700 else {
701 cmd.parm.setup.eazmsn[0] = msg->msg.connect_ind.eaz;
702 cmd.parm.setup.eazmsn[1] = 0;
703 }
704 memset(cmd.parm.setup.phone, 0, sizeof(cmd.parm.setup.phone));
705 memcpy(cmd.parm.setup.phone, msg->msg.connect_ind.addr.num,
706 msg->msg.connect_ind.addr.len - 1);
707 cmd.parm.setup.plan = msg->msg.connect_ind.addr.tnp;
708 cmd.parm.setup.screen = 0;
709 if (card->interface.statcallb(&cmd) == 2)
710 actcapi_connect_resp(card, &card->bch[chan], 0x15); /* Reject Call */
711 }
712 break;
713 case 0x0302:
714 /* CONNECT_ACTIVE_IND */
715 chan = find_plci(card, msg->msg.connect_active_ind.plci);
716 if (chan >= 0)
717 switch (card->bch[chan].fsm_state) {
718 case ACT2000_STATE_IWAIT:
719 actcapi_connect_active_resp(card, &card->bch[chan]);
720 break;
721 case ACT2000_STATE_OWAIT:
722 actcapi_connect_active_resp(card, &card->bch[chan]);
723 actcapi_select_b2_protocol_req(card, &card->bch[chan]);
724 break;
725 }
726 break;
727 case 0x8202:
728 /* CONNECT_B3_IND */
729 chan = find_plci(card, msg->msg.connect_b3_ind.plci);
730 if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_IBWAIT)) {
731 card->bch[chan].ncci = msg->msg.connect_b3_ind.ncci;
732 actcapi_connect_b3_resp(card, &card->bch[chan], 0);
733 } else {
734 ctmp = (act2000_chan *)tmp;
735 ctmp->ncci = msg->msg.connect_b3_ind.ncci;
736 actcapi_connect_b3_resp(card, ctmp, 0x11); /* All Card-Cannels busy */
737 }
738 break;
739 case 0x8302:
740 /* CONNECT_B3_ACTIVE_IND */
741 chan = find_ncci(card, msg->msg.connect_b3_active_ind.ncci);
742 if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_BWAIT)) {
743 actcapi_connect_b3_active_resp(card, &card->bch[chan]);
744 cmd.driver = card->myid;
745 cmd.command = ISDN_STAT_BCONN;
746 cmd.arg = chan;
747 card->interface.statcallb(&cmd);
748 }
749 break;
750 case 0x8402:
751 /* DISCONNECT_B3_IND */
752 chan = find_ncci(card, msg->msg.disconnect_b3_ind.ncci);
753 if (chan >= 0) {
754 ctmp = &card->bch[chan];
755 actcapi_disconnect_b3_resp(card, ctmp);
756 switch (ctmp->fsm_state) {
757 case ACT2000_STATE_ACTIVE:
758 ctmp->fsm_state = ACT2000_STATE_DHWAIT2;
759 cmd.driver = card->myid;
760 cmd.command = ISDN_STAT_BHUP;
761 cmd.arg = chan;
762 card->interface.statcallb(&cmd);
763 break;
764 case ACT2000_STATE_BHWAIT2:
765 actcapi_disconnect_req(card, ctmp);
766 ctmp->fsm_state = ACT2000_STATE_DHWAIT;
767 cmd.driver = card->myid;
768 cmd.command = ISDN_STAT_BHUP;
769 cmd.arg = chan;
770 card->interface.statcallb(&cmd);
771 break;
772 }
773 }
774 break;
775 case 0x0402:
776 /* DISCONNECT_IND */
777 chan = find_plci(card, msg->msg.disconnect_ind.plci);
778 if (chan >= 0) {
779 ctmp = &card->bch[chan];
780 actcapi_disconnect_resp(card, ctmp);
781 ctmp->fsm_state = ACT2000_STATE_NULL;
782 cmd.driver = card->myid;
783 cmd.command = ISDN_STAT_DHUP;
784 cmd.arg = chan;
785 card->interface.statcallb(&cmd);
786 } else {
787 ctmp = (act2000_chan *)tmp;
788 ctmp->plci = msg->msg.disconnect_ind.plci;
789 actcapi_disconnect_resp(card, ctmp);
790 }
791 break;
792 case 0x4001:
793 /* SELECT_B2_PROTOCOL_CONF */
794 chan = find_plci(card, msg->msg.select_b2_protocol_conf.plci);
795 if (chan >= 0)
796 switch (card->bch[chan].fsm_state) {
797 case ACT2000_STATE_ICALL:
798 case ACT2000_STATE_OWAIT:
799 ctmp = &card->bch[chan];
800 if (msg->msg.select_b2_protocol_conf.info == 0)
801 actcapi_select_b3_protocol_req(card, ctmp);
802 else {
803 ctmp->fsm_state = ACT2000_STATE_NULL;
804 cmd.driver = card->myid;
805 cmd.command = ISDN_STAT_DHUP;
806 cmd.arg = chan;
807 card->interface.statcallb(&cmd);
808 }
809 break;
810 }
811 break;
812 case 0x8001:
813 /* SELECT_B3_PROTOCOL_CONF */
814 chan = find_plci(card, msg->msg.select_b3_protocol_conf.plci);
815 if (chan >= 0)
816 switch (card->bch[chan].fsm_state) {
817 case ACT2000_STATE_ICALL:
818 case ACT2000_STATE_OWAIT:
819 ctmp = &card->bch[chan];
820 if (msg->msg.select_b3_protocol_conf.info == 0)
821 actcapi_listen_b3_req(card, ctmp);
822 else {
823 ctmp->fsm_state = ACT2000_STATE_NULL;
824 cmd.driver = card->myid;
825 cmd.command = ISDN_STAT_DHUP;
826 cmd.arg = chan;
827 card->interface.statcallb(&cmd);
828 }
829 }
830 break;
831 case 0x8101:
832 /* LISTEN_B3_CONF */
833 chan = find_plci(card, msg->msg.listen_b3_conf.plci);
834 if (chan >= 0)
835 switch (card->bch[chan].fsm_state) {
836 case ACT2000_STATE_ICALL:
837 ctmp = &card->bch[chan];
838 if (msg->msg.listen_b3_conf.info == 0)
839 actcapi_connect_resp(card, ctmp, 0);
840 else {
841 ctmp->fsm_state = ACT2000_STATE_NULL;
842 cmd.driver = card->myid;
843 cmd.command = ISDN_STAT_DHUP;
844 cmd.arg = chan;
845 card->interface.statcallb(&cmd);
846 }
847 break;
848 case ACT2000_STATE_OWAIT:
849 ctmp = &card->bch[chan];
850 if (msg->msg.listen_b3_conf.info == 0) {
851 actcapi_connect_b3_req(card, ctmp);
852 ctmp->fsm_state = ACT2000_STATE_OBWAIT;
853 cmd.driver = card->myid;
854 cmd.command = ISDN_STAT_DCONN;
855 cmd.arg = chan;
856 card->interface.statcallb(&cmd);
857 } else {
858 ctmp->fsm_state = ACT2000_STATE_NULL;
859 cmd.driver = card->myid;
860 cmd.command = ISDN_STAT_DHUP;
861 cmd.arg = chan;
862 card->interface.statcallb(&cmd);
863 }
864 break;
865 }
866 break;
867 case 0x8201:
868 /* CONNECT_B3_CONF */
869 chan = find_plci(card, msg->msg.connect_b3_conf.plci);
870 if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_OBWAIT)) {
871 ctmp = &card->bch[chan];
872 if (msg->msg.connect_b3_conf.info) {
873 ctmp->fsm_state = ACT2000_STATE_NULL;
874 cmd.driver = card->myid;
875 cmd.command = ISDN_STAT_DHUP;
876 cmd.arg = chan;
877 card->interface.statcallb(&cmd);
878 } else {
879 ctmp->ncci = msg->msg.connect_b3_conf.ncci;
880 ctmp->fsm_state = ACT2000_STATE_BWAIT;
881 }
882 }
883 break;
884 case 0x8401:
885 /* DISCONNECT_B3_CONF */
886 chan = find_ncci(card, msg->msg.disconnect_b3_conf.ncci);
887 if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_BHWAIT))
888 card->bch[chan].fsm_state = ACT2000_STATE_BHWAIT2;
889 break;
890 case 0x0702:
891 /* INFO_IND */
892 chan = find_plci(card, msg->msg.info_ind.plci);
893 if (chan >= 0)
894 /* TODO: Eval Charging info / cause */
895 actcapi_info_resp(card, &card->bch[chan]);
896 break;
897 case 0x0401:
898 /* LISTEN_CONF */
899 case 0x0501:
900 /* LISTEN_CONF */
901 case 0xff01:
902 /* MANUFACTURER_CONF */
903 break;
904 case 0xff02:
905 /* MANUFACTURER_IND */
906 if (msg->msg.manuf_msg == 3) {
907 memset(tmp, 0, sizeof(tmp));
908 strncpy(tmp,
909 &msg->msg.manufacturer_ind_err.errstring,
910 msg->hdr.len - 16);
911 if (msg->msg.manufacturer_ind_err.errcode)
912 printk(KERN_WARNING "act2000: %s\n", tmp);
913 else {
914 printk(KERN_DEBUG "act2000: %s\n", tmp);
915 if ((!strncmp(tmp, "INFO: Trace buffer con", 22)) ||
916 (!strncmp(tmp, "INFO: Compile Date/Tim", 22))) {
917 card->flags |= ACT2000_FLAGS_RUNNING;
918 cmd.command = ISDN_STAT_RUN;
919 cmd.driver = card->myid;
920 cmd.arg = 0;
921 actcapi_manufacturer_req_net(card);
922 actcapi_manufacturer_req_msn(card);
923 actcapi_listen_req(card);
924 card->interface.statcallb(&cmd);
925 }
926 }
927 }
928 break;
929 default:
930 printk(KERN_WARNING "act2000: UNHANDLED Message %04x\n", ccmd);
931 break;
932 }
933 dev_kfree_skb(skb);
934 }
935}
936
937#ifdef DEBUG_MSG
938static void
939actcapi_debug_caddr(actcapi_addr *addr)
940{
941 char tmp[30];
942
943 printk(KERN_DEBUG " Alen = %d\n", addr->len);
944 if (addr->len > 0)
945 printk(KERN_DEBUG " Atnp = 0x%02x\n", addr->tnp);
946 if (addr->len > 1) {
947 memset(tmp, 0, 30);
948 memcpy(tmp, addr->num, addr->len - 1);
949 printk(KERN_DEBUG " Anum = '%s'\n", tmp);
950 }
951}
952
953static void
954actcapi_debug_ncpi(actcapi_ncpi *ncpi)
955{
956 printk(KERN_DEBUG " ncpi.len = %d\n", ncpi->len);
957 if (ncpi->len >= 2)
958 printk(KERN_DEBUG " ncpi.lic = 0x%04x\n", ncpi->lic);
959 if (ncpi->len >= 4)
960 printk(KERN_DEBUG " ncpi.hic = 0x%04x\n", ncpi->hic);
961 if (ncpi->len >= 6)
962 printk(KERN_DEBUG " ncpi.ltc = 0x%04x\n", ncpi->ltc);
963 if (ncpi->len >= 8)
964 printk(KERN_DEBUG " ncpi.htc = 0x%04x\n", ncpi->htc);
965 if (ncpi->len >= 10)
966 printk(KERN_DEBUG " ncpi.loc = 0x%04x\n", ncpi->loc);
967 if (ncpi->len >= 12)
968 printk(KERN_DEBUG " ncpi.hoc = 0x%04x\n", ncpi->hoc);
969 if (ncpi->len >= 13)
970 printk(KERN_DEBUG " ncpi.mod = %d\n", ncpi->modulo);
971}
972
973static void
974actcapi_debug_dlpd(actcapi_dlpd *dlpd)
975{
976 printk(KERN_DEBUG " dlpd.len = %d\n", dlpd->len);
977 if (dlpd->len >= 2)
978 printk(KERN_DEBUG " dlpd.dlen = 0x%04x\n", dlpd->dlen);
979 if (dlpd->len >= 3)
980 printk(KERN_DEBUG " dlpd.laa = 0x%02x\n", dlpd->laa);
981 if (dlpd->len >= 4)
982 printk(KERN_DEBUG " dlpd.lab = 0x%02x\n", dlpd->lab);
983 if (dlpd->len >= 5)
984 printk(KERN_DEBUG " dlpd.modulo = %d\n", dlpd->modulo);
985 if (dlpd->len >= 6)
986 printk(KERN_DEBUG " dlpd.win = %d\n", dlpd->win);
987}
988
989#ifdef DEBUG_DUMP_SKB
990static void dump_skb(struct sk_buff *skb) {
991 char tmp[80];
992 char *p = skb->data;
993 char *t = tmp;
994 int i;
995
996 for (i = 0; i < skb->len; i++) {
997 t += sprintf(t, "%02x ", *p++ & 0xff);
998 if ((i & 0x0f) == 8) {
999 printk(KERN_DEBUG "dump: %s\n", tmp);
1000 t = tmp;
1001 }
1002 }
1003 if (i & 0x07)
1004 printk(KERN_DEBUG "dump: %s\n", tmp);
1005}
1006#endif
1007
1008void
1009actcapi_debug_msg(struct sk_buff *skb, int direction)
1010{
1011 actcapi_msg *msg = (actcapi_msg *)skb->data;
1012 char *descr;
1013 int i;
1014 char tmp[170];
1015
1016#ifndef DEBUG_DATA_MSG
1017 if (msg->hdr.cmd.cmd == 0x86)
1018 return;
1019#endif
1020 descr = "INVALID";
1021#ifdef DEBUG_DUMP_SKB
1022 dump_skb(skb);
1023#endif
1024 for (i = 0; i < num_valid_msg; i++)
1025 if ((msg->hdr.cmd.cmd == valid_msg[i].cmd.cmd) &&
1026 (msg->hdr.cmd.subcmd == valid_msg[i].cmd.subcmd)) {
1027 descr = valid_msg[i].description;
1028 break;
1029 }
1030 printk(KERN_DEBUG "%s %s msg\n", direction?"Outgoing":"Incoming", descr);
1031 printk(KERN_DEBUG " ApplID = %d\n", msg->hdr.applicationID);
1032 printk(KERN_DEBUG " Len = %d\n", msg->hdr.len);
1033 printk(KERN_DEBUG " MsgNum = 0x%04x\n", msg->hdr.msgnum);
1034 printk(KERN_DEBUG " Cmd = 0x%02x\n", msg->hdr.cmd.cmd);
1035 printk(KERN_DEBUG " SubCmd = 0x%02x\n", msg->hdr.cmd.subcmd);
1036 switch (i) {
1037 case 0:
1038 /* DATA B3 IND */
1039 printk(KERN_DEBUG " BLOCK = 0x%02x\n",
1040 msg->msg.data_b3_ind.blocknr);
1041 break;
1042 case 2:
1043 /* CONNECT CONF */
1044 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1045 msg->msg.connect_conf.plci);
1046 printk(KERN_DEBUG " Info = 0x%04x\n",
1047 msg->msg.connect_conf.info);
1048 break;
1049 case 3:
1050 /* CONNECT IND */
1051 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1052 msg->msg.connect_ind.plci);
1053 printk(KERN_DEBUG " Contr = %d\n",
1054 msg->msg.connect_ind.controller);
1055 printk(KERN_DEBUG " SI1 = %d\n",
1056 msg->msg.connect_ind.si1);
1057 printk(KERN_DEBUG " SI2 = %d\n",
1058 msg->msg.connect_ind.si2);
1059 printk(KERN_DEBUG " EAZ = '%c'\n",
1060 msg->msg.connect_ind.eaz);
1061 actcapi_debug_caddr(&msg->msg.connect_ind.addr);
1062 break;
1063 case 5:
1064 /* CONNECT ACTIVE IND */
1065 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1066 msg->msg.connect_active_ind.plci);
1067 actcapi_debug_caddr(&msg->msg.connect_active_ind.addr);
1068 break;
1069 case 8:
1070 /* LISTEN CONF */
1071 printk(KERN_DEBUG " Contr = %d\n",
1072 msg->msg.listen_conf.controller);
1073 printk(KERN_DEBUG " Info = 0x%04x\n",
1074 msg->msg.listen_conf.info);
1075 break;
1076 case 11:
1077 /* INFO IND */
1078 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1079 msg->msg.info_ind.plci);
1080 printk(KERN_DEBUG " Imsk = 0x%04x\n",
1081 msg->msg.info_ind.nr.mask);
1082 if (msg->hdr.len > 12) {
1083 int l = msg->hdr.len - 12;
1084 int j;
1085 char *p = tmp;
1086 for (j = 0; j < l ; j++)
1087 p += sprintf(p, "%02x ", msg->msg.info_ind.el.display[j]);
1088 printk(KERN_DEBUG " D = '%s'\n", tmp);
1089 }
1090 break;
1091 case 14:
1092 /* SELECT B2 PROTOCOL CONF */
1093 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1094 msg->msg.select_b2_protocol_conf.plci);
1095 printk(KERN_DEBUG " Info = 0x%04x\n",
1096 msg->msg.select_b2_protocol_conf.info);
1097 break;
1098 case 15:
1099 /* SELECT B3 PROTOCOL CONF */
1100 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1101 msg->msg.select_b3_protocol_conf.plci);
1102 printk(KERN_DEBUG " Info = 0x%04x\n",
1103 msg->msg.select_b3_protocol_conf.info);
1104 break;
1105 case 16:
1106 /* LISTEN B3 CONF */
1107 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1108 msg->msg.listen_b3_conf.plci);
1109 printk(KERN_DEBUG " Info = 0x%04x\n",
1110 msg->msg.listen_b3_conf.info);
1111 break;
1112 case 18:
1113 /* CONNECT B3 IND */
1114 printk(KERN_DEBUG " NCCI = 0x%04x\n",
1115 msg->msg.connect_b3_ind.ncci);
1116 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1117 msg->msg.connect_b3_ind.plci);
1118 actcapi_debug_ncpi(&msg->msg.connect_b3_ind.ncpi);
1119 break;
1120 case 19:
1121 /* CONNECT B3 ACTIVE IND */
1122 printk(KERN_DEBUG " NCCI = 0x%04x\n",
1123 msg->msg.connect_b3_active_ind.ncci);
1124 actcapi_debug_ncpi(&msg->msg.connect_b3_active_ind.ncpi);
1125 break;
1126 case 26:
1127 /* MANUFACTURER IND */
1128 printk(KERN_DEBUG " Mmsg = 0x%02x\n",
1129 msg->msg.manufacturer_ind_err.manuf_msg);
1130 switch (msg->msg.manufacturer_ind_err.manuf_msg) {
1131 case 3:
1132 printk(KERN_DEBUG " Contr = %d\n",
1133 msg->msg.manufacturer_ind_err.controller);
1134 printk(KERN_DEBUG " Code = 0x%08x\n",
1135 msg->msg.manufacturer_ind_err.errcode);
1136 memset(tmp, 0, sizeof(tmp));
1137 strncpy(tmp, &msg->msg.manufacturer_ind_err.errstring,
1138 msg->hdr.len - 16);
1139 printk(KERN_DEBUG " Emsg = '%s'\n", tmp);
1140 break;
1141 }
1142 break;
1143 case 30:
1144 /* LISTEN REQ */
1145 printk(KERN_DEBUG " Imsk = 0x%08x\n",
1146 msg->msg.listen_req.infomask);
1147 printk(KERN_DEBUG " Emsk = 0x%04x\n",
1148 msg->msg.listen_req.eazmask);
1149 printk(KERN_DEBUG " Smsk = 0x%04x\n",
1150 msg->msg.listen_req.simask);
1151 break;
1152 case 35:
1153 /* SELECT_B2_PROTOCOL_REQ */
1154 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1155 msg->msg.select_b2_protocol_req.plci);
1156 printk(KERN_DEBUG " prot = 0x%02x\n",
1157 msg->msg.select_b2_protocol_req.protocol);
1158 if (msg->hdr.len >= 11)
1159 printk(KERN_DEBUG "No dlpd\n");
1160 else
1161 actcapi_debug_dlpd(&msg->msg.select_b2_protocol_req.dlpd);
1162 break;
1163 case 44:
1164 /* CONNECT RESP */
1165 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1166 msg->msg.connect_resp.plci);
1167 printk(KERN_DEBUG " CAUSE = 0x%02x\n",
1168 msg->msg.connect_resp.rejectcause);
1169 break;
1170 case 45:
1171 /* CONNECT ACTIVE RESP */
1172 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1173 msg->msg.connect_active_resp.plci);
1174 break;
1175 }
1176}
1177#endif
diff --git a/drivers/isdn/act2000/capi.h b/drivers/isdn/act2000/capi.h
new file mode 100644
index 000000000000..04d2bcdd37a7
--- /dev/null
+++ b/drivers/isdn/act2000/capi.h
@@ -0,0 +1,366 @@
1/* $Id: capi.h,v 1.6.6.2 2001/09/23 22:24:32 kai Exp $
2 *
3 * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
4 *
5 * Author Fritz Elfert
6 * Copyright by Fritz Elfert <fritz@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 * Thanks to Friedemann Baitinger and IBM Germany
12 *
13 */
14
15#ifndef CAPI_H
16#define CAPI_H
17
18/* Command-part of a CAPI message */
19typedef struct actcapi_msgcmd {
20 __u8 cmd;
21 __u8 subcmd;
22} actcapi_msgcmd;
23
24/* CAPI message header */
25typedef struct actcapi_msghdr {
26 __u16 len;
27 __u16 applicationID;
28 actcapi_msgcmd cmd;
29 __u16 msgnum;
30} actcapi_msghdr;
31
32/* CAPI message description (for debugging) */
33typedef struct actcapi_msgdsc {
34 actcapi_msgcmd cmd;
35 char *description;
36} actcapi_msgdsc;
37
38/* CAPI Address */
39typedef struct actcapi_addr {
40 __u8 len; /* Length of element */
41 __u8 tnp; /* Type/Numbering Plan */
42 __u8 num[20]; /* Caller ID */
43} actcapi_addr;
44
45/* CAPI INFO element mask */
46typedef union actcapi_infonr { /* info number */
47 __u16 mask; /* info-mask field */
48 struct bmask { /* bit definitions */
49 unsigned codes : 3; /* code set */
50 unsigned rsvd : 5; /* reserved */
51 unsigned svind : 1; /* single, variable length ind. */
52 unsigned wtype : 7; /* W-element type */
53 } bmask;
54} actcapi_infonr;
55
56/* CAPI INFO element */
57typedef union actcapi_infoel { /* info element */
58 __u8 len; /* length of info element */
59 __u8 display[40]; /* display contents */
60 __u8 uuinfo[40]; /* User-user info field */
61 struct cause { /* Cause information */
62 unsigned ext2 : 1; /* extension */
63 unsigned cod : 2; /* coding standard */
64 unsigned spare : 1; /* spare */
65 unsigned loc : 4; /* location */
66 unsigned ext1 : 1; /* extension */
67 unsigned cval : 7; /* Cause value */
68 } cause;
69 struct charge { /* Charging information */
70 __u8 toc; /* type of charging info */
71 __u8 unit[10]; /* charging units */
72 } charge;
73 __u8 date[20]; /* date fields */
74 __u8 stat; /* state of remote party */
75} actcapi_infoel;
76
77/* Message for EAZ<->MSN Mapping */
78typedef struct actcapi_msn {
79 __u8 eaz;
80 __u8 len; /* Length of MSN */
81 __u8 msn[15] __attribute__ ((packed));
82} actcapi_msn;
83
84typedef struct actcapi_dlpd {
85 __u8 len; /* Length of structure */
86 __u16 dlen __attribute__ ((packed)); /* Data Length */
87 __u8 laa __attribute__ ((packed)); /* Link Address A */
88 __u8 lab; /* Link Address B */
89 __u8 modulo; /* Modulo Mode */
90 __u8 win; /* Window size */
91 __u8 xid[100]; /* XID Information */
92} actcapi_dlpd;
93
94typedef struct actcapi_ncpd {
95 __u8 len; /* Length of structure */
96 __u16 lic __attribute__ ((packed));
97 __u16 hic __attribute__ ((packed));
98 __u16 ltc __attribute__ ((packed));
99 __u16 htc __attribute__ ((packed));
100 __u16 loc __attribute__ ((packed));
101 __u16 hoc __attribute__ ((packed));
102 __u8 modulo __attribute__ ((packed));
103} actcapi_ncpd;
104#define actcapi_ncpi actcapi_ncpd
105
106/*
107 * Layout of NCCI field in a B3 DATA CAPI message is different from
108 * standard at act2000:
109 *
110 * Bit 0-4 = PLCI
111 * Bit 5-7 = Controller
112 * Bit 8-15 = NCCI
113 */
114#define MAKE_NCCI(plci,contr,ncci) \
115 ((plci & 0x1f) | ((contr & 0x7) << 5) | ((ncci & 0xff) << 8))
116
117#define EVAL_NCCI(fakencci,plci,contr,ncci) { \
118 plci = fakencci & 0x1f; \
119 contr = (fakencci >> 5) & 0x7; \
120 ncci = (fakencci >> 8) & 0xff; \
121}
122
123/*
124 * Layout of PLCI field in a B3 DATA CAPI message is different from
125 * standard at act2000:
126 *
127 * Bit 0-4 = PLCI
128 * Bit 5-7 = Controller
129 * Bit 8-15 = reserved (must be 0)
130 */
131#define MAKE_PLCI(plci,contr) \
132 ((plci & 0x1f) | ((contr & 0x7) << 5))
133
134#define EVAL_PLCI(fakeplci,plci,contr) { \
135 plci = fakeplci & 0x1f; \
136 contr = (fakeplci >> 5) & 0x7; \
137}
138
139typedef struct actcapi_msg {
140 actcapi_msghdr hdr;
141 union {
142 __u16 manuf_msg;
143 struct manufacturer_req_net {
144 __u16 manuf_msg;
145 __u16 controller;
146 __u8 nettype;
147 } manufacturer_req_net;
148 struct manufacturer_req_v42 {
149 __u16 manuf_msg;
150 __u16 controller;
151 __u32 v42control;
152 } manufacturer_req_v42;
153 struct manufacturer_conf_v42 {
154 __u16 manuf_msg;
155 __u16 controller;
156 } manufacturer_conf_v42;
157 struct manufacturer_req_err {
158 __u16 manuf_msg;
159 __u16 controller;
160 } manufacturer_req_err;
161 struct manufacturer_ind_err {
162 __u16 manuf_msg;
163 __u16 controller;
164 __u32 errcode;
165 __u8 errstring; /* actually up to 160 */
166 } manufacturer_ind_err;
167 struct manufacturer_req_msn {
168 __u16 manuf_msg;
169 __u16 controller;
170 actcapi_msn msnmap;
171 } manufacturer_req_msn;
172 /* TODO: TraceInit-req/conf/ind/resp and
173 * TraceDump-req/conf/ind/resp
174 */
175 struct connect_req {
176 __u8 controller;
177 __u8 bchan;
178 __u32 infomask __attribute__ ((packed));
179 __u8 si1;
180 __u8 si2;
181 __u8 eaz;
182 actcapi_addr addr;
183 } connect_req;
184 struct connect_conf {
185 __u16 plci;
186 __u16 info;
187 } connect_conf;
188 struct connect_ind {
189 __u16 plci;
190 __u8 controller;
191 __u8 si1;
192 __u8 si2;
193 __u8 eaz;
194 actcapi_addr addr;
195 } connect_ind;
196 struct connect_resp {
197 __u16 plci;
198 __u8 rejectcause;
199 } connect_resp;
200 struct connect_active_ind {
201 __u16 plci;
202 actcapi_addr addr;
203 } connect_active_ind;
204 struct connect_active_resp {
205 __u16 plci;
206 } connect_active_resp;
207 struct connect_b3_req {
208 __u16 plci;
209 actcapi_ncpi ncpi;
210 } connect_b3_req;
211 struct connect_b3_conf {
212 __u16 plci;
213 __u16 ncci;
214 __u16 info;
215 } connect_b3_conf;
216 struct connect_b3_ind {
217 __u16 ncci;
218 __u16 plci;
219 actcapi_ncpi ncpi;
220 } connect_b3_ind;
221 struct connect_b3_resp {
222 __u16 ncci;
223 __u8 rejectcause;
224 actcapi_ncpi ncpi __attribute__ ((packed));
225 } connect_b3_resp;
226 struct disconnect_req {
227 __u16 plci;
228 __u8 cause;
229 } disconnect_req;
230 struct disconnect_conf {
231 __u16 plci;
232 __u16 info;
233 } disconnect_conf;
234 struct disconnect_ind {
235 __u16 plci;
236 __u16 info;
237 } disconnect_ind;
238 struct disconnect_resp {
239 __u16 plci;
240 } disconnect_resp;
241 struct connect_b3_active_ind {
242 __u16 ncci;
243 actcapi_ncpi ncpi;
244 } connect_b3_active_ind;
245 struct connect_b3_active_resp {
246 __u16 ncci;
247 } connect_b3_active_resp;
248 struct disconnect_b3_req {
249 __u16 ncci;
250 actcapi_ncpi ncpi;
251 } disconnect_b3_req;
252 struct disconnect_b3_conf {
253 __u16 ncci;
254 __u16 info;
255 } disconnect_b3_conf;
256 struct disconnect_b3_ind {
257 __u16 ncci;
258 __u16 info;
259 actcapi_ncpi ncpi;
260 } disconnect_b3_ind;
261 struct disconnect_b3_resp {
262 __u16 ncci;
263 } disconnect_b3_resp;
264 struct info_ind {
265 __u16 plci;
266 actcapi_infonr nr;
267 actcapi_infoel el;
268 } info_ind;
269 struct info_resp {
270 __u16 plci;
271 } info_resp;
272 struct listen_b3_req {
273 __u16 plci;
274 } listen_b3_req;
275 struct listen_b3_conf {
276 __u16 plci;
277 __u16 info;
278 } listen_b3_conf;
279 struct select_b2_protocol_req {
280 __u16 plci;
281 __u8 protocol;
282 actcapi_dlpd dlpd __attribute__ ((packed));
283 } select_b2_protocol_req;
284 struct select_b2_protocol_conf {
285 __u16 plci;
286 __u16 info;
287 } select_b2_protocol_conf;
288 struct select_b3_protocol_req {
289 __u16 plci;
290 __u8 protocol;
291 actcapi_ncpd ncpd __attribute__ ((packed));
292 } select_b3_protocol_req;
293 struct select_b3_protocol_conf {
294 __u16 plci;
295 __u16 info;
296 } select_b3_protocol_conf;
297 struct listen_req {
298 __u8 controller;
299 __u32 infomask __attribute__ ((packed));
300 __u16 eazmask __attribute__ ((packed));
301 __u16 simask __attribute__ ((packed));
302 } listen_req;
303 struct listen_conf {
304 __u8 controller;
305 __u16 info __attribute__ ((packed));
306 } listen_conf;
307 struct data_b3_req {
308 __u16 fakencci;
309 __u16 datalen;
310 __u32 unused;
311 __u8 blocknr;
312 __u16 flags __attribute__ ((packed));
313 } data_b3_req;
314 struct data_b3_ind {
315 __u16 fakencci;
316 __u16 datalen;
317 __u32 unused;
318 __u8 blocknr;
319 __u16 flags __attribute__ ((packed));
320 } data_b3_ind;
321 struct data_b3_resp {
322 __u16 ncci;
323 __u8 blocknr;
324 } data_b3_resp;
325 struct data_b3_conf {
326 __u16 ncci;
327 __u8 blocknr;
328 __u16 info __attribute__ ((packed));
329 } data_b3_conf;
330 } msg;
331} actcapi_msg;
332
333extern __inline__ unsigned short
334actcapi_nextsmsg(act2000_card *card)
335{
336 unsigned long flags;
337 unsigned short n;
338
339 spin_lock_irqsave(&card->mnlock, flags);
340 n = card->msgnum;
341 card->msgnum++;
342 card->msgnum &= 0x7fff;
343 spin_unlock_irqrestore(&card->mnlock, flags);
344 return n;
345}
346#define DEBUG_MSG
347#undef DEBUG_DATA_MSG
348#undef DEBUG_DUMP_SKB
349
350extern int actcapi_chkhdr(act2000_card *, actcapi_msghdr *);
351extern int actcapi_listen_req(act2000_card *);
352extern int actcapi_manufacturer_req_net(act2000_card *);
353extern int actcapi_manufacturer_req_v42(act2000_card *, ulong);
354extern int actcapi_manufacturer_req_errh(act2000_card *);
355extern int actcapi_manufacturer_req_msn(act2000_card *);
356extern int actcapi_connect_req(act2000_card *, act2000_chan *, char *, char, int, int);
357extern void actcapi_select_b2_protocol_req(act2000_card *, act2000_chan *);
358extern void actcapi_disconnect_b3_req(act2000_card *, act2000_chan *);
359extern void actcapi_connect_resp(act2000_card *, act2000_chan *, __u8);
360extern void actcapi_dispatch(act2000_card *);
361#ifdef DEBUG_MSG
362extern void actcapi_debug_msg(struct sk_buff *skb, int);
363#else
364#define actcapi_debug_msg(skb, len)
365#endif
366#endif
diff --git a/drivers/isdn/act2000/module.c b/drivers/isdn/act2000/module.c
new file mode 100644
index 000000000000..d89dcde4eade
--- /dev/null
+++ b/drivers/isdn/act2000/module.c
@@ -0,0 +1,808 @@
1/* $Id: module.c,v 1.14.6.4 2001/09/23 22:24:32 kai Exp $
2 *
3 * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
4 *
5 * Author Fritz Elfert
6 * Copyright by Fritz Elfert <fritz@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 * Thanks to Friedemann Baitinger and IBM Germany
12 *
13 */
14
15#include "act2000.h"
16#include "act2000_isa.h"
17#include "capi.h"
18#include <linux/module.h>
19#include <linux/init.h>
20
21static unsigned short act2000_isa_ports[] =
22{
23 0x0200, 0x0240, 0x0280, 0x02c0, 0x0300, 0x0340, 0x0380,
24 0xcfe0, 0xcfa0, 0xcf60, 0xcf20, 0xcee0, 0xcea0, 0xce60,
25};
26#define ISA_NRPORTS (sizeof(act2000_isa_ports)/sizeof(unsigned short))
27
28static act2000_card *cards = (act2000_card *) NULL;
29
30/* Parameters to be set by insmod */
31static int act_bus = 0;
32static int act_port = -1; /* -1 = Autoprobe */
33static int act_irq = -1;
34static char *act_id = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
35
36MODULE_DESCRIPTION( "ISDN4Linux: Driver for IBM Active 2000 ISDN card");
37MODULE_AUTHOR( "Fritz Elfert");
38MODULE_LICENSE( "GPL");
39MODULE_PARM_DESC(act_bus, "BusType of first card, 1=ISA, 2=MCA, 3=PCMCIA, currently only ISA");
40MODULE_PARM_DESC(membase, "Base port address of first card");
41MODULE_PARM_DESC(act_irq, "IRQ of first card");
42MODULE_PARM_DESC(act_id, "ID-String of first card");
43module_param(act_bus, int, 0);
44module_param(act_port, int, 0);
45module_param(act_irq, int, 0);
46module_param(act_id, charp, 0);
47
48static int act2000_addcard(int, int, int, char *);
49
50static act2000_chan *
51find_channel(act2000_card *card, int channel)
52{
53 if ((channel >= 0) && (channel < ACT2000_BCH))
54 return &(card->bch[channel]);
55 printk(KERN_WARNING "act2000: Invalid channel %d\n", channel);
56 return NULL;
57}
58
59/*
60 * Free MSN list
61 */
62static void
63act2000_clear_msn(act2000_card *card)
64{
65 struct msn_entry *p = card->msn_list;
66 struct msn_entry *q;
67 unsigned long flags;
68
69 spin_lock_irqsave(&card->lock, flags);
70 card->msn_list = NULL;
71 spin_unlock_irqrestore(&card->lock, flags);
72 while (p) {
73 q = p->next;
74 kfree(p);
75 p = q;
76 }
77}
78
79/*
80 * Find an MSN entry in the list.
81 * If ia5 != 0, return IA5-encoded EAZ, else
82 * return a bitmask with corresponding bit set.
83 */
84static __u16
85act2000_find_msn(act2000_card *card, char *msn, int ia5)
86{
87 struct msn_entry *p = card->msn_list;
88 __u8 eaz = '0';
89
90 while (p) {
91 if (!strcmp(p->msn, msn)) {
92 eaz = p->eaz;
93 break;
94 }
95 p = p->next;
96 }
97 if (!ia5)
98 return (1 << (eaz - '0'));
99 else
100 return eaz;
101}
102
103/*
104 * Find an EAZ entry in the list.
105 * return a string with corresponding msn.
106 */
107char *
108act2000_find_eaz(act2000_card *card, char eaz)
109{
110 struct msn_entry *p = card->msn_list;
111
112 while (p) {
113 if (p->eaz == eaz)
114 return(p->msn);
115 p = p->next;
116 }
117 return("\0");
118}
119
120/*
121 * Add or delete an MSN to the MSN list
122 *
123 * First character of msneaz is EAZ, rest is MSN.
124 * If length of eazmsn is 1, delete that entry.
125 */
126static int
127act2000_set_msn(act2000_card *card, char *eazmsn)
128{
129 struct msn_entry *p = card->msn_list;
130 struct msn_entry *q = NULL;
131 unsigned long flags;
132 int i;
133
134 if (!strlen(eazmsn))
135 return 0;
136 if (strlen(eazmsn) > 16)
137 return -EINVAL;
138 for (i = 0; i < strlen(eazmsn); i++)
139 if (!isdigit(eazmsn[i]))
140 return -EINVAL;
141 if (strlen(eazmsn) == 1) {
142 /* Delete a single MSN */
143 while (p) {
144 if (p->eaz == eazmsn[0]) {
145 spin_lock_irqsave(&card->lock, flags);
146 if (q)
147 q->next = p->next;
148 else
149 card->msn_list = p->next;
150 spin_unlock_irqrestore(&card->lock, flags);
151 kfree(p);
152 printk(KERN_DEBUG
153 "Mapping for EAZ %c deleted\n",
154 eazmsn[0]);
155 return 0;
156 }
157 q = p;
158 p = p->next;
159 }
160 return 0;
161 }
162 /* Add a single MSN */
163 while (p) {
164 /* Found in list, replace MSN */
165 if (p->eaz == eazmsn[0]) {
166 spin_lock_irqsave(&card->lock, flags);
167 strcpy(p->msn, &eazmsn[1]);
168 spin_unlock_irqrestore(&card->lock, flags);
169 printk(KERN_DEBUG
170 "Mapping for EAZ %c changed to %s\n",
171 eazmsn[0],
172 &eazmsn[1]);
173 return 0;
174 }
175 p = p->next;
176 }
177 /* Not found in list, add new entry */
178 p = kmalloc(sizeof(msn_entry), GFP_KERNEL);
179 if (!p)
180 return -ENOMEM;
181 p->eaz = eazmsn[0];
182 strcpy(p->msn, &eazmsn[1]);
183 p->next = card->msn_list;
184 spin_lock_irqsave(&card->lock, flags);
185 card->msn_list = p;
186 spin_unlock_irqrestore(&card->lock, flags);
187 printk(KERN_DEBUG
188 "Mapping %c -> %s added\n",
189 eazmsn[0],
190 &eazmsn[1]);
191 return 0;
192}
193
194static void
195act2000_transmit(struct act2000_card *card)
196{
197 switch (card->bus) {
198 case ACT2000_BUS_ISA:
199 act2000_isa_send(card);
200 break;
201 case ACT2000_BUS_PCMCIA:
202 case ACT2000_BUS_MCA:
203 default:
204 printk(KERN_WARNING
205 "act2000_transmit: Illegal bustype %d\n", card->bus);
206 }
207}
208
209static void
210act2000_receive(struct act2000_card *card)
211{
212 switch (card->bus) {
213 case ACT2000_BUS_ISA:
214 act2000_isa_receive(card);
215 break;
216 case ACT2000_BUS_PCMCIA:
217 case ACT2000_BUS_MCA:
218 default:
219 printk(KERN_WARNING
220 "act2000_receive: Illegal bustype %d\n", card->bus);
221 }
222}
223
224static void
225act2000_poll(unsigned long data)
226{
227 act2000_card * card = (act2000_card *)data;
228 unsigned long flags;
229
230 act2000_receive(card);
231 spin_lock_irqsave(&card->lock, flags);
232 mod_timer(&card->ptimer, jiffies+3);
233 spin_unlock_irqrestore(&card->lock, flags);
234}
235
236static int
237act2000_command(act2000_card * card, isdn_ctrl * c)
238{
239 ulong a;
240 act2000_chan *chan;
241 act2000_cdef cdef;
242 isdn_ctrl cmd;
243 char tmp[17];
244 int ret;
245 unsigned long flags;
246 void __user *arg;
247
248 switch (c->command) {
249 case ISDN_CMD_IOCTL:
250 memcpy(&a, c->parm.num, sizeof(ulong));
251 arg = (void __user *)a;
252 switch (c->arg) {
253 case ACT2000_IOCTL_LOADBOOT:
254 switch (card->bus) {
255 case ACT2000_BUS_ISA:
256 ret = act2000_isa_download(card,
257 arg);
258 if (!ret) {
259 card->flags |= ACT2000_FLAGS_LOADED;
260 if (!(card->flags & ACT2000_FLAGS_IVALID)) {
261 card->ptimer.expires = jiffies + 3;
262 card->ptimer.function = act2000_poll;
263 card->ptimer.data = (unsigned long)card;
264 add_timer(&card->ptimer);
265 }
266 actcapi_manufacturer_req_errh(card);
267 }
268 break;
269 default:
270 printk(KERN_WARNING
271 "act2000: Illegal BUS type %d\n",
272 card->bus);
273 ret = -EIO;
274 }
275 return ret;
276 case ACT2000_IOCTL_SETPROTO:
277 card->ptype = a?ISDN_PTYPE_EURO:ISDN_PTYPE_1TR6;
278 if (!(card->flags & ACT2000_FLAGS_RUNNING))
279 return 0;
280 actcapi_manufacturer_req_net(card);
281 return 0;
282 case ACT2000_IOCTL_SETMSN:
283 if (copy_from_user(tmp, arg,
284 sizeof(tmp)))
285 return -EFAULT;
286 if ((ret = act2000_set_msn(card, tmp)))
287 return ret;
288 if (card->flags & ACT2000_FLAGS_RUNNING)
289 return(actcapi_manufacturer_req_msn(card));
290 return 0;
291 case ACT2000_IOCTL_ADDCARD:
292 if (copy_from_user(&cdef, arg,
293 sizeof(cdef)))
294 return -EFAULT;
295 if (act2000_addcard(cdef.bus, cdef.port, cdef.irq, cdef.id))
296 return -EIO;
297 return 0;
298 case ACT2000_IOCTL_TEST:
299 if (!(card->flags & ACT2000_FLAGS_RUNNING))
300 return -ENODEV;
301 return 0;
302 default:
303 return -EINVAL;
304 }
305 break;
306 case ISDN_CMD_DIAL:
307 if (!card->flags & ACT2000_FLAGS_RUNNING)
308 return -ENODEV;
309 if (!(chan = find_channel(card, c->arg & 0x0f)))
310 break;
311 spin_lock_irqsave(&card->lock, flags);
312 if (chan->fsm_state != ACT2000_STATE_NULL) {
313 spin_unlock_irqrestore(&card->lock, flags);
314 printk(KERN_WARNING "Dial on channel with state %d\n",
315 chan->fsm_state);
316 return -EBUSY;
317 }
318 if (card->ptype == ISDN_PTYPE_EURO)
319 tmp[0] = act2000_find_msn(card, c->parm.setup.eazmsn, 1);
320 else
321 tmp[0] = c->parm.setup.eazmsn[0];
322 chan->fsm_state = ACT2000_STATE_OCALL;
323 chan->callref = 0xffff;
324 spin_unlock_irqrestore(&card->lock, flags);
325 ret = actcapi_connect_req(card, chan, c->parm.setup.phone,
326 tmp[0], c->parm.setup.si1,
327 c->parm.setup.si2);
328 if (ret) {
329 cmd.driver = card->myid;
330 cmd.command = ISDN_STAT_DHUP;
331 cmd.arg &= 0x0f;
332 card->interface.statcallb(&cmd);
333 }
334 return ret;
335 case ISDN_CMD_ACCEPTD:
336 if (!card->flags & ACT2000_FLAGS_RUNNING)
337 return -ENODEV;
338 if (!(chan = find_channel(card, c->arg & 0x0f)))
339 break;
340 if (chan->fsm_state == ACT2000_STATE_ICALL)
341 actcapi_select_b2_protocol_req(card, chan);
342 return 0;
343 case ISDN_CMD_ACCEPTB:
344 if (!card->flags & ACT2000_FLAGS_RUNNING)
345 return -ENODEV;
346 return 0;
347 case ISDN_CMD_HANGUP:
348 if (!card->flags & ACT2000_FLAGS_RUNNING)
349 return -ENODEV;
350 if (!(chan = find_channel(card, c->arg & 0x0f)))
351 break;
352 switch (chan->fsm_state) {
353 case ACT2000_STATE_ICALL:
354 case ACT2000_STATE_BSETUP:
355 actcapi_connect_resp(card, chan, 0x15);
356 break;
357 case ACT2000_STATE_ACTIVE:
358 actcapi_disconnect_b3_req(card, chan);
359 break;
360 }
361 return 0;
362 case ISDN_CMD_SETEAZ:
363 if (!card->flags & ACT2000_FLAGS_RUNNING)
364 return -ENODEV;
365 if (!(chan = find_channel(card, c->arg & 0x0f)))
366 break;
367 if (strlen(c->parm.num)) {
368 if (card->ptype == ISDN_PTYPE_EURO) {
369 chan->eazmask = act2000_find_msn(card, c->parm.num, 0);
370 }
371 if (card->ptype == ISDN_PTYPE_1TR6) {
372 int i;
373 chan->eazmask = 0;
374 for (i = 0; i < strlen(c->parm.num); i++)
375 if (isdigit(c->parm.num[i]))
376 chan->eazmask |= (1 << (c->parm.num[i] - '0'));
377 }
378 } else
379 chan->eazmask = 0x3ff;
380 actcapi_listen_req(card);
381 return 0;
382 case ISDN_CMD_CLREAZ:
383 if (!card->flags & ACT2000_FLAGS_RUNNING)
384 return -ENODEV;
385 if (!(chan = find_channel(card, c->arg & 0x0f)))
386 break;
387 chan->eazmask = 0;
388 actcapi_listen_req(card);
389 return 0;
390 case ISDN_CMD_SETL2:
391 if (!card->flags & ACT2000_FLAGS_RUNNING)
392 return -ENODEV;
393 if (!(chan = find_channel(card, c->arg & 0x0f)))
394 break;
395 chan->l2prot = (c->arg >> 8);
396 return 0;
397 case ISDN_CMD_SETL3:
398 if (!card->flags & ACT2000_FLAGS_RUNNING)
399 return -ENODEV;
400 if ((c->arg >> 8) != ISDN_PROTO_L3_TRANS) {
401 printk(KERN_WARNING "L3 protocol unknown\n");
402 return -1;
403 }
404 if (!(chan = find_channel(card, c->arg & 0x0f)))
405 break;
406 chan->l3prot = (c->arg >> 8);
407 return 0;
408 }
409
410 return -EINVAL;
411}
412
413static int
414act2000_sendbuf(act2000_card *card, int channel, int ack, struct sk_buff *skb)
415{
416 struct sk_buff *xmit_skb;
417 int len;
418 act2000_chan *chan;
419 actcapi_msg *msg;
420
421 if (!(chan = find_channel(card, channel)))
422 return -1;
423 if (chan->fsm_state != ACT2000_STATE_ACTIVE)
424 return -1;
425 len = skb->len;
426 if ((chan->queued + len) >= ACT2000_MAX_QUEUED)
427 return 0;
428 if (!len)
429 return 0;
430 if (skb_headroom(skb) < 19) {
431 printk(KERN_WARNING "act2000_sendbuf: Headroom only %d\n",
432 skb_headroom(skb));
433 xmit_skb = alloc_skb(len + 19, GFP_ATOMIC);
434 if (!xmit_skb) {
435 printk(KERN_WARNING "act2000_sendbuf: Out of memory\n");
436 return 0;
437 }
438 skb_reserve(xmit_skb, 19);
439 memcpy(skb_put(xmit_skb, len), skb->data, len);
440 } else {
441 xmit_skb = skb_clone(skb, GFP_ATOMIC);
442 if (!xmit_skb) {
443 printk(KERN_WARNING "act2000_sendbuf: Out of memory\n");
444 return 0;
445 }
446 }
447 dev_kfree_skb(skb);
448 msg = (actcapi_msg *)skb_push(xmit_skb, 19);
449 msg->hdr.len = 19 + len;
450 msg->hdr.applicationID = 1;
451 msg->hdr.cmd.cmd = 0x86;
452 msg->hdr.cmd.subcmd = 0x00;
453 msg->hdr.msgnum = actcapi_nextsmsg(card);
454 msg->msg.data_b3_req.datalen = len;
455 msg->msg.data_b3_req.blocknr = (msg->hdr.msgnum & 0xff);
456 msg->msg.data_b3_req.fakencci = MAKE_NCCI(chan->plci, 0, chan->ncci);
457 msg->msg.data_b3_req.flags = ack; /* Will be set to 0 on actual sending */
458 actcapi_debug_msg(xmit_skb, 1);
459 chan->queued += len;
460 skb_queue_tail(&card->sndq, xmit_skb);
461 act2000_schedule_tx(card);
462 return len;
463}
464
465
466/* Read the Status-replies from the Interface */
467static int
468act2000_readstatus(u_char __user * buf, int len, act2000_card * card)
469{
470 int count;
471 u_char __user *p;
472
473 for (p = buf, count = 0; count < len; p++, count++) {
474 if (card->status_buf_read == card->status_buf_write)
475 return count;
476 put_user(*card->status_buf_read++, p);
477 if (card->status_buf_read > card->status_buf_end)
478 card->status_buf_read = card->status_buf;
479 }
480 return count;
481}
482
483/*
484 * Find card with given driverId
485 */
486static inline act2000_card *
487act2000_findcard(int driverid)
488{
489 act2000_card *p = cards;
490
491 while (p) {
492 if (p->myid == driverid)
493 return p;
494 p = p->next;
495 }
496 return (act2000_card *) 0;
497}
498
499/*
500 * Wrapper functions for interface to linklevel
501 */
502static int
503if_command(isdn_ctrl * c)
504{
505 act2000_card *card = act2000_findcard(c->driver);
506
507 if (card)
508 return (act2000_command(card, c));
509 printk(KERN_ERR
510 "act2000: if_command %d called with invalid driverId %d!\n",
511 c->command, c->driver);
512 return -ENODEV;
513}
514
515static int
516if_writecmd(const u_char __user *buf, int len, int id, int channel)
517{
518 act2000_card *card = act2000_findcard(id);
519
520 if (card) {
521 if (!card->flags & ACT2000_FLAGS_RUNNING)
522 return -ENODEV;
523 return (len);
524 }
525 printk(KERN_ERR
526 "act2000: if_writecmd called with invalid driverId!\n");
527 return -ENODEV;
528}
529
530static int
531if_readstatus(u_char __user * buf, int len, int id, int channel)
532{
533 act2000_card *card = act2000_findcard(id);
534
535 if (card) {
536 if (!card->flags & ACT2000_FLAGS_RUNNING)
537 return -ENODEV;
538 return (act2000_readstatus(buf, len, card));
539 }
540 printk(KERN_ERR
541 "act2000: if_readstatus called with invalid driverId!\n");
542 return -ENODEV;
543}
544
545static int
546if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
547{
548 act2000_card *card = act2000_findcard(id);
549
550 if (card) {
551 if (!card->flags & ACT2000_FLAGS_RUNNING)
552 return -ENODEV;
553 return (act2000_sendbuf(card, channel, ack, skb));
554 }
555 printk(KERN_ERR
556 "act2000: if_sendbuf called with invalid driverId!\n");
557 return -ENODEV;
558}
559
560
561/*
562 * Allocate a new card-struct, initialize it
563 * link it into cards-list.
564 */
565static void
566act2000_alloccard(int bus, int port, int irq, char *id)
567{
568 int i;
569 act2000_card *card;
570 if (!(card = (act2000_card *) kmalloc(sizeof(act2000_card), GFP_KERNEL))) {
571 printk(KERN_WARNING
572 "act2000: (%s) Could not allocate card-struct.\n", id);
573 return;
574 }
575 memset((char *) card, 0, sizeof(act2000_card));
576 spin_lock_init(&card->lock);
577 spin_lock_init(&card->mnlock);
578 skb_queue_head_init(&card->sndq);
579 skb_queue_head_init(&card->rcvq);
580 skb_queue_head_init(&card->ackq);
581 INIT_WORK(&card->snd_tq, (void *) (void *) act2000_transmit, card);
582 INIT_WORK(&card->rcv_tq, (void *) (void *) actcapi_dispatch, card);
583 INIT_WORK(&card->poll_tq, (void *) (void *) act2000_receive, card);
584 init_timer(&card->ptimer);
585 card->interface.owner = THIS_MODULE;
586 card->interface.channels = ACT2000_BCH;
587 card->interface.maxbufsize = 4000;
588 card->interface.command = if_command;
589 card->interface.writebuf_skb = if_sendbuf;
590 card->interface.writecmd = if_writecmd;
591 card->interface.readstat = if_readstatus;
592 card->interface.features =
593 ISDN_FEATURE_L2_X75I |
594 ISDN_FEATURE_L2_HDLC |
595 ISDN_FEATURE_L3_TRANS |
596 ISDN_FEATURE_P_UNKNOWN;
597 card->interface.hl_hdrlen = 20;
598 card->ptype = ISDN_PTYPE_EURO;
599 strlcpy(card->interface.id, id, sizeof(card->interface.id));
600 for (i=0; i<ACT2000_BCH; i++) {
601 card->bch[i].plci = 0x8000;
602 card->bch[i].ncci = 0x8000;
603 card->bch[i].l2prot = ISDN_PROTO_L2_X75I;
604 card->bch[i].l3prot = ISDN_PROTO_L3_TRANS;
605 }
606 card->myid = -1;
607 card->bus = bus;
608 card->port = port;
609 card->irq = irq;
610 card->next = cards;
611 cards = card;
612}
613
614/*
615 * register card at linklevel
616 */
617static int
618act2000_registercard(act2000_card * card)
619{
620 switch (card->bus) {
621 case ACT2000_BUS_ISA:
622 break;
623 case ACT2000_BUS_MCA:
624 case ACT2000_BUS_PCMCIA:
625 default:
626 printk(KERN_WARNING
627 "act2000: Illegal BUS type %d\n",
628 card->bus);
629 return -1;
630 }
631 if (!register_isdn(&card->interface)) {
632 printk(KERN_WARNING
633 "act2000: Unable to register %s\n",
634 card->interface.id);
635 return -1;
636 }
637 card->myid = card->interface.channels;
638 sprintf(card->regname, "act2000-isdn (%s)", card->interface.id);
639 return 0;
640}
641
642static void
643unregister_card(act2000_card * card)
644{
645 isdn_ctrl cmd;
646
647 cmd.command = ISDN_STAT_UNLOAD;
648 cmd.driver = card->myid;
649 card->interface.statcallb(&cmd);
650 switch (card->bus) {
651 case ACT2000_BUS_ISA:
652 act2000_isa_release(card);
653 break;
654 case ACT2000_BUS_MCA:
655 case ACT2000_BUS_PCMCIA:
656 default:
657 printk(KERN_WARNING
658 "act2000: Invalid BUS type %d\n",
659 card->bus);
660 break;
661 }
662}
663
664static int
665act2000_addcard(int bus, int port, int irq, char *id)
666{
667 act2000_card *p;
668 act2000_card *q = NULL;
669 int initialized;
670 int added = 0;
671 int failed = 0;
672 int i;
673
674 if (!bus)
675 bus = ACT2000_BUS_ISA;
676 if (port != -1) {
677 /* Port defined, do fixed setup */
678 act2000_alloccard(bus, port, irq, id);
679 } else {
680 /* No port defined, perform autoprobing.
681 * This may result in more than one card detected.
682 */
683 switch (bus) {
684 case ACT2000_BUS_ISA:
685 for (i = 0; i < ISA_NRPORTS; i++)
686 if (act2000_isa_detect(act2000_isa_ports[i])) {
687 printk(KERN_INFO
688 "act2000: Detected ISA card at port 0x%x\n",
689 act2000_isa_ports[i]);
690 act2000_alloccard(bus, act2000_isa_ports[i], irq, id);
691 }
692 break;
693 case ACT2000_BUS_MCA:
694 case ACT2000_BUS_PCMCIA:
695 default:
696 printk(KERN_WARNING
697 "act2000: addcard: Invalid BUS type %d\n",
698 bus);
699 }
700 }
701 if (!cards)
702 return 1;
703 p = cards;
704 while (p) {
705 initialized = 0;
706 if (!p->interface.statcallb) {
707 /* Not yet registered.
708 * Try to register and activate it.
709 */
710 added++;
711 switch (p->bus) {
712 case ACT2000_BUS_ISA:
713 if (act2000_isa_detect(p->port)) {
714 if (act2000_registercard(p))
715 break;
716 if (act2000_isa_config_port(p, p->port)) {
717 printk(KERN_WARNING
718 "act2000: Could not request port 0x%04x\n",
719 p->port);
720 unregister_card(p);
721 p->interface.statcallb = NULL;
722 break;
723 }
724 if (act2000_isa_config_irq(p, p->irq)) {
725 printk(KERN_INFO
726 "act2000: No IRQ available, fallback to polling\n");
727 /* Fall back to polled operation */
728 p->irq = 0;
729 }
730 printk(KERN_INFO
731 "act2000: ISA"
732 "-type card at port "
733 "0x%04x ",
734 p->port);
735 if (p->irq)
736 printk("irq %d\n", p->irq);
737 else
738 printk("polled\n");
739 initialized = 1;
740 }
741 break;
742 case ACT2000_BUS_MCA:
743 case ACT2000_BUS_PCMCIA:
744 default:
745 printk(KERN_WARNING
746 "act2000: addcard: Invalid BUS type %d\n",
747 p->bus);
748 }
749 } else
750 /* Card already initialized */
751 initialized = 1;
752 if (initialized) {
753 /* Init OK, next card ... */
754 q = p;
755 p = p->next;
756 } else {
757 /* Init failed, remove card from list, free memory */
758 printk(KERN_WARNING
759 "act2000: Initialization of %s failed\n",
760 p->interface.id);
761 if (q) {
762 q->next = p->next;
763 kfree(p);
764 p = q->next;
765 } else {
766 cards = p->next;
767 kfree(p);
768 p = cards;
769 }
770 failed++;
771 }
772 }
773 return (added - failed);
774}
775
776#define DRIVERNAME "IBM Active 2000 ISDN driver"
777
778static int __init act2000_init(void)
779{
780 printk(KERN_INFO "%s\n", DRIVERNAME);
781 if (!cards)
782 act2000_addcard(act_bus, act_port, act_irq, act_id);
783 if (!cards)
784 printk(KERN_INFO "act2000: No cards defined yet\n");
785 return 0;
786}
787
788static void __exit act2000_exit(void)
789{
790 act2000_card *card = cards;
791 act2000_card *last;
792 while (card) {
793 unregister_card(card);
794 del_timer(&card->ptimer);
795 card = card->next;
796 }
797 card = cards;
798 while (card) {
799 last = card;
800 card = card->next;
801 act2000_clear_msn(last);
802 kfree(last);
803 }
804 printk(KERN_INFO "%s unloaded\n", DRIVERNAME);
805}
806
807module_init(act2000_init);
808module_exit(act2000_exit);