📄 icn.c
字号:
if (card->xmit_lock[channel]) { restore_flags(flags); break; } card->xmit_lock[channel]++; restore_flags(flags); skb = skb_dequeue(&card->spqueue[channel]); 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); card->sndcount[channel] -= cnt; sbnext; /* switch to next buffer */ icn_maprelease_channel(card, mch & 2); if (!skb->len) { dev_kfree_skb(skb, FREE_WRITE); cmd.command = ISDN_STAT_BSENT; cmd.driver = card->myid; cmd.arg = channel; card->interface.statcallb(&cmd); } else skb_queue_head(&card->spqueue[channel], skb); card->xmit_lock[channel] = 0; 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 voidicn_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 */ save_flags(flags); cli(); del_timer(&card->rb_timer); 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;/* *INDENT-OFF* */static icn_stat icn_stat_table[] ={ {"BCON_", ISDN_STAT_BCONN, 1}, /* B-Channel connected */ {"BDIS_", ISDN_STAT_BHUP, 2}, /* B-Channel disconnected */#ifdef CONFIG_ISDN_WITH_ABC {"DCON_", ISDN_STAT_DCONN, 10}, /* D-Channel connected */ {"DDIS_", ISDN_STAT_DHUP, 11}, /* D-Channel disconnected */#else {"DCON_", ISDN_STAT_DCONN, 0}, /* D-Channel connected */ {"DDIS_", ISDN_STAT_DHUP, 0}, /* D-Channel disconnected */#endif {"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 */ {"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 inticn_parse_status(u_char * status, int channel, icn_card * card){ 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) {#ifdef CONFIG_ISDN_WITH_ABC case 11: save_flags(flags); cli(); icn_free_queue(card,channel); card->rcvidx[channel] = 0; if( card->flags & ((channel)?ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE)) { isdn_ctrl ncmd; printk(KERN_INFO "icn: D-Channel hangup before B-Channel hangup\n"); 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; restore_flags(flags); card->interface.statcallb(&cmd); dflag |= (channel+1); } else restore_flags(flags); break;#endif case 1:#ifdef CONFIG_ISDN_WITH_ABC icn_free_queue(card,channel);#endif 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, channel); save_flags(flags); cli(); card->rcvidx[channel] = 0; restore_flags(flags); dflag |= (channel + 1); break; case 3: { char *t = status + 6; char *s = strpbrk(t, ","); memset(&cmd.parm.setup, 0, sizeof(cmd.parm.setup)); if (!s) break; *s++ = '\0'; strncpy(cmd.parm.setup.phone, t, sizeof(cmd.parm.setup.phone)); if (!(s = strpbrk(t = s, ","))) break; *s++ = '\0'; if (!strlen(t)) cmd.parm.setup.si1 = 0; else cmd.parm.setup.si1 = simple_strtoul(t, NULL, 10); if (!(s = strpbrk(t = s, ","))) break; *s++ = '\0'; if (!strlen(t)) cmd.parm.setup.si2 = 0; else cmd.parm.setup.si2 = simple_strtoul(t, NULL, 10); strncpy(cmd.parm.setup.eazmsn, s, sizeof(cmd.parm.setup.eazmsn)); } 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: strncpy(cmd.parm.num, status + 3, sizeof(cmd.parm.num) - 1); break; case 6: sprintf(cmd.parm.num, "%d", (int) simple_strtoul(status + 7, NULL, 16)); break; case 7: status += 3; if (strlen(status) == 4) sprintf(cmd.parm.num, "%s%c%c", status + 2, *status, *(status + 1)); else strncpy(cmd.parm.num, status + 1, sizeof(cmd.parm.num) - 1); break; case 8: dflag = 3; card->flags &= ~ICN_FLAGS_B1ACTIVE; icn_free_queue(card, 0); save_flags(flags); cli(); card->rcvidx[0] = 0; restore_flags(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; card->flags &= ~ICN_FLAGS_B2ACTIVE; icn_free_queue(card, 1); save_flags(flags); cli(); card->rcvidx[1] = 0; restore_flags(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 dflag;}static voidicn_putmsg(icn_card * card, unsigned char c){ ulong flags; 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);}static voidicn_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 = 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]; 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++; } } 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); } 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(); del_timer(&card->st_timer); card->st_timer.expires = jiffies + ICN_TIMER_DCREAD; add_timer(&card->st_timer); restore_flags(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, 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; save_flags(flags); cli(); nskb = skb_clone(skb, GFP_ATOMIC); if (nskb) { skb_queue_tail(&card->spqueue[channel], nskb); dev_kfree_skb(skb, FREE_WRITE); } else len = 0; card->sndcount[channel] += len; restore_flags(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 current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + ICN_BOOT_TIMEOUT1; schedule(); } 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:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -