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