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