123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692 |
- /* $Id: icn.c,v 1.65.6.8 2001/09/23 22:24:55 kai Exp $
- *
- * ISDN low-level module for the ICN active ISDN-Card.
- *
- * Copyright 1994,95,96 by Fritz Elfert (fritz@isdn4linux.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
- #include "icn.h"
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/sched.h>
- static int portbase = ICN_BASEADDR;
- static unsigned long membase = ICN_MEMADDR;
- static char *icn_id = "\0";
- static char *icn_id2 = "\0";
- MODULE_DESCRIPTION("ISDN4Linux: Driver for ICN active ISDN card");
- MODULE_AUTHOR("Fritz Elfert");
- MODULE_LICENSE("GPL");
- module_param(portbase, int, 0);
- MODULE_PARM_DESC(portbase, "Port address of first card");
- module_param(membase, ulong, 0);
- MODULE_PARM_DESC(membase, "Shared memory address of all cards");
- module_param(icn_id, charp, 0);
- MODULE_PARM_DESC(icn_id, "ID-String of first card");
- module_param(icn_id2, charp, 0);
- MODULE_PARM_DESC(icn_id2, "ID-String of first card, second S0 (4B only)");
- /*
- * Verbose bootcode- and protocol-downloading.
- */
- #undef BOOT_DEBUG
- /*
- * Verbose Shmem-Mapping.
- */
- #undef MAP_DEBUG
- static char
- *revision = "$Revision: 1.65.6.8 $";
- static int icn_addcard(int, char *, char *);
- /*
- * Free send-queue completely.
- * Parameter:
- * card = pointer to card struct
- * channel = channel number
- */
- static void
- icn_free_queue(icn_card * card, int channel)
- {
- struct sk_buff_head *queue = &card->spqueue[channel];
- struct sk_buff *skb;
- skb_queue_purge(queue);
- card->xlen[channel] = 0;
- card->sndcount[channel] = 0;
- if ((skb = card->xskb[channel])) {
- card->xskb[channel] = NULL;
- dev_kfree_skb(skb);
- }
- }
- /* Put a value into a shift-register, highest bit first.
- * Parameters:
- * port = port for output (bit 0 is significant)
- * val = value to be output
- * firstbit = Bit-Number of highest bit
- * bitcount = Number of bits to output
- */
- static inline void
- icn_shiftout(unsigned short port,
- unsigned long val,
- int firstbit,
- int bitcount)
- {
- 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);
- }
- /*
- * disable a cards shared memory
- */
- static inline void
- icn_disable_ram(icn_card * card)
- {
- 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)
- *
- * must called with holding the devlock
- */
- 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);
- #endif
- 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");
- #endif
- }
- /*
- * Lock a cards channel.
- * Return 0 if requested card/channel is unmapped (failure).
- * Return 1 on success.
- *
- * must called with holding the devlock
- */
- static inline int
- icn_lock_channel(icn_card * card, int channel)
- {
- register int retval;
- #ifdef MAP_DEBUG
- printk(KERN_DEBUG "icn_lock_channel %d\n", channel);
- #endif
- if ((dev.channel == channel) && (card == dev.mcard)) {
- dev.chanlock++;
- retval = 1;
- #ifdef MAP_DEBUG
- printk(KERN_DEBUG "icn_lock_channel %d OK\n", channel);
- #endif
- } else {
- retval = 0;
- #ifdef MAP_DEBUG
- printk(KERN_DEBUG "icn_lock_channel %d FAILED, dc=%d\n", channel, dev.channel);
- #endif
- }
- return retval;
- }
- /*
- * Release current card/channel lock
- *
- * must called with holding the devlock
- */
- static inline void
- __icn_release_channel(void)
- {
- #ifdef MAP_DEBUG
- printk(KERN_DEBUG "icn_release_channel l=%d\n", dev.chanlock);
- #endif
- if (dev.chanlock > 0)
- dev.chanlock--;
- }
- /*
- * Release current card/channel lock
- */
- static inline void
- icn_release_channel(void)
- {
- ulong flags;
- spin_lock_irqsave(&dev.devlock, flags);
- __icn_release_channel();
- spin_unlock_irqrestore(&dev.devlock, flags);
- }
- /*
- * 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;
- #ifdef MAP_DEBUG
- printk(KERN_DEBUG "trymaplock c=%d dc=%d l=%d\n", channel, dev.channel,
- dev.chanlock);
- #endif
- spin_lock_irqsave(&dev.devlock, flags);
- if ((!dev.chanlock) ||
- ((dev.channel == channel) && (dev.mcard == card))) {
- dev.chanlock++;
- icn_map_channel(card, channel);
- spin_unlock_irqrestore(&dev.devlock, flags);
- #ifdef MAP_DEBUG
- printk(KERN_DEBUG "trymaplock %d OK\n", channel);
- #endif
- return 1;
- }
- spin_unlock_irqrestore(&dev.devlock, flags);
- #ifdef MAP_DEBUG
- printk(KERN_DEBUG "trymaplock %d FAILED\n", channel);
- #endif
- return 0;
- }
- /*
- * Release current card/channel lock,
- * then map same or other channel without locking.
- */
- static inline void
- icn_maprelease_channel(icn_card * card, int channel)
- {
- ulong flags;
- #ifdef MAP_DEBUG
- printk(KERN_DEBUG "map_release c=%d l=%d\n", channel, dev.chanlock);
- #endif
- spin_lock_irqsave(&dev.devlock, flags);
- if (dev.chanlock > 0)
- dev.chanlock--;
- if (!dev.chanlock)
- icn_map_channel(card, channel);
- spin_unlock_irqrestore(&dev.devlock, 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 icn_pollbchan().
- */
- 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 = readb(&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_fromio(&card->rcvbuf[channel][card->rcvidx[channel]],
- &rbuf_d, cnt);
- card->rcvidx[channel] += cnt;
- eflag = readb(&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 "icn: 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 icn_pollbchan() or
- * directly from icn_sendbuf().
- */
- static void
- icn_pollbchan_send(int channel, icn_card * card)
- {
- int mch = channel + ((card->secondhalf) ? 2 : 0);
- int cnt;
- unsigned long flags;
- struct sk_buff *skb;
- isdn_ctrl cmd;
- if (!(card->sndcount[channel] || card->xskb[channel] ||
- !skb_queue_empty(&card->spqueue[channel])))
- return;
- if (icn_trymaplock_channel(card, mch)) {
- while (sbfree &&
- (card->sndcount[channel] ||
- !skb_queue_empty(&card->spqueue[channel]) ||
- card->xskb[channel])) {
- spin_lock_irqsave(&card->lock, flags);
- if (card->xmit_lock[channel]) {
- spin_unlock_irqrestore(&card->lock, flags);
- break;
- }
- card->xmit_lock[channel]++;
- spin_unlock_irqrestore(&card->lock, flags);
- skb = card->xskb[channel];
- if (!skb) {
- skb = skb_dequeue(&card->spqueue[channel]);
- if (skb) {
- /* Pop ACK-flag off skb.
- * Store length to xlen.
- */
- if (*(skb_pull(skb,1)))
- card->xlen[channel] = skb->len;
- else
- card->xlen[channel] = 0;
- }
- }
- if (!skb)
- break;
- if (skb->len > ICN_FRAGSIZE) {
- writeb(0xff, &sbuf_f);
- cnt = ICN_FRAGSIZE;
- } else {
- writeb(0x0, &sbuf_f);
- cnt = skb->len;
- }
- writeb(cnt, &sbuf_l);
- memcpy_toio(&sbuf_d, skb->data, cnt);
- skb_pull(skb, cnt);
- sbnext; /* switch to next buffer */
- icn_maprelease_channel(card, mch & 2);
- spin_lock_irqsave(&card->lock, flags);
- card->sndcount[channel] -= cnt;
- if (!skb->len) {
- if (card->xskb[channel])
- card->xskb[channel] = NULL;
- card->xmit_lock[channel] = 0;
- spin_unlock_irqrestore(&card->lock, flags);
- dev_kfree_skb(skb);
- if (card->xlen[channel]) {
- cmd.command = ISDN_STAT_BSENT;
- cmd.driver = card->myid;
- cmd.arg = channel;
- cmd.parm.length = card->xlen[channel];
- card->interface.statcallb(&cmd);
- }
- } else {
- card->xskb[channel] = skb;
- card->xmit_lock[channel] = 0;
- spin_unlock_irqrestore(&card->lock, flags);
- }
- if (!icn_trymaplock_channel(card, mch))
- break;
- }
- icn_maprelease_channel(card, mch & 2);
- }
- }
- /* Send/Receive Data to/from the B-Channel.
- * This routine is called via timer-callback.
- * It schedules itself while any B-Channel is open.
- */
- static void
- icn_pollbchan(unsigned long data)
- {
- icn_card *card = (icn_card *) data;
- unsigned long 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 */
- spin_lock_irqsave(&card->lock, flags);
- mod_timer(&card->rb_timer, jiffies+ICN_TIMER_BCREAD);
- card->flags |= ICN_FLAGS_RBTIMER;
- spin_unlock_irqrestore(&card->lock, flags);
- } else
- card->flags &= ~ICN_FLAGS_RBTIMER;
- }
- typedef struct icn_stat {
- char *statstr;
- int command;
- int action;
- } icn_stat;
- /* *INDENT-OFF* */
- static icn_stat icn_stat_table[] =
- {
- {"BCON_", ISDN_STAT_BCONN, 1}, /* B-Channel connected */
- {"BDIS_", ISDN_STAT_BHUP, 2}, /* B-Channel disconnected */
- /*
- ** add d-channel connect and disconnect support to link-level
- */
- {"DCON_", ISDN_STAT_DCONN, 10}, /* D-Channel connected */
- {"DDIS_", ISDN_STAT_DHUP, 11}, /* 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 */
- {"E_L1: ACT FAIL", ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */
- {"E_L2: DATA LIN", ISDN_STAT_BHUP, 8}, /* Layer-2 data link lost */
- {"E_L1: ACTIVATION FAILED",
- ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */
- {NULL, 0, -1}
- };
- /* *INDENT-ON* */
- /*
- * 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.
- * If there are B-Channels open, initiate a timer-callback to
- * icn_pollbchan().
- * This routine is called periodically via timer.
- */
- static void
- icn_parse_status(u_char * status, int channel, icn_card * card)
- {
- icn_stat *s = icn_stat_table;
- int action = -1;
- 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;
- cmd.driver = card->myid;
- cmd.arg = channel;
- switch (action) {
- case 11:
- spin_lock_irqsave(&card->lock, flags);
- icn_free_queue(card,channel);
- card->rcvidx[channel] = 0;
- if (card->flags &
- ((channel)?ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE)) {
-
- isdn_ctrl ncmd;
-
- card->flags &= ~((channel)?
- ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE);
-
- memset(&ncmd, 0, sizeof(ncmd));
-
- ncmd.driver = card->myid;
- ncmd.arg = channel;
- ncmd.command = ISDN_STAT_BHUP;
- spin_unlock_irqrestore(&card->lock, flags);
- card->interface.statcallb(&cmd);
- } else
- spin_unlock_irqrestore(&card->lock, flags);
- break;
- case 1:
- spin_lock_irqsave(&card->lock, flags);
- icn_free_queue(card,channel);
- card->flags |= (channel) ?
- ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE;
- spin_unlock_irqrestore(&card->lock, flags);
- break;
- case 2:
- spin_lock_irqsave(&card->lock, flags);
- card->flags &= ~((channel) ?
- ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE);
- icn_free_queue(card, channel);
- card->rcvidx[channel] = 0;
- spin_unlock_irqrestore(&card->lock, flags);
- break;
- case 3:
- {
- char *t = status + 6;
- char *s = strchr(t, ',');
- *s++ = '\0';
- strlcpy(cmd.parm.setup.phone, t,
- sizeof(cmd.parm.setup.phone));
- s = strchr(t = s, ',');
- *s++ = '\0';
- if (!strlen(t))
- cmd.parm.setup.si1 = 0;
- else
- cmd.parm.setup.si1 =
- simple_strtoul(t, NULL, 10);
- s = strchr(t = s, ',');
- *s++ = '\0';
- if (!strlen(t))
- cmd.parm.setup.si2 = 0;
- else
- cmd.parm.setup.si2 =
- simple_strtoul(t, NULL, 10);
- strlcpy(cmd.parm.setup.eazmsn, s,
- sizeof(cmd.parm.setup.eazmsn));
- }
- cmd.parm.setup.plan = 0;
- cmd.parm.setup.screen = 0;
- break;
- case 4:
- sprintf(cmd.parm.setup.phone, "LEASED%d", card->myid);
- sprintf(cmd.parm.setup.eazmsn, "%d", channel + 1);
- cmd.parm.setup.si1 = 7;
- cmd.parm.setup.si2 = 0;
- cmd.parm.setup.plan = 0;
- cmd.parm.setup.screen = 0;
- break;
- case 5:
- strlcpy(cmd.parm.num, status + 3, sizeof(cmd.parm.num));
- break;
- case 6:
- snprintf(cmd.parm.num, sizeof(cmd.parm.num), "%d",
- (int) simple_strtoul(status + 7, NULL, 16));
- break;
- case 7:
- status += 3;
- if (strlen(status) == 4)
- snprintf(cmd.parm.num, sizeof(cmd.parm.num), "%s%c%c",
- status + 2, *status, *(status + 1));
- else
- strlcpy(cmd.parm.num, status + 1, sizeof(cmd.parm.num));
- break;
- case 8:
- spin_lock_irqsave(&card->lock, flags);
- card->flags &= ~ICN_FLAGS_B1ACTIVE;
- icn_free_queue(card, 0);
- card->rcvidx[0] = 0;
- spin_unlock_irqrestore(&card->lock, flags);
- 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;
- spin_lock_irqsave(&card->lock, flags);
- card->flags &= ~ICN_FLAGS_B2ACTIVE;
- icn_free_queue(card, 1);
- card->rcvidx[1] = 0;
- spin_unlock_irqrestore(&card->lock, flags);
- 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;
- }
- static void
- icn_putmsg(icn_card * card, unsigned char c)
- {
- ulong flags;
- spin_lock_irqsave(&card->lock, flags);
- *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;
- spin_unlock_irqrestore(&card->lock, flags);
- }
- static void
- icn_polldchan(unsigned long data)
- {
- icn_card *card = (icn_card *) data;
- int mch = card->secondhalf ? 2 : 0;
- int avail = 0;
- int left;
- u_char c;
- int ch;
- unsigned long flags;
- int i;
- u_char *p;
- isdn_ctrl cmd;
- if (icn_trymaplock_channel(card, mch)) {
- avail = msg_avail;
- for (left = avail, i = readb(&msg_o); left > 0; i++, left--) {
- c = readb(&dev.shmem->comm_buffers.iopc_buf[i & 0xff]);
- icn_putmsg(card, c);
- 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];
- 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++;
- }
- }
- writeb((readb(&msg_o) + avail) & 0xff, &msg_o);
- icn_release_channel();
- }
- if (avail) {
- cmd.command = ISDN_STAT_STAVAIL;
- cmd.driver = card->myid;
- cmd.arg = avail;
- card->interface.statcallb(&cmd);
- }
- spin_lock_irqsave(&card->lock, flags);
- if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE))
- if (!(card->flags & ICN_FLAGS_RBTIMER)) {
- /* schedule b-channel polling */
- card->flags |= ICN_FLAGS_RBTIMER;
- 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);
- }
- /* schedule again */
- mod_timer(&card->st_timer, jiffies+ICN_TIMER_DCREAD);
- spin_unlock_irqrestore(&card->lock, flags);
- }
- /* Append a packet to the transmit buffer-queue.
- * Parameters:
- * channel = Number of B-channel
- * skb = pointer to sk_buff
- * card = pointer to card-struct
- * Return:
- * Number of bytes transferred, -E??? on error
- */
- static int
- icn_sendbuf(int channel, int ack, struct sk_buff *skb, icn_card * card)
- {
- int len = skb->len;
- unsigned long flags;
- struct sk_buff *nskb;
- if (len > 4000) {
- printk(KERN_WARNING
- "icn: Send packet too large\n");
- 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;
- #warning TODO test headroom or use skb->nb to flag ACK
- nskb = skb_clone(skb, GFP_ATOMIC);
- if (nskb) {
- /* Push ACK flag as one
- * byte in front of data.
- */
- *(skb_push(nskb, 1)) = ack?1:0;
- skb_queue_tail(&card->spqueue[channel], nskb);
- dev_kfree_skb(skb);
- } else
- len = 0;
- spin_lock_irqsave(&card->lock, flags);
- card->sndcount[channel] += len;
- spin_unlock_irqrestore(&card->lock, flags);
- }
- return len;
- }
- /*
- * Check card's status after starting the bootstrap loader.
- * On entry, the card's shared memory has already to be mapped.
- * Return:
- * 0 on success (Boot loader ready)
- * -EIO on failure (timeout)
- */
- static int
- icn_check_loader(int cardnumber)
- {
- int timer = 0;
- while (1) {
- #ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Loader %d ?\n", cardnumber);
- #endif
- if (readb(&dev.shmem->data_control.scns) ||
- readb(&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);
- #endif
- msleep_interruptible(ICN_BOOT_TIMEOUT1);
- } else {
- #ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Loader %d OK\n", cardnumber);
- #endif
- icn_release_channel();
- return 0;
- }
- }
- }
- /* Load the boot-code into the interface-card's memory and start it.
- * Always called from user-process.
- *
- * Parameters:
- * buffer = pointer to packet
- * Return:
- * 0 if successfully loaded
- */
- #ifdef BOOT_DEBUG
- #define SLEEP(sec) { \
- int slsec = sec; \
- printk(KERN_DEBUG "SLEEP(%d)\n",slsec); \
- while (slsec) { \
- msleep_interruptible(1000); \
- slsec--; \
- } \
- }
- #else
- #define SLEEP(sec)
- #endif
- static int
- icn_loadboot(u_char __user * buffer, icn_card * card)
- {
- int ret;
- u_char *codebuf;
- unsigned long flags;
- #ifdef BOOT_DEBUG
- printk(KERN_DEBUG "icn_loadboot called, buffaddr=%08lx\n", (ulong) buffer);
- #endif
- if (!(codebuf = kmalloc(ICN_CODE_STAGE1, GFP_KERNEL))) {
- printk(KERN_WARNING "icn: Could not allocate code buffer\n");
- ret = -ENOMEM;
- goto out;
- }
- if (copy_from_user(codebuf, buffer, ICN_CODE_STAGE1)) {
- ret = -EFAULT;
- goto out_kfree;
- }
- if (!card->rvalid) {
- if (!request_region(card->port, ICN_PORTLEN, card->regname)) {
- printk(KERN_WARNING
- "icn: (%s) ports 0x%03x-0x%03x in use.\n",
- CID,
- card->port,
- card->port + ICN_PORTLEN);
- ret = -EBUSY;
- goto out_kfree;
- }
- card->rvalid = 1;
- if (card->doubleS0)
- card->other->rvalid = 1;
- }
- if (!dev.mvalid) {
- if (!request_mem_region(dev.memaddr, 0x4000, "icn-isdn (all cards)")) {
- printk(KERN_WARNING
- "icn: memory at 0x%08lx in use.\n", dev.memaddr);
- ret = -EBUSY;
- goto out_kfree;
- }
- dev.shmem = ioremap(dev.memaddr, 0x4000);
- dev.mvalid = 1;
- }
- 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, dev.memaddr, 23, 10); /* Set RAM-Addr. */
- #ifdef BOOT_DEBUG
- printk(KERN_DEBUG "shmem=%08lx\n", dev.memaddr);
- #endif
- SLEEP(1);
- #ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Map Bank 0\n");
- #endif
- spin_lock_irqsave(&dev.devlock, flags);
- icn_map_channel(card, 0); /* Select Bank 0 */
- icn_lock_channel(card, 0); /* Lock Bank 0 */
- spin_unlock_irqrestore(&dev.devlock, flags);
- SLEEP(1);
- memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); /* Copy code */
- #ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Bootloader transferred\n");
- #endif
- if (card->doubleS0) {
- SLEEP(1);
- #ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Map Bank 8\n");
- #endif
- spin_lock_irqsave(&dev.devlock, flags);
- __icn_release_channel();
- icn_map_channel(card, 2); /* Select Bank 8 */
- icn_lock_channel(card, 2); /* Lock Bank 8 */
- spin_unlock_irqrestore(&dev.devlock, flags);
- SLEEP(1);
- memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); /* Copy code */
- #ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Bootloader transferred\n");
- #endif
- }
- SLEEP(1);
- OUTB_P(0xff, ICN_RUN); /* Start Boot-Code */
- if ((ret = icn_check_loader(card->doubleS0 ? 2 : 1))) {
- goto out_kfree;
- }
- if (!card->doubleS0) {
- ret = 0;
- goto out_kfree;
- }
- /* reached only, if we have a Double-S0-Card */
- #ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Map Bank 0\n");
- #endif
- spin_lock_irqsave(&dev.devlock, flags);
- icn_map_channel(card, 0); /* Select Bank 0 */
- icn_lock_channel(card, 0); /* Lock Bank 0 */
- spin_unlock_irqrestore(&dev.devlock, flags);
- SLEEP(1);
- ret = (icn_check_loader(1));
- out_kfree:
- kfree(codebuf);
- out:
- return ret;
- }
- static int
- icn_loadproto(u_char __user * buffer, icn_card * card)
- {
- register u_char __user *p = buffer;
- u_char codebuf[256];
- uint left = ICN_CODE_STAGE2;
- uint cnt;
- int timer;
- unsigned long flags;
- #ifdef BOOT_DEBUG
- printk(KERN_DEBUG "icn_loadproto called\n");
- #endif
- if (!access_ok(VERIFY_READ, buffer, ICN_CODE_STAGE2))
- return -EFAULT;
- timer = 0;
- spin_lock_irqsave(&dev.devlock, flags);
- if (card->secondhalf) {
- icn_map_channel(card, 2);
- icn_lock_channel(card, 2);
- } else {
- icn_map_channel(card, 0);
- icn_lock_channel(card, 0);
- }
- spin_unlock_irqrestore(&dev.devlock, flags);
- while (left) {
- if (sbfree) { /* If there is a free buffer... */
- cnt = left;
- if (cnt > 256)
- cnt = 256;
- if (copy_from_user(codebuf, p, cnt)) {
- icn_maprelease_channel(card, 0);
- return -EFAULT;
- }
- memcpy_toio(&sbuf_l, codebuf, 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");
- #endif
- if (timer++ > 5) {
- icn_maprelease_channel(card, 0);
- return -EIO;
- }
- schedule_timeout_interruptible(10);
- }
- }
- writeb(0x20, &sbuf_n);
- timer = 0;
- while (1) {
- if (readb(&cmd_o) || readb(&cmd_i)) {
- #ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Proto?\n");
- #endif
- if (timer++ > 5) {
- printk(KERN_WARNING
- "icn: (%s) Protocol timed out.\n",
- CID);
- #ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Proto TO!\n");
- #endif
- icn_maprelease_channel(card, 0);
- return -EIO;
- }
- #ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Proto TO?\n");
- #endif
- msleep_interruptible(ICN_BOOT_TIMEOUT1);
- } else {
- if ((card->secondhalf) || (!card->doubleS0)) {
- #ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Proto loaded, install poll-timer %d\n",
- card->secondhalf);
- #endif
- spin_lock_irqsave(&card->lock, flags);
- 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;
- }
- spin_unlock_irqrestore(&card->lock, flags);
- }
- icn_maprelease_channel(card, 0);
- return 0;
- }
- }
- }
- /* Read the Status-replies from the Interface */
- static int
- icn_readstatus(u_char __user *buf, int len, icn_card * card)
- {
- int count;
- u_char __user *p;
- for (p = buf, count = 0; count < len; p++, count++) {
- if (card->msg_buf_read == card->msg_buf_write)
- return count;
- if (put_user(*card->msg_buf_read++, p))
- return -EFAULT;
- 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_card * card)
- {
- int mch = card->secondhalf ? 2 : 0;
- int pp;
- int i;
- int count;
- int xcount;
- int ocount;
- int loop;
- unsigned long flags;
- int lastmap_channel;
- struct icn_card *lastmap_card;
- u_char *p;
- isdn_ctrl cmd;
- u_char msg[0x100];
- ocount = 1;
- xcount = loop = 0;
- while (len) {
- count = cmd_free;
- if (count > len)
- count = len;
- if (user) {
- if (copy_from_user(msg, buf, count))
- return -EFAULT;
- } else
- memcpy(msg, buf, count);
- spin_lock_irqsave(&dev.devlock, flags);
- lastmap_card = dev.mcard;
- lastmap_channel = dev.channel;
- icn_map_channel(card, mch);
- icn_putmsg(card, '>');
- for (p = msg, pp = readb(&cmd_i), i = count; i > 0; i--, p++, pp
- ++) {
- writeb((*p == '\n') ? 0xff : *p,
- &dev.shmem->comm_buffers.pcio_buf[pp & 0xff]);
- len--;
- xcount++;
- icn_putmsg(card, *p);
- if ((*p == '\n') && (i > 1)) {
- icn_putmsg(card, '>');
- ocount++;
- }
- ocount++;
- }
- writeb((readb(&cmd_i) + count) & 0xff, &cmd_i);
- if (lastmap_card)
- icn_map_channel(lastmap_card, lastmap_channel);
- spin_unlock_irqrestore(&dev.devlock, flags);
- if (len) {
- mdelay(1);
- if (loop++ > 20)
- break;
- } else
- break;
- }
- if (len && (!user))
- printk(KERN_WARNING "icn: writemsg incomplete!\n");
- cmd.command = ISDN_STAT_STAVAIL;
- cmd.driver = card->myid;
- cmd.arg = ocount;
- card->interface.statcallb(&cmd);
- return xcount;
- }
- /*
- * Delete card's pending timers, send STOP to linklevel
- */
- static void
- icn_stopcard(icn_card * card)
- {
- unsigned long flags;
- isdn_ctrl cmd;
- spin_lock_irqsave(&card->lock, flags);
- if (card->flags & ICN_FLAGS_RUNNING) {
- card->flags &= ~ICN_FLAGS_RUNNING;
- del_timer(&card->st_timer);
- del_timer(&card->rb_timer);
- spin_unlock_irqrestore(&card->lock, flags);
- cmd.command = ISDN_STAT_STOP;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
- if (card->doubleS0)
- icn_stopcard(card->other);
- } else
- spin_unlock_irqrestore(&card->lock, flags);
- }
- static void
- icn_stopallcards(void)
- {
- icn_card *p = cards;
- while (p) {
- icn_stopcard(p);
- p = p->next;
- }
- }
- /*
- * Unmap all cards, because some of them may be mapped accidetly during
- * autoprobing of some network drivers (SMC-driver?)
- */
- static void
- icn_disable_cards(void)
- {
- icn_card *card = cards;
- while (card) {
- if (!request_region(card->port, ICN_PORTLEN, "icn-isdn")) {
- printk(KERN_WARNING
- "icn: (%s) ports 0x%03x-0x%03x in use.\n",
- CID,
- card->port,
- card->port + ICN_PORTLEN);
- } else {
- OUTB_P(0, ICN_RUN); /* Reset Controller */
- OUTB_P(0, ICN_MAPRAM); /* Disable RAM */
- release_region(card->port, ICN_PORTLEN);
- }
- card = card->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;
- char __user *arg;
- switch (c->command) {
- case ISDN_CMD_IOCTL:
- memcpy(&a, c->parm.num, sizeof(ulong));
- arg = (char __user *)a;
- switch (c->arg) {
- case ICN_IOCTL_SETMMIO:
- if (dev.memaddr != (a & 0x0ffc000)) {
- if (!request_mem_region(a & 0x0ffc000, 0x4000, "icn-isdn (all cards)")) {
- printk(KERN_WARNING
- "icn: memory at 0x%08lx in use.\n",
- a & 0x0ffc000);
- return -EINVAL;
- }
- release_mem_region(a & 0x0ffc000, 0x4000);
- icn_stopallcards();
- spin_lock_irqsave(&card->lock, flags);
- if (dev.mvalid) {
- iounmap(dev.shmem);
- release_mem_region(dev.memaddr, 0x4000);
- }
- dev.mvalid = 0;
- dev.memaddr = a & 0x0ffc000;
- spin_unlock_irqrestore(&card->lock, flags);
- printk(KERN_INFO
- "icn: (%s) mmio set to 0x%08lx\n",
- CID,
- dev.memaddr);
- }
- break;
- case ICN_IOCTL_GETMMIO:
- return (long) dev.memaddr;
- 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 (!request_region((unsigned short) a, ICN_PORTLEN, "icn-isdn")) {
- printk(KERN_WARNING
- "icn: (%s) ports 0x%03x-0x%03x in use.\n",
- CID, (int) a, (int) a + ICN_PORTLEN);
- return -EINVAL;
- }
- release_region((unsigned short) a, ICN_PORTLEN);
- icn_stopcard(card);
- spin_lock_irqsave(&card->lock, flags);
- 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;
- }
- spin_unlock_irqrestore(&card->lock, 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:
- if (copy_to_user(arg,
- &card,
- sizeof(ulong)))
- return -EFAULT;
- a += sizeof(ulong);
- {
- ulong l = (ulong) & dev;
- if (copy_to_user(arg,
- &l,
- sizeof(ulong)))
- return -EFAULT;
- }
- return 0;
- case ICN_IOCTL_LOADBOOT:
- if (dev.firstload) {
- icn_disable_cards();
- dev.firstload = 0;
- }
- icn_stopcard(card);
- return (icn_loadboot(arg, card));
- case ICN_IOCTL_LOADPROTO:
- icn_stopcard(card);
- if ((i = (icn_loadproto(arg, card))))
- return i;
- if (card->doubleS0)
- i = icn_loadproto(arg + ICN_CODE_STAGE2, card->other);
- return i;
- break;
- case ICN_IOCTL_ADDCARD:
- if (!dev.firstload)
- return -EBUSY;
- if (copy_from_user(&cdef,
- arg,
- sizeof(cdef)))
- return -EFAULT;
- 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) {
- msleep_interruptible(ICN_BOOT_TIMEOUT1);
- }
- msleep_interruptible(ICN_BOOT_TIMEOUT1);
- sprintf(cbuf, "00;FV2ON\n01;EAZ%c\n02;EAZ%c\n",
- (a & 1)?'1':'C', (a & 2)?'2':'C');
- i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
- 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);
- 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 dial[50];
- char dcode[4];
- a = c->arg;
- p = c->parm.setup.phone;
- if (*p == 's' || *p == 'S') {
- /* Dial for SPV */
- p++;
- strcpy(dcode, "SCA");
- } else
- /* Normal Dial */
- strcpy(dcode, "CAL");
- strcpy(dial, p);
- sprintf(cbuf, "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1),
- dcode, dial, c->parm.setup.si1,
- c->parm.setup.si2, c->parm.setup.eazmsn);
- i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
- }
- 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);
- }
- sprintf(cbuf, "%02d;DCON_R\n", (int) a);
- i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
- }
- 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);
- }
- 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);
- }
- 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->parm.num[0] ? "N" : "ALL", c->parm.num);
- } else
- sprintf(cbuf, "%02d;EAZ%s\n", (int) a,
- c->parm.num[0] ? (char *)(c->parm.num) : "0123456789");
- i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
- }
- 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);
- }
- 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);
- card->l2_proto[a & 255] = (a >> 8);
- }
- break;
- case ISDN_CMD_SETL3:
- if (!(card->flags & ICN_FLAGS_RUNNING))
- return -ENODEV;
- return 0;
- default:
- return -EINVAL;
- }
- return 0;
- }
- /*
- * Find card with given driverId
- */
- static inline icn_card *
- icn_findcard(int driverid)
- {
- icn_card *p = cards;
- while (p) {
- if (p->myid == driverid)
- return p;
- p = p->next;
- }
- return (icn_card *) 0;
- }
- /*
- * Wrapper functions for interface to linklevel
- */
- static int
- if_command(isdn_ctrl * c)
- {
- icn_card *card = icn_findcard(c->driver);
- if (card)
- return (icn_command(c, card));
- printk(KERN_ERR
- "icn: if_command %d called with invalid driverId %d!\n",
- c->command, c->driver);
- return -ENODEV;
- }
- static int
- if_writecmd(const u_char __user *buf, int len, int id, int channel)
- {
- icn_card *card = icn_findcard(id);
- if (card) {
- if (!(card->flags & ICN_FLAGS_RUNNING))
- return -ENODEV;
- return (icn_writecmd(buf, len, 1, card));
- }
- printk(KERN_ERR
- "icn: if_writecmd called with invalid driverId!\n");
- return -ENODEV;
- }
- static int
- if_readstatus(u_char __user *buf, int len, int id, int channel)
- {
- icn_card *card = icn_findcard(id);
- if (card) {
- if (!(card->flags & ICN_FLAGS_RUNNING))
- return -ENODEV;
- return (icn_readstatus(buf, len, card));
- }
- printk(KERN_ERR
- "icn: if_readstatus called with invalid driverId!\n");
- return -ENODEV;
- }
- static int
- if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
- {
- icn_card *card = icn_findcard(id);
- if (card) {
- if (!(card->flags & ICN_FLAGS_RUNNING))
- return -ENODEV;
- return (icn_sendbuf(channel, ack, skb, card));
- }
- printk(KERN_ERR
- "icn: if_sendbuf called with invalid driverId!\n");
- return -ENODEV;
- }
- /*
- * 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 = kzalloc(sizeof(icn_card), GFP_KERNEL))) {
- printk(KERN_WARNING
- "icn: (%s) Could not allocate card-struct.\n", id);
- return (icn_card *) 0;
- }
- spin_lock_init(&card->lock);
- card->port = port;
- card->interface.owner = THIS_MODULE;
- card->interface.hl_hdrlen = 1;
- card->interface.channels = ICN_BCH;
- card->interface.maxbufsize = 4000;
- card->interface.command = if_command;
- 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;
- strlcpy(card->interface.id, id, sizeof(card->interface.id));
- 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)
- {
- icn_card *card;
- icn_card *card2;
- if (!(card = icn_initcard(port, id1))) {
- return -EIO;
- }
- if (!strlen(id2)) {
- printk(KERN_INFO
- "icn: (%s) ICN-2B, port 0x%x added\n",
- card->interface.id, port);
- return 0;
- }
- if (!(card2 = icn_initcard(port, id2))) {
- 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;
- printk(KERN_INFO
- "icn: (%s and %s) ICN-4B, port 0x%x added\n",
- card->interface.id, card2->interface.id, port);
- return 0;
- }
- #ifndef MODULE
- static int __init
- icn_setup(char *line)
- {
- char *p, *str;
- int ints[3];
- static char sid[20];
- static char sid2[20];
- str = get_options(line, 2, ints);
- if (ints[0])
- portbase = ints[1];
- if (ints[0] > 1)
- membase = (unsigned long)ints[2];
- if (str && *str) {
- strcpy(sid, str);
- icn_id = sid;
- if ((p = strchr(sid, ','))) {
- *p++ = 0;
- strcpy(sid2, p);
- icn_id2 = sid2;
- }
- }
- return(1);
- }
- __setup("icn=", icn_setup);
- #endif /* MODULE */
- static int __init icn_init(void)
- {
- char *p;
- char rev[10];
- memset(&dev, 0, sizeof(icn_dev));
- dev.memaddr = (membase & 0x0ffc000);
- dev.channel = -1;
- dev.mcard = NULL;
- dev.firstload = 1;
- spin_lock_init(&dev.devlock);
- 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%08lx\n", rev,
- dev.memaddr);
- return (icn_addcard(portbase, icn_id, icn_id2));
- }
- static void __exit icn_exit(void)
- {
- isdn_ctrl cmd;
- icn_card *card = cards;
- icn_card *last, *tmpcard;
- int i;
- unsigned long flags;
- icn_stopallcards();
- while (card) {
- cmd.command = ISDN_STAT_UNLOAD;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
- spin_lock_irqsave(&card->lock, flags);
- 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, i);
- }
- tmpcard = card->next;
- spin_unlock_irqrestore(&card->lock, flags);
- card = tmpcard;
- }
- card = cards;
- cards = NULL;
- while (card) {
- last = card;
- card = card->next;
- kfree(last);
- }
- if (dev.mvalid) {
- iounmap(dev.shmem);
- release_mem_region(dev.memaddr, 0x4000);
- }
- printk(KERN_NOTICE "ICN-ISDN-driver unloaded\n");
- }
- module_init(icn_init);
- module_exit(icn_exit);
|