📄 capidrv.c
字号:
0, /* B3configuration */ 0, /* ConnectedNumber */ 0, /* ConnectedSubaddress */ 0, /* LLC */ 0, /* BChannelinformation */ 0, /* Keypadfacility */ 0, /* Useruserdata */ 0 /* Facilitydataarray */ ); capi_cmsg2message(&cmdcmsg, cmdcmsg.buf); plci_change_state(card, bchan->plcip, EV_PLCI_CONNECT_RESP); send_message(card, &cmdcmsg); return 0; case ISDN_CMD_ACCEPTB: if (debugmode) printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTB(ch=%ld)\n", card->contrnr, c->arg); return -ENOSYS; case ISDN_CMD_HANGUP: if (debugmode) printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_HANGUP(ch=%ld)\n", card->contrnr, c->arg); bchan = &card->bchans[c->arg % card->nbchan]; if (bchan->disconnecting) { if (debugmode) printk(KERN_DEBUG "capidrv-%d: chan %ld already disconnecting ...\n", card->contrnr, c->arg); return 0; } if (bchan->nccip) { bchan->disconnecting = 1; capi_fill_DISCONNECT_B3_REQ(&cmdcmsg, global.appid, card->msgid++, bchan->nccip->ncci, 0 /* NCPI */ ); ncci_change_state(card, bchan->nccip, EV_NCCI_DISCONNECT_B3_REQ); send_message(card, &cmdcmsg); } else if (bchan->plcip) { bchan->disconnecting = 1; if (bchan->plcip->state == ST_PLCI_INCOMING) { /* just ignore, we a called from isdn_status_callback(), * which will return 0 or 2, this is handled by the * CONNECT_IND handler */ } else { capi_fill_DISCONNECT_REQ(&cmdcmsg, global.appid, card->msgid++, bchan->plcip->plci, 0, /* BChannelinformation */ 0, /* Keypadfacility */ 0, /* Useruserdata */ 0 /* Facilitydataarray */ ); plci_change_state(card, bchan->plcip, EV_PLCI_DISCONNECT_REQ); send_message(card, &cmdcmsg); } }/* ready */ case ISDN_CMD_SETL2: if (debugmode) printk(KERN_DEBUG "capidrv-%d: set L2 on chan %ld to %ld\n", card->contrnr, (c->arg & 0xff), (c->arg >> 8)); bchan = &card->bchans[(c->arg & 0xff) % card->nbchan]; bchan->l2 = (c->arg >> 8); return 0; case ISDN_CMD_SETL3: if (debugmode) printk(KERN_DEBUG "capidrv-%d: set L3 on chan %ld to %ld\n", card->contrnr, (c->arg & 0xff), (c->arg >> 8)); bchan = &card->bchans[(c->arg & 0xff) % card->nbchan]; bchan->l3 = (c->arg >> 8); return 0; case ISDN_CMD_SETEAZ: if (debugmode) printk(KERN_DEBUG "capidrv-%d: set EAZ \"%s\" on chan %ld\n", card->contrnr, c->parm.num, c->arg); bchan = &card->bchans[c->arg % card->nbchan]; strncpy(bchan->msn, c->parm.num, ISDN_MSNLEN); return 0; case ISDN_CMD_CLREAZ: if (debugmode) printk(KERN_DEBUG "capidrv-%d: clearing EAZ on chan %ld\n", card->contrnr, c->arg); bchan = &card->bchans[c->arg % card->nbchan]; bchan->msn[0] = 0; return 0; case ISDN_CMD_LOCK: if (debugmode > 1) printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_LOCK (%ld)\n", card->contrnr, c->arg); MOD_INC_USE_COUNT; break; case ISDN_CMD_UNLOCK: if (debugmode > 1) printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_UNLOCK (%ld)\n", card->contrnr, c->arg); MOD_DEC_USE_COUNT; break;/* never called */ case ISDN_CMD_GETL2: if (debugmode) printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_GETL2\n", card->contrnr); return -ENODEV; case ISDN_CMD_GETL3: if (debugmode) printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_GETL3\n", card->contrnr); return -ENODEV; case ISDN_CMD_GETEAZ: if (debugmode) printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_GETEAZ\n", card->contrnr); return -ENODEV; case ISDN_CMD_SETSIL: if (debugmode) printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_SETSIL\n", card->contrnr); return -ENODEV; case ISDN_CMD_GETSIL: if (debugmode) printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_GETSIL\n", card->contrnr); return -ENODEV; default: printk(KERN_ERR "capidrv-%d: ISDN_CMD_%d, Huh?\n", card->contrnr, c->command); return -EINVAL; } return 0;}static int if_command(isdn_ctrl * c){ capidrv_contr *card = findcontrbydriverid(c->driver); if (card) return capidrv_command(c, card); printk(KERN_ERR "capidrv-%d: if_command %d called with invalid driverId %d!\n", card->contrnr, c->command, c->driver); return -ENODEV;}static _cmsg sendcmsg;static int if_sendbuf(int id, int channel, struct sk_buff *skb){ capidrv_contr *card = findcontrbydriverid(id); capidrv_bchan *bchan; capidrv_ncci *nccip; int len = skb->len; size_t msglen; __u16 errcode; if (!card) { printk(KERN_ERR "capidrv-%d: if_sendbuf called with invalid driverId %d!\n", card->contrnr, id); return 0; } bchan = &card->bchans[channel % card->nbchan]; nccip = bchan->nccip; if (!nccip || nccip->state != ST_NCCI_ACTIVE) { printk(KERN_ERR "capidrv-%d: if_sendbuf: %s:%d: chan not up!\n", card->contrnr, card->name, channel); return 0; } capi_fill_DATA_B3_REQ(&sendcmsg, global.appid, card->msgid++, nccip->ncci, /* adr */ (__u32) skb->data, /* Data */ skb->len, /* DataLength */ nccip->datahandle++, /* DataHandle */ 0 /* Flags */ ); capi_cmsg2message(&sendcmsg, sendcmsg.buf); msglen = CAPIMSG_LEN(sendcmsg.buf); if (skb_headroom(skb) < msglen) { struct sk_buff *nskb = dev_alloc_skb(msglen + skb->len); if (!nskb) { printk(KERN_ERR "capidrv-%d: if_sendbuf: no memory\n", card->contrnr); return 0; }#if 0 printk(KERN_DEBUG "capidrv-%d: only %d bytes headroom\n", card->contrnr, skb_headroom(skb));#endif SET_SKB_FREE(nskb); memcpy(skb_put(nskb, msglen), sendcmsg.buf, msglen); memcpy(skb_put(nskb, skb->len), skb->data, skb->len); errcode = (*capifuncs->capi_put_message) (global.appid, nskb); switch (errcode) { case CAPI_NOERROR: dev_kfree_skb(skb, FREE_WRITE); return len; case CAPI_SENDQUEUEFULL: dev_kfree_skb(nskb, FREE_WRITE); return 0; default: return -1; } } else { memcpy(skb_push(skb, msglen), sendcmsg.buf, msglen); errcode = (*capifuncs->capi_put_message) (global.appid, skb); switch (errcode) { case CAPI_NOERROR: return len; case CAPI_SENDQUEUEFULL: return 0; default: return -1; } }}static int if_readstat(__u8 *buf, int len, int user, int id, int channel){ capidrv_contr *card = findcontrbydriverid(id); int count; __u8 *p; if (!card) { printk(KERN_ERR "capidrv-%d: if_readstat called with invalid driverId %d!\n", card->contrnr, id); return -ENODEV; } for (p=buf, count=0; count < len; p++, count++) { if (user) put_user(*card->q931_read++, p); else *p = *card->q931_read++; 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 = (*capifuncs->capi_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\n", card->name); return; } errcode = (*capifuncs->capi_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.appid, 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.appid, card->msgid++, contr, 0x214D5641, /* ManuID */ 0, /* Class */ 1, /* Function */ (_cstruct)"\004\002\003\000\000"); } send_message(card, &cmdcmsg);}static int capidrv_addcontr(__u16 contr, struct capi_profile *profp){ capidrv_contr *card; isdn_ctrl cmd; char id[20]; int i; sprintf(id, "capidrv-%d", contr); 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)); 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); 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 = 0; card->interface.readstat = if_readstat; card->interface.features = ISDN_FEATURE_L2_X75I | ISDN_FEATURE_L2_X75UI | ISDN_FEATURE_L2_X75BUI | ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L2_TRANS | ISDN_FEATURE_L3_TRANS | ISDN_FEATURE_P_UNKNOWN; card->interface.hl_hdrlen = 22; /* len of DATA_B3_REQ */ strncpy(card->interface.id, id, sizeof(card->interface.id) - 1); card->next = global.contr_list; global.contr_list = card; global.ncontr++; 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)) { global.contr_list = global.contr_list->next; printk(KERN_ERR "capidrv: Unable to register contr %s\n", id); kfree(card->bchans); 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; } cmd.driver = card->myid; cmd.command = ISDN_STAT_RUN; card->interface.statcallb(&cmd); card->cipmask = 0x1FFF03FF; /* any */ card->cipmask2 = 0; capi_fill_LISTEN_REQ(&cmdcmsg, global.appid, card->msgid++, contr, /* controller */ 1 << 6, /* Infomask */ card->cipmask, card->cipmask2, 0, 0); send_message(card, &cmdcmsg); listen_change_state(card, EV_LISTEN_REQ); printk(KERN_INFO "%s: now up (%d B channels)\n", card->name, card->nbchan); if (card->nbchan == 2) /* no T1 */ enable_dchannel_trace(card); return 0;}static int capidrv_delcontr(__u16 contr){ capidrv_contr **pp, *card; isdn_ctrl cmd; int i; for (pp = &global.contr_list; *pp; pp = &(*pp)->next) { if ((*pp)->contrnr == contr) break; } if (!*pp) { printk(KERN_ERR "capidrv: delcontr: no contr %u\n", contr); return -1; } card = *pp; *pp = (*pp)->next; global.ncontr--; for (i = 0; i < card->nbchan; i++) { if (card->bchans[i].nccip) free_ncci(card, card->bchans[i].nccip); if (card->bchans[i].plcip) free_plci(card, card->bchans[i].plcip); if (card->plci_list) printk(KERN_ERR "capidrv: bug in free_plci()\n"); } kfree(card->bchans); cmd.command = ISDN_STAT_UNLOAD; cmd.driver = card->myid; card->interface.statcallb(&cmd); printk(KERN_INFO "%s: now down.\n", card->name); kfree(card); return 0;}static void lower_callback(unsigned int cmd, __u16 contr, void *data){ switch (cmd) { case KCI_CONTRUP: (void) capidrv_addcontr(contr, (capi_profile *) data); break; case KCI_CONTRDOWN: (void) capidrv_delcontr(contr); break; }}static struct capi_interface_user cuser = { "capidrv", lower_callback};#ifdef MODULE#define capidrv_init init_module#endifint capidrv_init(void){ struct capi_register_params rparam; capi_profile profile; char rev[10]; char *p; __u32 ncontr, contr; __u16 errcode; capifuncs = attach_capi_interface(&cuser); if (!capifuncs) return -EIO;#ifndef HAS_NEW_SYMTAB /* No symbols to export, hide all symbols */ register_symtab(NULL);#endif if ((p = strchr(revision, ':'))) { strcpy(rev, p + 1); p = strchr(rev, '$'); *p = 0; } else strcpy(rev, " ??? "); rparam.level3cnt = -2; /* number of bchannels twice */ rparam.datablkcnt = 16; rparam.datablklen = 2048; errcode = (*capifuncs->capi_register) (&rparam, &global.appid); if (errcode) { detach_capi_interface(&cuser); return -EIO; } errcode = (*capifuncs->capi_get_profile) (0, &profile); if (errcode != CAPI_NOERROR) { (void) (*capifuncs->capi_release) (global.appid); detach_capi_interface(&cuser); return -EIO; } (void) (*capifuncs->capi_set_signal) (global.appid, capidrv_signal, 0); ncontr = profile.ncontroller; for (contr = 1; contr <= ncontr; contr++) { errcode = (*capifuncs->capi_get_profile) (contr, &profile); if (errcode != CAPI_NOERROR) continue; (void) capidrv_addcontr(contr, &profile); } return 0;}#ifdef MODULEvoid cleanup_module(void){ capidrv_contr *card, *next; char rev[10]; char *p; if ((p = strchr(revision, ':'))) { strcpy(rev, p + 1); p = strchr(rev, '$'); *p = 0; } else { strcpy(rev, " ??? "); } for (card = global.contr_list; card; card = next) { next = card->next; capidrv_delcontr(card->contrnr); } (void) (*capifuncs->capi_release) (global.appid); detach_capi_interface(&cuser); printk(KERN_NOTICE "capidrv: Rev%s: unloaded\n", rev);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -