📄 icn.c
字号:
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 voidicn_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 voidicn_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 inticn_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 inticn_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)#endifstatic inticn_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 inticn_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 inticn_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; put_user(*card->msg_buf_read++, p); 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 inticn_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 voidicn_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 voidicn_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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -