📄 capidrv.c
字号:
/* * $Id: capidrv.c,v 1.1.1.1 1999/11/15 13:42:17 vadim Exp $ * * ISDN4Linux Driver, using capi20 interface (kernelcapi) * * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capidrv.c,v $ * Revision 1.1.1.1 1999/11/15 13:42:17 vadim * Initial import * * Revision 1.3.2.12 1998/09/11 15:37:11 calle * Started with support for CAPI channel allocation/bundling. * * Revision 1.3.2.11 1998/04/02 10:27:59 calle * version check for D2 trace was wrong :-( * * Revision 1.3.2.10 1998/03/20 14:38:24 calle * capidrv: prepared state machines for suspend/resume/hold * capidrv: fix bug in state machine if B1/T1 is out of nccis * b1capi: changed some errno returns. * b1capi: detect if you try to add same T1 to different io address. * b1capi: change number of nccis depending on number of channels. * b1lli: cosmetics * * Revision 1.3.2.9 1998/03/20 09:01:12 calle * Changes capi_register handling to get full support for 30 bchannels. * * Revision 1.3.2.8 1998/03/18 17:51:28 calle * added controller number to error messages * * Revision 1.3.2.7 1998/02/27 15:40:47 calle * T1 running with slow link. bugfix in capi_release. * * Revision 1.3.2.6 1998/02/02 19:51:13 calle * Fixed vbox (audio) acceptb. * * Revision 1.3.2.5 1997/10/29 09:35:29 calle * correct byteorder problem with new isdnlog interface. * * Revision 1.3.2.4 1997/10/26 15:04:24 calle * prepared isdnlog interface for d2-trace in newer firmware. * * Revision 1.3.2.3 1997/10/24 06:37:00 calle * changed LISTEN cipmask, now we can distinguish voice, fax und data calls. * * Revision 1.3.2.2 1997/10/08 05:42:25 calle * Added isdnlog support. patch to isdnlog needed. * * Revision 1.3.2.1 1997/07/13 12:16:48 calle * bug fix for more than one controller in connect_req. * * Revision 1.3 1997/05/18 09:24:15 calle * added verbose disconnect reason reporting to avmb1. * some fixes in capi20 interface. * changed info messages for B1-PCI * * Revision 1.2 1997/03/05 21:19:59 fritz * Removed include of config.h (mkdep stated this is unneded). * * Revision 1.1 1997/03/04 21:50:31 calle * Frirst version in isdn4linux * * Revision 2.2 1997/02/12 09:31:39 calle * new version * * Revision 1.1 1997/01/31 10:32:20 calle * Initial revision * */#include <linux/module.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/major.h>#include <linux/sched.h>#include <linux/malloc.h>#include <linux/fcntl.h>#include <linux/fs.h>#include <linux/signal.h>#include <linux/mm.h>#include <linux/timer.h>#include <linux/wait.h>#include <linux/skbuff.h>#include <linux/isdn.h>#include <linux/isdnif.h>#include <linux/capi.h>#include <linux/kernelcapi.h>#include <linux/ctype.h>#include "compat.h"#include "capiutil.h"#include "capicmd.h"#include "capidrv.h"static char *revision = "$Revision: 1.1.1.1 $";int debugmode = 0;#ifdef HAS_NEW_SYMTABMODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");MODULE_PARM(debugmode, "i");#endif/* -------- type definitions ----------------------------------------- */struct capidrv_contr { struct capidrv_contr *next; __u32 contrnr; char name[20]; /* * for isdn4linux */ isdn_if interface; int myid; /* * LISTEN state */ int state; __u32 cipmask; __u32 cipmask2; /* * ID of capi message sent */ __u16 msgid; /* * B-Channels */ int nbchan; struct capidrv_bchan { struct capidrv_contr *contr; __u8 msn[ISDN_MSNLEN]; int l2; int l3; __u8 num[ISDN_MSNLEN]; __u8 mynum[ISDN_MSNLEN]; int si1; int si2; int incoming; int disconnecting; struct capidrv_plci { struct capidrv_plci *next; __u32 plci; __u32 ncci; /* ncci for CONNECT_ACTIVE_IND */ __u16 msgid; /* to identfy CONNECT_CONF */ int chan; int state; int leasedline; struct capidrv_ncci { struct capidrv_ncci *next; struct capidrv_plci *plcip; __u32 ncci; __u16 msgid; /* to identfy CONNECT_B3_CONF */ int chan; int state; int oldstate; /* */ __u16 datahandle; } *ncci_list; } *plcip; struct capidrv_ncci *nccip; } *bchans; struct capidrv_plci *plci_list; /* for q931 data */ __u8 q931_buf[4096]; __u8 *q931_read; __u8 *q931_write; __u8 *q931_end;};struct capidrv_data { __u16 appid; int ncontr; struct capidrv_contr *contr_list;};typedef struct capidrv_plci capidrv_plci;typedef struct capidrv_ncci capidrv_ncci;typedef struct capidrv_contr capidrv_contr;typedef struct capidrv_data capidrv_data;typedef struct capidrv_bchan capidrv_bchan;/* -------- data definitions ----------------------------------------- */static capidrv_data global;static struct capi_interface *capifuncs;static void handle_dtrace_data(capidrv_contr *card, int send, int level2, __u8 *data, __u16 len);/* -------- convert functions ---------------------------------------- */static inline __u32 b1prot(int l2, int l3){ switch (l2) { case ISDN_PROTO_L2_X75I: case ISDN_PROTO_L2_X75UI: case ISDN_PROTO_L2_X75BUI: return 0; case ISDN_PROTO_L2_HDLC: default: return 0; case ISDN_PROTO_L2_TRANS: return 1; }}static inline __u32 b2prot(int l2, int l3){ switch (l2) { case ISDN_PROTO_L2_X75I: case ISDN_PROTO_L2_X75UI: case ISDN_PROTO_L2_X75BUI: default: return 0; case ISDN_PROTO_L2_HDLC: case ISDN_PROTO_L2_TRANS: return 1; }}static inline __u32 b3prot(int l2, int l3){ switch (l2) { case ISDN_PROTO_L2_X75I: case ISDN_PROTO_L2_X75UI: case ISDN_PROTO_L2_X75BUI: case ISDN_PROTO_L2_HDLC: case ISDN_PROTO_L2_TRANS: default: return 0; }}static inline __u16 si2cip(__u8 si1, __u8 si2){ static const __u8 cip[17][5] = { /* 0 1 2 3 4 */ {0, 0, 0, 0, 0}, /*0 */ {16, 16, 4, 26, 16}, /*1 */ {17, 17, 17, 4, 4}, /*2 */ {2, 2, 2, 2, 2}, /*3 */ {18, 18, 18, 18, 18}, /*4 */ {2, 2, 2, 2, 2}, /*5 */ {0, 0, 0, 0, 0}, /*6 */ {2, 2, 2, 2, 2}, /*7 */ {2, 2, 2, 2, 2}, /*8 */ {21, 21, 21, 21, 21}, /*9 */ {19, 19, 19, 19, 19}, /*10 */ {0, 0, 0, 0, 0}, /*11 */ {0, 0, 0, 0, 0}, /*12 */ {0, 0, 0, 0, 0}, /*13 */ {0, 0, 0, 0, 0}, /*14 */ {22, 22, 22, 22, 22}, /*15 */ {27, 27, 27, 28, 27} /*16 */ }; if (si1 > 16) si1 = 0; if (si2 > 4) si2 = 0; return (__u16) cip[si1][si2];}static inline __u8 cip2si1(__u16 cipval){ static const __u8 si[32] = {7, 1, 7, 7, 1, 1, 7, 7, /*0-7 */ 7, 1, 0, 0, 0, 0, 0, 0, /*8-15 */ 1, 2, 4, 10, 9, 9, 15, 7, /*16-23 */ 7, 7, 1, 16, 16, 0, 0, 0}; /*24-31 */ if (cipval > 31) cipval = 0; /* .... */ return si[cipval];}static inline __u8 cip2si2(__u16 cipval){ static const __u8 si[32] = {0, 0, 0, 0, 2, 3, 0, 0, /*0-7 */ 0, 3, 0, 0, 0, 0, 0, 0, /*8-15 */ 1, 2, 0, 0, 9, 0, 0, 0, /*16-23 */ 0, 0, 3, 2, 3, 0, 0, 0}; /*24-31 */ if (cipval > 31) cipval = 0; /* .... */ return si[cipval];}/* -------- controller managment ------------------------------------- */static inline capidrv_contr *findcontrbydriverid(int driverid){ capidrv_contr *p = global.contr_list; while (p) { if (p->myid == driverid) return p; p = p->next; } return (capidrv_contr *) 0;}static capidrv_contr *findcontrbynumber(__u32 contr){ capidrv_contr *p = global.contr_list; while (p) { if (p->contrnr == contr) return p; p = p->next; } return (capidrv_contr *) 0;}/* -------- plci management ------------------------------------------ */static capidrv_plci *new_plci(capidrv_contr * card, int chan){ capidrv_plci *plcip; plcip = (capidrv_plci *) kmalloc(sizeof(capidrv_plci), GFP_ATOMIC); if (plcip == 0) return 0; memset(plcip, 0, sizeof(capidrv_plci)); plcip->state = ST_PLCI_NONE; plcip->plci = 0; plcip->msgid = 0; plcip->chan = chan; plcip->next = card->plci_list; card->plci_list = plcip; card->bchans[chan].plcip = plcip; return plcip;}static capidrv_plci *find_plci_by_plci(capidrv_contr * card, __u32 plci){ capidrv_plci *p; for (p = card->plci_list; p; p = p->next) if (p->plci == plci) return p; return 0;}static capidrv_plci *find_plci_by_msgid(capidrv_contr * card, __u16 msgid){ capidrv_plci *p; for (p = card->plci_list; p; p = p->next) if (p->msgid == msgid) return p; return 0;}static capidrv_plci *find_plci_by_ncci(capidrv_contr * card, __u32 ncci){ capidrv_plci *p; for (p = card->plci_list; p; p = p->next) if (p->plci == (ncci & 0xffff)) return p; return 0;}static void free_plci(capidrv_contr * card, capidrv_plci * plcip){ capidrv_plci **pp; for (pp = &card->plci_list; *pp; pp = &(*pp)->next) { if (*pp == plcip) { *pp = (*pp)->next; card->bchans[plcip->chan].plcip = 0; card->bchans[plcip->chan].disconnecting = 0; card->bchans[plcip->chan].incoming = 0; kfree(plcip); return; } } printk(KERN_ERR "capidrv-%d: free_plci %p (0x%x) not found, Huh?\n", card->contrnr, plcip, plcip->plci);}/* -------- ncci management ------------------------------------------ */static inline capidrv_ncci *new_ncci(capidrv_contr * card, capidrv_plci * plcip, __u32 ncci){ capidrv_ncci *nccip; nccip = (capidrv_ncci *) kmalloc(sizeof(capidrv_ncci), GFP_ATOMIC); if (nccip == 0) return 0; memset(nccip, 0, sizeof(capidrv_ncci)); nccip->ncci = ncci; nccip->state = ST_NCCI_NONE; nccip->plcip = plcip; nccip->chan = plcip->chan; nccip->datahandle = 0; nccip->next = plcip->ncci_list; plcip->ncci_list = nccip; card->bchans[plcip->chan].nccip = nccip; return nccip;}static inline capidrv_ncci *find_ncci(capidrv_contr * card, __u32 ncci){ capidrv_plci *plcip; capidrv_ncci *p; if ((plcip = find_plci_by_ncci(card, ncci)) == 0) return 0; for (p = plcip->ncci_list; p; p = p->next) if (p->ncci == ncci) return p; return 0;}static inline capidrv_ncci *find_ncci_by_msgid(capidrv_contr * card, __u32 ncci, __u16 msgid){ capidrv_plci *plcip; capidrv_ncci *p; if ((plcip = find_plci_by_ncci(card, ncci)) == 0) return 0; for (p = plcip->ncci_list; p; p = p->next) if (p->msgid == msgid) return p; return 0;}static void free_ncci(capidrv_contr * card, struct capidrv_ncci *nccip){ struct capidrv_ncci **pp; for (pp = &(nccip->plcip->ncci_list); *pp; pp = &(*pp)->next) { if (*pp == nccip) { *pp = (*pp)->next; break; } } card->bchans[nccip->chan].nccip = 0; kfree(nccip);}/* -------- convert and send capi message ---------------------------- */static void send_message(capidrv_contr * card, _cmsg * cmsg){ struct sk_buff *skb; size_t len; capi_cmsg2message(cmsg, cmsg->buf); len = CAPIMSG_LEN(cmsg->buf); skb = dev_alloc_skb(len); SET_SKB_FREE(skb); memcpy(skb_put(skb, len), cmsg->buf, len); (*capifuncs->capi_put_message) (global.appid, skb);}/* -------- state machine -------------------------------------------- */struct listenstatechange { int actstate; int nextstate; int event;};static struct listenstatechange listentable[] ={ {ST_LISTEN_NONE, ST_LISTEN_WAIT_CONF, EV_LISTEN_REQ}, {ST_LISTEN_ACTIVE, ST_LISTEN_ACTIVE_WAIT_CONF, EV_LISTEN_REQ}, {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_ERROR}, {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_ERROR}, {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY}, {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY}, {ST_LISTEN_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK}, {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK}, {},};static void listen_change_state(capidrv_contr * card, int event){ struct listenstatechange *p = listentable; while (p->event) { if (card->state == p->actstate && p->event == event) { if (debugmode) printk(KERN_DEBUG "capidrv-%d: listen_change_state %d -> %d\n", card->contrnr, card->state, p->nextstate); card->state = p->nextstate; return; } p++; } printk(KERN_ERR "capidrv-%d: listen_change_state state=%d event=%d ????\n", card->contrnr, card->state, event);}/* ------------------------------------------------------------------ */static void p0(capidrv_contr * card, capidrv_plci * plci){ isdn_ctrl cmd; card->bchans[plci->chan].contr = 0; cmd.command = ISDN_STAT_DHUP; cmd.driver = card->myid; cmd.arg = plci->chan; card->interface.statcallb(&cmd); free_plci(card, plci);}/* ------------------------------------------------------------------ */struct plcistatechange { int actstate; int nextstate; int event; void (*changefunc) (capidrv_contr * card, capidrv_plci * plci);};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -