blob: bf7997abc4ac6da27bf972677ac3283e7e68d49c [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* $Id: icn.c,v 1.65.6.8 2001/09/23 22:24:55 kai Exp $
2 *
3 * ISDN low-level module for the ICN active ISDN-Card.
4 *
5 * Copyright 1994,95,96 by Fritz Elfert (fritz@isdn4linux.de)
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#include "icn.h"
13#include <linux/module.h>
14#include <linux/init.h>
Alexey Dobriyane8edc6e2007-05-21 01:22:52 +040015#include <linux/sched.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016
17static int portbase = ICN_BASEADDR;
18static unsigned long membase = ICN_MEMADDR;
19static char *icn_id = "\0";
20static char *icn_id2 = "\0";
21
22MODULE_DESCRIPTION("ISDN4Linux: Driver for ICN active ISDN card");
23MODULE_AUTHOR("Fritz Elfert");
24MODULE_LICENSE("GPL");
25module_param(portbase, int, 0);
26MODULE_PARM_DESC(portbase, "Port address of first card");
27module_param(membase, ulong, 0);
28MODULE_PARM_DESC(membase, "Shared memory address of all cards");
29module_param(icn_id, charp, 0);
30MODULE_PARM_DESC(icn_id, "ID-String of first card");
31module_param(icn_id2, charp, 0);
32MODULE_PARM_DESC(icn_id2, "ID-String of first card, second S0 (4B only)");
33
34/*
35 * Verbose bootcode- and protocol-downloading.
36 */
37#undef BOOT_DEBUG
38
39/*
40 * Verbose Shmem-Mapping.
41 */
42#undef MAP_DEBUG
43
44static char
45*revision = "$Revision: 1.65.6.8 $";
46
47static int icn_addcard(int, char *, char *);
48
49/*
50 * Free send-queue completely.
51 * Parameter:
52 * card = pointer to card struct
53 * channel = channel number
54 */
55static void
56icn_free_queue(icn_card * card, int channel)
57{
58 struct sk_buff_head *queue = &card->spqueue[channel];
59 struct sk_buff *skb;
60
61 skb_queue_purge(queue);
62 card->xlen[channel] = 0;
63 card->sndcount[channel] = 0;
64 if ((skb = card->xskb[channel])) {
65 card->xskb[channel] = NULL;
66 dev_kfree_skb(skb);
67 }
68}
69
70/* Put a value into a shift-register, highest bit first.
71 * Parameters:
72 * port = port for output (bit 0 is significant)
73 * val = value to be output
74 * firstbit = Bit-Number of highest bit
75 * bitcount = Number of bits to output
76 */
77static inline void
78icn_shiftout(unsigned short port,
79 unsigned long val,
80 int firstbit,
81 int bitcount)
82{
83
84 register u_char s;
85 register u_char c;
86
87 for (s = firstbit, c = bitcount; c > 0; s--, c--)
88 OUTB_P((u_char) ((val >> s) & 1) ? 0xff : 0, port);
89}
90
91/*
92 * disable a cards shared memory
93 */
94static inline void
95icn_disable_ram(icn_card * card)
96{
97 OUTB_P(0, ICN_MAPRAM);
98}
99
100/*
101 * enable a cards shared memory
102 */
103static inline void
104icn_enable_ram(icn_card * card)
105{
106 OUTB_P(0xff, ICN_MAPRAM);
107}
108
109/*
110 * Map a cards channel0 (Bank0/Bank8) or channel1 (Bank4/Bank12)
111 *
112 * must called with holding the devlock
113 */
114static inline void
115icn_map_channel(icn_card * card, int channel)
116{
117#ifdef MAP_DEBUG
118 printk(KERN_DEBUG "icn_map_channel %d %d\n", dev.channel, channel);
119#endif
120 if ((channel == dev.channel) && (card == dev.mcard))
121 return;
122 if (dev.mcard)
123 icn_disable_ram(dev.mcard);
124 icn_shiftout(ICN_BANK, chan2bank[channel], 3, 4); /* Select Bank */
125 icn_enable_ram(card);
126 dev.mcard = card;
127 dev.channel = channel;
128#ifdef MAP_DEBUG
129 printk(KERN_DEBUG "icn_map_channel done\n");
130#endif
131}
132
133/*
134 * Lock a cards channel.
135 * Return 0 if requested card/channel is unmapped (failure).
136 * Return 1 on success.
137 *
138 * must called with holding the devlock
139 */
140static inline int
141icn_lock_channel(icn_card * card, int channel)
142{
143 register int retval;
144
145#ifdef MAP_DEBUG
146 printk(KERN_DEBUG "icn_lock_channel %d\n", channel);
147#endif
148 if ((dev.channel == channel) && (card == dev.mcard)) {
149 dev.chanlock++;
150 retval = 1;
151#ifdef MAP_DEBUG
152 printk(KERN_DEBUG "icn_lock_channel %d OK\n", channel);
153#endif
154 } else {
155 retval = 0;
156#ifdef MAP_DEBUG
157 printk(KERN_DEBUG "icn_lock_channel %d FAILED, dc=%d\n", channel, dev.channel);
158#endif
159 }
160 return retval;
161}
162
163/*
164 * Release current card/channel lock
165 *
166 * must called with holding the devlock
167 */
168static inline void
169__icn_release_channel(void)
170{
171#ifdef MAP_DEBUG
172 printk(KERN_DEBUG "icn_release_channel l=%d\n", dev.chanlock);
173#endif
174 if (dev.chanlock > 0)
175 dev.chanlock--;
176}
177
178/*
179 * Release current card/channel lock
180 */
181static inline void
182icn_release_channel(void)
183{
184 ulong flags;
185
186 spin_lock_irqsave(&dev.devlock, flags);
187 __icn_release_channel();
188 spin_unlock_irqrestore(&dev.devlock, flags);
189}
190
191/*
192 * Try to map and lock a cards channel.
193 * Return 1 on success, 0 on failure.
194 */
195static inline int
196icn_trymaplock_channel(icn_card * card, int channel)
197{
198 ulong flags;
199
200#ifdef MAP_DEBUG
201 printk(KERN_DEBUG "trymaplock c=%d dc=%d l=%d\n", channel, dev.channel,
202 dev.chanlock);
203#endif
204 spin_lock_irqsave(&dev.devlock, flags);
205 if ((!dev.chanlock) ||
206 ((dev.channel == channel) && (dev.mcard == card))) {
207 dev.chanlock++;
208 icn_map_channel(card, channel);
209 spin_unlock_irqrestore(&dev.devlock, flags);
210#ifdef MAP_DEBUG
211 printk(KERN_DEBUG "trymaplock %d OK\n", channel);
212#endif
213 return 1;
214 }
215 spin_unlock_irqrestore(&dev.devlock, flags);
216#ifdef MAP_DEBUG
217 printk(KERN_DEBUG "trymaplock %d FAILED\n", channel);
218#endif
219 return 0;
220}
221
222/*
223 * Release current card/channel lock,
224 * then map same or other channel without locking.
225 */
226static inline void
227icn_maprelease_channel(icn_card * card, int channel)
228{
229 ulong flags;
230
231#ifdef MAP_DEBUG
232 printk(KERN_DEBUG "map_release c=%d l=%d\n", channel, dev.chanlock);
233#endif
234 spin_lock_irqsave(&dev.devlock, flags);
235 if (dev.chanlock > 0)
236 dev.chanlock--;
237 if (!dev.chanlock)
238 icn_map_channel(card, channel);
239 spin_unlock_irqrestore(&dev.devlock, flags);
240}
241
242/* Get Data from the B-Channel, assemble fragmented packets and put them
243 * into receive-queue. Wake up any B-Channel-reading processes.
244 * This routine is called via timer-callback from icn_pollbchan().
245 */
246
247static void
248icn_pollbchan_receive(int channel, icn_card * card)
249{
250 int mch = channel + ((card->secondhalf) ? 2 : 0);
251 int eflag;
252 int cnt;
253 struct sk_buff *skb;
254
255 if (icn_trymaplock_channel(card, mch)) {
256 while (rbavl) {
257 cnt = readb(&rbuf_l);
258 if ((card->rcvidx[channel] + cnt) > 4000) {
259 printk(KERN_WARNING
260 "icn: (%s) bogus packet on ch%d, dropping.\n",
261 CID,
262 channel + 1);
263 card->rcvidx[channel] = 0;
264 eflag = 0;
265 } else {
266 memcpy_fromio(&card->rcvbuf[channel][card->rcvidx[channel]],
267 &rbuf_d, cnt);
268 card->rcvidx[channel] += cnt;
269 eflag = readb(&rbuf_f);
270 }
271 rbnext;
272 icn_maprelease_channel(card, mch & 2);
273 if (!eflag) {
274 if ((cnt = card->rcvidx[channel])) {
275 if (!(skb = dev_alloc_skb(cnt))) {
276 printk(KERN_WARNING "icn: receive out of memory\n");
277 break;
278 }
279 memcpy(skb_put(skb, cnt), card->rcvbuf[channel], cnt);
280 card->rcvidx[channel] = 0;
281 card->interface.rcvcallb_skb(card->myid, channel, skb);
282 }
283 }
284 if (!icn_trymaplock_channel(card, mch))
285 break;
286 }
287 icn_maprelease_channel(card, mch & 2);
288 }
289}
290
291/* Send data-packet to B-Channel, split it up into fragments of
292 * ICN_FRAGSIZE length. If last fragment is sent out, signal
293 * success to upper layers via statcallb with ISDN_STAT_BSENT argument.
294 * This routine is called via timer-callback from icn_pollbchan() or
295 * directly from icn_sendbuf().
296 */
297
298static void
299icn_pollbchan_send(int channel, icn_card * card)
300{
301 int mch = channel + ((card->secondhalf) ? 2 : 0);
302 int cnt;
303 unsigned long flags;
304 struct sk_buff *skb;
305 isdn_ctrl cmd;
306
307 if (!(card->sndcount[channel] || card->xskb[channel] ||
David S. Millerb03efcf2005-07-08 14:57:23 -0700308 !skb_queue_empty(&card->spqueue[channel])))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 return;
310 if (icn_trymaplock_channel(card, mch)) {
311 while (sbfree &&
312 (card->sndcount[channel] ||
David S. Millerb03efcf2005-07-08 14:57:23 -0700313 !skb_queue_empty(&card->spqueue[channel]) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 card->xskb[channel])) {
315 spin_lock_irqsave(&card->lock, flags);
316 if (card->xmit_lock[channel]) {
317 spin_unlock_irqrestore(&card->lock, flags);
318 break;
319 }
320 card->xmit_lock[channel]++;
321 spin_unlock_irqrestore(&card->lock, flags);
322 skb = card->xskb[channel];
323 if (!skb) {
324 skb = skb_dequeue(&card->spqueue[channel]);
325 if (skb) {
326 /* Pop ACK-flag off skb.
327 * Store length to xlen.
328 */
329 if (*(skb_pull(skb,1)))
330 card->xlen[channel] = skb->len;
331 else
332 card->xlen[channel] = 0;
333 }
334 }
335 if (!skb)
336 break;
337 if (skb->len > ICN_FRAGSIZE) {
338 writeb(0xff, &sbuf_f);
339 cnt = ICN_FRAGSIZE;
340 } else {
341 writeb(0x0, &sbuf_f);
342 cnt = skb->len;
343 }
344 writeb(cnt, &sbuf_l);
345 memcpy_toio(&sbuf_d, skb->data, cnt);
346 skb_pull(skb, cnt);
347 sbnext; /* switch to next buffer */
348 icn_maprelease_channel(card, mch & 2);
349 spin_lock_irqsave(&card->lock, flags);
350 card->sndcount[channel] -= cnt;
351 if (!skb->len) {
352 if (card->xskb[channel])
353 card->xskb[channel] = NULL;
354 card->xmit_lock[channel] = 0;
355 spin_unlock_irqrestore(&card->lock, flags);
356 dev_kfree_skb(skb);
357 if (card->xlen[channel]) {
358 cmd.command = ISDN_STAT_BSENT;
359 cmd.driver = card->myid;
360 cmd.arg = channel;
361 cmd.parm.length = card->xlen[channel];
362 card->interface.statcallb(&cmd);
363 }
364 } else {
365 card->xskb[channel] = skb;
366 card->xmit_lock[channel] = 0;
367 spin_unlock_irqrestore(&card->lock, flags);
368 }
369 if (!icn_trymaplock_channel(card, mch))
370 break;
371 }
372 icn_maprelease_channel(card, mch & 2);
373 }
374}
375
376/* Send/Receive Data to/from the B-Channel.
377 * This routine is called via timer-callback.
378 * It schedules itself while any B-Channel is open.
379 */
380
381static void
382icn_pollbchan(unsigned long data)
383{
384 icn_card *card = (icn_card *) data;
385 unsigned long flags;
386
387 if (card->flags & ICN_FLAGS_B1ACTIVE) {
388 icn_pollbchan_receive(0, card);
389 icn_pollbchan_send(0, card);
390 }
391 if (card->flags & ICN_FLAGS_B2ACTIVE) {
392 icn_pollbchan_receive(1, card);
393 icn_pollbchan_send(1, card);
394 }
395 if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE)) {
396 /* schedule b-channel polling again */
397 spin_lock_irqsave(&card->lock, flags);
398 mod_timer(&card->rb_timer, jiffies+ICN_TIMER_BCREAD);
399 card->flags |= ICN_FLAGS_RBTIMER;
400 spin_unlock_irqrestore(&card->lock, flags);
401 } else
402 card->flags &= ~ICN_FLAGS_RBTIMER;
403}
404
405typedef struct icn_stat {
406 char *statstr;
407 int command;
408 int action;
409} icn_stat;
410/* *INDENT-OFF* */
411static icn_stat icn_stat_table[] =
412{
413 {"BCON_", ISDN_STAT_BCONN, 1}, /* B-Channel connected */
414 {"BDIS_", ISDN_STAT_BHUP, 2}, /* B-Channel disconnected */
415 /*
416 ** add d-channel connect and disconnect support to link-level
417 */
418 {"DCON_", ISDN_STAT_DCONN, 10}, /* D-Channel connected */
419 {"DDIS_", ISDN_STAT_DHUP, 11}, /* D-Channel disconnected */
420 {"DCAL_I", ISDN_STAT_ICALL, 3}, /* Incoming call dialup-line */
421 {"DSCA_I", ISDN_STAT_ICALL, 3}, /* Incoming call 1TR6-SPV */
422 {"FCALL", ISDN_STAT_ICALL, 4}, /* Leased line connection up */
423 {"CIF", ISDN_STAT_CINF, 5}, /* Charge-info, 1TR6-type */
424 {"AOC", ISDN_STAT_CINF, 6}, /* Charge-info, DSS1-type */
425 {"CAU", ISDN_STAT_CAUSE, 7}, /* Cause code */
426 {"TEI OK", ISDN_STAT_RUN, 0}, /* Card connected to wallplug */
427 {"E_L1: ACT FAIL", ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */
428 {"E_L2: DATA LIN", ISDN_STAT_BHUP, 8}, /* Layer-2 data link lost */
429 {"E_L1: ACTIVATION FAILED",
430 ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */
431 {NULL, 0, -1}
432};
433/* *INDENT-ON* */
434
435
436/*
437 * Check Statusqueue-Pointer from isdn-cards.
438 * If there are new status-replies from the interface, check
439 * them against B-Channel-connects/disconnects and set flags accordingly.
440 * Wake-Up any processes, who are reading the status-device.
441 * If there are B-Channels open, initiate a timer-callback to
442 * icn_pollbchan().
443 * This routine is called periodically via timer.
444 */
445
446static void
447icn_parse_status(u_char * status, int channel, icn_card * card)
448{
449 icn_stat *s = icn_stat_table;
450 int action = -1;
451 unsigned long flags;
452 isdn_ctrl cmd;
453
454 while (s->statstr) {
455 if (!strncmp(status, s->statstr, strlen(s->statstr))) {
456 cmd.command = s->command;
457 action = s->action;
458 break;
459 }
460 s++;
461 }
462 if (action == -1)
463 return;
464 cmd.driver = card->myid;
465 cmd.arg = channel;
466 switch (action) {
467 case 11:
468 spin_lock_irqsave(&card->lock, flags);
469 icn_free_queue(card,channel);
470 card->rcvidx[channel] = 0;
471
472 if (card->flags &
473 ((channel)?ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE)) {
474
475 isdn_ctrl ncmd;
476
477 card->flags &= ~((channel)?
478 ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE);
479
480 memset(&ncmd, 0, sizeof(ncmd));
481
482 ncmd.driver = card->myid;
483 ncmd.arg = channel;
484 ncmd.command = ISDN_STAT_BHUP;
485 spin_unlock_irqrestore(&card->lock, flags);
486 card->interface.statcallb(&cmd);
487 } else
488 spin_unlock_irqrestore(&card->lock, flags);
489 break;
490 case 1:
491 spin_lock_irqsave(&card->lock, flags);
492 icn_free_queue(card,channel);
493 card->flags |= (channel) ?
494 ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE;
495 spin_unlock_irqrestore(&card->lock, flags);
496 break;
497 case 2:
498 spin_lock_irqsave(&card->lock, flags);
499 card->flags &= ~((channel) ?
500 ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE);
501 icn_free_queue(card, channel);
502 card->rcvidx[channel] = 0;
503 spin_unlock_irqrestore(&card->lock, flags);
504 break;
505 case 3:
506 {
507 char *t = status + 6;
508 char *s = strchr(t, ',');
509
510 *s++ = '\0';
511 strlcpy(cmd.parm.setup.phone, t,
512 sizeof(cmd.parm.setup.phone));
513 s = strchr(t = s, ',');
514 *s++ = '\0';
515 if (!strlen(t))
516 cmd.parm.setup.si1 = 0;
517 else
518 cmd.parm.setup.si1 =
519 simple_strtoul(t, NULL, 10);
520 s = strchr(t = s, ',');
521 *s++ = '\0';
522 if (!strlen(t))
523 cmd.parm.setup.si2 = 0;
524 else
525 cmd.parm.setup.si2 =
526 simple_strtoul(t, NULL, 10);
527 strlcpy(cmd.parm.setup.eazmsn, s,
528 sizeof(cmd.parm.setup.eazmsn));
529 }
530 cmd.parm.setup.plan = 0;
531 cmd.parm.setup.screen = 0;
532 break;
533 case 4:
534 sprintf(cmd.parm.setup.phone, "LEASED%d", card->myid);
535 sprintf(cmd.parm.setup.eazmsn, "%d", channel + 1);
536 cmd.parm.setup.si1 = 7;
537 cmd.parm.setup.si2 = 0;
538 cmd.parm.setup.plan = 0;
539 cmd.parm.setup.screen = 0;
540 break;
541 case 5:
542 strlcpy(cmd.parm.num, status + 3, sizeof(cmd.parm.num));
543 break;
544 case 6:
545 snprintf(cmd.parm.num, sizeof(cmd.parm.num), "%d",
546 (int) simple_strtoul(status + 7, NULL, 16));
547 break;
548 case 7:
549 status += 3;
550 if (strlen(status) == 4)
551 snprintf(cmd.parm.num, sizeof(cmd.parm.num), "%s%c%c",
552 status + 2, *status, *(status + 1));
553 else
554 strlcpy(cmd.parm.num, status + 1, sizeof(cmd.parm.num));
555 break;
556 case 8:
557 spin_lock_irqsave(&card->lock, flags);
558 card->flags &= ~ICN_FLAGS_B1ACTIVE;
559 icn_free_queue(card, 0);
560 card->rcvidx[0] = 0;
561 spin_unlock_irqrestore(&card->lock, flags);
562 cmd.arg = 0;
563 cmd.driver = card->myid;
564 card->interface.statcallb(&cmd);
565 cmd.command = ISDN_STAT_DHUP;
566 cmd.arg = 0;
567 cmd.driver = card->myid;
568 card->interface.statcallb(&cmd);
569 cmd.command = ISDN_STAT_BHUP;
570 spin_lock_irqsave(&card->lock, flags);
571 card->flags &= ~ICN_FLAGS_B2ACTIVE;
572 icn_free_queue(card, 1);
573 card->rcvidx[1] = 0;
574 spin_unlock_irqrestore(&card->lock, flags);
575 cmd.arg = 1;
576 cmd.driver = card->myid;
577 card->interface.statcallb(&cmd);
578 cmd.command = ISDN_STAT_DHUP;
579 cmd.arg = 1;
580 cmd.driver = card->myid;
581 break;
582 }
583 card->interface.statcallb(&cmd);
584 return;
585}
586
587static void
588icn_putmsg(icn_card * card, unsigned char c)
589{
590 ulong flags;
591
592 spin_lock_irqsave(&card->lock, flags);
593 *card->msg_buf_write++ = (c == 0xff) ? '\n' : c;
594 if (card->msg_buf_write == card->msg_buf_read) {
595 if (++card->msg_buf_read > card->msg_buf_end)
596 card->msg_buf_read = card->msg_buf;
597 }
598 if (card->msg_buf_write > card->msg_buf_end)
599 card->msg_buf_write = card->msg_buf;
600 spin_unlock_irqrestore(&card->lock, flags);
601}
602
603static void
604icn_polldchan(unsigned long data)
605{
606 icn_card *card = (icn_card *) data;
607 int mch = card->secondhalf ? 2 : 0;
608 int avail = 0;
609 int left;
610 u_char c;
611 int ch;
612 unsigned long flags;
613 int i;
614 u_char *p;
615 isdn_ctrl cmd;
616
617 if (icn_trymaplock_channel(card, mch)) {
618 avail = msg_avail;
619 for (left = avail, i = readb(&msg_o); left > 0; i++, left--) {
620 c = readb(&dev.shmem->comm_buffers.iopc_buf[i & 0xff]);
621 icn_putmsg(card, c);
622 if (c == 0xff) {
623 card->imsg[card->iptr] = 0;
624 card->iptr = 0;
625 if (card->imsg[0] == '0' && card->imsg[1] >= '0' &&
626 card->imsg[1] <= '2' && card->imsg[2] == ';') {
627 ch = (card->imsg[1] - '0') - 1;
628 p = &card->imsg[3];
629 icn_parse_status(p, ch, card);
630 } else {
631 p = card->imsg;
632 if (!strncmp(p, "DRV1.", 5)) {
633 u_char vstr[10];
634 u_char *q = vstr;
635
636 printk(KERN_INFO "icn: (%s) %s\n", CID, p);
637 if (!strncmp(p + 7, "TC", 2)) {
638 card->ptype = ISDN_PTYPE_1TR6;
639 card->interface.features |= ISDN_FEATURE_P_1TR6;
640 printk(KERN_INFO
641 "icn: (%s) 1TR6-Protocol loaded and running\n", CID);
642 }
643 if (!strncmp(p + 7, "EC", 2)) {
644 card->ptype = ISDN_PTYPE_EURO;
645 card->interface.features |= ISDN_FEATURE_P_EURO;
646 printk(KERN_INFO
647 "icn: (%s) Euro-Protocol loaded and running\n", CID);
648 }
649 p = strstr(card->imsg, "BRV") + 3;
650 while (*p) {
651 if (*p >= '0' && *p <= '9')
652 *q++ = *p;
653 p++;
654 }
655 *q = '\0';
656 strcat(vstr, "000");
657 vstr[3] = '\0';
658 card->fw_rev = (int) simple_strtoul(vstr, NULL, 10);
659 continue;
660
661 }
662 }
663 } else {
664 card->imsg[card->iptr] = c;
665 if (card->iptr < 59)
666 card->iptr++;
667 }
668 }
669 writeb((readb(&msg_o) + avail) & 0xff, &msg_o);
670 icn_release_channel();
671 }
672 if (avail) {
673 cmd.command = ISDN_STAT_STAVAIL;
674 cmd.driver = card->myid;
675 cmd.arg = avail;
676 card->interface.statcallb(&cmd);
677 }
678 spin_lock_irqsave(&card->lock, flags);
679 if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE))
680 if (!(card->flags & ICN_FLAGS_RBTIMER)) {
681 /* schedule b-channel polling */
682 card->flags |= ICN_FLAGS_RBTIMER;
683 del_timer(&card->rb_timer);
684 card->rb_timer.function = icn_pollbchan;
685 card->rb_timer.data = (unsigned long) card;
686 card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD;
687 add_timer(&card->rb_timer);
688 }
689 /* schedule again */
690 mod_timer(&card->st_timer, jiffies+ICN_TIMER_DCREAD);
691 spin_unlock_irqrestore(&card->lock, flags);
692}
693
694/* Append a packet to the transmit buffer-queue.
695 * Parameters:
696 * channel = Number of B-channel
697 * skb = pointer to sk_buff
698 * card = pointer to card-struct
699 * Return:
700 * Number of bytes transferred, -E??? on error
701 */
702
703static int
704icn_sendbuf(int channel, int ack, struct sk_buff *skb, icn_card * card)
705{
706 int len = skb->len;
707 unsigned long flags;
708 struct sk_buff *nskb;
709
710 if (len > 4000) {
711 printk(KERN_WARNING
712 "icn: Send packet too large\n");
713 return -EINVAL;
714 }
715 if (len) {
716 if (!(card->flags & (channel) ? ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE))
717 return 0;
718 if (card->sndcount[channel] > ICN_MAX_SQUEUE)
719 return 0;
720 #warning TODO test headroom or use skb->nb to flag ACK
721 nskb = skb_clone(skb, GFP_ATOMIC);
722 if (nskb) {
723 /* Push ACK flag as one
724 * byte in front of data.
725 */
726 *(skb_push(nskb, 1)) = ack?1:0;
727 skb_queue_tail(&card->spqueue[channel], nskb);
728 dev_kfree_skb(skb);
729 } else
730 len = 0;
731 spin_lock_irqsave(&card->lock, flags);
732 card->sndcount[channel] += len;
733 spin_unlock_irqrestore(&card->lock, flags);
734 }
735 return len;
736}
737
738/*
739 * Check card's status after starting the bootstrap loader.
740 * On entry, the card's shared memory has already to be mapped.
741 * Return:
742 * 0 on success (Boot loader ready)
743 * -EIO on failure (timeout)
744 */
745static int
746icn_check_loader(int cardnumber)
747{
748 int timer = 0;
749
750 while (1) {
751#ifdef BOOT_DEBUG
752 printk(KERN_DEBUG "Loader %d ?\n", cardnumber);
753#endif
754 if (readb(&dev.shmem->data_control.scns) ||
755 readb(&dev.shmem->data_control.scnr)) {
756 if (timer++ > 5) {
757 printk(KERN_WARNING
758 "icn: Boot-Loader %d timed out.\n",
759 cardnumber);
760 icn_release_channel();
761 return -EIO;
762 }
763#ifdef BOOT_DEBUG
764 printk(KERN_DEBUG "Loader %d TO?\n", cardnumber);
765#endif
766 msleep_interruptible(ICN_BOOT_TIMEOUT1);
767 } else {
768#ifdef BOOT_DEBUG
769 printk(KERN_DEBUG "Loader %d OK\n", cardnumber);
770#endif
771 icn_release_channel();
772 return 0;
773 }
774 }
775}
776
777/* Load the boot-code into the interface-card's memory and start it.
778 * Always called from user-process.
779 *
780 * Parameters:
781 * buffer = pointer to packet
782 * Return:
783 * 0 if successfully loaded
784 */
785
786#ifdef BOOT_DEBUG
787#define SLEEP(sec) { \
788int slsec = sec; \
789 printk(KERN_DEBUG "SLEEP(%d)\n",slsec); \
790 while (slsec) { \
791 msleep_interruptible(1000); \
792 slsec--; \
793 } \
794}
795#else
796#define SLEEP(sec)
797#endif
798
799static int
800icn_loadboot(u_char __user * buffer, icn_card * card)
801{
802 int ret;
803 u_char *codebuf;
804 unsigned long flags;
805
806#ifdef BOOT_DEBUG
807 printk(KERN_DEBUG "icn_loadboot called, buffaddr=%08lx\n", (ulong) buffer);
808#endif
809 if (!(codebuf = kmalloc(ICN_CODE_STAGE1, GFP_KERNEL))) {
810 printk(KERN_WARNING "icn: Could not allocate code buffer\n");
811 ret = -ENOMEM;
812 goto out;
813 }
814 if (copy_from_user(codebuf, buffer, ICN_CODE_STAGE1)) {
815 ret = -EFAULT;
816 goto out_kfree;
817 }
818 if (!card->rvalid) {
819 if (!request_region(card->port, ICN_PORTLEN, card->regname)) {
820 printk(KERN_WARNING
821 "icn: (%s) ports 0x%03x-0x%03x in use.\n",
822 CID,
823 card->port,
824 card->port + ICN_PORTLEN);
825 ret = -EBUSY;
826 goto out_kfree;
827 }
828 card->rvalid = 1;
829 if (card->doubleS0)
830 card->other->rvalid = 1;
831 }
832 if (!dev.mvalid) {
833 if (!request_mem_region(dev.memaddr, 0x4000, "icn-isdn (all cards)")) {
834 printk(KERN_WARNING
835 "icn: memory at 0x%08lx in use.\n", dev.memaddr);
836 ret = -EBUSY;
837 goto out_kfree;
838 }
839 dev.shmem = ioremap(dev.memaddr, 0x4000);
840 dev.mvalid = 1;
841 }
842 OUTB_P(0, ICN_RUN); /* Reset Controller */
843 OUTB_P(0, ICN_MAPRAM); /* Disable RAM */
844 icn_shiftout(ICN_CFG, 0x0f, 3, 4); /* Windowsize= 16k */
845 icn_shiftout(ICN_CFG, dev.memaddr, 23, 10); /* Set RAM-Addr. */
846#ifdef BOOT_DEBUG
847 printk(KERN_DEBUG "shmem=%08lx\n", dev.memaddr);
848#endif
849 SLEEP(1);
850#ifdef BOOT_DEBUG
851 printk(KERN_DEBUG "Map Bank 0\n");
852#endif
853 spin_lock_irqsave(&dev.devlock, flags);
854 icn_map_channel(card, 0); /* Select Bank 0 */
855 icn_lock_channel(card, 0); /* Lock Bank 0 */
856 spin_unlock_irqrestore(&dev.devlock, flags);
857 SLEEP(1);
858 memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); /* Copy code */
859#ifdef BOOT_DEBUG
860 printk(KERN_DEBUG "Bootloader transferred\n");
861#endif
862 if (card->doubleS0) {
863 SLEEP(1);
864#ifdef BOOT_DEBUG
865 printk(KERN_DEBUG "Map Bank 8\n");
866#endif
867 spin_lock_irqsave(&dev.devlock, flags);
868 __icn_release_channel();
869 icn_map_channel(card, 2); /* Select Bank 8 */
870 icn_lock_channel(card, 2); /* Lock Bank 8 */
871 spin_unlock_irqrestore(&dev.devlock, flags);
872 SLEEP(1);
873 memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); /* Copy code */
874#ifdef BOOT_DEBUG
875 printk(KERN_DEBUG "Bootloader transferred\n");
876#endif
877 }
878 SLEEP(1);
879 OUTB_P(0xff, ICN_RUN); /* Start Boot-Code */
880 if ((ret = icn_check_loader(card->doubleS0 ? 2 : 1))) {
881 goto out_kfree;
882 }
883 if (!card->doubleS0) {
884 ret = 0;
885 goto out_kfree;
886 }
887 /* reached only, if we have a Double-S0-Card */
888#ifdef BOOT_DEBUG
889 printk(KERN_DEBUG "Map Bank 0\n");
890#endif
891 spin_lock_irqsave(&dev.devlock, flags);
892 icn_map_channel(card, 0); /* Select Bank 0 */
893 icn_lock_channel(card, 0); /* Lock Bank 0 */
894 spin_unlock_irqrestore(&dev.devlock, flags);
895 SLEEP(1);
896 ret = (icn_check_loader(1));
897
898 out_kfree:
899 kfree(codebuf);
900 out:
901 return ret;
902}
903
904static int
905icn_loadproto(u_char __user * buffer, icn_card * card)
906{
907 register u_char __user *p = buffer;
908 u_char codebuf[256];
909 uint left = ICN_CODE_STAGE2;
910 uint cnt;
911 int timer;
912 unsigned long flags;
913
914#ifdef BOOT_DEBUG
915 printk(KERN_DEBUG "icn_loadproto called\n");
916#endif
917 if (!access_ok(VERIFY_READ, buffer, ICN_CODE_STAGE2))
918 return -EFAULT;
919 timer = 0;
920 spin_lock_irqsave(&dev.devlock, flags);
921 if (card->secondhalf) {
922 icn_map_channel(card, 2);
923 icn_lock_channel(card, 2);
924 } else {
925 icn_map_channel(card, 0);
926 icn_lock_channel(card, 0);
927 }
928 spin_unlock_irqrestore(&dev.devlock, flags);
929 while (left) {
930 if (sbfree) { /* If there is a free buffer... */
931 cnt = left;
932 if (cnt > 256)
933 cnt = 256;
934 if (copy_from_user(codebuf, p, cnt)) {
935 icn_maprelease_channel(card, 0);
936 return -EFAULT;
937 }
938 memcpy_toio(&sbuf_l, codebuf, cnt); /* copy data */
939 sbnext; /* switch to next buffer */
940 p += cnt;
941 left -= cnt;
942 timer = 0;
943 } else {
944#ifdef BOOT_DEBUG
945 printk(KERN_DEBUG "boot 2 !sbfree\n");
946#endif
947 if (timer++ > 5) {
948 icn_maprelease_channel(card, 0);
949 return -EIO;
950 }
Nishanth Aravamudan24763c42005-11-07 01:01:16 -0800951 schedule_timeout_interruptible(10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 }
953 }
954 writeb(0x20, &sbuf_n);
955 timer = 0;
956 while (1) {
957 if (readb(&cmd_o) || readb(&cmd_i)) {
958#ifdef BOOT_DEBUG
959 printk(KERN_DEBUG "Proto?\n");
960#endif
961 if (timer++ > 5) {
962 printk(KERN_WARNING
963 "icn: (%s) Protocol timed out.\n",
964 CID);
965#ifdef BOOT_DEBUG
966 printk(KERN_DEBUG "Proto TO!\n");
967#endif
968 icn_maprelease_channel(card, 0);
969 return -EIO;
970 }
971#ifdef BOOT_DEBUG
972 printk(KERN_DEBUG "Proto TO?\n");
973#endif
974 msleep_interruptible(ICN_BOOT_TIMEOUT1);
975 } else {
976 if ((card->secondhalf) || (!card->doubleS0)) {
977#ifdef BOOT_DEBUG
978 printk(KERN_DEBUG "Proto loaded, install poll-timer %d\n",
979 card->secondhalf);
980#endif
981 spin_lock_irqsave(&card->lock, flags);
982 init_timer(&card->st_timer);
983 card->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
984 card->st_timer.function = icn_polldchan;
985 card->st_timer.data = (unsigned long) card;
986 add_timer(&card->st_timer);
987 card->flags |= ICN_FLAGS_RUNNING;
988 if (card->doubleS0) {
989 init_timer(&card->other->st_timer);
990 card->other->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
991 card->other->st_timer.function = icn_polldchan;
992 card->other->st_timer.data = (unsigned long) card->other;
993 add_timer(&card->other->st_timer);
994 card->other->flags |= ICN_FLAGS_RUNNING;
995 }
996 spin_unlock_irqrestore(&card->lock, flags);
997 }
998 icn_maprelease_channel(card, 0);
999 return 0;
1000 }
1001 }
1002}
1003
1004/* Read the Status-replies from the Interface */
1005static int
1006icn_readstatus(u_char __user *buf, int len, icn_card * card)
1007{
1008 int count;
1009 u_char __user *p;
1010
1011 for (p = buf, count = 0; count < len; p++, count++) {
1012 if (card->msg_buf_read == card->msg_buf_write)
1013 return count;
Jeff Garzik7786ce12006-10-17 00:10:40 -07001014 if (put_user(*card->msg_buf_read++, p))
1015 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 if (card->msg_buf_read > card->msg_buf_end)
1017 card->msg_buf_read = card->msg_buf;
1018 }
1019 return count;
1020}
1021
1022/* Put command-strings into the command-queue of the Interface */
1023static int
1024icn_writecmd(const u_char * buf, int len, int user, icn_card * card)
1025{
1026 int mch = card->secondhalf ? 2 : 0;
1027 int pp;
1028 int i;
1029 int count;
1030 int xcount;
1031 int ocount;
1032 int loop;
1033 unsigned long flags;
1034 int lastmap_channel;
1035 struct icn_card *lastmap_card;
1036 u_char *p;
1037 isdn_ctrl cmd;
1038 u_char msg[0x100];
1039
1040 ocount = 1;
1041 xcount = loop = 0;
1042 while (len) {
1043 count = cmd_free;
1044 if (count > len)
1045 count = len;
1046 if (user) {
1047 if (copy_from_user(msg, buf, count))
1048 return -EFAULT;
1049 } else
1050 memcpy(msg, buf, count);
1051
1052 spin_lock_irqsave(&dev.devlock, flags);
1053 lastmap_card = dev.mcard;
1054 lastmap_channel = dev.channel;
1055 icn_map_channel(card, mch);
1056
1057 icn_putmsg(card, '>');
1058 for (p = msg, pp = readb(&cmd_i), i = count; i > 0; i--, p++, pp
1059 ++) {
1060 writeb((*p == '\n') ? 0xff : *p,
1061 &dev.shmem->comm_buffers.pcio_buf[pp & 0xff]);
1062 len--;
1063 xcount++;
1064 icn_putmsg(card, *p);
1065 if ((*p == '\n') && (i > 1)) {
1066 icn_putmsg(card, '>');
1067 ocount++;
1068 }
1069 ocount++;
1070 }
1071 writeb((readb(&cmd_i) + count) & 0xff, &cmd_i);
1072 if (lastmap_card)
1073 icn_map_channel(lastmap_card, lastmap_channel);
1074 spin_unlock_irqrestore(&dev.devlock, flags);
1075 if (len) {
1076 mdelay(1);
1077 if (loop++ > 20)
1078 break;
1079 } else
1080 break;
1081 }
1082 if (len && (!user))
1083 printk(KERN_WARNING "icn: writemsg incomplete!\n");
1084 cmd.command = ISDN_STAT_STAVAIL;
1085 cmd.driver = card->myid;
1086 cmd.arg = ocount;
1087 card->interface.statcallb(&cmd);
1088 return xcount;
1089}
1090
1091/*
1092 * Delete card's pending timers, send STOP to linklevel
1093 */
1094static void
1095icn_stopcard(icn_card * card)
1096{
1097 unsigned long flags;
1098 isdn_ctrl cmd;
1099
1100 spin_lock_irqsave(&card->lock, flags);
1101 if (card->flags & ICN_FLAGS_RUNNING) {
1102 card->flags &= ~ICN_FLAGS_RUNNING;
1103 del_timer(&card->st_timer);
1104 del_timer(&card->rb_timer);
1105 spin_unlock_irqrestore(&card->lock, flags);
1106 cmd.command = ISDN_STAT_STOP;
1107 cmd.driver = card->myid;
1108 card->interface.statcallb(&cmd);
1109 if (card->doubleS0)
1110 icn_stopcard(card->other);
1111 } else
1112 spin_unlock_irqrestore(&card->lock, flags);
1113}
1114
1115static void
1116icn_stopallcards(void)
1117{
1118 icn_card *p = cards;
1119
1120 while (p) {
1121 icn_stopcard(p);
1122 p = p->next;
1123 }
1124}
1125
1126/*
1127 * Unmap all cards, because some of them may be mapped accidetly during
1128 * autoprobing of some network drivers (SMC-driver?)
1129 */
1130static void
1131icn_disable_cards(void)
1132{
1133 icn_card *card = cards;
1134
1135 while (card) {
1136 if (!request_region(card->port, ICN_PORTLEN, "icn-isdn")) {
1137 printk(KERN_WARNING
1138 "icn: (%s) ports 0x%03x-0x%03x in use.\n",
1139 CID,
1140 card->port,
1141 card->port + ICN_PORTLEN);
1142 } else {
1143 OUTB_P(0, ICN_RUN); /* Reset Controller */
1144 OUTB_P(0, ICN_MAPRAM); /* Disable RAM */
1145 release_region(card->port, ICN_PORTLEN);
1146 }
1147 card = card->next;
1148 }
1149}
1150
1151static int
1152icn_command(isdn_ctrl * c, icn_card * card)
1153{
1154 ulong a;
1155 ulong flags;
1156 int i;
1157 char cbuf[60];
1158 isdn_ctrl cmd;
1159 icn_cdef cdef;
1160 char __user *arg;
1161
1162 switch (c->command) {
1163 case ISDN_CMD_IOCTL:
1164 memcpy(&a, c->parm.num, sizeof(ulong));
1165 arg = (char __user *)a;
1166 switch (c->arg) {
1167 case ICN_IOCTL_SETMMIO:
1168 if (dev.memaddr != (a & 0x0ffc000)) {
1169 if (!request_mem_region(a & 0x0ffc000, 0x4000, "icn-isdn (all cards)")) {
1170 printk(KERN_WARNING
1171 "icn: memory at 0x%08lx in use.\n",
1172 a & 0x0ffc000);
1173 return -EINVAL;
1174 }
1175 release_mem_region(a & 0x0ffc000, 0x4000);
1176 icn_stopallcards();
1177 spin_lock_irqsave(&card->lock, flags);
1178 if (dev.mvalid) {
1179 iounmap(dev.shmem);
1180 release_mem_region(dev.memaddr, 0x4000);
1181 }
1182 dev.mvalid = 0;
1183 dev.memaddr = a & 0x0ffc000;
1184 spin_unlock_irqrestore(&card->lock, flags);
1185 printk(KERN_INFO
1186 "icn: (%s) mmio set to 0x%08lx\n",
1187 CID,
1188 dev.memaddr);
1189 }
1190 break;
1191 case ICN_IOCTL_GETMMIO:
1192 return (long) dev.memaddr;
1193 case ICN_IOCTL_SETPORT:
1194 if (a == 0x300 || a == 0x310 || a == 0x320 || a == 0x330
1195 || a == 0x340 || a == 0x350 || a == 0x360 ||
1196 a == 0x308 || a == 0x318 || a == 0x328 || a == 0x338
1197 || a == 0x348 || a == 0x358 || a == 0x368) {
1198 if (card->port != (unsigned short) a) {
1199 if (!request_region((unsigned short) a, ICN_PORTLEN, "icn-isdn")) {
1200 printk(KERN_WARNING
1201 "icn: (%s) ports 0x%03x-0x%03x in use.\n",
1202 CID, (int) a, (int) a + ICN_PORTLEN);
1203 return -EINVAL;
1204 }
1205 release_region((unsigned short) a, ICN_PORTLEN);
1206 icn_stopcard(card);
1207 spin_lock_irqsave(&card->lock, flags);
1208 if (card->rvalid)
1209 release_region(card->port, ICN_PORTLEN);
1210 card->port = (unsigned short) a;
1211 card->rvalid = 0;
1212 if (card->doubleS0) {
1213 card->other->port = (unsigned short) a;
1214 card->other->rvalid = 0;
1215 }
1216 spin_unlock_irqrestore(&card->lock, flags);
1217 printk(KERN_INFO
1218 "icn: (%s) port set to 0x%03x\n",
1219 CID, card->port);
1220 }
1221 } else
1222 return -EINVAL;
1223 break;
1224 case ICN_IOCTL_GETPORT:
1225 return (int) card->port;
1226 case ICN_IOCTL_GETDOUBLE:
1227 return (int) card->doubleS0;
1228 case ICN_IOCTL_DEBUGVAR:
1229 if (copy_to_user(arg,
1230 &card,
1231 sizeof(ulong)))
1232 return -EFAULT;
1233 a += sizeof(ulong);
1234 {
1235 ulong l = (ulong) & dev;
1236 if (copy_to_user(arg,
1237 &l,
1238 sizeof(ulong)))
1239 return -EFAULT;
1240 }
1241 return 0;
1242 case ICN_IOCTL_LOADBOOT:
1243 if (dev.firstload) {
1244 icn_disable_cards();
1245 dev.firstload = 0;
1246 }
1247 icn_stopcard(card);
1248 return (icn_loadboot(arg, card));
1249 case ICN_IOCTL_LOADPROTO:
1250 icn_stopcard(card);
1251 if ((i = (icn_loadproto(arg, card))))
1252 return i;
1253 if (card->doubleS0)
1254 i = icn_loadproto(arg + ICN_CODE_STAGE2, card->other);
1255 return i;
1256 break;
1257 case ICN_IOCTL_ADDCARD:
1258 if (!dev.firstload)
1259 return -EBUSY;
1260 if (copy_from_user(&cdef,
1261 arg,
1262 sizeof(cdef)))
1263 return -EFAULT;
1264 return (icn_addcard(cdef.port, cdef.id1, cdef.id2));
1265 break;
1266 case ICN_IOCTL_LEASEDCFG:
1267 if (a) {
1268 if (!card->leased) {
1269 card->leased = 1;
1270 while (card->ptype == ISDN_PTYPE_UNKNOWN) {
1271 msleep_interruptible(ICN_BOOT_TIMEOUT1);
1272 }
1273 msleep_interruptible(ICN_BOOT_TIMEOUT1);
1274 sprintf(cbuf, "00;FV2ON\n01;EAZ%c\n02;EAZ%c\n",
1275 (a & 1)?'1':'C', (a & 2)?'2':'C');
1276 i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
1277 printk(KERN_INFO
1278 "icn: (%s) Leased-line mode enabled\n",
1279 CID);
1280 cmd.command = ISDN_STAT_RUN;
1281 cmd.driver = card->myid;
1282 cmd.arg = 0;
1283 card->interface.statcallb(&cmd);
1284 }
1285 } else {
1286 if (card->leased) {
1287 card->leased = 0;
1288 sprintf(cbuf, "00;FV2OFF\n");
1289 i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
1290 printk(KERN_INFO
1291 "icn: (%s) Leased-line mode disabled\n",
1292 CID);
1293 cmd.command = ISDN_STAT_RUN;
1294 cmd.driver = card->myid;
1295 cmd.arg = 0;
1296 card->interface.statcallb(&cmd);
1297 }
1298 }
1299 return 0;
1300 default:
1301 return -EINVAL;
1302 }
1303 break;
1304 case ISDN_CMD_DIAL:
Alexey Dobriyaneaa0ff12008-02-06 01:36:06 -08001305 if (!(card->flags & ICN_FLAGS_RUNNING))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 return -ENODEV;
1307 if (card->leased)
1308 break;
1309 if ((c->arg & 255) < ICN_BCH) {
1310 char *p;
1311 char dial[50];
1312 char dcode[4];
1313
1314 a = c->arg;
1315 p = c->parm.setup.phone;
1316 if (*p == 's' || *p == 'S') {
1317 /* Dial for SPV */
1318 p++;
1319 strcpy(dcode, "SCA");
1320 } else
1321 /* Normal Dial */
1322 strcpy(dcode, "CAL");
1323 strcpy(dial, p);
1324 sprintf(cbuf, "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1),
1325 dcode, dial, c->parm.setup.si1,
1326 c->parm.setup.si2, c->parm.setup.eazmsn);
1327 i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
1328 }
1329 break;
1330 case ISDN_CMD_ACCEPTD:
Alexey Dobriyaneaa0ff12008-02-06 01:36:06 -08001331 if (!(card->flags & ICN_FLAGS_RUNNING))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 return -ENODEV;
1333 if (c->arg < ICN_BCH) {
1334 a = c->arg + 1;
1335 if (card->fw_rev >= 300) {
1336 switch (card->l2_proto[a - 1]) {
1337 case ISDN_PROTO_L2_X75I:
1338 sprintf(cbuf, "%02d;BX75\n", (int) a);
1339 break;
1340 case ISDN_PROTO_L2_HDLC:
1341 sprintf(cbuf, "%02d;BTRA\n", (int) a);
1342 break;
1343 }
1344 i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
1345 }
1346 sprintf(cbuf, "%02d;DCON_R\n", (int) a);
1347 i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
1348 }
1349 break;
1350 case ISDN_CMD_ACCEPTB:
Alexey Dobriyaneaa0ff12008-02-06 01:36:06 -08001351 if (!(card->flags & ICN_FLAGS_RUNNING))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 return -ENODEV;
1353 if (c->arg < ICN_BCH) {
1354 a = c->arg + 1;
1355 if (card->fw_rev >= 300)
1356 switch (card->l2_proto[a - 1]) {
1357 case ISDN_PROTO_L2_X75I:
1358 sprintf(cbuf, "%02d;BCON_R,BX75\n", (int) a);
1359 break;
1360 case ISDN_PROTO_L2_HDLC:
1361 sprintf(cbuf, "%02d;BCON_R,BTRA\n", (int) a);
1362 break;
1363 } else
1364 sprintf(cbuf, "%02d;BCON_R\n", (int) a);
1365 i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
1366 }
1367 break;
1368 case ISDN_CMD_HANGUP:
Alexey Dobriyaneaa0ff12008-02-06 01:36:06 -08001369 if (!(card->flags & ICN_FLAGS_RUNNING))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 return -ENODEV;
1371 if (c->arg < ICN_BCH) {
1372 a = c->arg + 1;
1373 sprintf(cbuf, "%02d;BDIS_R\n%02d;DDIS_R\n", (int) a, (int) a);
1374 i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
1375 }
1376 break;
1377 case ISDN_CMD_SETEAZ:
Alexey Dobriyaneaa0ff12008-02-06 01:36:06 -08001378 if (!(card->flags & ICN_FLAGS_RUNNING))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 return -ENODEV;
1380 if (card->leased)
1381 break;
1382 if (c->arg < ICN_BCH) {
1383 a = c->arg + 1;
1384 if (card->ptype == ISDN_PTYPE_EURO) {
1385 sprintf(cbuf, "%02d;MS%s%s\n", (int) a,
1386 c->parm.num[0] ? "N" : "ALL", c->parm.num);
1387 } else
1388 sprintf(cbuf, "%02d;EAZ%s\n", (int) a,
1389 c->parm.num[0] ? (char *)(c->parm.num) : "0123456789");
1390 i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
1391 }
1392 break;
1393 case ISDN_CMD_CLREAZ:
Alexey Dobriyaneaa0ff12008-02-06 01:36:06 -08001394 if (!(card->flags & ICN_FLAGS_RUNNING))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 return -ENODEV;
1396 if (card->leased)
1397 break;
1398 if (c->arg < ICN_BCH) {
1399 a = c->arg + 1;
1400 if (card->ptype == ISDN_PTYPE_EURO)
1401 sprintf(cbuf, "%02d;MSNC\n", (int) a);
1402 else
1403 sprintf(cbuf, "%02d;EAZC\n", (int) a);
1404 i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
1405 }
1406 break;
1407 case ISDN_CMD_SETL2:
Alexey Dobriyaneaa0ff12008-02-06 01:36:06 -08001408 if (!(card->flags & ICN_FLAGS_RUNNING))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 return -ENODEV;
1410 if ((c->arg & 255) < ICN_BCH) {
1411 a = c->arg;
1412 switch (a >> 8) {
1413 case ISDN_PROTO_L2_X75I:
1414 sprintf(cbuf, "%02d;BX75\n", (int) (a & 255) + 1);
1415 break;
1416 case ISDN_PROTO_L2_HDLC:
1417 sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1);
1418 break;
1419 default:
1420 return -EINVAL;
1421 }
1422 i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
1423 card->l2_proto[a & 255] = (a >> 8);
1424 }
1425 break;
1426 case ISDN_CMD_SETL3:
Alexey Dobriyaneaa0ff12008-02-06 01:36:06 -08001427 if (!(card->flags & ICN_FLAGS_RUNNING))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 return -ENODEV;
1429 return 0;
1430 default:
1431 return -EINVAL;
1432 }
1433 return 0;
1434}
1435
1436/*
1437 * Find card with given driverId
1438 */
1439static inline icn_card *
1440icn_findcard(int driverid)
1441{
1442 icn_card *p = cards;
1443
1444 while (p) {
1445 if (p->myid == driverid)
1446 return p;
1447 p = p->next;
1448 }
1449 return (icn_card *) 0;
1450}
1451
1452/*
1453 * Wrapper functions for interface to linklevel
1454 */
1455static int
1456if_command(isdn_ctrl * c)
1457{
1458 icn_card *card = icn_findcard(c->driver);
1459
1460 if (card)
1461 return (icn_command(c, card));
1462 printk(KERN_ERR
1463 "icn: if_command %d called with invalid driverId %d!\n",
1464 c->command, c->driver);
1465 return -ENODEV;
1466}
1467
1468static int
1469if_writecmd(const u_char __user *buf, int len, int id, int channel)
1470{
1471 icn_card *card = icn_findcard(id);
1472
1473 if (card) {
Alexey Dobriyaneaa0ff12008-02-06 01:36:06 -08001474 if (!(card->flags & ICN_FLAGS_RUNNING))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 return -ENODEV;
1476 return (icn_writecmd(buf, len, 1, card));
1477 }
1478 printk(KERN_ERR
1479 "icn: if_writecmd called with invalid driverId!\n");
1480 return -ENODEV;
1481}
1482
1483static int
1484if_readstatus(u_char __user *buf, int len, int id, int channel)
1485{
1486 icn_card *card = icn_findcard(id);
1487
1488 if (card) {
Alexey Dobriyaneaa0ff12008-02-06 01:36:06 -08001489 if (!(card->flags & ICN_FLAGS_RUNNING))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 return -ENODEV;
1491 return (icn_readstatus(buf, len, card));
1492 }
1493 printk(KERN_ERR
1494 "icn: if_readstatus called with invalid driverId!\n");
1495 return -ENODEV;
1496}
1497
1498static int
1499if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
1500{
1501 icn_card *card = icn_findcard(id);
1502
1503 if (card) {
Alexey Dobriyaneaa0ff12008-02-06 01:36:06 -08001504 if (!(card->flags & ICN_FLAGS_RUNNING))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 return -ENODEV;
1506 return (icn_sendbuf(channel, ack, skb, card));
1507 }
1508 printk(KERN_ERR
1509 "icn: if_sendbuf called with invalid driverId!\n");
1510 return -ENODEV;
1511}
1512
1513/*
1514 * Allocate a new card-struct, initialize it
1515 * link it into cards-list and register it at linklevel.
1516 */
1517static icn_card *
1518icn_initcard(int port, char *id)
1519{
1520 icn_card *card;
1521 int i;
1522
Burman Yan41f96932006-12-08 02:39:35 -08001523 if (!(card = kzalloc(sizeof(icn_card), GFP_KERNEL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 printk(KERN_WARNING
1525 "icn: (%s) Could not allocate card-struct.\n", id);
1526 return (icn_card *) 0;
1527 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 spin_lock_init(&card->lock);
1529 card->port = port;
1530 card->interface.owner = THIS_MODULE;
1531 card->interface.hl_hdrlen = 1;
1532 card->interface.channels = ICN_BCH;
1533 card->interface.maxbufsize = 4000;
1534 card->interface.command = if_command;
1535 card->interface.writebuf_skb = if_sendbuf;
1536 card->interface.writecmd = if_writecmd;
1537 card->interface.readstat = if_readstatus;
1538 card->interface.features = ISDN_FEATURE_L2_X75I |
1539 ISDN_FEATURE_L2_HDLC |
1540 ISDN_FEATURE_L3_TRANS |
1541 ISDN_FEATURE_P_UNKNOWN;
1542 card->ptype = ISDN_PTYPE_UNKNOWN;
1543 strlcpy(card->interface.id, id, sizeof(card->interface.id));
1544 card->msg_buf_write = card->msg_buf;
1545 card->msg_buf_read = card->msg_buf;
1546 card->msg_buf_end = &card->msg_buf[sizeof(card->msg_buf) - 1];
1547 for (i = 0; i < ICN_BCH; i++) {
1548 card->l2_proto[i] = ISDN_PROTO_L2_X75I;
1549 skb_queue_head_init(&card->spqueue[i]);
1550 }
1551 card->next = cards;
1552 cards = card;
1553 if (!register_isdn(&card->interface)) {
1554 cards = cards->next;
1555 printk(KERN_WARNING
1556 "icn: Unable to register %s\n", id);
1557 kfree(card);
1558 return (icn_card *) 0;
1559 }
1560 card->myid = card->interface.channels;
1561 sprintf(card->regname, "icn-isdn (%s)", card->interface.id);
1562 return card;
1563}
1564
1565static int
1566icn_addcard(int port, char *id1, char *id2)
1567{
1568 icn_card *card;
1569 icn_card *card2;
1570
1571 if (!(card = icn_initcard(port, id1))) {
1572 return -EIO;
1573 }
1574 if (!strlen(id2)) {
1575 printk(KERN_INFO
1576 "icn: (%s) ICN-2B, port 0x%x added\n",
1577 card->interface.id, port);
1578 return 0;
1579 }
1580 if (!(card2 = icn_initcard(port, id2))) {
1581 printk(KERN_INFO
1582 "icn: (%s) half ICN-4B, port 0x%x added\n",
1583 card2->interface.id, port);
1584 return 0;
1585 }
1586 card->doubleS0 = 1;
1587 card->secondhalf = 0;
1588 card->other = card2;
1589 card2->doubleS0 = 1;
1590 card2->secondhalf = 1;
1591 card2->other = card;
1592 printk(KERN_INFO
1593 "icn: (%s and %s) ICN-4B, port 0x%x added\n",
1594 card->interface.id, card2->interface.id, port);
1595 return 0;
1596}
1597
1598#ifndef MODULE
1599static int __init
1600icn_setup(char *line)
1601{
1602 char *p, *str;
1603 int ints[3];
1604 static char sid[20];
1605 static char sid2[20];
1606
1607 str = get_options(line, 2, ints);
1608 if (ints[0])
1609 portbase = ints[1];
1610 if (ints[0] > 1)
1611 membase = (unsigned long)ints[2];
1612 if (str && *str) {
1613 strcpy(sid, str);
1614 icn_id = sid;
1615 if ((p = strchr(sid, ','))) {
1616 *p++ = 0;
1617 strcpy(sid2, p);
1618 icn_id2 = sid2;
1619 }
1620 }
1621 return(1);
1622}
1623__setup("icn=", icn_setup);
1624#endif /* MODULE */
1625
1626static int __init icn_init(void)
1627{
1628 char *p;
1629 char rev[10];
1630
1631 memset(&dev, 0, sizeof(icn_dev));
1632 dev.memaddr = (membase & 0x0ffc000);
1633 dev.channel = -1;
1634 dev.mcard = NULL;
1635 dev.firstload = 1;
1636 spin_lock_init(&dev.devlock);
1637
1638 if ((p = strchr(revision, ':'))) {
1639 strcpy(rev, p + 1);
1640 p = strchr(rev, '$');
1641 *p = 0;
1642 } else
1643 strcpy(rev, " ??? ");
1644 printk(KERN_NOTICE "ICN-ISDN-driver Rev%smem=0x%08lx\n", rev,
1645 dev.memaddr);
1646 return (icn_addcard(portbase, icn_id, icn_id2));
1647}
1648
1649static void __exit icn_exit(void)
1650{
1651 isdn_ctrl cmd;
1652 icn_card *card = cards;
Dave Jones138b9dd2005-08-08 16:13:15 -07001653 icn_card *last, *tmpcard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 int i;
1655 unsigned long flags;
1656
1657 icn_stopallcards();
1658 while (card) {
1659 cmd.command = ISDN_STAT_UNLOAD;
1660 cmd.driver = card->myid;
1661 card->interface.statcallb(&cmd);
1662 spin_lock_irqsave(&card->lock, flags);
1663 if (card->rvalid) {
1664 OUTB_P(0, ICN_RUN); /* Reset Controller */
1665 OUTB_P(0, ICN_MAPRAM); /* Disable RAM */
1666 if (card->secondhalf || (!card->doubleS0)) {
1667 release_region(card->port, ICN_PORTLEN);
1668 card->rvalid = 0;
1669 }
1670 for (i = 0; i < ICN_BCH; i++)
1671 icn_free_queue(card, i);
1672 }
Dave Jones138b9dd2005-08-08 16:13:15 -07001673 tmpcard = card->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 spin_unlock_irqrestore(&card->lock, flags);
Dave Jones138b9dd2005-08-08 16:13:15 -07001675 card = tmpcard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 }
1677 card = cards;
1678 cards = NULL;
1679 while (card) {
1680 last = card;
1681 card = card->next;
1682 kfree(last);
1683 }
1684 if (dev.mvalid) {
1685 iounmap(dev.shmem);
1686 release_mem_region(dev.memaddr, 0x4000);
1687 }
1688 printk(KERN_NOTICE "ICN-ISDN-driver unloaded\n");
1689}
1690
1691module_init(icn_init);
1692module_exit(icn_exit);