blob: 6a7447c304acc39e6edc422bf8f6533acfde93b5 [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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090015#include <linux/slab.h>
Alexey Dobriyane8edc6e2007-05-21 01:22:52 +040016#include <linux/sched.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017
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
Joe Perches475be4d2012-02-19 19:52:38 -080057icn_free_queue(icn_card *card, int channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -070058{
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;
65 if ((skb = card->xskb[channel])) {
66 card->xskb[channel] = NULL;
67 dev_kfree_skb(skb);
68 }
69}
70
71/* Put a value into a shift-register, highest bit first.
72 * Parameters:
73 * port = port for output (bit 0 is significant)
74 * val = value to be output
75 * firstbit = Bit-Number of highest bit
76 * bitcount = Number of bits to output
77 */
78static inline void
79icn_shiftout(unsigned short port,
80 unsigned long val,
81 int firstbit,
82 int bitcount)
83{
84
85 register u_char s;
86 register u_char c;
87
88 for (s = firstbit, c = bitcount; c > 0; s--, c--)
89 OUTB_P((u_char) ((val >> s) & 1) ? 0xff : 0, port);
90}
91
92/*
93 * disable a cards shared memory
94 */
95static inline void
Joe Perches475be4d2012-02-19 19:52:38 -080096icn_disable_ram(icn_card *card)
Linus Torvalds1da177e2005-04-16 15:20:36 -070097{
98 OUTB_P(0, ICN_MAPRAM);
99}
100
101/*
102 * enable a cards shared memory
103 */
104static inline void
Joe Perches475be4d2012-02-19 19:52:38 -0800105icn_enable_ram(icn_card *card)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106{
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
Joe Perches475be4d2012-02-19 19:52:38 -0800116icn_map_channel(icn_card *card, int channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117{
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
Joe Perches475be4d2012-02-19 19:52:38 -0800142icn_lock_channel(icn_card *card, int channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143{
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
Joe Perches475be4d2012-02-19 19:52:38 -0800197icn_trymaplock_channel(icn_card *card, int channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198{
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
Joe Perches475be4d2012-02-19 19:52:38 -0800228icn_maprelease_channel(icn_card *card, int channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229{
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
Joe Perches475be4d2012-02-19 19:52:38 -0800249icn_pollbchan_receive(int channel, icn_card *card)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250{
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) {
275 if ((cnt = card->rcvidx[channel])) {
276 if (!(skb = dev_alloc_skb(cnt))) {
277 printk(KERN_WARNING "icn: receive out of memory\n");
278 break;
279 }
280 memcpy(skb_put(skb, cnt), card->rcvbuf[channel], cnt);
281 card->rcvidx[channel] = 0;
282 card->interface.rcvcallb_skb(card->myid, channel, skb);
283 }
284 }
285 if (!icn_trymaplock_channel(card, mch))
286 break;
287 }
288 icn_maprelease_channel(card, mch & 2);
289 }
290}
291
292/* Send data-packet to B-Channel, split it up into fragments of
293 * ICN_FRAGSIZE length. If last fragment is sent out, signal
294 * success to upper layers via statcallb with ISDN_STAT_BSENT argument.
295 * This routine is called via timer-callback from icn_pollbchan() or
296 * directly from icn_sendbuf().
297 */
298
299static void
Joe Perches475be4d2012-02-19 19:52:38 -0800300icn_pollbchan_send(int channel, icn_card *card)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301{
302 int mch = channel + ((card->secondhalf) ? 2 : 0);
303 int cnt;
304 unsigned long flags;
305 struct sk_buff *skb;
306 isdn_ctrl cmd;
307
308 if (!(card->sndcount[channel] || card->xskb[channel] ||
David S. Millerb03efcf2005-07-08 14:57:23 -0700309 !skb_queue_empty(&card->spqueue[channel])))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 return;
311 if (icn_trymaplock_channel(card, mch)) {
Joe Perches475be4d2012-02-19 19:52:38 -0800312 while (sbfree &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 (card->sndcount[channel] ||
David S. Millerb03efcf2005-07-08 14:57:23 -0700314 !skb_queue_empty(&card->spqueue[channel]) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 card->xskb[channel])) {
316 spin_lock_irqsave(&card->lock, flags);
317 if (card->xmit_lock[channel]) {
318 spin_unlock_irqrestore(&card->lock, flags);
319 break;
320 }
321 card->xmit_lock[channel]++;
322 spin_unlock_irqrestore(&card->lock, flags);
323 skb = card->xskb[channel];
324 if (!skb) {
325 skb = skb_dequeue(&card->spqueue[channel]);
326 if (skb) {
327 /* Pop ACK-flag off skb.
328 * Store length to xlen.
329 */
Joe Perches475be4d2012-02-19 19:52:38 -0800330 if (*(skb_pull(skb, 1)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 card->xlen[channel] = skb->len;
332 else
333 card->xlen[channel] = 0;
334 }
335 }
336 if (!skb)
337 break;
338 if (skb->len > ICN_FRAGSIZE) {
339 writeb(0xff, &sbuf_f);
340 cnt = ICN_FRAGSIZE;
341 } else {
342 writeb(0x0, &sbuf_f);
343 cnt = skb->len;
344 }
345 writeb(cnt, &sbuf_l);
346 memcpy_toio(&sbuf_d, skb->data, cnt);
347 skb_pull(skb, cnt);
348 sbnext; /* switch to next buffer */
349 icn_maprelease_channel(card, mch & 2);
350 spin_lock_irqsave(&card->lock, flags);
351 card->sndcount[channel] -= cnt;
352 if (!skb->len) {
353 if (card->xskb[channel])
354 card->xskb[channel] = NULL;
355 card->xmit_lock[channel] = 0;
356 spin_unlock_irqrestore(&card->lock, flags);
357 dev_kfree_skb(skb);
358 if (card->xlen[channel]) {
359 cmd.command = ISDN_STAT_BSENT;
360 cmd.driver = card->myid;
361 cmd.arg = channel;
362 cmd.parm.length = card->xlen[channel];
363 card->interface.statcallb(&cmd);
364 }
365 } else {
366 card->xskb[channel] = skb;
367 card->xmit_lock[channel] = 0;
368 spin_unlock_irqrestore(&card->lock, flags);
369 }
370 if (!icn_trymaplock_channel(card, mch))
371 break;
372 }
373 icn_maprelease_channel(card, mch & 2);
374 }
375}
376
377/* Send/Receive Data to/from the B-Channel.
378 * This routine is called via timer-callback.
379 * It schedules itself while any B-Channel is open.
380 */
381
382static void
383icn_pollbchan(unsigned long data)
384{
385 icn_card *card = (icn_card *) data;
386 unsigned long flags;
387
388 if (card->flags & ICN_FLAGS_B1ACTIVE) {
389 icn_pollbchan_receive(0, card);
390 icn_pollbchan_send(0, card);
391 }
392 if (card->flags & ICN_FLAGS_B2ACTIVE) {
393 icn_pollbchan_receive(1, card);
394 icn_pollbchan_send(1, card);
395 }
396 if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE)) {
397 /* schedule b-channel polling again */
398 spin_lock_irqsave(&card->lock, flags);
Joe Perches475be4d2012-02-19 19:52:38 -0800399 mod_timer(&card->rb_timer, jiffies + ICN_TIMER_BCREAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 card->flags |= ICN_FLAGS_RBTIMER;
401 spin_unlock_irqrestore(&card->lock, flags);
402 } else
403 card->flags &= ~ICN_FLAGS_RBTIMER;
404}
405
406typedef struct icn_stat {
407 char *statstr;
408 int command;
409 int action;
410} icn_stat;
411/* *INDENT-OFF* */
412static icn_stat icn_stat_table[] =
413{
414 {"BCON_", ISDN_STAT_BCONN, 1}, /* B-Channel connected */
415 {"BDIS_", ISDN_STAT_BHUP, 2}, /* B-Channel disconnected */
416 /*
417 ** add d-channel connect and disconnect support to link-level
418 */
419 {"DCON_", ISDN_STAT_DCONN, 10}, /* D-Channel connected */
420 {"DDIS_", ISDN_STAT_DHUP, 11}, /* D-Channel disconnected */
421 {"DCAL_I", ISDN_STAT_ICALL, 3}, /* Incoming call dialup-line */
422 {"DSCA_I", ISDN_STAT_ICALL, 3}, /* Incoming call 1TR6-SPV */
423 {"FCALL", ISDN_STAT_ICALL, 4}, /* Leased line connection up */
424 {"CIF", ISDN_STAT_CINF, 5}, /* Charge-info, 1TR6-type */
425 {"AOC", ISDN_STAT_CINF, 6}, /* Charge-info, DSS1-type */
426 {"CAU", ISDN_STAT_CAUSE, 7}, /* Cause code */
427 {"TEI OK", ISDN_STAT_RUN, 0}, /* Card connected to wallplug */
428 {"E_L1: ACT FAIL", ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */
429 {"E_L2: DATA LIN", ISDN_STAT_BHUP, 8}, /* Layer-2 data link lost */
430 {"E_L1: ACTIVATION FAILED",
Joe Perches475be4d2012-02-19 19:52:38 -0800431 ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 {NULL, 0, -1}
433};
434/* *INDENT-ON* */
435
436
437/*
438 * Check Statusqueue-Pointer from isdn-cards.
439 * If there are new status-replies from the interface, check
440 * them against B-Channel-connects/disconnects and set flags accordingly.
441 * Wake-Up any processes, who are reading the status-device.
442 * If there are B-Channels open, initiate a timer-callback to
443 * icn_pollbchan().
444 * This routine is called periodically via timer.
445 */
446
447static void
Joe Perches475be4d2012-02-19 19:52:38 -0800448icn_parse_status(u_char *status, int channel, icn_card *card)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449{
450 icn_stat *s = icn_stat_table;
451 int action = -1;
452 unsigned long flags;
453 isdn_ctrl cmd;
454
455 while (s->statstr) {
456 if (!strncmp(status, s->statstr, strlen(s->statstr))) {
457 cmd.command = s->command;
458 action = s->action;
459 break;
460 }
461 s++;
462 }
463 if (action == -1)
464 return;
465 cmd.driver = card->myid;
466 cmd.arg = channel;
467 switch (action) {
Joe Perches475be4d2012-02-19 19:52:38 -0800468 case 11:
469 spin_lock_irqsave(&card->lock, flags);
470 icn_free_queue(card, channel);
471 card->rcvidx[channel] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472
Joe Perches475be4d2012-02-19 19:52:38 -0800473 if (card->flags &
474 ((channel) ? ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE)) {
475
476 isdn_ctrl ncmd;
477
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 card->flags &= ~((channel) ?
Joe Perches475be4d2012-02-19 19:52:38 -0800479 ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480
Joe Perches475be4d2012-02-19 19:52:38 -0800481 memset(&ncmd, 0, sizeof(ncmd));
482
483 ncmd.driver = card->myid;
484 ncmd.arg = channel;
485 ncmd.command = ISDN_STAT_BHUP;
486 spin_unlock_irqrestore(&card->lock, flags);
487 card->interface.statcallb(&cmd);
488 } else
489 spin_unlock_irqrestore(&card->lock, flags);
490 break;
491 case 1:
492 spin_lock_irqsave(&card->lock, flags);
493 icn_free_queue(card, channel);
494 card->flags |= (channel) ?
495 ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE;
496 spin_unlock_irqrestore(&card->lock, flags);
497 break;
498 case 2:
499 spin_lock_irqsave(&card->lock, flags);
500 card->flags &= ~((channel) ?
501 ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE);
502 icn_free_queue(card, channel);
503 card->rcvidx[channel] = 0;
504 spin_unlock_irqrestore(&card->lock, flags);
505 break;
506 case 3:
507 {
508 char *t = status + 6;
509 char *s = strchr(t, ',');
510
511 *s++ = '\0';
512 strlcpy(cmd.parm.setup.phone, t,
513 sizeof(cmd.parm.setup.phone));
514 s = strchr(t = s, ',');
515 *s++ = '\0';
516 if (!strlen(t))
517 cmd.parm.setup.si1 = 0;
518 else
519 cmd.parm.setup.si1 =
520 simple_strtoul(t, NULL, 10);
521 s = strchr(t = s, ',');
522 *s++ = '\0';
523 if (!strlen(t))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 cmd.parm.setup.si2 = 0;
Joe Perches475be4d2012-02-19 19:52:38 -0800525 else
526 cmd.parm.setup.si2 =
527 simple_strtoul(t, NULL, 10);
528 strlcpy(cmd.parm.setup.eazmsn, s,
529 sizeof(cmd.parm.setup.eazmsn));
530 }
531 cmd.parm.setup.plan = 0;
532 cmd.parm.setup.screen = 0;
533 break;
534 case 4:
535 sprintf(cmd.parm.setup.phone, "LEASED%d", card->myid);
536 sprintf(cmd.parm.setup.eazmsn, "%d", channel + 1);
537 cmd.parm.setup.si1 = 7;
538 cmd.parm.setup.si2 = 0;
539 cmd.parm.setup.plan = 0;
540 cmd.parm.setup.screen = 0;
541 break;
542 case 5:
543 strlcpy(cmd.parm.num, status + 3, sizeof(cmd.parm.num));
544 break;
545 case 6:
546 snprintf(cmd.parm.num, sizeof(cmd.parm.num), "%d",
547 (int) simple_strtoul(status + 7, NULL, 16));
548 break;
549 case 7:
550 status += 3;
551 if (strlen(status) == 4)
552 snprintf(cmd.parm.num, sizeof(cmd.parm.num), "%s%c%c",
553 status + 2, *status, *(status + 1));
554 else
555 strlcpy(cmd.parm.num, status + 1, sizeof(cmd.parm.num));
556 break;
557 case 8:
558 spin_lock_irqsave(&card->lock, flags);
559 card->flags &= ~ICN_FLAGS_B1ACTIVE;
560 icn_free_queue(card, 0);
561 card->rcvidx[0] = 0;
562 spin_unlock_irqrestore(&card->lock, flags);
563 cmd.arg = 0;
564 cmd.driver = card->myid;
565 card->interface.statcallb(&cmd);
566 cmd.command = ISDN_STAT_DHUP;
567 cmd.arg = 0;
568 cmd.driver = card->myid;
569 card->interface.statcallb(&cmd);
570 cmd.command = ISDN_STAT_BHUP;
571 spin_lock_irqsave(&card->lock, flags);
572 card->flags &= ~ICN_FLAGS_B2ACTIVE;
573 icn_free_queue(card, 1);
574 card->rcvidx[1] = 0;
575 spin_unlock_irqrestore(&card->lock, flags);
576 cmd.arg = 1;
577 cmd.driver = card->myid;
578 card->interface.statcallb(&cmd);
579 cmd.command = ISDN_STAT_DHUP;
580 cmd.arg = 1;
581 cmd.driver = card->myid;
582 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 }
584 card->interface.statcallb(&cmd);
585 return;
586}
587
588static void
Joe Perches475be4d2012-02-19 19:52:38 -0800589icn_putmsg(icn_card *card, unsigned char c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590{
591 ulong flags;
592
593 spin_lock_irqsave(&card->lock, flags);
594 *card->msg_buf_write++ = (c == 0xff) ? '\n' : c;
595 if (card->msg_buf_write == card->msg_buf_read) {
596 if (++card->msg_buf_read > card->msg_buf_end)
597 card->msg_buf_read = card->msg_buf;
598 }
599 if (card->msg_buf_write > card->msg_buf_end)
600 card->msg_buf_write = card->msg_buf;
601 spin_unlock_irqrestore(&card->lock, flags);
602}
603
604static void
605icn_polldchan(unsigned long data)
606{
607 icn_card *card = (icn_card *) data;
608 int mch = card->secondhalf ? 2 : 0;
609 int avail = 0;
610 int left;
611 u_char c;
612 int ch;
613 unsigned long flags;
614 int i;
615 u_char *p;
616 isdn_ctrl cmd;
617
618 if (icn_trymaplock_channel(card, mch)) {
619 avail = msg_avail;
620 for (left = avail, i = readb(&msg_o); left > 0; i++, left--) {
621 c = readb(&dev.shmem->comm_buffers.iopc_buf[i & 0xff]);
622 icn_putmsg(card, c);
623 if (c == 0xff) {
624 card->imsg[card->iptr] = 0;
625 card->iptr = 0;
626 if (card->imsg[0] == '0' && card->imsg[1] >= '0' &&
627 card->imsg[1] <= '2' && card->imsg[2] == ';') {
628 ch = (card->imsg[1] - '0') - 1;
629 p = &card->imsg[3];
630 icn_parse_status(p, ch, card);
631 } else {
632 p = card->imsg;
633 if (!strncmp(p, "DRV1.", 5)) {
634 u_char vstr[10];
635 u_char *q = vstr;
636
637 printk(KERN_INFO "icn: (%s) %s\n", CID, p);
638 if (!strncmp(p + 7, "TC", 2)) {
639 card->ptype = ISDN_PTYPE_1TR6;
640 card->interface.features |= ISDN_FEATURE_P_1TR6;
641 printk(KERN_INFO
642 "icn: (%s) 1TR6-Protocol loaded and running\n", CID);
643 }
644 if (!strncmp(p + 7, "EC", 2)) {
645 card->ptype = ISDN_PTYPE_EURO;
646 card->interface.features |= ISDN_FEATURE_P_EURO;
647 printk(KERN_INFO
648 "icn: (%s) Euro-Protocol loaded and running\n", CID);
649 }
650 p = strstr(card->imsg, "BRV") + 3;
651 while (*p) {
652 if (*p >= '0' && *p <= '9')
653 *q++ = *p;
654 p++;
655 }
656 *q = '\0';
657 strcat(vstr, "000");
658 vstr[3] = '\0';
659 card->fw_rev = (int) simple_strtoul(vstr, NULL, 10);
660 continue;
661
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;
686 card->rb_timer.data = (unsigned long) card;
687 card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD;
688 add_timer(&card->rb_timer);
689 }
690 /* schedule again */
Joe Perches475be4d2012-02-19 19:52:38 -0800691 mod_timer(&card->st_timer, jiffies + ICN_TIMER_DCREAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 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
Joe Perches475be4d2012-02-19 19:52:38 -0800705icn_sendbuf(int channel, int ack, struct sk_buff *skb, icn_card *card)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706{
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;
Joe Perches475be4d2012-02-19 19:52:38 -0800721#warning TODO test headroom or use skb->nb to flag ACK
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 nskb = skb_clone(skb, GFP_ATOMIC);
723 if (nskb) {
724 /* Push ACK flag as one
725 * byte in front of data.
726 */
Joe Perches475be4d2012-02-19 19:52:38 -0800727 *(skb_push(nskb, 1)) = ack ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 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
Joe Perches475be4d2012-02-19 19:52:38 -0800788#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 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796#else
797#define SLEEP(sec)
798#endif
799
800static int
Joe Perches475be4d2012-02-19 19:52:38 -0800801icn_loadboot(u_char __user *buffer, icn_card *card)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802{
803 int ret;
804 u_char *codebuf;
805 unsigned long flags;
806
807#ifdef BOOT_DEBUG
808 printk(KERN_DEBUG "icn_loadboot called, buffaddr=%08lx\n", (ulong) buffer);
809#endif
810 if (!(codebuf = kmalloc(ICN_CODE_STAGE1, GFP_KERNEL))) {
811 printk(KERN_WARNING "icn: Could not allocate code buffer\n");
812 ret = -ENOMEM;
813 goto out;
814 }
815 if (copy_from_user(codebuf, buffer, ICN_CODE_STAGE1)) {
816 ret = -EFAULT;
817 goto out_kfree;
818 }
819 if (!card->rvalid) {
820 if (!request_region(card->port, ICN_PORTLEN, card->regname)) {
821 printk(KERN_WARNING
822 "icn: (%s) ports 0x%03x-0x%03x in use.\n",
823 CID,
824 card->port,
825 card->port + ICN_PORTLEN);
826 ret = -EBUSY;
827 goto out_kfree;
828 }
829 card->rvalid = 1;
830 if (card->doubleS0)
831 card->other->rvalid = 1;
832 }
833 if (!dev.mvalid) {
834 if (!request_mem_region(dev.memaddr, 0x4000, "icn-isdn (all cards)")) {
835 printk(KERN_WARNING
836 "icn: memory at 0x%08lx in use.\n", dev.memaddr);
837 ret = -EBUSY;
838 goto out_kfree;
839 }
840 dev.shmem = ioremap(dev.memaddr, 0x4000);
841 dev.mvalid = 1;
842 }
843 OUTB_P(0, ICN_RUN); /* Reset Controller */
844 OUTB_P(0, ICN_MAPRAM); /* Disable RAM */
845 icn_shiftout(ICN_CFG, 0x0f, 3, 4); /* Windowsize= 16k */
846 icn_shiftout(ICN_CFG, dev.memaddr, 23, 10); /* Set RAM-Addr. */
847#ifdef BOOT_DEBUG
848 printk(KERN_DEBUG "shmem=%08lx\n", dev.memaddr);
849#endif
850 SLEEP(1);
851#ifdef BOOT_DEBUG
852 printk(KERN_DEBUG "Map Bank 0\n");
853#endif
854 spin_lock_irqsave(&dev.devlock, flags);
855 icn_map_channel(card, 0); /* Select Bank 0 */
856 icn_lock_channel(card, 0); /* Lock Bank 0 */
857 spin_unlock_irqrestore(&dev.devlock, flags);
858 SLEEP(1);
859 memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); /* Copy code */
860#ifdef BOOT_DEBUG
861 printk(KERN_DEBUG "Bootloader transferred\n");
862#endif
863 if (card->doubleS0) {
864 SLEEP(1);
865#ifdef BOOT_DEBUG
866 printk(KERN_DEBUG "Map Bank 8\n");
867#endif
868 spin_lock_irqsave(&dev.devlock, flags);
869 __icn_release_channel();
870 icn_map_channel(card, 2); /* Select Bank 8 */
871 icn_lock_channel(card, 2); /* Lock Bank 8 */
872 spin_unlock_irqrestore(&dev.devlock, flags);
873 SLEEP(1);
874 memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); /* Copy code */
875#ifdef BOOT_DEBUG
876 printk(KERN_DEBUG "Bootloader transferred\n");
877#endif
878 }
879 SLEEP(1);
880 OUTB_P(0xff, ICN_RUN); /* Start Boot-Code */
881 if ((ret = icn_check_loader(card->doubleS0 ? 2 : 1))) {
882 goto out_kfree;
883 }
884 if (!card->doubleS0) {
885 ret = 0;
886 goto out_kfree;
887 }
888 /* reached only, if we have a Double-S0-Card */
889#ifdef BOOT_DEBUG
890 printk(KERN_DEBUG "Map Bank 0\n");
891#endif
892 spin_lock_irqsave(&dev.devlock, flags);
893 icn_map_channel(card, 0); /* Select Bank 0 */
894 icn_lock_channel(card, 0); /* Lock Bank 0 */
895 spin_unlock_irqrestore(&dev.devlock, flags);
896 SLEEP(1);
897 ret = (icn_check_loader(1));
898
Joe Perches475be4d2012-02-19 19:52:38 -0800899out_kfree:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 kfree(codebuf);
Joe Perches475be4d2012-02-19 19:52:38 -0800901out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 return ret;
903}
904
905static int
Joe Perches475be4d2012-02-19 19:52:38 -0800906icn_loadproto(u_char __user *buffer, icn_card *card)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907{
908 register u_char __user *p = buffer;
909 u_char codebuf[256];
910 uint left = ICN_CODE_STAGE2;
911 uint cnt;
912 int timer;
913 unsigned long flags;
914
915#ifdef BOOT_DEBUG
916 printk(KERN_DEBUG "icn_loadproto called\n");
917#endif
918 if (!access_ok(VERIFY_READ, buffer, ICN_CODE_STAGE2))
919 return -EFAULT;
920 timer = 0;
921 spin_lock_irqsave(&dev.devlock, flags);
922 if (card->secondhalf) {
923 icn_map_channel(card, 2);
924 icn_lock_channel(card, 2);
925 } else {
926 icn_map_channel(card, 0);
927 icn_lock_channel(card, 0);
928 }
929 spin_unlock_irqrestore(&dev.devlock, flags);
930 while (left) {
931 if (sbfree) { /* If there is a free buffer... */
932 cnt = left;
933 if (cnt > 256)
934 cnt = 256;
935 if (copy_from_user(codebuf, p, cnt)) {
936 icn_maprelease_channel(card, 0);
937 return -EFAULT;
938 }
939 memcpy_toio(&sbuf_l, codebuf, cnt); /* copy data */
940 sbnext; /* switch to next buffer */
941 p += cnt;
942 left -= cnt;
943 timer = 0;
944 } else {
945#ifdef BOOT_DEBUG
946 printk(KERN_DEBUG "boot 2 !sbfree\n");
947#endif
948 if (timer++ > 5) {
949 icn_maprelease_channel(card, 0);
950 return -EIO;
951 }
Nishanth Aravamudan24763c42005-11-07 01:01:16 -0800952 schedule_timeout_interruptible(10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 }
954 }
955 writeb(0x20, &sbuf_n);
956 timer = 0;
957 while (1) {
958 if (readb(&cmd_o) || readb(&cmd_i)) {
959#ifdef BOOT_DEBUG
960 printk(KERN_DEBUG "Proto?\n");
961#endif
962 if (timer++ > 5) {
963 printk(KERN_WARNING
964 "icn: (%s) Protocol timed out.\n",
965 CID);
966#ifdef BOOT_DEBUG
967 printk(KERN_DEBUG "Proto TO!\n");
968#endif
969 icn_maprelease_channel(card, 0);
970 return -EIO;
971 }
972#ifdef BOOT_DEBUG
973 printk(KERN_DEBUG "Proto TO?\n");
974#endif
975 msleep_interruptible(ICN_BOOT_TIMEOUT1);
976 } else {
977 if ((card->secondhalf) || (!card->doubleS0)) {
978#ifdef BOOT_DEBUG
979 printk(KERN_DEBUG "Proto loaded, install poll-timer %d\n",
980 card->secondhalf);
981#endif
982 spin_lock_irqsave(&card->lock, flags);
983 init_timer(&card->st_timer);
984 card->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
985 card->st_timer.function = icn_polldchan;
986 card->st_timer.data = (unsigned long) card;
987 add_timer(&card->st_timer);
988 card->flags |= ICN_FLAGS_RUNNING;
989 if (card->doubleS0) {
990 init_timer(&card->other->st_timer);
991 card->other->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
992 card->other->st_timer.function = icn_polldchan;
993 card->other->st_timer.data = (unsigned long) card->other;
994 add_timer(&card->other->st_timer);
995 card->other->flags |= ICN_FLAGS_RUNNING;
996 }
997 spin_unlock_irqrestore(&card->lock, flags);
998 }
999 icn_maprelease_channel(card, 0);
1000 return 0;
1001 }
1002 }
1003}
1004
1005/* Read the Status-replies from the Interface */
1006static int
Joe Perches475be4d2012-02-19 19:52:38 -08001007icn_readstatus(u_char __user *buf, int len, icn_card *card)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008{
1009 int count;
1010 u_char __user *p;
1011
1012 for (p = buf, count = 0; count < len; p++, count++) {
1013 if (card->msg_buf_read == card->msg_buf_write)
1014 return count;
Jeff Garzik7786ce12006-10-17 00:10:40 -07001015 if (put_user(*card->msg_buf_read++, p))
1016 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 if (card->msg_buf_read > card->msg_buf_end)
1018 card->msg_buf_read = card->msg_buf;
1019 }
1020 return count;
1021}
1022
1023/* Put command-strings into the command-queue of the Interface */
1024static int
Joe Perches475be4d2012-02-19 19:52:38 -08001025icn_writecmd(const u_char *buf, int len, int user, icn_card *card)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026{
1027 int mch = card->secondhalf ? 2 : 0;
1028 int pp;
1029 int i;
1030 int count;
1031 int xcount;
1032 int ocount;
1033 int loop;
1034 unsigned long flags;
1035 int lastmap_channel;
1036 struct icn_card *lastmap_card;
1037 u_char *p;
1038 isdn_ctrl cmd;
1039 u_char msg[0x100];
1040
1041 ocount = 1;
1042 xcount = loop = 0;
1043 while (len) {
1044 count = cmd_free;
1045 if (count > len)
1046 count = len;
1047 if (user) {
1048 if (copy_from_user(msg, buf, count))
1049 return -EFAULT;
1050 } else
1051 memcpy(msg, buf, count);
1052
1053 spin_lock_irqsave(&dev.devlock, flags);
1054 lastmap_card = dev.mcard;
1055 lastmap_channel = dev.channel;
1056 icn_map_channel(card, mch);
1057
1058 icn_putmsg(card, '>');
1059 for (p = msg, pp = readb(&cmd_i), i = count; i > 0; i--, p++, pp
Joe Perches475be4d2012-02-19 19:52:38 -08001060 ++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 writeb((*p == '\n') ? 0xff : *p,
Joe Perches475be4d2012-02-19 19:52:38 -08001062 &dev.shmem->comm_buffers.pcio_buf[pp & 0xff]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 len--;
1064 xcount++;
1065 icn_putmsg(card, *p);
1066 if ((*p == '\n') && (i > 1)) {
1067 icn_putmsg(card, '>');
1068 ocount++;
1069 }
1070 ocount++;
1071 }
1072 writeb((readb(&cmd_i) + count) & 0xff, &cmd_i);
1073 if (lastmap_card)
1074 icn_map_channel(lastmap_card, lastmap_channel);
1075 spin_unlock_irqrestore(&dev.devlock, flags);
1076 if (len) {
1077 mdelay(1);
1078 if (loop++ > 20)
1079 break;
1080 } else
1081 break;
1082 }
1083 if (len && (!user))
1084 printk(KERN_WARNING "icn: writemsg incomplete!\n");
1085 cmd.command = ISDN_STAT_STAVAIL;
1086 cmd.driver = card->myid;
1087 cmd.arg = ocount;
1088 card->interface.statcallb(&cmd);
1089 return xcount;
1090}
1091
1092/*
1093 * Delete card's pending timers, send STOP to linklevel
1094 */
1095static void
Joe Perches475be4d2012-02-19 19:52:38 -08001096icn_stopcard(icn_card *card)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097{
1098 unsigned long flags;
1099 isdn_ctrl cmd;
1100
1101 spin_lock_irqsave(&card->lock, flags);
1102 if (card->flags & ICN_FLAGS_RUNNING) {
1103 card->flags &= ~ICN_FLAGS_RUNNING;
1104 del_timer(&card->st_timer);
1105 del_timer(&card->rb_timer);
1106 spin_unlock_irqrestore(&card->lock, flags);
1107 cmd.command = ISDN_STAT_STOP;
1108 cmd.driver = card->myid;
1109 card->interface.statcallb(&cmd);
1110 if (card->doubleS0)
1111 icn_stopcard(card->other);
1112 } else
1113 spin_unlock_irqrestore(&card->lock, flags);
1114}
1115
1116static void
1117icn_stopallcards(void)
1118{
1119 icn_card *p = cards;
1120
1121 while (p) {
1122 icn_stopcard(p);
1123 p = p->next;
1124 }
1125}
1126
1127/*
1128 * Unmap all cards, because some of them may be mapped accidetly during
1129 * autoprobing of some network drivers (SMC-driver?)
1130 */
1131static void
1132icn_disable_cards(void)
1133{
1134 icn_card *card = cards;
1135
1136 while (card) {
1137 if (!request_region(card->port, ICN_PORTLEN, "icn-isdn")) {
1138 printk(KERN_WARNING
1139 "icn: (%s) ports 0x%03x-0x%03x in use.\n",
1140 CID,
1141 card->port,
1142 card->port + ICN_PORTLEN);
1143 } else {
1144 OUTB_P(0, ICN_RUN); /* Reset Controller */
1145 OUTB_P(0, ICN_MAPRAM); /* Disable RAM */
1146 release_region(card->port, ICN_PORTLEN);
1147 }
1148 card = card->next;
1149 }
1150}
1151
1152static int
Joe Perches475be4d2012-02-19 19:52:38 -08001153icn_command(isdn_ctrl *c, icn_card *card)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154{
1155 ulong a;
1156 ulong flags;
1157 int i;
Dan Carpenterb7a31402014-04-16 14:25:16 +03001158 char cbuf[80];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 isdn_ctrl cmd;
1160 icn_cdef cdef;
1161 char __user *arg;
1162
1163 switch (c->command) {
Joe Perches475be4d2012-02-19 19:52:38 -08001164 case ISDN_CMD_IOCTL:
1165 memcpy(&a, c->parm.num, sizeof(ulong));
1166 arg = (char __user *)a;
1167 switch (c->arg) {
1168 case ICN_IOCTL_SETMMIO:
1169 if (dev.memaddr != (a & 0x0ffc000)) {
1170 if (!request_mem_region(a & 0x0ffc000, 0x4000, "icn-isdn (all cards)")) {
1171 printk(KERN_WARNING
1172 "icn: memory at 0x%08lx in use.\n",
1173 a & 0x0ffc000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 }
Joe Perches475be4d2012-02-19 19:52:38 -08001176 release_mem_region(a & 0x0ffc000, 0x4000);
1177 icn_stopallcards();
1178 spin_lock_irqsave(&card->lock, flags);
1179 if (dev.mvalid) {
1180 iounmap(dev.shmem);
1181 release_mem_region(dev.memaddr, 0x4000);
1182 }
1183 dev.mvalid = 0;
1184 dev.memaddr = a & 0x0ffc000;
1185 spin_unlock_irqrestore(&card->lock, flags);
1186 printk(KERN_INFO
1187 "icn: (%s) mmio set to 0x%08lx\n",
1188 CID,
1189 dev.memaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 }
1191 break;
Joe Perches475be4d2012-02-19 19:52:38 -08001192 case ICN_IOCTL_GETMMIO:
1193 return (long) dev.memaddr;
1194 case ICN_IOCTL_SETPORT:
1195 if (a == 0x300 || a == 0x310 || a == 0x320 || a == 0x330
1196 || a == 0x340 || a == 0x350 || a == 0x360 ||
1197 a == 0x308 || a == 0x318 || a == 0x328 || a == 0x338
1198 || a == 0x348 || a == 0x358 || a == 0x368) {
1199 if (card->port != (unsigned short) a) {
1200 if (!request_region((unsigned short) a, ICN_PORTLEN, "icn-isdn")) {
1201 printk(KERN_WARNING
1202 "icn: (%s) ports 0x%03x-0x%03x in use.\n",
1203 CID, (int) a, (int) a + ICN_PORTLEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 return -EINVAL;
Joe Perches475be4d2012-02-19 19:52:38 -08001205 }
1206 release_region((unsigned short) a, ICN_PORTLEN);
1207 icn_stopcard(card);
1208 spin_lock_irqsave(&card->lock, flags);
1209 if (card->rvalid)
1210 release_region(card->port, ICN_PORTLEN);
1211 card->port = (unsigned short) a;
1212 card->rvalid = 0;
1213 if (card->doubleS0) {
1214 card->other->port = (unsigned short) a;
1215 card->other->rvalid = 0;
1216 }
1217 spin_unlock_irqrestore(&card->lock, flags);
1218 printk(KERN_INFO
1219 "icn: (%s) port set to 0x%03x\n",
1220 CID, card->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 }
Joe Perches475be4d2012-02-19 19:52:38 -08001222 } else
1223 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 break;
Joe Perches475be4d2012-02-19 19:52:38 -08001225 case ICN_IOCTL_GETPORT:
1226 return (int) card->port;
1227 case ICN_IOCTL_GETDOUBLE:
1228 return (int) card->doubleS0;
1229 case ICN_IOCTL_DEBUGVAR:
1230 if (copy_to_user(arg,
1231 &card,
1232 sizeof(ulong)))
1233 return -EFAULT;
1234 a += sizeof(ulong);
1235 {
1236 ulong l = (ulong)&dev;
1237 if (copy_to_user(arg,
1238 &l,
1239 sizeof(ulong)))
1240 return -EFAULT;
1241 }
1242 return 0;
1243 case ICN_IOCTL_LOADBOOT:
1244 if (dev.firstload) {
1245 icn_disable_cards();
1246 dev.firstload = 0;
1247 }
1248 icn_stopcard(card);
1249 return (icn_loadboot(arg, card));
1250 case ICN_IOCTL_LOADPROTO:
1251 icn_stopcard(card);
1252 if ((i = (icn_loadproto(arg, card))))
1253 return i;
1254 if (card->doubleS0)
1255 i = icn_loadproto(arg + ICN_CODE_STAGE2, card->other);
1256 return i;
1257 break;
1258 case ICN_IOCTL_ADDCARD:
1259 if (!dev.firstload)
1260 return -EBUSY;
1261 if (copy_from_user(&cdef,
1262 arg,
1263 sizeof(cdef)))
1264 return -EFAULT;
1265 return (icn_addcard(cdef.port, cdef.id1, cdef.id2));
1266 break;
1267 case ICN_IOCTL_LEASEDCFG:
1268 if (a) {
1269 if (!card->leased) {
1270 card->leased = 1;
1271 while (card->ptype == ISDN_PTYPE_UNKNOWN) {
1272 msleep_interruptible(ICN_BOOT_TIMEOUT1);
1273 }
1274 msleep_interruptible(ICN_BOOT_TIMEOUT1);
1275 sprintf(cbuf, "00;FV2ON\n01;EAZ%c\n02;EAZ%c\n",
1276 (a & 1) ? '1' : 'C', (a & 2) ? '2' : 'C');
1277 i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
1278 printk(KERN_INFO
1279 "icn: (%s) Leased-line mode enabled\n",
1280 CID);
1281 cmd.command = ISDN_STAT_RUN;
1282 cmd.driver = card->myid;
1283 cmd.arg = 0;
1284 card->interface.statcallb(&cmd);
1285 }
1286 } else {
1287 if (card->leased) {
1288 card->leased = 0;
1289 sprintf(cbuf, "00;FV2OFF\n");
1290 i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
1291 printk(KERN_INFO
1292 "icn: (%s) Leased-line mode disabled\n",
1293 CID);
1294 cmd.command = ISDN_STAT_RUN;
1295 cmd.driver = card->myid;
1296 cmd.arg = 0;
1297 card->interface.statcallb(&cmd);
1298 }
1299 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 return 0;
1301 default:
1302 return -EINVAL;
Joe Perches475be4d2012-02-19 19:52:38 -08001303 }
1304 break;
1305 case ISDN_CMD_DIAL:
1306 if (!(card->flags & ICN_FLAGS_RUNNING))
1307 return -ENODEV;
1308 if (card->leased)
1309 break;
1310 if ((c->arg & 255) < ICN_BCH) {
1311 char *p;
Joe Perches475be4d2012-02-19 19:52:38 -08001312 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");
Dan Carpenterb7a31402014-04-16 14:25:16 +03001323 snprintf(cbuf, sizeof(cbuf),
1324 "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1),
1325 dcode, p, c->parm.setup.si1,
1326 c->parm.setup.si2, c->parm.setup.eazmsn);
Joe Perches475be4d2012-02-19 19:52:38 -08001327 i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
1328 }
1329 break;
1330 case ISDN_CMD_ACCEPTD:
1331 if (!(card->flags & ICN_FLAGS_RUNNING))
1332 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:
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:
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:
1369 if (!(card->flags & ICN_FLAGS_RUNNING))
1370 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:
1378 if (!(card->flags & ICN_FLAGS_RUNNING))
1379 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:
1394 if (!(card->flags & ICN_FLAGS_RUNNING))
1395 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:
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:
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:
1427 if (!(card->flags & ICN_FLAGS_RUNNING))
1428 return -ENODEV;
1429 return 0;
1430 default:
1431 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 }
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
Joe Perches475be4d2012-02-19 19:52:38 -08001456if_command(isdn_ctrl *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457{
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 |
Joe Perches475be4d2012-02-19 19:52:38 -08001539 ISDN_FEATURE_L2_HDLC |
1540 ISDN_FEATURE_L3_TRANS |
1541 ISDN_FEATURE_P_UNKNOWN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 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
Dan Carpenter56000902013-11-07 10:58:06 +03001582 "icn: (%s) half ICN-4B, port 0x%x added\n", id2, port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 return 0;
1584 }
1585 card->doubleS0 = 1;
1586 card->secondhalf = 0;
1587 card->other = card2;
1588 card2->doubleS0 = 1;
1589 card2->secondhalf = 1;
1590 card2->other = card;
1591 printk(KERN_INFO
1592 "icn: (%s and %s) ICN-4B, port 0x%x added\n",
1593 card->interface.id, card2->interface.id, port);
1594 return 0;
1595}
1596
1597#ifndef MODULE
1598static int __init
1599icn_setup(char *line)
1600{
1601 char *p, *str;
1602 int ints[3];
1603 static char sid[20];
1604 static char sid2[20];
1605
1606 str = get_options(line, 2, ints);
1607 if (ints[0])
1608 portbase = ints[1];
1609 if (ints[0] > 1)
1610 membase = (unsigned long)ints[2];
1611 if (str && *str) {
1612 strcpy(sid, str);
1613 icn_id = sid;
1614 if ((p = strchr(sid, ','))) {
1615 *p++ = 0;
1616 strcpy(sid2, p);
1617 icn_id2 = sid2;
1618 }
1619 }
Joe Perches475be4d2012-02-19 19:52:38 -08001620 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621}
1622__setup("icn=", icn_setup);
1623#endif /* MODULE */
1624
1625static int __init icn_init(void)
1626{
1627 char *p;
Stefan Weila29ae232011-01-30 10:31:26 +00001628 char rev[21];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629
1630 memset(&dev, 0, sizeof(icn_dev));
1631 dev.memaddr = (membase & 0x0ffc000);
1632 dev.channel = -1;
1633 dev.mcard = NULL;
1634 dev.firstload = 1;
1635 spin_lock_init(&dev.devlock);
1636
1637 if ((p = strchr(revision, ':'))) {
Steven Rostedt44480082010-11-24 11:19:05 -08001638 strncpy(rev, p + 1, 20);
Stefan Weila29ae232011-01-30 10:31:26 +00001639 rev[20] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 p = strchr(rev, '$');
Steven Rostedt44480082010-11-24 11:19:05 -08001641 if (p)
1642 *p = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 } else
1644 strcpy(rev, " ??? ");
1645 printk(KERN_NOTICE "ICN-ISDN-driver Rev%smem=0x%08lx\n", rev,
1646 dev.memaddr);
1647 return (icn_addcard(portbase, icn_id, icn_id2));
1648}
1649
1650static void __exit icn_exit(void)
1651{
1652 isdn_ctrl cmd;
1653 icn_card *card = cards;
Dave Jones138b9dd2005-08-08 16:13:15 -07001654 icn_card *last, *tmpcard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 int i;
1656 unsigned long flags;
1657
1658 icn_stopallcards();
1659 while (card) {
1660 cmd.command = ISDN_STAT_UNLOAD;
1661 cmd.driver = card->myid;
1662 card->interface.statcallb(&cmd);
1663 spin_lock_irqsave(&card->lock, flags);
1664 if (card->rvalid) {
1665 OUTB_P(0, ICN_RUN); /* Reset Controller */
1666 OUTB_P(0, ICN_MAPRAM); /* Disable RAM */
1667 if (card->secondhalf || (!card->doubleS0)) {
1668 release_region(card->port, ICN_PORTLEN);
1669 card->rvalid = 0;
1670 }
1671 for (i = 0; i < ICN_BCH; i++)
1672 icn_free_queue(card, i);
1673 }
Dave Jones138b9dd2005-08-08 16:13:15 -07001674 tmpcard = card->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 spin_unlock_irqrestore(&card->lock, flags);
Dave Jones138b9dd2005-08-08 16:13:15 -07001676 card = tmpcard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 }
1678 card = cards;
1679 cards = NULL;
1680 while (card) {
1681 last = card;
1682 card = card->next;
1683 kfree(last);
1684 }
1685 if (dev.mvalid) {
1686 iounmap(dev.shmem);
1687 release_mem_region(dev.memaddr, 0x4000);
1688 }
1689 printk(KERN_NOTICE "ICN-ISDN-driver unloaded\n");
1690}
1691
1692module_init(icn_init);
1693module_exit(icn_exit);