patch-pre2.0.6 linux/drivers/isdn/icn/icn.c
Next file: linux/drivers/isdn/icn/icn.h
Previous file: linux/drivers/isdn/Makefile
Back to the patch index
Back to the overall index
- Lines: 2699
- Date:
Sun May 19 15:29:29 1996
- Orig file:
pre2.0.5/linux/drivers/isdn/icn/icn.c
- Orig date:
Sun Apr 21 19:22:06 1996
diff -u --recursive --new-file pre2.0.5/linux/drivers/isdn/icn/icn.c linux/drivers/isdn/icn/icn.c
@@ -1,4 +1,4 @@
-/* $Id icn.c,v 1.15 1996/01/10 20:57:39 fritz Exp fritz $
+/* $Id: icn.c,v 1.22 1996/05/17 15:46:41 fritz Exp $
*
* ISDN low-level module for the ICN active ISDN-Card.
*
@@ -19,6 +19,22 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: icn.c,v $
+ * Revision 1.22 1996/05/17 15:46:41 fritz
+ * Removed own queue management.
+ * Changed queue management to use sk_buffs.
+ *
+ * Revision 1.21 1996/05/02 04:01:20 fritz
+ * Bugfix:
+ * - icn_addcard() evalueated wrong driverId.
+ *
+ * Revision 1.20 1996/05/02 00:40:27 fritz
+ * Major rewrite to support more than one card
+ * with a single module.
+ * Support for new firmware.
+ *
+ * Revision 1.19 1996/04/21 17:43:32 fritz
+ * Changes for Support of new Firmware BRV3.02
+ *
* Revision 1.18 1996/04/20 16:50:26 fritz
* Fixed status-buffer overrun.
* Misc. typos
@@ -86,8 +102,6 @@
#include "icn.h"
-
-
/*
* Verbose bootcode- and protocol-downloading.
*/
@@ -98,58 +112,29 @@
*/
#undef MAP_DEBUG
-/* If defined, no bootcode- and protocol-downloading is supported and
- * you must use an external loader
- */
-#undef LOADEXTERN
-
static char
-*revision = "$Revision: 1.18 $";
+*revision = "$Revision: 1.22 $";
-static void icn_pollcard(unsigned long dummy);
+static int icn_addcard(int, char *, char *);
-/* Try to allocate a new buffer, link it into queue. */
-static u_char *
- icn_new_buf(pqueue ** queue, int length)
-{
- pqueue *p;
- pqueue *q;
-
- if ((p = *queue)) {
- while (p) {
- q = p;
- p = (pqueue *) p->next;
- }
- p = (pqueue *) kmalloc(sizeof(pqueue) + length, GFP_ATOMIC);
- q->next = (u_char *) p;
- } else
- p = *queue = (pqueue *) kmalloc(sizeof(pqueue) + length, GFP_ATOMIC);
- if (p) {
- p->size = sizeof(pqueue) + length;
- p->length = length;
- p->next = NULL;
- p->rptr = p->buffer;
- return p->buffer;
- } else {
- return (u_char *) NULL;
- }
-}
-
-#ifdef MODULE
-static void icn_free_queue(pqueue ** queue)
+/*
+ * Free queue completely.
+ * Parameter:
+ * queue = pointer to queue-head
+ */
+static void icn_free_queue(struct sk_buff_head *queue)
{
- pqueue *p;
- pqueue *q;
-
- p = *queue;
- while (p) {
- q = p;
- p = (pqueue *) p->next;
- kfree_s(q, q->size);
- }
- *queue = (pqueue *) 0;
+ struct sk_buff *skb;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ while ((skb = skb_dequeue(queue))) {
+ skb->free = 1;
+ kfree_skb(skb, FREE_WRITE);
+ }
+ restore_flags(flags);
}
-#endif
/* Put a value into a shift-register, highest bit first.
* Parameters:
@@ -159,241 +144,257 @@
* bitcount = Number of bits to output
*/
static inline void icn_shiftout(unsigned short port,
- unsigned long val,
- int firstbit,
- int bitcount)
+ unsigned long val,
+ int firstbit,
+ int bitcount)
{
- register u_char s;
- register u_char c;
+ register u_char s;
+ register u_char c;
- for (s = firstbit, c = bitcount; c > 0; s--, c--)
- OUTB_P((u_char) ((val >> s) & 1) ? 0xff : 0, port);
+ for (s = firstbit, c = bitcount; c > 0; s--, c--)
+ OUTB_P((u_char) ((val >> s) & 1) ? 0xff : 0, port);
}
/*
- * Map Cannel0 (Bank0/Bank8) or Channel1 (Bank4/Bank12)
+ * disable a cards shared memory
*/
-static inline void icn_map_channel(int channel)
+static inline void icn_disable_ram(icn_card *card)
{
- static u_char chan2bank[] =
- {0, 4, 8, 12};
+ OUTB_P(0, ICN_MAPRAM);
+}
+/*
+ * enable a cards shared memory
+ */
+static inline void icn_enable_ram(icn_card *card)
+{
+ OUTB_P(0xff, ICN_MAPRAM);
+}
+
+/*
+ * Map a cards channel0 (Bank0/Bank8) or channel1 (Bank4/Bank12)
+ */
+static inline void icn_map_channel(icn_card *card, int channel)
+{
#ifdef MAP_DEBUG
- printk(KERN_DEBUG "icn_map_channel %d %d\n", dev->channel, channel);
+ printk(KERN_DEBUG "icn_map_channel %d %d\n", dev->channel, channel);
#endif
- if (channel == dev->channel)
- return;
- OUTB_P(0, ICN_MAPRAM); /* Disable RAM */
- icn_shiftout(ICN_BANK, chan2bank[channel], 3, 4); /* Select Bank */
- OUTB_P(0xff, ICN_MAPRAM); /* Enable RAM */
- dev->channel = channel;
+ if ((channel == dev.channel) && (card == dev.mcard))
+ return;
+ if (dev.mcard)
+ icn_disable_ram(dev.mcard);
+ icn_shiftout(ICN_BANK, chan2bank[channel], 3, 4); /* Select Bank */
+ icn_enable_ram(card);
+ dev.mcard = card;
+ dev.channel = channel;
#ifdef MAP_DEBUG
- printk(KERN_DEBUG "icn_map_channel done\n");
+ printk(KERN_DEBUG "icn_map_channel done\n");
#endif
}
-static inline int icn_lock_channel(int channel)
+/*
+ * Lock a cards channel.
+ * Return 0 if requested card/channel is unmapped (failure).
+ * Return 1 on success.
+ */
+static inline int icn_lock_channel(icn_card *card, int channel)
{
- register int retval;
- ulong flags;
+ register int retval;
+ ulong flags;
#ifdef MAP_DEBUG
- printk(KERN_DEBUG "icn_lock_channel %d\n", channel);
+ printk(KERN_DEBUG "icn_lock_channel %d\n", channel);
#endif
- save_flags(flags);
- cli();
- if (dev->channel == channel) {
- dev->chanlock++;
- retval = 1;
+ save_flags(flags);
+ cli();
+ if ((dev.channel == channel) && (card == dev.mcard)) {
+ dev.chanlock++;
+ retval = 1;
#ifdef MAP_DEBUG
- printk(KERN_DEBUG "icn_lock_channel %d OK\n", channel);
+ printk(KERN_DEBUG "icn_lock_channel %d OK\n", channel);
#endif
- } else {
- retval = 0;
+ } else {
+ retval = 0;
#ifdef MAP_DEBUG
- printk(KERN_DEBUG "icn_lock_channel %d FAILED, dc=%d\n", channel, dev->channel);
+ printk(KERN_DEBUG "icn_lock_channel %d FAILED, dc=%d\n", channel, device->channel);
#endif
- }
- restore_flags(flags);
- return retval;
+ }
+ restore_flags(flags);
+ return retval;
}
+/*
+ * Release current card/channel lock
+ */
static inline void icn_release_channel(void)
{
- ulong flags;
+ ulong flags;
#ifdef MAP_DEBUG
- printk(KERN_DEBUG "icn_release_channel l=%d\n", dev->chanlock);
+ printk(KERN_DEBUG "icn_release_channel l=%d\n", device->chanlock);
#endif
- save_flags(flags);
- cli();
- if (dev->chanlock)
- dev->chanlock--;
- restore_flags(flags);
+ save_flags(flags);
+ cli();
+ if (dev.chanlock)
+ dev.chanlock--;
+ restore_flags(flags);
}
-static inline int icn_trymaplock_channel(int channel)
+/*
+ * Try to map and lock a cards channel.
+ * Return 1 on success, 0 on failure.
+ */
+static inline int icn_trymaplock_channel(icn_card *card, int channel)
{
- ulong flags;
+ ulong flags;
- save_flags(flags);
- cli();
+ save_flags(flags);
+ cli();
#ifdef MAP_DEBUG
- printk(KERN_DEBUG "trymaplock c=%d dc=%d l=%d\n", channel, dev->channel,
- dev->chanlock);
+ printk(KERN_DEBUG "trymaplock c=%d dc=%d l=%d\n", channel, dev.channel,
+ dev.chanlock);
#endif
- if ((!dev->chanlock) || (dev->channel == channel)) {
- dev->chanlock++;
- icn_map_channel(channel);
- restore_flags(flags);
+ if ((!dev.chanlock) ||
+ ((dev.channel == channel) && (dev.mcard == card))) {
+ dev.chanlock++;
+ icn_map_channel(card,channel);
+ restore_flags(flags);
#ifdef MAP_DEBUG
- printk(KERN_DEBUG "trymaplock %d OK\n", channel);
+ printk(KERN_DEBUG "trymaplock %d OK\n", channel);
#endif
- return 1;
- }
- restore_flags(flags);
+ return 1;
+ }
+ restore_flags(flags);
#ifdef MAP_DEBUG
- printk(KERN_DEBUG "trymaplock %d FAILED\n", channel);
+ printk(KERN_DEBUG "trymaplock %d FAILED\n", channel);
#endif
- return 0;
+ return 0;
}
-static inline void icn_maprelease_channel(int channel)
+/*
+ * Release currend card/channel lock,
+ * then map same or other channel without locking.
+ */
+static inline void icn_maprelease_channel(icn_card *card, int channel)
{
- ulong flags;
+ ulong flags;
- save_flags(flags);
- cli();
+ save_flags(flags);
+ cli();
#ifdef MAP_DEBUG
- printk(KERN_DEBUG "map_release c=%d l=%d\n", channel, dev->chanlock);
+ printk(KERN_DEBUG "map_release c=%d l=%d\n", channel, dev.chanlock);
#endif
- if (dev->chanlock)
- dev->chanlock--;
- if (!dev->chanlock)
- icn_map_channel(channel);
- restore_flags(flags);
+ if (dev.chanlock)
+ dev.chanlock--;
+ if (!dev.chanlock)
+ icn_map_channel(card,channel);
+ restore_flags(flags);
}
/* Get Data from the B-Channel, assemble fragmented packets and put them
* into receive-queue. Wake up any B-Channel-reading processes.
- * This routine is called via timer-callback from pollbchan().
- * It schedules itself while any B-Channel is open.
+ * This routine is called via timer-callback from icn_pollbchan().
*/
-#ifdef DEBUG_RCVCALLBACK
-static int max_pending[2] =
-{0, 0};
-#endif
-
-static void icn_pollbchan_receive(int channel, icn_dev * dev)
-{
- int mch = channel + ((dev->secondhalf) ? 2 : 0);
- int eflag;
- int cnt;
- int flags;
-#ifdef DEBUG_RCVCALLBACK
- int rcv_pending1;
- int rcv_pending2;
- int akt_pending;
-#endif
-
- if (icn_trymaplock_channel(mch)) {
- while (rbavl) {
- cnt = rbuf_l;
- if ((dev->rcvidx[channel] + cnt) > 4000) {
- printk(KERN_WARNING "icn: bogus packet on ch%d, dropping.\n",
- channel + 1);
- dev->rcvidx[channel] = 0;
- eflag = 0;
- } else {
- memcpy(&dev->rcvbuf[channel][dev->rcvidx[channel]], rbuf_d, cnt);
- dev->rcvidx[channel] += cnt;
- eflag = rbuf_f;
- }
- rbnext;
- icn_maprelease_channel(mch & 2);
- if (!eflag) {
- save_flags(flags);
- cli();
-#ifdef DEBUG_RCVCALLBACK
- rcv_pending1 =
- (dev->shmem->data_control.ecnr > dev->shmem->data_control.ecns) ?
- 0xf - dev->shmem->data_control.ecnr + dev->shmem->data_control.ecns :
- dev->shmem->data_control.ecns - dev->shmem->data_control.ecnr;
-#endif
- dev->interface.rcvcallb(dev->myid, channel, dev->rcvbuf[channel],
- dev->rcvidx[channel]);
- dev->rcvidx[channel] = 0;
-#ifdef DEBUG_RCVCALLBACK
- rcv_pending2 =
- (dev->shmem->data_control.ecnr > dev->shmem->data_control.ecns) ?
- 0xf - dev->shmem->data_control.ecnr + dev->shmem->data_control.ecns :
- dev->shmem->data_control.ecns - dev->shmem->data_control.ecnr;
- akt_pending = rcv_pending2 - rcv_pending1;
- if (akt_pending > max_pending[channel]) {
- max_pending[channel] = akt_pending;
- printk(KERN_DEBUG "ICN_DEBUG: pend: %d %d\n", max_pending[0], max_pending[1]);
- }
-#endif
- restore_flags(flags);
- }
- if (!icn_trymaplock_channel(mch))
- break;
- }
- icn_maprelease_channel(mch & 2);
- }
+static void icn_pollbchan_receive(int channel, icn_card *card)
+{
+ int mch = channel + ((card->secondhalf) ? 2 : 0);
+ int eflag;
+ int cnt;
+ struct sk_buff *skb;
+
+ if (icn_trymaplock_channel(card,mch)) {
+ while (rbavl) {
+ cnt = rbuf_l;
+ if ((card->rcvidx[channel] + cnt) > 4000) {
+ printk(KERN_WARNING
+ "icn: (%s) bogus packet on ch%d, dropping.\n",
+ CID,
+ channel + 1);
+ card->rcvidx[channel] = 0;
+ eflag = 0;
+ } else {
+ memcpy(&card->rcvbuf[channel][card->rcvidx[channel]], rbuf_d, cnt);
+ card->rcvidx[channel] += cnt;
+ eflag = rbuf_f;
+ }
+ rbnext;
+ icn_maprelease_channel(card, mch & 2);
+ if (!eflag) {
+ if ((cnt = card->rcvidx[channel])) {
+ if (!(skb = dev_alloc_skb(cnt))) {
+ printk(KERN_WARNING "ïcn: receive out of memory\n");
+ break;
+ }
+ memcpy(skb_put(skb, cnt), card->rcvbuf[channel], cnt);
+ card->rcvidx[channel] = 0;
+ card->interface.rcvcallb_skb(card->myid, channel, skb);
+ }
+ }
+ if (!icn_trymaplock_channel(card, mch))
+ break;
+ }
+ icn_maprelease_channel(card, mch & 2);
+ }
}
/* Send data-packet to B-Channel, split it up into fragments of
* ICN_FRAGSIZE length. If last fragment is sent out, signal
* success to upper layers via statcallb with ISDN_STAT_BSENT argument.
- * This routine is called via timer-callback from pollbchan() or
- * directly from sendbuf().
+ * This routine is called via timer-callback from icn_pollbchan() or
+ * directly from icn_sendbuf().
*/
-static void icn_pollbchan_send(int channel, icn_dev * dev)
+static void icn_pollbchan_send(int channel, icn_card *card)
{
- int mch = channel + ((dev->secondhalf) ? 2 : 0);
- int eflag = 0;
- int cnt;
- int left;
- int flags;
- pqueue *p;
- isdn_ctrl cmd;
-
- if (!dev->sndcount[channel])
- return;
- if (icn_trymaplock_channel(mch)) {
- while (sbfree && dev->sndcount[channel]) {
- left = dev->spqueue[channel]->length;
- cnt =
- (sbuf_l =
- (left > ICN_FRAGSIZE) ? ((sbuf_f = 0xff), ICN_FRAGSIZE) : ((sbuf_f = 0), left));
- memcpy(sbuf_d, dev->spqueue[channel]->rptr, cnt);
- sbnext; /* switch to next buffer */
- icn_maprelease_channel(mch & 2);
- dev->spqueue[channel]->rptr += cnt;
- eflag = ((dev->spqueue[channel]->length -= cnt) == 0);
- save_flags(flags);
- cli();
- p = dev->spqueue[channel];
- dev->sndcount[channel] -= cnt;
- if (eflag)
- dev->spqueue[channel] = (pqueue *) dev->spqueue[channel]->next;
- restore_flags(flags);
- if (eflag) {
- kfree_s(p, p->size);
- cmd.command = ISDN_STAT_BSENT;
- cmd.driver = dev->myid;
- cmd.arg = channel;
- dev->interface.statcallb(&cmd);
- }
- if (!icn_trymaplock_channel(mch))
- break;
- }
- icn_maprelease_channel(mch & 2);
- }
+ int mch = channel + ((card->secondhalf) ? 2 : 0);
+ int cnt;
+ unsigned long flags;
+ struct sk_buff *skb;
+ isdn_ctrl cmd;
+
+ if (!card->sndcount[channel])
+ return;
+ if (icn_trymaplock_channel(card,mch)) {
+ while (sbfree && card->sndcount[channel]) {
+ save_flags(flags);
+ cli();
+ skb = skb_peek(&card->spqueue[channel]);
+ if (!skb) {
+ restore_flags(flags);
+ break;
+ }
+ if (skb->lock) {
+ restore_flags(flags);
+ break;
+ }
+ skb->lock = 1;
+ restore_flags(flags);
+ cnt =
+ (sbuf_l =
+ (skb->len > ICN_FRAGSIZE) ? ((sbuf_f = 0xff), ICN_FRAGSIZE) : ((sbuf_f = 0), skb->len));
+ memcpy(sbuf_d, skb->data, cnt);
+ skb_pull(skb, cnt);
+ card->sndcount[channel] -= cnt;
+ sbnext; /* switch to next buffer */
+ icn_maprelease_channel(card, mch & 2);
+ if (!skb->len) {
+ skb = skb_dequeue(&card->spqueue[channel]);
+ skb->free = 1;
+ skb->lock = 0;
+ kfree_skb(skb, FREE_WRITE);
+ cmd.command = ISDN_STAT_BSENT;
+ cmd.driver = card->myid;
+ cmd.arg = channel;
+ card->interface.statcallb(&cmd);
+ } else
+ skb->lock = 0;
+ if (!icn_trymaplock_channel(card, mch))
+ break;
+ }
+ icn_maprelease_channel(card, mch & 2);
+ }
}
/* Send/Receive Data to/from the B-Channel.
@@ -401,253 +402,56 @@
* It schedules itself while any B-Channel is open.
*/
-static void icn_pollbchan(unsigned long dummy)
+static void icn_pollbchan(unsigned long data)
{
- unsigned long flags;
+ icn_card *card = (icn_card *)data;
+ unsigned long flags;
- dev->flags |= ICN_FLAGS_RBTIMER;
- if (dev->flags & ICN_FLAGS_B1ACTIVE) {
- icn_pollbchan_receive(0, dev);
- icn_pollbchan_send(0, dev);
- }
- if (dev->flags & ICN_FLAGS_B2ACTIVE) {
- icn_pollbchan_receive(1, dev);
- icn_pollbchan_send(1, dev);
- }
- if (dev->doubleS0) {
- if (dev2->flags & ICN_FLAGS_B1ACTIVE) {
- icn_pollbchan_receive(0, dev2);
- icn_pollbchan_send(0, dev2);
- }
- if (dev2->flags & ICN_FLAGS_B2ACTIVE) {
- icn_pollbchan_receive(1, dev2);
- icn_pollbchan_send(1, dev2);
- }
- }
- if (dev->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE)) {
- /* schedule b-channel polling again */
- save_flags(flags);
- cli();
- del_timer(&dev->rb_timer);
- dev->rb_timer.function = icn_pollbchan;
- dev->rb_timer.expires = jiffies + ICN_TIMER_BCREAD;
- add_timer(&dev->rb_timer);
- restore_flags(flags);
- } else
- dev->flags &= ~ICN_FLAGS_RBTIMER;
- if (dev->doubleS0) {
- if (dev2->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE)) {
- /* schedule b-channel polling again */
- save_flags(flags);
- cli();
- del_timer(&dev2->rb_timer);
- dev2->rb_timer.function = icn_pollbchan;
- dev2->rb_timer.expires = jiffies + ICN_TIMER_BCREAD;
- add_timer(&dev2->rb_timer);
- restore_flags(flags);
- } else
- dev2->flags &= ~ICN_FLAGS_RBTIMER;
- }
-}
-
-static void icn_pollit(icn_dev * dev)
-{
- int mch = dev->secondhalf ? 2 : 0;
- int avail = 0;
- int dflag = 0;
- int left;
- u_char c;
- int ch;
- int flags;
- int i;
- u_char *p;
- isdn_ctrl cmd;
-
- if (icn_trymaplock_channel(mch)) {
- avail = msg_avail;
- for (left = avail, i = msg_o; left > 0; i++, left--) {
- c = dev->shmem->comm_buffers.iopc_buf[i & 0xff];
- save_flags(flags);
- cli();
- *dev->msg_buf_write++ = (c == 0xff) ? '\n' : c;
- if (dev->msg_buf_write == dev->msg_buf_read) {
- if (++dev->msg_buf_read > dev->msg_buf_end)
- dev->msg_buf_read = dev->msg_buf;
- }
- if (dev->msg_buf_write > dev->msg_buf_end)
- dev->msg_buf_write = dev->msg_buf;
- restore_flags(flags);
- if (c == 0xff) {
- dev->imsg[dev->iptr] = 0;
- dev->iptr = 0;
- if (dev->imsg[0] == '0' && dev->imsg[1] >= '0' &&
- dev->imsg[1] <= '2' && dev->imsg[2] == ';') {
- ch = dev->imsg[1] - '0';
- p = &dev->imsg[3];
- if (!strncmp(p, "BCON_", 5)) {
- switch (ch) {
- case 1:
- dev->flags |= ICN_FLAGS_B1ACTIVE;
- break;
- case 2:
- dev->flags |= ICN_FLAGS_B2ACTIVE;
- break;
- }
- cmd.command = ISDN_STAT_BCONN;
- cmd.driver = dev->myid;
- cmd.arg = ch - 1;
- dev->interface.statcallb(&cmd);
- continue;
- }
- if (!strncmp(p, "TEI OK", 6)) {
- cmd.command = ISDN_STAT_RUN;
- cmd.driver = dev->myid;
- cmd.arg = ch - 1;
- dev->interface.statcallb(&cmd);
- continue;
- }
- if (!strncmp(p, "BDIS_", 5)) {
- switch (ch) {
- case 1:
- dev->flags &= ~ICN_FLAGS_B1ACTIVE;
- dflag |= 1;
- break;
- case 2:
- dev->flags &= ~ICN_FLAGS_B2ACTIVE;
- dflag |= 2;
- break;
- }
- cmd.command = ISDN_STAT_BHUP;
- cmd.arg = ch - 1;
- cmd.driver = dev->myid;
- dev->interface.statcallb(&cmd);
- continue;
- }
- if (!strncmp(p, "DCON_", 5)) {
- cmd.command = ISDN_STAT_DCONN;
- cmd.arg = ch - 1;
- cmd.driver = dev->myid;
- dev->interface.statcallb(&cmd);
- continue;
- }
- if (!strncmp(p, "DDIS_", 5)) {
- cmd.command = ISDN_STAT_DHUP;
- cmd.arg = ch - 1;
- cmd.driver = dev->myid;
- dev->interface.statcallb(&cmd);
- continue;
- }
- if (!strncmp(p, "E_L1: ACT FAIL", 14)) {
- cmd.command = ISDN_STAT_BHUP;
- cmd.arg = 0;
- cmd.driver = dev->myid;
- dev->interface.statcallb(&cmd);
- cmd.command = ISDN_STAT_DHUP;
- cmd.arg = 0;
- cmd.driver = dev->myid;
- dev->interface.statcallb(&cmd);
- continue;
- }
- if (!strncmp(p, "CIF", 3)) {
- cmd.command = ISDN_STAT_CINF;
- cmd.arg = ch - 1;
- strncpy(cmd.num, p + 3, sizeof(cmd.num) - 1);
- cmd.driver = dev->myid;
- dev->interface.statcallb(&cmd);
- continue;
- }
- if (!strncmp(p, "CAU", 3)) {
- cmd.command = ISDN_STAT_CAUSE;
- cmd.arg = ch - 1;
- strncpy(cmd.num, p + 3, sizeof(cmd.num) - 1);
- cmd.driver = dev->myid;
- dev->interface.statcallb(&cmd);
- continue;
- }
- if (!strncmp(p, "DCAL_I", 6)) {
- cmd.command = ISDN_STAT_ICALL;
- cmd.driver = dev->myid;
- cmd.arg = ch - 1;
- strncpy(cmd.num, p + 6, sizeof(cmd.num) - 1);
- dev->interface.statcallb(&cmd);
- continue;
- }
- if (!strncmp(p, "FCALL", 5)) {
- cmd.command = ISDN_STAT_ICALL;
- cmd.driver = dev->myid;
- cmd.arg = ch - 1;
- strcpy(cmd.num, "LEASED,07,00,1");
- dev->interface.statcallb(&cmd);
- continue;
- }
- if (!strncmp(p, "DSCA_I", 6)) {
- cmd.command = ISDN_STAT_ICALL;
- cmd.driver = dev->myid;
- cmd.arg = ch - 1;
- strncpy(cmd.num, p + 6, sizeof(cmd.num) - 1);
- dev->interface.statcallb(&cmd);
- continue;
- }
- if (!strncmp(p, "NO D-CHAN", 9)) {
- cmd.command = ISDN_STAT_NODCH;
- cmd.driver = dev->myid;
- cmd.arg = ch - 1;
- strncpy(cmd.num, p + 6, sizeof(cmd.num) - 1);
- dev->interface.statcallb(&cmd);
- continue;
- }
- } else {
- p = dev->imsg;
- if (!strncmp(p, "DRV1.", 5)) {
- printk(KERN_INFO "icn: %s\n",p);
- if (!strncmp(p + 7, "TC", 2)) {
- dev->ptype = ISDN_PTYPE_1TR6;
- dev->interface.features |= ISDN_FEATURE_P_1TR6;
- printk(KERN_INFO "icn: 1TR6-Protocol loaded and running\n");
- }
- if (!strncmp(p + 7, "EC", 2)) {
- dev->ptype = ISDN_PTYPE_EURO;
- dev->interface.features |= ISDN_FEATURE_P_EURO;
- printk(KERN_INFO "icn: Euro-Protocol loaded and running\n");
- }
- continue;
- }
- }
- } else {
- dev->imsg[dev->iptr] = c;
- if (dev->iptr < 59)
- dev->iptr++;
- }
- }
- msg_o = (msg_o + avail) & 0xff;
- icn_release_channel();
- }
- if (avail) {
- cmd.command = ISDN_STAT_STAVAIL;
- cmd.driver = dev->myid;
- cmd.arg = avail;
- dev->interface.statcallb(&cmd);
- }
- if (dflag & 1)
- dev->interface.rcvcallb(dev->myid, 0, dev->rcvbuf[0], 0);
- if (dflag & 2)
- dev->interface.rcvcallb(dev->myid, 1, dev->rcvbuf[1], 0);
- if (dev->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE))
- if (!(dev->flags & ICN_FLAGS_RBTIMER)) {
- /* schedule b-channel polling */
- dev->flags |= ICN_FLAGS_RBTIMER;
- save_flags(flags);
- cli();
- del_timer(&dev->rb_timer);
- dev->rb_timer.function = icn_pollbchan;
- dev->rb_timer.expires = jiffies + ICN_TIMER_BCREAD;
- add_timer(&dev->rb_timer);
- restore_flags(flags);
- }
-}
+ if (card->flags & ICN_FLAGS_B1ACTIVE) {
+ icn_pollbchan_receive(0, card);
+ icn_pollbchan_send(0, card);
+ }
+ if (card->flags & ICN_FLAGS_B2ACTIVE) {
+ icn_pollbchan_receive(1, card);
+ icn_pollbchan_send(1, card);
+ }
+ if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE)) {
+ /* schedule b-channel polling again */
+ save_flags(flags);
+ cli();
+ card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD;
+ add_timer(&card->rb_timer);
+ card->flags |= ICN_FLAGS_RBTIMER;
+ restore_flags(flags);
+ } else
+ card->flags &= ~ICN_FLAGS_RBTIMER;
+}
+
+typedef struct icn_stat {
+ char *statstr;
+ int command;
+ int action;
+} icn_stat;
+
+static icn_stat icn_stat_table[] = {
+ {"BCON_", ISDN_STAT_BCONN, 1}, /* B-Channel connected */
+ {"BDIS_", ISDN_STAT_BHUP, 2}, /* B-Channel disconnected */
+ {"DCON_", ISDN_STAT_DCONN, 0}, /* D-Channel connected */
+ {"DDIS_", ISDN_STAT_DHUP, 0}, /* D-Channel disconnected */
+ {"DCAL_I", ISDN_STAT_ICALL, 3}, /* Incoming call dialup-line */
+ {"DSCA_I", ISDN_STAT_ICALL, 3}, /* Incoming call 1TR6-SPV */
+ {"FCALL", ISDN_STAT_ICALL, 4}, /* Leased line connection up */
+ {"CIF", ISDN_STAT_CINF, 5}, /* Charge-info, 1TR6-type */
+ {"AOC", ISDN_STAT_CINF, 6}, /* Charge-info, DSS1-type */
+ {"CAU", ISDN_STAT_CAUSE, 7}, /* Cause code */
+ {"TEI OK", ISDN_STAT_RUN, 0}, /* Card connected to wallplug */
+ {"NO D-CHAN", ISDN_STAT_NODCH, 0}, /* No D-channel available */
+ {"E_L1: ACT FAIL", ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */
+ {NULL, 0 , -1}
+};
/*
- * Check Statusqueue-Pointer from isdn-card.
+ * Check Statusqueue-Pointer from isdn-cards.
* If there are new status-replies from the interface, check
* them against B-Channel-connects/disconnects and set flags accordingly.
* Wake-Up any processes, who are reading the status-device.
@@ -656,93 +460,260 @@
* This routine is called periodically via timer.
*/
-static void icn_pollcard(unsigned long dummy)
+static int icn_parse_status(u_char *status, int channel, icn_card *card)
{
- ulong flags;
-
- icn_pollit(dev);
- if (dev->doubleS0)
- icn_pollit(dev2);
- /* schedule again */
- save_flags(flags);
- cli();
- del_timer(&dev->st_timer);
- dev->st_timer.function = icn_pollcard;
- dev->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
- add_timer(&dev->st_timer);
- restore_flags(flags);
+ icn_stat *s = icn_stat_table;
+ int action = -1;
+ int dflag = 0;
+ unsigned long flags;
+ isdn_ctrl cmd;
+
+ while (s->statstr) {
+ if (!strncmp(status,s->statstr,strlen(s->statstr))) {
+ cmd.command = s->command;
+ action = s->action;
+ break;
+ }
+ s++;
+ }
+ if (action==-1)
+ return 0;
+ cmd.driver = card->myid;
+ cmd.arg = channel;
+ switch (action) {
+ case 1:
+ card->flags |= (channel)?
+ ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE;
+ break;
+ case 2:
+ card->flags &= ~((channel)?
+ ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE);
+ icn_free_queue(&card->spqueue[channel]);
+ save_flags(flags);
+ cli();
+ card->rcvidx[channel] = 0;
+ restore_flags(flags);
+ dflag |= (channel+1);
+ break;
+ case 3:
+ strncpy(cmd.num, status + 6, sizeof(cmd.num) - 1);
+ break;
+ case 4:
+ sprintf(cmd.num,"LEASED%d,07,00,%d",
+ card->myid,channel+1);
+ break;
+ case 5:
+ strncpy(cmd.num, status + 3, sizeof(cmd.num) - 1);
+ break;
+ case 6:
+ sprintf(cmd.num,"%d",
+ (int)simple_strtoul(status + 7,NULL,16));
+ break;
+ case 7:
+ status += 3;
+ if (strlen(status)==4)
+ sprintf(cmd.num,"%s%c%c",
+ status+2,*status,*(status+1));
+ else
+ strncpy(cmd.num, status+1, sizeof(cmd.num) - 1);
+ break;
+ case 8:
+ cmd.arg = 0;
+ cmd.driver = card->myid;
+ card->interface.statcallb(&cmd);
+ cmd.command = ISDN_STAT_DHUP;
+ cmd.arg = 0;
+ cmd.driver = card->myid;
+ card->interface.statcallb(&cmd);
+ cmd.command = ISDN_STAT_BHUP;
+ cmd.arg = 1;
+ cmd.driver = card->myid;
+ card->interface.statcallb(&cmd);
+ cmd.command = ISDN_STAT_DHUP;
+ cmd.arg = 1;
+ cmd.driver = card->myid;
+ break;
+ }
+ card->interface.statcallb(&cmd);
+ return dflag;
+}
+
+static void icn_polldchan(unsigned long data)
+{
+ icn_card *card = (icn_card *)data;
+ int mch = card->secondhalf ? 2 : 0;
+ int avail = 0;
+ int dflag = 0;
+ int left;
+ u_char c;
+ int ch;
+ int flags;
+ int i;
+ u_char *p;
+ isdn_ctrl cmd;
+
+ if (icn_trymaplock_channel(card,mch)) {
+ avail = msg_avail;
+ for (left = avail, i = msg_o; left > 0; i++, left--) {
+ c = dev.shmem->comm_buffers.iopc_buf[i & 0xff];
+ save_flags(flags);
+ cli();
+ *card->msg_buf_write++ = (c == 0xff) ? '\n' : c;
+ if (card->msg_buf_write == card->msg_buf_read) {
+ if (++card->msg_buf_read > card->msg_buf_end)
+ card->msg_buf_read = card->msg_buf;
+ }
+ if (card->msg_buf_write > card->msg_buf_end)
+ card->msg_buf_write = card->msg_buf;
+ restore_flags(flags);
+ if (c == 0xff) {
+ card->imsg[card->iptr] = 0;
+ card->iptr = 0;
+ if (card->imsg[0] == '0' && card->imsg[1] >= '0' &&
+ card->imsg[1] <= '2' && card->imsg[2] == ';') {
+ ch = (card->imsg[1] - '0') - 1;
+ p = &card->imsg[3];
+ dflag |= icn_parse_status(p, ch, card);
+ } else {
+ p = card->imsg;
+ if (!strncmp(p, "DRV1.", 5)) {
+ u_char vstr[10];
+ u_char *q = vstr;
+
+ printk(KERN_INFO "icn: (%s) %s\n",CID,p);
+ if (!strncmp(p + 7, "TC", 2)) {
+ card->ptype = ISDN_PTYPE_1TR6;
+ card->interface.features |= ISDN_FEATURE_P_1TR6;
+ printk(KERN_INFO
+ "icn: (%s) 1TR6-Protocol loaded and running\n",CID);
+ }
+ if (!strncmp(p + 7, "EC", 2)) {
+ card->ptype = ISDN_PTYPE_EURO;
+ card->interface.features |= ISDN_FEATURE_P_EURO;
+ printk(KERN_INFO
+ "icn: (%s) Euro-Protocol loaded and running\n",CID);
+ }
+ p = strstr(card->imsg,"BRV") + 3;
+ while (*p) {
+ if (*p>='0' && *p<='9')
+ *q++ = *p;
+ p++;
+ }
+ *q = '\0';
+ strcat(vstr,"000");
+ vstr[3] = '\0';
+ card->fw_rev = (int)simple_strtoul(vstr,NULL,10);
+ continue;
+
+ }
+ }
+ } else {
+ card->imsg[card->iptr] = c;
+ if (card->iptr < 59)
+ card->iptr++;
+ }
+ }
+ msg_o = (msg_o + avail) & 0xff;
+ icn_release_channel();
+ }
+ if (avail) {
+ cmd.command = ISDN_STAT_STAVAIL;
+ cmd.driver = card->myid;
+ cmd.arg = avail;
+ card->interface.statcallb(&cmd);
+ }
+ if (dflag & 1)
+ card->interface.rcvcallb(card->myid, 0, card->rcvbuf[0], 0);
+ if (dflag & 2)
+ card->interface.rcvcallb(card->myid, 1, card->rcvbuf[1], 0);
+ if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE))
+ if (!(card->flags & ICN_FLAGS_RBTIMER)) {
+ /* schedule b-channel polling */
+ card->flags |= ICN_FLAGS_RBTIMER;
+ save_flags(flags);
+ cli();
+ del_timer(&card->rb_timer);
+ card->rb_timer.function = icn_pollbchan;
+ card->rb_timer.data = (unsigned long)card;
+ card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD;
+ add_timer(&card->rb_timer);
+ restore_flags(flags);
+ }
+ /* schedule again */
+ save_flags(flags);
+ cli();
+ card->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
+ add_timer(&card->st_timer);
+ restore_flags(flags);
}
-/* Send a packet to the transmit-buffers, handle fragmentation if necessary.
+/* Append a packet to the transmit buffer-queue.
* Parameters:
- * channel = Number of B-channel
- * buffer = pointer to packet
- * len = size of packet (max 4000)
- * dev = pointer to device-struct
- * user = 1 = call from userproc, 0 = call from kernel
+ * channel = Number of B-channel
+ * buffer = pointer to packet
+ * len = size of packet (max 4000)
+ * user = 1 = call from userproc, 0 = call from kernel
+ * card = pointer to card-struct
* Return:
- * Number of bytes transferred, -E??? on error
+ * Number of bytes transferred, -E??? on error
*/
-static int icn_sendbuf(int channel, const u_char * buffer, int len, int user, icn_dev * dev)
+static int icn_sendbuf(int channel, struct sk_buff *skb, icn_card * card)
{
- register u_char *p;
- int flags;
+ int len = skb->len;
+ unsigned long flags;
- if (len > 4000)
- return -EINVAL;
- if (len) {
- if (dev->sndcount[channel] > ICN_MAX_SQUEUE)
- return 0;
- save_flags(flags);
- cli();
- p = icn_new_buf(&dev->spqueue[channel], len);
- if (!p) {
- restore_flags(flags);
- return 0;
- }
- if (user) {
- memcpy_fromfs(p, buffer, len);
- } else {
- memcpy(p, buffer, len);
- }
- dev->sndcount[channel] += len;
- icn_pollbchan_send(channel, dev);
- restore_flags(flags);
- }
- return len;
+ if (len > 4000) {
+ skb->free = 1;
+ kfree_skb(skb, FREE_WRITE);
+ return -EINVAL;
+ }
+ if (len) {
+ if (!(card->flags & (channel)?ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE))
+ return 0;
+ if (card->sndcount[channel] > ICN_MAX_SQUEUE)
+ return 0;
+ save_flags(flags);
+ cli();
+ card->sndcount[channel] += len;
+ skb_queue_tail(&card->spqueue[channel], skb);
+ restore_flags(flags);
+ icn_pollbchan_send(channel, card);
+ }
+ return len;
}
-#ifndef LOADEXTERN
static int icn_check_loader(int cardnumber)
{
- int timer = 0;
+ int timer = 0;
- while (1) {
+ while (1) {
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Loader %d ?\n", cardnumber);
+ printk(KERN_DEBUG "Loader %d ?\n", cardnumber);
#endif
- if (dev->shmem->data_control.scns ||
- dev->shmem->data_control.scnr) {
- if (timer++ > 5) {
- printk(KERN_WARNING "icn: Boot-Loader %d timed out.\n", cardnumber);
- icn_release_channel();
- return -EIO;
- }
+ if (dev.shmem->data_control.scns ||
+ dev.shmem->data_control.scnr) {
+ if (timer++ > 5) {
+ printk(KERN_WARNING
+ "icn: Boot-Loader %d timed out.\n",
+ cardnumber);
+ icn_release_channel();
+ return -EIO;
+ }
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Loader %d TO?\n", cardnumber);
+ printk(KERN_DEBUG "Loader %d TO?\n", cardnumber);
#endif
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
- schedule();
- } else {
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
+ schedule();
+ } else {
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Loader %d OK\n", cardnumber);
+ printk(KERN_DEBUG "Loader %d OK\n", cardnumber);
#endif
- icn_release_channel();
- return 0;
- }
- }
+ icn_release_channel();
+ return 0;
+ }
+ }
}
/* Load the boot-code into the interface-card's memory and start it.
@@ -769,585 +740,782 @@
#define SLEEP(sec)
#endif
-static int icn_loadboot(u_char * buffer, icn_dev * dev)
+static int icn_loadboot(u_char * buffer, icn_card * card)
{
- int ret;
- ulong flags;
+ int ret;
+ ulong flags;
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "icn_loadboot called, buffaddr=%08lx\n", (ulong) buffer);
+ printk(KERN_DEBUG "icn_loadboot called, buffaddr=%08lx\n", (ulong) buffer);
#endif
- if ((ret = verify_area(VERIFY_READ, (void *) buffer, ICN_CODE_STAGE1)))
- return ret;
- save_flags(flags);
- cli();
- if (!dev->rvalid) {
- if (check_region(dev->port, ICN_PORTLEN)) {
- printk(KERN_WARNING "icn: ports 0x%03x-0x%03x in use.\n", dev->port,
- dev->port + ICN_PORTLEN);
- restore_flags(flags);
- return -EBUSY;
- }
- request_region(dev->port, ICN_PORTLEN, regname);
- dev->rvalid = 1;
- }
- if (!dev->mvalid) {
- if (check_shmem((ulong) dev->shmem, 0x4000)) {
- printk(KERN_WARNING "icn: memory at 0x%08lx in use.\n", (ulong) dev->shmem);
- restore_flags(flags);
- return -EBUSY;
- }
- request_shmem((ulong) dev->shmem, 0x4000, regname);
- dev->mvalid = 1;
- }
- restore_flags(flags);
- OUTB_P(0, ICN_RUN); /* Reset Controller */
- OUTB_P(0, ICN_MAPRAM); /* Disable RAM */
- icn_shiftout(ICN_CFG, 0x0f, 3, 4); /* Windowsize= 16k */
- icn_shiftout(ICN_CFG, (unsigned long) dev->shmem, 23, 10); /* Set RAM-Addr. */
+ if ((ret = verify_area(VERIFY_READ, (void *) buffer, ICN_CODE_STAGE1)))
+ return ret;
+ save_flags(flags);
+ cli();
+ if (!card->rvalid) {
+ if (check_region(card->port, ICN_PORTLEN)) {
+ printk(KERN_WARNING
+ "icn: (%s) ports 0x%03x-0x%03x in use.\n",
+ CID,
+ card->port,
+ card->port + ICN_PORTLEN);
+ restore_flags(flags);
+ return -EBUSY;
+ }
+ request_region(card->port, ICN_PORTLEN, card->regname);
+ card->rvalid = 1;
+ if (card->doubleS0)
+ card->other->rvalid = 1;
+ }
+ if (!dev.mvalid) {
+ if (check_shmem((ulong) dev.shmem, 0x4000)) {
+ printk(KERN_WARNING
+ "icn: memory at 0x%08lx in use.\n",
+ (ulong) dev.shmem);
+ restore_flags(flags);
+ return -EBUSY;
+ }
+ request_shmem((ulong) dev.shmem, 0x4000, "icn");
+ dev.mvalid = 1;
+ }
+ restore_flags(flags);
+ OUTB_P(0, ICN_RUN); /* Reset Controller */
+ OUTB_P(0, ICN_MAPRAM); /* Disable RAM */
+ icn_shiftout(ICN_CFG, 0x0f, 3, 4); /* Windowsize= 16k */
+ icn_shiftout(ICN_CFG, (unsigned long) dev.shmem, 23, 10); /* Set RAM-Addr. */
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "shmem=%08lx\n", (ulong) dev->shmem);
+ printk(KERN_DEBUG "shmem=%08lx\n", (ulong) dev.shmem);
#endif
- SLEEP(1);
- save_flags(flags);
- cli();
- dev->channel = 1; /* Force Mapping */
+ SLEEP(1);
+ save_flags(flags);
+ cli();
+ dev.channel = 1; /* Force Mapping */
+ dev.mcard = NULL;
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Map Bank 0\n");
+ printk(KERN_DEBUG "Map Bank 0\n");
#endif
- icn_map_channel(0); /* Select Bank 0 */
- icn_lock_channel(0); /* Lock Bank 0 */
- restore_flags(flags);
- SLEEP(1);
- memcpy_fromfs(dev->shmem, buffer, ICN_CODE_STAGE1); /* Copy code */
+ icn_map_channel(card,0); /* Select Bank 0 */
+ icn_lock_channel(card,0); /* Lock Bank 0 */
+ restore_flags(flags);
+ SLEEP(1);
+ memcpy_fromfs(dev.shmem, buffer, ICN_CODE_STAGE1); /* Copy code */
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Bootloader transfered\n");
+ printk(KERN_DEBUG "Bootloader transfered\n");
#endif
- if (dev->doubleS0) {
- SLEEP(1);
- save_flags(flags);
- cli();
- icn_release_channel();
+ if (card->doubleS0) {
+ SLEEP(1);
+ save_flags(flags);
+ cli();
+ icn_release_channel();
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Map Bank 8\n");
+ printk(KERN_DEBUG "Map Bank 8\n");
#endif
- icn_map_channel(2); /* Select Bank 8 */
- icn_lock_channel(2); /* Lock Bank 8 */
- restore_flags(flags);
- SLEEP(1);
- memcpy_fromfs(dev->shmem, buffer, ICN_CODE_STAGE1); /* Copy code */
+ icn_map_channel(card,2); /* Select Bank 8 */
+ icn_lock_channel(card,2); /* Lock Bank 8 */
+ restore_flags(flags);
+ SLEEP(1);
+ memcpy_fromfs(dev.shmem, buffer, ICN_CODE_STAGE1); /* Copy code */
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Bootloader transfered\n");
+ printk(KERN_DEBUG "Bootloader transfered\n");
#endif
- }
- SLEEP(1);
- OUTB_P(0xff, ICN_RUN); /* Start Boot-Code */
- if ((ret = icn_check_loader(dev->doubleS0 ? 2 : 1)))
- return ret;
- if (!dev->doubleS0)
- return 0;
- /* reached only, if we have a Double-S0-Card */
- save_flags(flags);
- cli();
+ }
+ SLEEP(1);
+ OUTB_P(0xff, ICN_RUN); /* Start Boot-Code */
+ if ((ret = icn_check_loader(card->doubleS0 ? 2 : 1)))
+ return ret;
+ if (!card->doubleS0)
+ return 0;
+ /* reached only, if we have a Double-S0-Card */
+ save_flags(flags);
+ cli();
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Map Bank 0\n");
+ printk(KERN_DEBUG "Map Bank 0\n");
#endif
- icn_map_channel(0); /* Select Bank 0 */
- icn_lock_channel(0); /* Lock Bank 0 */
- restore_flags(flags);
- SLEEP(1);
- return (icn_check_loader(1));
-}
-
-static int icn_loadproto(u_char * buffer, icn_dev * ldev)
-{
- register u_char *p = buffer;
- uint left = ICN_CODE_STAGE2;
- uint cnt;
- int timer;
- int ret;
- unsigned long flags;
+ icn_map_channel(card,0); /* Select Bank 0 */
+ icn_lock_channel(card,0); /* Lock Bank 0 */
+ restore_flags(flags);
+ SLEEP(1);
+ return (icn_check_loader(1));
+}
+
+static int icn_loadproto(u_char * buffer, icn_card * card)
+{
+ register u_char *p = buffer;
+ uint left = ICN_CODE_STAGE2;
+ uint cnt;
+ int timer;
+ int ret;
+ unsigned long flags;
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "icn_loadproto called\n");
+ printk(KERN_DEBUG "icn_loadproto called\n");
#endif
- if ((ret = verify_area(VERIFY_READ, (void *) buffer, ICN_CODE_STAGE2)))
- return ret;
- timer = 0;
- save_flags(flags);
- cli();
- if (ldev->secondhalf) {
- icn_map_channel(2);
- icn_lock_channel(2);
- } else {
- icn_map_channel(0);
- icn_lock_channel(0);
- }
- restore_flags(flags);
- while (left) {
- if (sbfree) { /* If there is a free buffer... */
- cnt = MIN(256, left);
- memcpy_fromfs(&sbuf_l, p, cnt); /* copy data */
- sbnext; /* switch to next buffer */
- p += cnt;
- left -= cnt;
- timer = 0;
- } else {
+ if ((ret = verify_area(VERIFY_READ, (void *) buffer, ICN_CODE_STAGE2)))
+ return ret;
+ timer = 0;
+ save_flags(flags);
+ cli();
+ if (card->secondhalf) {
+ icn_map_channel(card, 2);
+ icn_lock_channel(card, 2);
+ } else {
+ icn_map_channel(card, 0);
+ icn_lock_channel(card, 0);
+ }
+ restore_flags(flags);
+ while (left) {
+ if (sbfree) { /* If there is a free buffer... */
+ cnt = MIN(256, left);
+ memcpy_fromfs(&sbuf_l, p, cnt); /* copy data */
+ sbnext; /* switch to next buffer */
+ p += cnt;
+ left -= cnt;
+ timer = 0;
+ } else {
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "boot 2 !sbfree\n");
+ printk(KERN_DEBUG "boot 2 !sbfree\n");
#endif
- if (timer++ > 5) {
- icn_maprelease_channel(0);
- return -EIO;
- }
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + 10;
- schedule();
- }
- }
- sbuf_n = 0x20;
- timer = 0;
- while (1) {
- if (cmd_o || cmd_i) {
+ if (timer++ > 5) {
+ icn_maprelease_channel(card, 0);
+ return -EIO;
+ }
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 10;
+ schedule();
+ }
+ }
+ sbuf_n = 0x20;
+ timer = 0;
+ while (1) {
+ if (cmd_o || cmd_i) {
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Proto?\n");
+ printk(KERN_DEBUG "Proto?\n");
#endif
- if (timer++ > 5) {
- printk(KERN_WARNING "icn: Protocol timed out.\n");
+ if (timer++ > 5) {
+ printk(KERN_WARNING
+ "icn: (%s) Protocol timed out.\n",
+ CID);
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Proto TO!\n");
+ printk(KERN_DEBUG "Proto TO!\n");
#endif
- icn_maprelease_channel(0);
- return -EIO;
- }
+ icn_maprelease_channel(card, 0);
+ return -EIO;
+ }
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Proto TO?\n");
+ printk(KERN_DEBUG "Proto TO?\n");
#endif
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
- schedule();
- } else {
- if ((ldev->secondhalf) || (!dev->doubleS0)) {
- save_flags(flags);
- cli();
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
+ schedule();
+ } else {
+ if ((card->secondhalf) || (!card->doubleS0)) {
+ save_flags(flags);
+ cli();
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Proto loaded, install poll-timer %d\n",
- ldev->secondhalf);
+ printk(KERN_DEBUG "Proto loaded, install poll-timer %d\n",
+ card->secondhalf);
#endif
- init_timer(&dev->st_timer);
- dev->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
- dev->st_timer.function = icn_pollcard;
- add_timer(&dev->st_timer);
- restore_flags(flags);
- }
- icn_maprelease_channel(0);
- return 0;
- }
- }
+ init_timer(&card->st_timer);
+ card->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
+ card->st_timer.function = icn_polldchan;
+ card->st_timer.data = (unsigned long)card;
+ add_timer(&card->st_timer);
+ card->flags |= ICN_FLAGS_RUNNING;
+ if (card->doubleS0) {
+ init_timer(&card->other->st_timer);
+ card->other->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
+ card->other->st_timer.function = icn_polldchan;
+ card->other->st_timer.data = (unsigned long)card->other;
+ add_timer(&card->other->st_timer);
+ card->other->flags |= ICN_FLAGS_RUNNING;
+ }
+ restore_flags(flags);
+ }
+ icn_maprelease_channel(card, 0);
+ return 0;
+ }
+ }
}
-#endif /* !LOADEXTERN */
/* Read the Status-replies from the Interface */
-static int icn_readstatus(u_char * buf, int len, int user, icn_dev * dev)
+static int icn_readstatus(u_char * buf, int len, int user, icn_card * card)
{
- int count;
- u_char *p;
+ int count;
+ u_char *p;
- for (p = buf, count = 0; count < len; p++, count++) {
- if (dev->msg_buf_read == dev->msg_buf_write)
+ for (p = buf, count = 0; count < len; p++, count++) {
+ if (card->msg_buf_read == card->msg_buf_write)
return count;
- if (user)
- put_fs_byte(*dev->msg_buf_read++, p);
- else
- *p = *dev->msg_buf_read++;
- if (dev->msg_buf_read > dev->msg_buf_end)
- dev->msg_buf_read = dev->msg_buf;
- }
- return count;
+ if (user)
+ put_fs_byte(*card->msg_buf_read++, p);
+ else
+ *p = *card->msg_buf_read++;
+ if (card->msg_buf_read > card->msg_buf_end)
+ card->msg_buf_read = card->msg_buf;
+ }
+ return count;
}
/* Put command-strings into the command-queue of the Interface */
-static int icn_writecmd(const u_char * buf, int len, int user, icn_dev * dev, int waitflg)
+static int icn_writecmd(const u_char * buf, int len, int user, icn_card * card, int waitflg)
{
- int mch = dev->secondhalf ? 2 : 0;
- int avail;
- int pp;
- int i;
- int count;
- int ocount;
- unsigned long flags;
- u_char *p;
- isdn_ctrl cmd;
- u_char msg[0x100];
-
- while (1) {
- if (icn_trymaplock_channel(mch)) {
- avail = cmd_free;
- count = MIN(avail, len);
- if (user)
- memcpy_fromfs(msg, buf, count);
- else
- memcpy(msg, buf, count);
- save_flags(flags);
- cli();
- ocount = 1;
- *dev->msg_buf_write++ = '>';
- if (dev->msg_buf_write > dev->msg_buf_end)
- dev->msg_buf_write = dev->msg_buf;
- for (p = msg, pp = cmd_i, i = count; i > 0; i--, p++, pp++) {
- dev->shmem->comm_buffers.pcio_buf[pp & 0xff] = (*p == '\n') ? 0xff : *p;
- *dev->msg_buf_write++ = *p;
- if ((*p == '\n') && (i > 1)) {
- *dev->msg_buf_write++ = '>';
- if (dev->msg_buf_write > dev->msg_buf_end)
- dev->msg_buf_write = dev->msg_buf;
- ocount++;
- }
- /* No checks for buffer overflow of raw-status-device */
- if (dev->msg_buf_write > dev->msg_buf_end)
- dev->msg_buf_write = dev->msg_buf;
- ocount++;
- }
- restore_flags(flags);
- cmd.command = ISDN_STAT_STAVAIL;
- cmd.driver = dev->myid;
- cmd.arg = ocount;
- dev->interface.statcallb(&cmd);
- cmd_i = (cmd_i + count) & 0xff;
- icn_release_channel();
- waitflg = 0;
- } else
- count = 0;
- if (!waitflg)
- break;
- current->timeout = jiffies + 10;
- schedule();
- }
- return count;
+ int mch = card->secondhalf ? 2 : 0;
+ int avail;
+ int pp;
+ int i;
+ int count;
+ int ocount;
+ unsigned long flags;
+ u_char *p;
+ isdn_ctrl cmd;
+ u_char msg[0x100];
+
+ while (1) {
+ if (icn_trymaplock_channel(card, mch)) {
+ avail = cmd_free;
+ count = MIN(avail, len);
+ if (user)
+ memcpy_fromfs(msg, buf, count);
+ else
+ memcpy(msg, buf, count);
+ save_flags(flags);
+ cli();
+ ocount = 1;
+ *card->msg_buf_write++ = '>';
+ if (card->msg_buf_write > card->msg_buf_end)
+ card->msg_buf_write = card->msg_buf;
+ for (p = msg, pp = cmd_i, i = count; i > 0; i--, p++, pp++) {
+ dev.shmem->comm_buffers.pcio_buf[pp & 0xff] = (*p == '\n') ? 0xff : *p;
+ *card->msg_buf_write++ = *p;
+ if ((*p == '\n') && (i > 1)) {
+ *card->msg_buf_write++ = '>';
+ if (card->msg_buf_write > card->msg_buf_end)
+ card->msg_buf_write = card->msg_buf;
+ ocount++;
+ }
+ /* No checks for buffer overflow of raw-status-device */
+ if (card->msg_buf_write > card->msg_buf_end)
+ card->msg_buf_write = card->msg_buf;
+ ocount++;
+ }
+ restore_flags(flags);
+ cmd.command = ISDN_STAT_STAVAIL;
+ cmd.driver = card->myid;
+ cmd.arg = ocount;
+ card->interface.statcallb(&cmd);
+ cmd_i = (cmd_i + count) & 0xff;
+ icn_release_channel();
+ waitflg = 0;
+ } else
+ count = 0;
+ if (!waitflg)
+ break;
+ current->timeout = jiffies + 10;
+ schedule();
+ }
+ return count;
}
-static void icn_stopdriver(icn_dev * ldev)
+/*
+ * Delete card's pending timers, send STOP to linklevel
+ */
+static void icn_stopcard(icn_card * card)
{
- unsigned long flags;
- isdn_ctrl cmd;
+ unsigned long flags;
+ isdn_ctrl cmd;
- save_flags(flags);
- cli();
- del_timer(&dev->st_timer);
- del_timer(&ldev->rb_timer);
- cmd.command = ISDN_STAT_STOP;
- cmd.driver = ldev->myid;
- ldev->interface.statcallb(&cmd);
- restore_flags(flags);
-}
-
-static int my_atoi(char *s)
-{
- int i, n;
-
- n = 0;
- if (!s)
- return -1;
- for (i = 0; *s >= '0' && *s <= '9'; i++, s++)
- n = 10 * n + (*s - '0');
- return n;
-}
-
-static int icn_command(isdn_ctrl * c, icn_dev * ldev)
-{
- ulong a;
- ulong flags;
- int i;
- char cbuf[60];
- isdn_ctrl cmd;
-
- switch (c->command) {
- case ISDN_CMD_IOCTL:
- memcpy(&a, c->num, sizeof(ulong));
- switch (c->arg) {
- case ICN_IOCTL_SETMMIO:
- if ((unsigned long) dev->shmem != (a & 0x0ffc000)) {
- if (check_shmem((ulong) (a & 0x0ffc000), 0x4000)) {
- printk(KERN_WARNING "icn: memory at 0x%08lx in use.\n",
- (ulong) (a & 0x0ffc000));
- return -EINVAL;
- }
- icn_stopdriver(dev);
- if (dev->doubleS0)
- icn_stopdriver(dev2);
- save_flags(flags);
- cli();
- if (dev->mvalid)
- release_shmem((ulong) dev->shmem, 0x4000);
- dev->mvalid = 0;
- dev->shmem = (icn_shmem *) (a & 0x0ffc000);
- if (dev->doubleS0)
- dev2->shmem = (icn_shmem *) (a & 0x0ffc000);
- restore_flags(flags);
- printk(KERN_INFO "icn: mmio set to 0x%08lx\n",
- (unsigned long) dev->shmem);
- }
- break;
- case ICN_IOCTL_GETMMIO:
- return (int) dev->shmem;
- case ICN_IOCTL_SETPORT:
- if (a == 0x300 || a == 0x310 || a == 0x320 || a == 0x330
- || a == 0x340 || a == 0x350 || a == 0x360 ||
- a == 0x308 || a == 0x318 || a == 0x328 || a == 0x338
- || a == 0x348 || a == 0x358 || a == 0x368) {
- if (dev->port != (unsigned short) a) {
- if (check_region((unsigned short) a, ICN_PORTLEN)) {
- printk(KERN_WARNING "icn: ports 0x%03x-0x%03x in use.\n",
- (int) a, (int) a + ICN_PORTLEN);
- return -EINVAL;
- }
- icn_stopdriver(dev);
- if (dev->doubleS0)
- icn_stopdriver(dev2);
- save_flags(flags);
- cli();
- if (dev->rvalid)
- release_region(dev->port, ICN_PORTLEN);
- dev->port = (unsigned short) a;
- dev->rvalid = 0;
- if (dev->doubleS0) {
- dev2->port = (unsigned short) a;
- dev2->rvalid = 0;
- }
- restore_flags(flags);
- printk(KERN_INFO "icn: port set to 0x%03x\n", dev->port);
- }
- } else
- return -EINVAL;
- break;
- case ICN_IOCTL_GETPORT:
- return (int) dev->port;
- case ICN_IOCTL_GETDOUBLE:
- return (int) dev->doubleS0;
- case ICN_IOCTL_DEBUGVAR:
- return (ulong) ldev;
-#ifndef LOADEXTERN
- case ICN_IOCTL_LOADBOOT:
- icn_stopdriver(dev);
- if (dev->doubleS0)
- icn_stopdriver(dev2);
- return (icn_loadboot((u_char *) a, dev));
- case ICN_IOCTL_LOADPROTO:
- icn_stopdriver(dev);
- if (dev->doubleS0)
- icn_stopdriver(dev2);
- if ((i = (icn_loadproto((u_char *) a, dev))))
- return i;
- if (dev->doubleS0)
- i = icn_loadproto((u_char *) (a + ICN_CODE_STAGE2), dev2);
- return i;
-#endif
- case ICN_IOCTL_LEASEDCFG:
- if (a) {
- if (!ldev->leased) {
- ldev->leased = 1;
- while (ldev->ptype == ISDN_PTYPE_UNKNOWN) {
- current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
- schedule();
- }
- current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
- schedule();
- sprintf(cbuf, "00;FV2ON\n01;EAZ1\n");
- i = icn_writecmd(cbuf, strlen(cbuf), 0, ldev, 1);
- printk(KERN_INFO "icn: Leased-line mode enabled\n");
- cmd.command = ISDN_STAT_RUN;
- cmd.driver = ldev->myid;
- cmd.arg = 0;
- ldev->interface.statcallb(&cmd);
- }
- } else {
- if (ldev->leased) {
- ldev->leased = 0;
- sprintf(cbuf, "00;FV2OFF\n");
- i = icn_writecmd(cbuf, strlen(cbuf), 0, ldev, 1);
- printk(KERN_INFO "icn: Leased-line mode disabled\n");
- cmd.command = ISDN_STAT_RUN;
- cmd.driver = ldev->myid;
- cmd.arg = 0;
- ldev->interface.statcallb(&cmd);
- }
- }
- return 0;
- default:
- return -EINVAL;
- }
- break;
- case ISDN_CMD_DIAL:
- if (ldev->leased)
- break;
- if ((c->arg & 255) < ICN_BCH) {
- char *p;
- char *p2;
- char dial[50];
- char sis[50];
- char dcode[4];
- int si1, si2;
-
- a = c->arg;
- strcpy(sis, c->num);
- p = strrchr(sis, ',');
- *p++ = '\0';
- si2 = my_atoi(p);
- p = strrchr(sis, ',') + 1;
- si1 = my_atoi(p);
- p = c->num;
- if (*p == 's' || *p == 'S') {
- /* Dial for SPV */
- p++;
- strcpy(dcode, "SCA");
- } else
- /* Normal Dial */
- strcpy(dcode, "CAL");
- strcpy(dial, p);
- p = strchr(dial, ',');
- *p++ = '\0';
- p2 = strchr(p, ',');
- *p2 = '\0';
- sprintf(cbuf, "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1), dcode, dial, si1,
- si2, p);
- i = icn_writecmd(cbuf, strlen(cbuf), 0, ldev, 1);
- }
- break;
- case ISDN_CMD_ACCEPTD:
- if (c->arg < ICN_BCH) {
- a = c->arg + 1;
- sprintf(cbuf, "%02d;DCON_R\n", (int) a);
- i = icn_writecmd(cbuf, strlen(cbuf), 0, ldev, 1);
- }
- break;
- case ISDN_CMD_ACCEPTB:
- if (c->arg < ICN_BCH) {
- a = c->arg + 1;
- sprintf(cbuf, "%02d;BCON_R\n", (int) a);
- i = icn_writecmd(cbuf, strlen(cbuf), 0, ldev, 1);
- }
- break;
- case ISDN_CMD_HANGUP:
- if (c->arg < ICN_BCH) {
- a = c->arg + 1;
- sprintf(cbuf, "%02d;BDIS_R\n%02d;DDIS_R\n", (int) a, (int) a);
- i = icn_writecmd(cbuf, strlen(cbuf), 0, ldev, 1);
- }
- break;
- case ISDN_CMD_SETEAZ:
- if (ldev->leased)
- break;
- if (c->arg < ICN_BCH) {
- a = c->arg + 1;
- if (ldev->ptype == ISDN_PTYPE_EURO) {
- sprintf(cbuf, "%02d;MS%s%s\n", (int) a, c->num[0] ? "N" : "ALL", c->num);
- } else
- sprintf(cbuf, "%02d;EAZ%s\n", (int) a, c->num[0] ? c->num : "0123456789");
- i = icn_writecmd(cbuf, strlen(cbuf), 0, ldev, 1);
- }
- break;
- case ISDN_CMD_CLREAZ:
- if (ldev->leased)
- break;
- if (c->arg < ICN_BCH) {
- a = c->arg + 1;
- if (ldev->ptype == ISDN_PTYPE_EURO)
- sprintf(cbuf, "%02d;MSNC\n", (int) a);
- else
- sprintf(cbuf, "%02d;EAZC\n", (int) a);
- i = icn_writecmd(cbuf, strlen(cbuf), 0, ldev, 1);
- }
- break;
- case ISDN_CMD_SETL2:
- if ((c->arg & 255) < ICN_BCH) {
- a = c->arg;
- switch (a >> 8) {
- case ISDN_PROTO_L2_X75I:
- sprintf(cbuf, "%02d;BX75\n", (int) (a & 255) + 1);
- break;
- case ISDN_PROTO_L2_HDLC:
- sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1);
- break;
- default:
- return -EINVAL;
- }
- i = icn_writecmd(cbuf, strlen(cbuf), 0, ldev, 1);
- ldev->l2_proto[a & 255] = (a >> 8);
- }
- break;
- case ISDN_CMD_GETL2:
- if ((c->arg & 255) < ICN_BCH)
- return ldev->l2_proto[c->arg & 255];
- else
- return -ENODEV;
- case ISDN_CMD_SETL3:
- return 0;
- case ISDN_CMD_GETL3:
- if ((c->arg & 255) < ICN_BCH)
- return ISDN_PROTO_L3_TRANS;
- else
- return -ENODEV;
- case ISDN_CMD_GETEAZ:
- break;
- case ISDN_CMD_SETSIL:
- break;
- case ISDN_CMD_GETSIL:
- break;
- case ISDN_CMD_LOCK:
- MOD_INC_USE_COUNT;
- break;
- case ISDN_CMD_UNLOCK:
- MOD_DEC_USE_COUNT;
- break;
- default:
- return -EINVAL;
- }
- return 0;
+ save_flags(flags);
+ cli();
+ if (card->flags & ICN_FLAGS_RUNNING) {
+ card->flags &= ~ICN_FLAGS_RUNNING;
+ del_timer(&card->st_timer);
+ del_timer(&card->rb_timer);
+ cmd.command = ISDN_STAT_STOP;
+ cmd.driver = card->myid;
+ card->interface.statcallb(&cmd);
+ if (card->doubleS0)
+ icn_stopcard(card->other);
+ }
+ restore_flags(flags);
+}
+
+static void icn_stopallcards(void)
+{
+ icn_card *p = cards;
+
+ while (p) {
+ icn_stopcard(p);
+ p = p->next;
+ }
+}
+
+static int icn_command(isdn_ctrl * c, icn_card * card)
+{
+ ulong a;
+ ulong flags;
+ int i;
+ char cbuf[60];
+ isdn_ctrl cmd;
+ icn_cdef cdef;
+
+ switch (c->command) {
+ case ISDN_CMD_IOCTL:
+ memcpy(&a, c->num, sizeof(ulong));
+ switch (c->arg) {
+ case ICN_IOCTL_SETMMIO:
+ if ((unsigned long) dev.shmem != (a & 0x0ffc000)) {
+ if (check_shmem((ulong) (a & 0x0ffc000), 0x4000)) {
+ printk(KERN_WARNING
+ "icn: memory at 0x%08lx in use.\n",
+ (ulong) (a & 0x0ffc000));
+ return -EINVAL;
+ }
+ icn_stopallcards();
+ save_flags(flags);
+ cli();
+ if (dev.mvalid)
+ release_shmem((ulong) dev.shmem, 0x4000);
+ dev.mvalid = 0;
+ dev.shmem = (icn_shmem *) (a & 0x0ffc000);
+ restore_flags(flags);
+ printk(KERN_INFO
+ "icn: (%s) mmio set to 0x%08lx\n",
+ CID,
+ (unsigned long) dev.shmem);
+ }
+ break;
+ case ICN_IOCTL_GETMMIO:
+ return (int) dev.shmem;
+ case ICN_IOCTL_SETPORT:
+ if (a == 0x300 || a == 0x310 || a == 0x320 || a == 0x330
+ || a == 0x340 || a == 0x350 || a == 0x360 ||
+ a == 0x308 || a == 0x318 || a == 0x328 || a == 0x338
+ || a == 0x348 || a == 0x358 || a == 0x368) {
+ if (card->port != (unsigned short) a) {
+ if (check_region((unsigned short) a, ICN_PORTLEN)) {
+ printk(KERN_WARNING
+ "icn: (%s) ports 0x%03x-0x%03x in use.\n",
+ CID, (int) a, (int) a + ICN_PORTLEN);
+ return -EINVAL;
+ }
+ icn_stopcard(card);
+ save_flags(flags);
+ cli();
+ if (card->rvalid)
+ release_region(card->port, ICN_PORTLEN);
+ card->port = (unsigned short) a;
+ card->rvalid = 0;
+ if (card->doubleS0) {
+ card->other->port = (unsigned short) a;
+ card->other->rvalid = 0;
+ }
+ restore_flags(flags);
+ printk(KERN_INFO
+ "icn: (%s) port set to 0x%03x\n",
+ CID, card->port);
+ }
+ } else
+ return -EINVAL;
+ break;
+ case ICN_IOCTL_GETPORT:
+ return (int) card->port;
+ case ICN_IOCTL_GETDOUBLE:
+ return (int) card->doubleS0;
+ case ICN_IOCTL_DEBUGVAR:
+ return (ulong) card;
+ case ICN_IOCTL_LOADBOOT:
+ icn_stopcard(card);
+ return (icn_loadboot((u_char *) a, card));
+ case ICN_IOCTL_LOADPROTO:
+ icn_stopcard(card);
+ if ((i = (icn_loadproto((u_char *) a, card))))
+ return i;
+ if (card->doubleS0)
+ i = icn_loadproto((u_char *) (a + ICN_CODE_STAGE2), card->other);
+ return i;
+ break;
+ case ICN_IOCTL_ADDCARD:
+ if ((i = verify_area(VERIFY_READ, (void *) a, sizeof(icn_cdef))))
+ return i;
+ memcpy_fromfs((char *)&cdef, (char *)a, sizeof(cdef));
+ return (icn_addcard(cdef.port, cdef.id1, cdef.id2));
+ break;
+ case ICN_IOCTL_LEASEDCFG:
+ if (a) {
+ if (!card->leased) {
+ card->leased = 1;
+ while (card->ptype == ISDN_PTYPE_UNKNOWN) {
+ current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
+ schedule();
+ }
+ current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
+ schedule();
+ sprintf(cbuf, "00;FV2ON\n01;EAZ1\n");
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+ printk(KERN_INFO
+ "icn: (%s) Leased-line mode enabled\n",
+ CID);
+ cmd.command = ISDN_STAT_RUN;
+ cmd.driver = card->myid;
+ cmd.arg = 0;
+ card->interface.statcallb(&cmd);
+ }
+ } else {
+ if (card->leased) {
+ card->leased = 0;
+ sprintf(cbuf, "00;FV2OFF\n");
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+ printk(KERN_INFO
+ "icn: (%s) Leased-line mode disabled\n",
+ CID);
+ cmd.command = ISDN_STAT_RUN;
+ cmd.driver = card->myid;
+ cmd.arg = 0;
+ card->interface.statcallb(&cmd);
+ }
+ }
+ return 0;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case ISDN_CMD_DIAL:
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ if (card->leased)
+ break;
+ if ((c->arg & 255) < ICN_BCH) {
+ char *p;
+ char *p2;
+ char dial[50];
+ char sis[50];
+ char dcode[4];
+ int si1, si2;
+
+ a = c->arg;
+ strcpy(sis, c->num);
+ p = strrchr(sis, ',');
+ *p++ = '\0';
+ si2 = simple_strtoul(p,NULL,10);
+ p = strrchr(sis, ',') + 1;
+ si1 = simple_strtoul(p,NULL,10);
+ p = c->num;
+ if (*p == 's' || *p == 'S') {
+ /* Dial for SPV */
+ p++;
+ strcpy(dcode, "SCA");
+ } else
+ /* Normal Dial */
+ strcpy(dcode, "CAL");
+ strcpy(dial, p);
+ p = strchr(dial, ',');
+ *p++ = '\0';
+ p2 = strchr(p, ',');
+ *p2 = '\0';
+ sprintf(cbuf, "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1), dcode, dial, si1,
+ si2, p);
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+ }
+ break;
+ case ISDN_CMD_ACCEPTD:
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ if (c->arg < ICN_BCH) {
+ a = c->arg + 1;
+ if (card->fw_rev >= 300) {
+ switch (card->l2_proto[a-1]) {
+ case ISDN_PROTO_L2_X75I:
+ sprintf(cbuf, "%02d;BX75\n", (int) a);
+ break;
+ case ISDN_PROTO_L2_HDLC:
+ sprintf(cbuf, "%02d;BTRA\n", (int) a);
+ break;
+ }
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+ }
+ sprintf(cbuf, "%02d;DCON_R\n", (int) a);
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+ }
+ break;
+ case ISDN_CMD_ACCEPTB:
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ if (c->arg < ICN_BCH) {
+ a = c->arg + 1;
+ if (card->fw_rev >= 300)
+ switch (card->l2_proto[a-1]) {
+ case ISDN_PROTO_L2_X75I:
+ sprintf(cbuf, "%02d;BCON_R,BX75\n", (int) a);
+ break;
+ case ISDN_PROTO_L2_HDLC:
+ sprintf(cbuf, "%02d;BCON_R,BTRA\n", (int) a);
+ break;
+ }
+ else
+ sprintf(cbuf, "%02d;BCON_R\n", (int) a);
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+ }
+ break;
+ case ISDN_CMD_HANGUP:
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ if (c->arg < ICN_BCH) {
+ a = c->arg + 1;
+ sprintf(cbuf, "%02d;BDIS_R\n%02d;DDIS_R\n", (int) a, (int) a);
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+ }
+ break;
+ case ISDN_CMD_SETEAZ:
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ if (card->leased)
+ break;
+ if (c->arg < ICN_BCH) {
+ a = c->arg + 1;
+ if (card->ptype == ISDN_PTYPE_EURO) {
+ sprintf(cbuf, "%02d;MS%s%s\n", (int) a,
+ c->num[0] ? "N" : "ALL", c->num);
+ } else
+ sprintf(cbuf, "%02d;EAZ%s\n", (int) a,
+ c->num[0] ? c->num : "0123456789");
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+ }
+ break;
+ case ISDN_CMD_CLREAZ:
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ if (card->leased)
+ break;
+ if (c->arg < ICN_BCH) {
+ a = c->arg + 1;
+ if (card->ptype == ISDN_PTYPE_EURO)
+ sprintf(cbuf, "%02d;MSNC\n", (int) a);
+ else
+ sprintf(cbuf, "%02d;EAZC\n", (int) a);
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+ }
+ break;
+ case ISDN_CMD_SETL2:
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ if ((c->arg & 255) < ICN_BCH) {
+ a = c->arg;
+ switch (a >> 8) {
+ case ISDN_PROTO_L2_X75I:
+ sprintf(cbuf, "%02d;BX75\n", (int) (a & 255) + 1);
+ break;
+ case ISDN_PROTO_L2_HDLC:
+ sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1);
+ break;
+ default:
+ return -EINVAL;
+ }
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+ card->l2_proto[a & 255] = (a >> 8);
+ }
+ break;
+ case ISDN_CMD_GETL2:
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ if ((c->arg & 255) < ICN_BCH)
+ return card->l2_proto[c->arg & 255];
+ else
+ return -ENODEV;
+ case ISDN_CMD_SETL3:
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ return 0;
+ case ISDN_CMD_GETL3:
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ if ((c->arg & 255) < ICN_BCH)
+ return ISDN_PROTO_L3_TRANS;
+ else
+ return -ENODEV;
+ case ISDN_CMD_GETEAZ:
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ break;
+ case ISDN_CMD_SETSIL:
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ break;
+ case ISDN_CMD_GETSIL:
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ break;
+ case ISDN_CMD_LOCK:
+ MOD_INC_USE_COUNT;
+ break;
+ case ISDN_CMD_UNLOCK:
+ MOD_DEC_USE_COUNT;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
}
/*
- * For second half of doubleS0-Card add channel-offset.
+ * Find card with given driverId
*/
-static int if_command1(isdn_ctrl * c)
+static inline icn_card *
+ icn_findcard(int driverid)
{
- return (icn_command(c, dev));
-}
+ icn_card *p = cards;
-static int if_command2(isdn_ctrl * c)
-{
- return (icn_command(c, dev2));
+ while (p) {
+ if (p->myid == driverid)
+ return p;
+ p = p->next;
+ }
+ return (icn_card *)0;
}
-static int if_writecmd1(const u_char * buf, int len, int user)
+/*
+ * Wrapper functions for interface to linklevel
+ */
+static int if_command(isdn_ctrl * c)
{
- return (icn_writecmd(buf, len, user, dev, 0));
-}
+ icn_card *card = icn_findcard(c->driver);
-static int if_writecmd2(const u_char * buf, int len, int user)
-{
- return (icn_writecmd(buf, len, user, dev2, 0));
+ if (card)
+ return (icn_command(c, card));
+ printk(KERN_ERR
+ "icn: if_command called with invalid driverId!\n");
+ return -ENODEV;
}
-static int if_readstatus1(u_char * buf, int len, int user)
+static int if_writecmd(const u_char * buf, int len, int user, int id, int channel)
{
- return (icn_readstatus(buf, len, user, dev));
+ icn_card *card = icn_findcard(id);
+
+ if (card) {
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ return (icn_writecmd(buf, len, user, card, 0));
+ }
+ printk(KERN_ERR
+ "icn: if_writecmd called with invalid driverId!\n");
+ return -ENODEV;
}
-static int if_readstatus2(u_char * buf, int len, int user)
+static int if_readstatus(u_char * buf, int len, int user, int id, int channel)
{
- return (icn_readstatus(buf, len, user, dev2));
+ icn_card *card = icn_findcard(id);
+
+ if (card) {
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ return (icn_readstatus(buf, len, user, card));
+ }
+ printk(KERN_ERR
+ "icn: if_readstatus called with invalid driverId!\n");
+ return -ENODEV;
}
-static int if_sendbuf1(int id, int channel, const u_char * buffer, int len,
- int user)
+static int if_sendbuf(int id, int channel, struct sk_buff *skb)
{
- return (icn_sendbuf(channel, buffer, len, user, dev));
+ icn_card *card = icn_findcard(id);
+
+ if (card) {
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ return (icn_sendbuf(channel, skb, card));
+ }
+ printk(KERN_ERR
+ "icn: if_readstatus called with invalid driverId!\n");
+ return -ENODEV;
}
-static int if_sendbuf2(int id, int channel, const u_char * buffer, int len,
- int user)
-{
- return (icn_sendbuf(channel, buffer, len, user, dev2));
+/*
+ * Allocate a new card-struct, initialize it
+ * link it into cards-list and register it at linklevel.
+ */
+static icn_card *icn_initcard(int port, char *id) {
+ icn_card *card;
+ int i;
+
+ if (!(card = (icn_card *) kmalloc(sizeof(icn_card), GFP_KERNEL))) {
+ printk(KERN_WARNING
+ "icn: (%s) Could not allocate card-struct.\n", id);
+ return (icn_card *)0;
+ }
+ memset((char *) card, 0, sizeof(icn_card));
+ card->port = port;
+ card->interface.channels = ICN_BCH;
+ card->interface.maxbufsize = 4000;
+ card->interface.command = if_command;
+ /*
+ card->interface.writebuf = if_sendbuf;
+ */
+ card->interface.writebuf_skb = if_sendbuf;
+ card->interface.writecmd = if_writecmd;
+ card->interface.readstat = if_readstatus;
+ card->interface.features = ISDN_FEATURE_L2_X75I |
+ ISDN_FEATURE_L2_HDLC |
+ ISDN_FEATURE_L3_TRANS |
+ ISDN_FEATURE_P_UNKNOWN;
+ card->ptype = ISDN_PTYPE_UNKNOWN;
+ strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
+ card->msg_buf_write = card->msg_buf;
+ card->msg_buf_read = card->msg_buf;
+ card->msg_buf_end = &card->msg_buf[sizeof(card->msg_buf) - 1];
+ for (i=0;i<ICN_BCH;i++) {
+ card->l2_proto[i] = ISDN_PROTO_L2_X75I;
+ skb_queue_head_init(&card->spqueue[i]);
+ }
+ card->next = cards;
+ cards = card;
+ if (!register_isdn(&card->interface)) {
+ cards = cards->next;
+ printk(KERN_WARNING
+ "icn: Unable to register %s\n", id);
+ kfree(card);
+ return (icn_card*)0;
+ }
+ card->myid = card->interface.channels;
+ sprintf(card->regname, "icn-isdn (%s)", card->interface.id);
+ return card;
+}
+
+static int icn_addcard(int port, char *id1, char *id2)
+{
+ ulong flags;
+ icn_card *card;
+ icn_card *card2;
+
+ save_flags(flags);
+ cli();
+ if (!(card = icn_initcard(port,id1))) {
+ restore_flags(flags);
+ return -EIO;
+ }
+ if (!strlen(id2)) {
+ restore_flags(flags);
+ printk(KERN_INFO
+ "icn: (%s) ICN-2B, port 0x%x added\n",
+ card->interface.id, port);
+ return 0;
+ }
+ if (!(card2 = icn_initcard(port,id2))) {
+ restore_flags(flags);
+ printk(KERN_INFO
+ "icn: (%s) half ICN-4B, port 0x%x added\n",
+ card2->interface.id, port);
+ return 0;
+ }
+ card->doubleS0 = 1;
+ card->secondhalf = 0;
+ card->other = card2;
+ card2->doubleS0 = 1;
+ card2->secondhalf = 1;
+ card2->other = card;
+ restore_flags(flags);
+ printk(KERN_INFO
+ "icn: (%s and %s) ICN-4B, port 0x%x added\n",
+ card->interface.id, card2->interface.id, port);
+ return 0;
}
#ifdef MODULE
@@ -1355,158 +1523,81 @@
#else
void icn_setup(char *str, int *ints)
{
- char *p;
- static char sid[20];
- static char sid2[20];
-
- if (ints[0])
- portbase = ints[1];
- if (ints[0]>1)
- membase = ints[2];
- if (strlen(str)) {
- strcpy(sid,str);
- icn_id = sid;
- if ((p = strchr(sid,','))) {
- *p++ = 0;
- strcpy(sid2,p);
- icn_id2 = sid2;
- }
- }
+ char *p;
+ static char sid[20];
+ static char sid2[20];
+
+ if (ints[0])
+ portbase = ints[1];
+ if (ints[0]>1)
+ membase = ints[2];
+ if (strlen(str)) {
+ strcpy(sid,str);
+ icn_id = sid;
+ if ((p = strchr(sid,','))) {
+ *p++ = 0;
+ strcpy(sid2,p);
+ icn_id2 = sid2;
+ }
+ }
}
#endif
int icn_init(void)
{
-#ifdef LOADEXTERN
- unsigned long flags;
-#endif
- char *p;
- isdn_ctrl cmd;
- char rev[10];
-
- if (!(dev = (icn_devptr) kmalloc(sizeof(icn_dev), GFP_KERNEL))) {
- printk(KERN_WARNING "icn: Could not allocate device-struct.\n");
- return -EIO;
- }
- memset((char *) dev, 0, sizeof(icn_dev));
- dev->port = portbase;
- dev->shmem = (icn_shmem *) (membase & 0x0ffc000);
- if (strlen(icn_id2))
- dev->doubleS0 = 1;
- dev->interface.channels = ICN_BCH;
- dev->interface.maxbufsize = 4000;
- dev->interface.command = if_command1;
- dev->interface.writebuf = if_sendbuf1;
- dev->interface.writecmd = if_writecmd1;
- dev->interface.readstat = if_readstatus1;
- dev->interface.features = ISDN_FEATURE_L2_X75I |
- ISDN_FEATURE_L2_HDLC |
- ISDN_FEATURE_L3_TRANS |
- ISDN_FEATURE_P_UNKNOWN;
- dev->ptype = ISDN_PTYPE_UNKNOWN;
- strncpy(dev->interface.id, icn_id, sizeof(dev->interface.id) - 1);
- dev->msg_buf_write = dev->msg_buf;
- dev->msg_buf_read = dev->msg_buf;
- dev->msg_buf_end = &dev->msg_buf[sizeof(dev->msg_buf) - 1];
- memset((char *) dev->l2_proto, ISDN_PROTO_L2_X75I, sizeof(dev->l2_proto));
- if (strlen(icn_id2)) {
- if (!(dev2 = (icn_devptr) kmalloc(sizeof(icn_dev), GFP_KERNEL))) {
- printk(KERN_WARNING "icn: Could not allocate device-struct.\n");
- kfree(dev);
- kfree(dev2);
- return -EIO;
- }
- memcpy((char *) dev2, (char *) dev, sizeof(icn_dev));
- dev2->interface.command = if_command2;
- dev2->interface.writebuf = if_sendbuf2;
- dev2->interface.writecmd = if_writecmd2;
- dev2->interface.readstat = if_readstatus2;
- strncpy(dev2->interface.id, icn_id2,
- sizeof(dev->interface.id) - 1);
- dev2->msg_buf_write = dev2->msg_buf;
- dev2->msg_buf_read = dev2->msg_buf;
- dev2->msg_buf_end = &dev2->msg_buf[sizeof(dev2->msg_buf) - 1];
- dev2->secondhalf = 1;
- }
- if (!register_isdn(&dev->interface)) {
- printk(KERN_WARNING "icn: Unable to register\n");
- kfree(dev);
- if (dev->doubleS0)
- kfree(dev2);
- return -EIO;
- }
- dev->myid = dev->interface.channels;
- sprintf(regname, "icn-isdn (%s)", dev->interface.id);
- if (dev->doubleS0) {
- if (!register_isdn(&dev2->interface)) {
- printk(KERN_WARNING "icn: Unable to register\n");
- kfree(dev2);
- if (dev->doubleS0) {
- icn_stopdriver(dev);
- cmd.command = ISDN_STAT_UNLOAD;
- cmd.driver = dev->myid;
- dev->interface.statcallb(&cmd);
- kfree(dev);
- }
- return -EIO;
- }
- dev2->myid = dev2->interface.channels;
- }
-
- /* No symbols to export, hide all symbols */
- register_symtab(NULL);
-
- if ((p = strchr(revision, ':'))) {
- strcpy(rev, p + 1);
- p = strchr(rev, '$');
- *p = 0;
- } else
- strcpy(rev, " ??? ");
- printk(KERN_NOTICE "ICN-ISDN-driver Rev%sport=0x%03x mmio=0x%08x id='%s'\n",
- rev, dev->port, (uint) dev->shmem, dev->interface.id);
-#ifdef LOADEXTERN
- save_flags(flags);
- cli();
- init_timer(&dev->st_timer);
- dev->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
- dev->st_timer.function = icn_pollcard;
- add_timer(&dev->st_timer);
- restore_flags(flags);
-#endif
- return 0;
+ char *p;
+ char rev[10];
+
+ memset(&dev, 0, sizeof(icn_dev));
+ dev.shmem = (icn_shmem *) (membase & 0x0ffc000);
+
+ /* No symbols to export, hide all symbols */
+ register_symtab(NULL);
+
+ if ((p = strchr(revision, ':'))) {
+ strcpy(rev, p + 1);
+ p = strchr(rev, '$');
+ *p = 0;
+ } else
+ strcpy(rev, " ??? ");
+ printk(KERN_NOTICE "ICN-ISDN-driver Rev%smem=0x%08x\n", rev,
+ (uint) dev.shmem);
+ return (icn_addcard(portbase,icn_id,icn_id2));
}
#ifdef MODULE
void cleanup_module(void)
{
- isdn_ctrl cmd;
- int i;
-
- icn_stopdriver(dev);
- cmd.command = ISDN_STAT_UNLOAD;
- cmd.driver = dev->myid;
- dev->interface.statcallb(&cmd);
- if (dev->doubleS0) {
- icn_stopdriver(dev2);
- cmd.command = ISDN_STAT_UNLOAD;
- cmd.driver = dev2->myid;
- dev2->interface.statcallb(&cmd);
- }
- if (dev->rvalid) {
- OUTB_P(0, ICN_RUN); /* Reset Controller */
- OUTB_P(0, ICN_MAPRAM); /* Disable RAM */
- release_region(dev->port, ICN_PORTLEN);
- }
- if (dev->mvalid)
- release_shmem((ulong) dev->shmem, 0x4000);
- if (dev->doubleS0) {
- for (i = 0; i < ICN_BCH; i++)
- icn_free_queue(&dev2->spqueue[1]);
- kfree(dev2);
- }
- for (i = 0; i < ICN_BCH; i++)
- icn_free_queue(&dev->spqueue[1]);
- kfree(dev);
- printk(KERN_NOTICE "ICN-ISDN-driver unloaded\n");
+ isdn_ctrl cmd;
+ icn_card *card = cards;
+ icn_card *last;
+ int i;
+
+ icn_stopallcards();
+ while (card) {
+ cmd.command = ISDN_STAT_UNLOAD;
+ cmd.driver = card->myid;
+ card->interface.statcallb(&cmd);
+ if (card->rvalid) {
+ OUTB_P(0, ICN_RUN); /* Reset Controller */
+ OUTB_P(0, ICN_MAPRAM); /* Disable RAM */
+ if (card->secondhalf || (!card->doubleS0)) {
+ release_region(card->port, ICN_PORTLEN);
+ card->rvalid = 0;
+ }
+ for (i = 0; i < ICN_BCH; i++)
+ icn_free_queue(&card->spqueue[i]);
+ }
+ card = card->next;
+ }
+ card = card;
+ while (card) {
+ last = card;
+ card = card->next;
+ kfree(last);
+ }
+ if (dev.mvalid)
+ release_shmem((ulong) dev.shmem, 0x4000);
+ printk(KERN_NOTICE "ICN-ISDN-driver unloaded\n");
}
#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this