📄 capidrv.c
字号:
/* $Id: capidrv.c,v 1.1.2.2 2004/01/12 23:17:24 keil Exp $ * * ISDN4Linux Driver, using capi20 interface (kernelcapi) * * Copyright 1997 by Carsten Paeth <calle@calle.de> * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * */#include <linux/module.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/major.h>#include <linux/sched.h>#include <linux/slab.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/proc_fs.h>#include <linux/capi.h>#include <linux/kernelcapi.h>#include <linux/ctype.h>#include <linux/init.h>#include <linux/moduleparam.h>#include <linux/isdn/capiutil.h>#include <linux/isdn/capicmd.h>#include "capidrv.h"static char *revision = "$Revision: 1.1.2.2 $";static int debugmode = 0;MODULE_DESCRIPTION("CAPI4Linux: Interface to ISDN4Linux");MODULE_AUTHOR("Carsten Paeth");MODULE_LICENSE("GPL");module_param(debugmode, uint, 0);/* -------- type definitions ----------------------------------------- */struct capidrv_contr { struct capidrv_contr *next; struct module *owner; u32 contrnr; char name[20]; /* * for isdn4linux */ isdn_if interface; int myid; /* * LISTEN state */ int state; u32 cipmask; u32 cipmask2; struct timer_list listentimer; /* * 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; struct ncci_datahandle_queue { struct ncci_datahandle_queue *next; u16 datahandle; int len; } *ackqueue; } *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 { struct capi20_appl ap; 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 DEFINE_SPINLOCK(global_lock);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; case ISDN_PROTO_L2_V11096: case ISDN_PROTO_L2_V11019: case ISDN_PROTO_L2_V11038: return 2; case ISDN_PROTO_L2_FAX: return 4; case ISDN_PROTO_L2_MODEM: return 8; }}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: case ISDN_PROTO_L2_V11096: case ISDN_PROTO_L2_V11019: case ISDN_PROTO_L2_V11038: case ISDN_PROTO_L2_MODEM: return 1; case ISDN_PROTO_L2_FAX: return 4; }}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: case ISDN_PROTO_L2_V11096: case ISDN_PROTO_L2_V11019: case ISDN_PROTO_L2_V11038: case ISDN_PROTO_L2_MODEM: default: return 0; case ISDN_PROTO_L2_FAX: return 4; }}static _cstruct b1config_async_v110(u16 rate){ /* CAPI-Spec "B1 Configuration" */ static unsigned char buf[9]; buf[0] = 8; /* len */ /* maximum bitrate */ buf[1] = rate & 0xff; buf[2] = (rate >> 8) & 0xff; buf[3] = 8; buf[4] = 0; /* 8 bits per character */ buf[5] = 0; buf[6] = 0; /* parity none */ buf[7] = 0; buf[8] = 0; /* 1 stop bit */ return buf;}static _cstruct b1config(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 NULL; case ISDN_PROTO_L2_V11096: return b1config_async_v110(9600); case ISDN_PROTO_L2_V11019: return b1config_async_v110(19200); case ISDN_PROTO_L2_V11038: return b1config_async_v110(38400); }}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 management ------------------------------------- */static inline capidrv_contr *findcontrbydriverid(int driverid){ unsigned long flags; capidrv_contr *p; spin_lock_irqsave(&global_lock, flags); for (p = global.contr_list; p; p = p->next) if (p->myid == driverid) break; spin_unlock_irqrestore(&global_lock, flags); return p;}static capidrv_contr *findcontrbynumber(u32 contr){ unsigned long flags; capidrv_contr *p = global.contr_list; spin_lock_irqsave(&global_lock, flags); for (p = global.contr_list; p; p = p->next) if (p->contrnr == contr) break; spin_unlock_irqrestore(&global_lock, flags); return p;}/* -------- 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 NULL; 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 NULL;}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 NULL;}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 NULL;}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 = NULL; 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 NULL; 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 NULL; for (p = plcip->ncci_list; p; p = p->next) if (p->ncci == ncci) return p; return NULL;}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 NULL; for (p = plcip->ncci_list; p; p = p->next) if (p->msgid == msgid) return p; return NULL;}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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -