📄 capidrv.c
字号:
msglen = CAPIMSG_LEN(sendcmsg.buf); if (skb_headroom(skb) < msglen) { struct sk_buff *nskb = skb_realloc_headroom(skb, msglen); if (!nskb) { printk(KERN_ERR "capidrv-%d: if_sendbuf: no memory\n", card->contrnr); (void)capidrv_del_ack(nccip, datahandle); return 0; } printk(KERN_DEBUG "capidrv-%d: only %d bytes headroom, need %d\n", card->contrnr, skb_headroom(skb), msglen); memcpy(skb_push(nskb, msglen), sendcmsg.buf, msglen); errcode = capi20_put_message(&global.ap, nskb); if (errcode == CAPI_NOERROR) { dev_kfree_skb(skb); nccip->datahandle++; return len; } if (debugmode > 3) printk(KERN_DEBUG "capidrv-%d: sendbuf putmsg ret(%x) - %s\n", card->contrnr, errcode, capi_info2str(errcode)); (void)capidrv_del_ack(nccip, datahandle); dev_kfree_skb(nskb); return errcode == CAPI_SENDQUEUEFULL ? 0 : -1; } else { memcpy(skb_push(skb, msglen), sendcmsg.buf, msglen); errcode = capi20_put_message(&global.ap, skb); if (errcode == CAPI_NOERROR) { nccip->datahandle++; return len; } if (debugmode > 3) printk(KERN_DEBUG "capidrv-%d: sendbuf putmsg ret(%x) - %s\n", card->contrnr, errcode, capi_info2str(errcode)); skb_pull(skb, msglen); (void)capidrv_del_ack(nccip, datahandle); return errcode == CAPI_SENDQUEUEFULL ? 0 : -1; }}static int if_readstat(u8 __user *buf, int len, int id, int channel){ capidrv_contr *card = findcontrbydriverid(id); int count; u8 __user *p; if (!card) { printk(KERN_ERR "capidrv: if_readstat called with invalid driverId %d!\n", id); return -ENODEV; } for (p=buf, count=0; count < len; p++, count++) { put_user(*card->q931_read++, p); if (card->q931_read > card->q931_end) card->q931_read = card->q931_buf; } return count;}static void enable_dchannel_trace(capidrv_contr *card){ u8 manufacturer[CAPI_MANUFACTURER_LEN]; capi_version version; u16 contr = card->contrnr; u16 errcode; u16 avmversion[3]; errcode = capi20_get_manufacturer(contr, manufacturer); if (errcode != CAPI_NOERROR) { printk(KERN_ERR "%s: can't get manufacturer (0x%x)\n", card->name, errcode); return; } if (strstr(manufacturer, "AVM") == 0) { printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n", card->name, manufacturer); return; } errcode = capi20_get_version(contr, &version); if (errcode != CAPI_NOERROR) { printk(KERN_ERR "%s: can't get version (0x%x)\n", card->name, errcode); return; } avmversion[0] = (version.majormanuversion >> 4) & 0x0f; avmversion[1] = (version.majormanuversion << 4) & 0xf0; avmversion[1] |= (version.minormanuversion >> 4) & 0x0f; avmversion[2] |= version.minormanuversion & 0x0f; if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 5)) { printk(KERN_INFO "%s: D2 trace enabled\n", card->name); capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.ap.applid, card->msgid++, contr, 0x214D5641, /* ManuID */ 0, /* Class */ 1, /* Function */ (_cstruct)"\004\200\014\000\000"); } else { printk(KERN_INFO "%s: D3 trace enabled\n", card->name); capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.ap.applid, card->msgid++, contr, 0x214D5641, /* ManuID */ 0, /* Class */ 1, /* Function */ (_cstruct)"\004\002\003\000\000"); } send_message(card, &cmdcmsg);}static void send_listen(capidrv_contr *card){ capi_fill_LISTEN_REQ(&cmdcmsg, global.ap.applid, card->msgid++, card->contrnr, /* controller */ 1 << 6, /* Infomask */ card->cipmask, card->cipmask2, NULL, NULL); send_message(card, &cmdcmsg); listen_change_state(card, EV_LISTEN_REQ);}static void listentimerfunc(unsigned long x){ capidrv_contr *card = (capidrv_contr *)x; if (card->state != ST_LISTEN_NONE && card->state != ST_LISTEN_ACTIVE) printk(KERN_ERR "%s: controller dead ??\n", card->name); send_listen(card); mod_timer(&card->listentimer, jiffies + 60*HZ);}static int capidrv_addcontr(u16 contr, struct capi_profile *profp){ capidrv_contr *card; unsigned long flags; isdn_ctrl cmd; char id[20]; int i; sprintf(id, "capidrv-%d", contr); if (!try_module_get(THIS_MODULE)) { printk(KERN_WARNING "capidrv: (%s) Could not reserve module\n", id); return -1; } if (!(card = (capidrv_contr *) kmalloc(sizeof(capidrv_contr), GFP_ATOMIC))) { printk(KERN_WARNING "capidrv: (%s) Could not allocate contr-struct.\n", id); return -1; } memset(card, 0, sizeof(capidrv_contr)); card->owner = THIS_MODULE; init_timer(&card->listentimer); strcpy(card->name, id); card->contrnr = contr; card->nbchan = profp->nbchannel; card->bchans = (capidrv_bchan *) kmalloc(sizeof(capidrv_bchan) * card->nbchan, GFP_ATOMIC); if (!card->bchans) { printk(KERN_WARNING "capidrv: (%s) Could not allocate bchan-structs.\n", id); module_put(card->owner); kfree(card); return -1; } card->interface.channels = profp->nbchannel; card->interface.maxbufsize = 2048; card->interface.command = if_command; card->interface.writebuf_skb = if_sendbuf; card->interface.writecmd = NULL; card->interface.readstat = if_readstat; card->interface.features = ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L2_TRANS | ISDN_FEATURE_L3_TRANS | ISDN_FEATURE_P_UNKNOWN | ISDN_FEATURE_L2_X75I | ISDN_FEATURE_L2_X75UI | ISDN_FEATURE_L2_X75BUI; if (profp->support1 & (1<<2)) card->interface.features |= ISDN_FEATURE_L2_V11096 | ISDN_FEATURE_L2_V11019 | ISDN_FEATURE_L2_V11038; if (profp->support1 & (1<<8)) card->interface.features |= ISDN_FEATURE_L2_MODEM; card->interface.hl_hdrlen = 22; /* len of DATA_B3_REQ */ strncpy(card->interface.id, id, sizeof(card->interface.id) - 1); card->q931_read = card->q931_buf; card->q931_write = card->q931_buf; card->q931_end = card->q931_buf + sizeof(card->q931_buf) - 1; if (!register_isdn(&card->interface)) { printk(KERN_ERR "capidrv: Unable to register contr %s\n", id); kfree(card->bchans); module_put(card->owner); kfree(card); return -1; } card->myid = card->interface.channels; memset(card->bchans, 0, sizeof(capidrv_bchan) * card->nbchan); for (i = 0; i < card->nbchan; i++) { card->bchans[i].contr = card; } spin_lock_irqsave(&global_lock, flags); card->next = global.contr_list; global.contr_list = card; global.ncontr++; spin_unlock_irqrestore(&global_lock, flags); cmd.command = ISDN_STAT_RUN; cmd.driver = card->myid; card->interface.statcallb(&cmd); card->cipmask = 0x1FFF03FF; /* any */ card->cipmask2 = 0; card->listentimer.data = (unsigned long)card; card->listentimer.function = listentimerfunc; send_listen(card); mod_timer(&card->listentimer, jiffies + 60*HZ); printk(KERN_INFO "%s: now up (%d B channels)\n", card->name, card->nbchan); enable_dchannel_trace(card); return 0;}static int capidrv_delcontr(u16 contr){ capidrv_contr **pp, *card; unsigned long flags; isdn_ctrl cmd; spin_lock_irqsave(&global_lock, flags); for (card = global.contr_list; card; card = card->next) { if (card->contrnr == contr) break; } if (!card) { spin_unlock_irqrestore(&global_lock, flags); printk(KERN_ERR "capidrv: delcontr: no contr %u\n", contr); return -1; } #warning FIXME: maybe a race condition the card should be removed here from global list /kkeil spin_unlock_irqrestore(&global_lock, flags); del_timer(&card->listentimer); if (debugmode) printk(KERN_DEBUG "capidrv-%d: id=%d unloading\n", card->contrnr, card->myid); cmd.command = ISDN_STAT_STOP; cmd.driver = card->myid; card->interface.statcallb(&cmd); while (card->nbchan) { cmd.command = ISDN_STAT_DISCH; cmd.driver = card->myid; cmd.arg = card->nbchan-1; cmd.parm.num[0] = 0; if (debugmode) printk(KERN_DEBUG "capidrv-%d: id=%d disable chan=%ld\n", card->contrnr, card->myid, cmd.arg); card->interface.statcallb(&cmd); if (card->bchans[card->nbchan-1].nccip) free_ncci(card, card->bchans[card->nbchan-1].nccip); if (card->bchans[card->nbchan-1].plcip) free_plci(card, card->bchans[card->nbchan-1].plcip); if (card->plci_list) printk(KERN_ERR "capidrv: bug in free_plci()\n"); card->nbchan--; } kfree(card->bchans); card->bchans = NULL; if (debugmode) printk(KERN_DEBUG "capidrv-%d: id=%d isdn unload\n", card->contrnr, card->myid); cmd.command = ISDN_STAT_UNLOAD; cmd.driver = card->myid; card->interface.statcallb(&cmd); if (debugmode) printk(KERN_DEBUG "capidrv-%d: id=%d remove contr from list\n", card->contrnr, card->myid); spin_lock_irqsave(&global_lock, flags); for (pp = &global.contr_list; *pp; pp = &(*pp)->next) { if (*pp == card) { *pp = (*pp)->next; card->next = NULL; global.ncontr--; break; } } spin_unlock_irqrestore(&global_lock, flags); module_put(card->owner); printk(KERN_INFO "%s: now down.\n", card->name); kfree(card); return 0;}static void lower_callback(unsigned int cmd, u32 contr, void *data){ switch (cmd) { case KCI_CONTRUP: printk(KERN_INFO "capidrv: controller %hu up\n", contr); (void) capidrv_addcontr(contr, (capi_profile *) data); break; case KCI_CONTRDOWN: printk(KERN_INFO "capidrv: controller %hu down\n", contr); (void) capidrv_delcontr(contr); break; }}/* * /proc/capi/capidrv: * nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt */static int proc_capidrv_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ int len = 0; len += sprintf(page+len, "%lu %lu %lu %lu\n", global.ap.nrecvctlpkt, global.ap.nrecvdatapkt, global.ap.nsentctlpkt, global.ap.nsentdatapkt); if (off+count >= len) *eof = 1; if (len < off) return 0; *start = page + off; return ((count < len-off) ? count : len-off);}static struct procfsentries { char *name; mode_t mode; int (*read_proc)(char *page, char **start, off_t off, int count, int *eof, void *data); struct proc_dir_entry *procent;} procfsentries[] = { /* { "capi", S_IFDIR, 0 }, */ { "capi/capidrv", 0 , proc_capidrv_read_proc },};static void __init proc_init(void){ int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]); int i; for (i=0; i < nelem; i++) { struct procfsentries *p = procfsentries + i; p->procent = create_proc_entry(p->name, p->mode, NULL); if (p->procent) p->procent->read_proc = p->read_proc; }}static void __exit proc_exit(void){ int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]); int i; for (i=nelem-1; i >= 0; i--) { struct procfsentries *p = procfsentries + i; if (p->procent) { remove_proc_entry(p->name, NULL); p->procent = NULL; } }}static int __init capidrv_init(void){ capi_profile profile; char rev[32]; char *p; u32 ncontr, contr; u16 errcode; if ((p = strchr(revision, ':')) != 0 && p[1]) { strncpy(rev, p + 2, sizeof(rev)); rev[sizeof(rev)-1] = 0; if ((p = strchr(rev, '$')) != 0 && p > rev) *(p-1) = 0; } else strcpy(rev, "1.0"); global.ap.rparam.level3cnt = -2; /* number of bchannels twice */ global.ap.rparam.datablkcnt = 16; global.ap.rparam.datablklen = 2048; global.ap.recv_message = capidrv_recv_message; errcode = capi20_register(&global.ap); if (errcode) { return -EIO; } capi20_set_callback(&global.ap, lower_callback); errcode = capi20_get_profile(0, &profile); if (errcode != CAPI_NOERROR) { capi20_release(&global.ap); return -EIO; } ncontr = profile.ncontroller; for (contr = 1; contr <= ncontr; contr++) { errcode = capi20_get_profile(contr, &profile); if (errcode != CAPI_NOERROR) continue; (void) capidrv_addcontr(contr, &profile); } proc_init(); printk(KERN_NOTICE "capidrv: Rev %s: loaded\n", rev); return 0;}static void __exit capidrv_exit(void){ char rev[10]; char *p; if ((p = strchr(revision, ':')) != 0) { strcpy(rev, p + 1); p = strchr(rev, '$'); *p = 0; } else { strcpy(rev, " ??? "); } capi20_release(&global.ap); proc_exit(); printk(KERN_NOTICE "capidrv: Rev%s: unloaded\n", rev);}module_init(capidrv_init);module_exit(capidrv_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -