📄 icn.c
字号:
card = card->next; } restore_flags(flags);}static inticn_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->parm.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 (long) 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: if ((i = copy_to_user((char *) a, (char *) &card, sizeof(ulong)))) return i; a += sizeof(ulong); { ulong l = (ulong) & dev; if ((i = copy_to_user((char *) a, (char *) &l, sizeof(ulong)))) return i; } return 0; case ICN_IOCTL_LOADBOOT: if (dev.firstload) { icn_disable_cards(); dev.firstload = 0; } 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 (!dev.firstload) return -EBUSY; if ((i = copy_from_user((char *) &cdef, (char *) a, sizeof(cdef)))) return i; 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) { schedule_timeout(ICN_BOOT_TIMEOUT1); } schedule_timeout(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_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;}/* * 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 * buf, int len, int user, 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, user, card)); } printk(KERN_ERR "icn: if_writecmd called with invalid driverId!\n"); return -ENODEV;}static intif_readstatus(u_char * buf, int len, int user, 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, user, 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)); card->port = port; 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; 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 inticn_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#define icn_init init_module#else#include <linux/init.h>static 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 = 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 /* MODULES */inticn_init(void){ char *p; char rev[10]; memset(&dev, 0, sizeof(icn_dev)); dev.shmem = (icn_shmem *) ((unsigned long) membase & 0x0ffc000); dev.channel = -1; dev.mcard = NULL; dev.firstload = 1; /* No symbols to export, hide all symbols */ EXPORT_NO_SYMBOLS; 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, (ulong) dev.shmem); return (icn_addcard(portbase, icn_id, icn_id2));}#ifdef MODULEvoidcleanup_module(void){ 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, i); } card = card->next; } card = cards; 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -