📄 b1capi.c
字号:
/* * $Id: b1capi.c,v 1.1.1.1 1999/11/15 13:42:16 vadim Exp $ * * CAPI 2.0 Module for AVM B1-card. * * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1capi.c,v $ * Revision 1.1.1.1 1999/11/15 13:42:16 vadim * Initial import * * Revision 1.4.2.19 1998/10/25 14:36:14 fritz * Backported from MIPS (Cobalt). * * Revision 1.4.2.18 1998/03/20 20:34:37 calle * port valid check now only for T1, because of the PCI and PCMCIA cards. * * Revision 1.4.2.17 1998/03/20 14:38:17 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.4.2.16 1998/03/20 09:01:08 calle * Changes capi_register handling to get full support for 30 bchannels. * * Revision 1.4.2.15 1998/03/18 17:43:26 calle * T1 with fastlink, bugfix for multicontroller support in capidrv.c * * Revision 1.4.2.14 1998/03/04 17:33:47 calle * Changes for T1. * * Revision 1.4.2.13 1998/02/27 15:40:41 calle * T1 running with slow link. bugfix in capi_release. * * Revision 1.4.2.12 1998/02/24 17:58:25 calle * changes for T1. * * Revision 1.4.2.11 1998/01/27 16:12:49 calle * Support for PCMCIA B1/M1/M2 ready. * * Revision 1.4.2.10 1998/01/26 14:53:30 calle * interface change for pcmcia cards * * Revision 1.4.2.9 1998/01/23 16:49:27 calle * added functions for pcmcia cards, * avmb1_addcard returns now the controller number. * * Revision 1.4.2.8 1998/01/16 14:04:15 calle * Decoding of manufacturer part of capi_profile, now show linetype and * protocol if possible. * * Revision 1.4.2.7 1998/01/15 15:33:34 calle * print cardtype, d2 protocol and linetype after load. * * Revision 1.4.2.6 1997/12/08 06:58:41 calle * correct typo. * * Revision 1.4.2.5 1997/12/07 19:59:54 calle * more changes for M1/T1/B1 + config * * Revision 1.4.2.4 1997/11/26 16:57:20 calle * more changes for B1/M1/T1. * * Revision 1.4.2.3 1997/11/26 10:46:52 calle * prepared for M1 (Mobile) and T1 (PMX) cards. * prepared to set configuration after load to support other D-channel * protocols, point-to-point and leased lines. * * Revision 1.4.2.2 1997/10/19 14:44:36 calle * fixed capi_get_version. * * Revision 1.4.2.1 1997/07/12 08:18:59 calle * Correct bug in CARD_NR macro, so now more than one card will work. * Allow card reset, even if card is in running state. * * Revision 1.4 1997/05/27 15:17:45 fritz * Added changes for recent 2.1.x kernels: * changed return type of isdn_close * queue_task_* -> queue_task * clear/set_bit -> test_and_... where apropriate. * changed type of hard_header_cache parameter. * * Revision 1.3 1997/05/18 09:24:09 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:20:41 fritz * Removed include of config.h (mkdep stated this is unneded). * * Revision 1.1 1997/03/04 21:50:27 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/kernel.h>#include <linux/mm.h>#include <linux/interrupt.h>#include <linux/ioport.h>#include <asm/segment.h>#include <linux/skbuff.h>#include <linux/tqueue.h>#include <linux/capi.h>#include <linux/b1lli.h>#include <linux/kernelcapi.h>#include "compat.h"#include "capicmd.h"#include "capiutil.h"static char *revision = "$Revision: 1.1.1.1 $";/* ------------------------------------------------------------- */int showcapimsgs = 0; /* used in lli.c */int loaddebug = 0;#ifdef HAS_NEW_SYMTABMODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");MODULE_PARM(showcapimsgs, "0-5i");MODULE_PARM(loaddebug, "0-1i");#endif/* ------------------------------------------------------------- */struct msgidqueue { struct msgidqueue *next; __u16 msgid;};typedef struct avmb1_ncci { struct avmb1_ncci *next; __u16 applid; __u32 ncci; __u32 winsize; struct msgidqueue *msgidqueue; struct msgidqueue *msgidlast; struct msgidqueue *msgidfree; struct msgidqueue msgidpool[CAPI_MAXDATAWINDOW];} avmb1_ncci;typedef struct avmb1_appl { __u16 applid; capi_register_params rparam; int releasing; __u32 param; void (*signal) (__u16 applid, __u32 param); struct sk_buff_head recv_queue; struct avmb1_ncci *nccilist;} avmb1_appl;/* ------------------------------------------------------------- */static struct capi_version driver_version = {2, 0, 1, 1<<4};static char driver_serial[CAPI_SERIAL_LEN] = "4711";static char capi_manufakturer[64] = "AVM Berlin";#define APPL(a) (&applications[(a)-1])#define VALID_APPLID(a) ((a) && (a) <= CAPI_MAXAPPL && APPL(a)->applid == a)#define APPL_IS_FREE(a) (APPL(a)->applid == 0)#define APPL_MARK_FREE(a) do{ APPL(a)->applid=0; MOD_DEC_USE_COUNT; }while(0);#define APPL_MARK_USED(a) do{ APPL(a)->applid=(a); MOD_INC_USE_COUNT; }while(0);#define NCCI2CTRL(ncci) (((ncci) >> 24) & 0x7f)#define VALID_CARD(c) ((c) > 0 && (c) <= CAPI_MAXCONTR)#define CARD(c) (&cards[(c)-1])#define CARDNR(cp) (((cp)-cards)+1)static avmb1_appl applications[CAPI_MAXAPPL];static avmb1_card cards[CAPI_MAXCONTR];static int ncards = 0;static struct sk_buff_head recv_queue;static struct capi_interface_user *capi_users = 0;static long notify_up_set = 0;static long notify_down_set = 0;static struct tq_struct tq_state_notify;static struct tq_struct tq_recv_notify;/* -------- util functions ------------------------------------ */static char *cardtype2str(int cardtype){ switch (cardtype) { default: case AVM_CARDTYPE_B1: return "B1"; case AVM_CARDTYPE_M1: return "M1"; case AVM_CARDTYPE_M2: return "M2"; case AVM_CARDTYPE_T1: return "T1"; }}static inline int capi_cmd_valid(__u8 cmd){ switch (cmd) { case CAPI_ALERT: case CAPI_CONNECT: case CAPI_CONNECT_ACTIVE: case CAPI_CONNECT_B3_ACTIVE: case CAPI_CONNECT_B3: case CAPI_CONNECT_B3_T90_ACTIVE: case CAPI_DATA_B3: case CAPI_DISCONNECT_B3: case CAPI_DISCONNECT: case CAPI_FACILITY: case CAPI_INFO: case CAPI_LISTEN: case CAPI_MANUFACTURER: case CAPI_RESET_B3: case CAPI_SELECT_B_PROTOCOL: return 1; } return 0;}static inline int capi_subcmd_valid(__u8 subcmd){ switch (subcmd) { case CAPI_REQ: case CAPI_CONF: case CAPI_IND: case CAPI_RESP: return 1; } return 0;}/* -------- NCCI Handling ------------------------------------- */static inline void mq_init(avmb1_ncci * np){ int i; np->msgidqueue = 0; np->msgidlast = 0; memset(np->msgidpool, 0, sizeof(np->msgidpool)); np->msgidfree = &np->msgidpool[0]; for (i = 1; i < np->winsize; i++) { np->msgidpool[i].next = np->msgidfree; np->msgidfree = &np->msgidpool[i]; }}static inline int mq_enqueue(avmb1_ncci * np, __u16 msgid){ struct msgidqueue *mq; if ((mq = np->msgidfree) == 0) return 0; np->msgidfree = mq->next; mq->msgid = msgid; mq->next = 0; if (np->msgidlast) np->msgidlast->next = mq; np->msgidlast = mq; if (!np->msgidqueue) np->msgidqueue = mq; return 1;}static inline int mq_dequeue(avmb1_ncci * np, __u16 msgid){ struct msgidqueue **pp; for (pp = &np->msgidqueue; *pp; pp = &(*pp)->next) { if ((*pp)->msgid == msgid) { struct msgidqueue *mq = *pp; *pp = mq->next; if (mq == np->msgidlast) np->msgidlast = 0; mq->next = np->msgidfree; np->msgidfree = mq; return 1; } } return 0;}void avmb1_handle_new_ncci(avmb1_card * card, __u16 appl, __u32 ncci, __u32 winsize){ avmb1_ncci *np; if (!VALID_APPLID(appl)) { printk(KERN_ERR "avmb1_handle_new_ncci: illegal appl %d\n", appl); return; } if ((np = (avmb1_ncci *) kmalloc(sizeof(avmb1_ncci), GFP_ATOMIC)) == 0) { printk(KERN_ERR "avmb1_handle_new_ncci: alloc failed ncci 0x%x\n", ncci); return; } if (winsize > CAPI_MAXDATAWINDOW) { printk(KERN_ERR "avmb1_handle_new_ncci: winsize %d too big, set to %d\n", winsize, CAPI_MAXDATAWINDOW); winsize = CAPI_MAXDATAWINDOW; } np->applid = appl; np->ncci = ncci; np->winsize = winsize; mq_init(np); np->next = APPL(appl)->nccilist; APPL(appl)->nccilist = np; printk(KERN_INFO "b1capi: appl %d ncci 0x%x up\n", appl, ncci);}void avmb1_handle_free_ncci(avmb1_card * card, __u16 appl, __u32 ncci){ if (!VALID_APPLID(appl)) { printk(KERN_ERR "avmb1_handle_free_ncci: illegal appl %d\n", appl); return; } if (ncci != 0xffffffff) { avmb1_ncci **pp; for (pp = &APPL(appl)->nccilist; *pp; pp = &(*pp)->next) { if ((*pp)->ncci == ncci) { avmb1_ncci *np = *pp; *pp = np->next; kfree(np); printk(KERN_INFO "b1capi: appl %d ncci 0x%x down\n", appl, ncci); return; } } printk(KERN_ERR "avmb1_handle_free_ncci: ncci 0x%x not found\n", ncci); } else { avmb1_ncci **pp, **nextpp; for (pp = &APPL(appl)->nccilist; *pp; pp = nextpp) { if (NCCI2CTRL((*pp)->ncci) == card->cnr) { avmb1_ncci *np = *pp; *pp = np->next; printk(KERN_INFO "b1capi: appl %d ncci 0x%x down!\n", appl, np->ncci); kfree(np); nextpp = pp; } else { nextpp = &(*pp)->next; } } APPL(appl)->releasing--; if (APPL(appl)->releasing <= 0) { APPL(appl)->signal = 0; APPL_MARK_FREE(appl); printk(KERN_INFO "b1capi: appl %d down\n", appl); } }}static avmb1_ncci *find_ncci(avmb1_appl * app, __u32 ncci){ avmb1_ncci *np; for (np = app->nccilist; np; np = np->next) { if (np->ncci == ncci) return np; } return 0;}/* -------- Receiver ------------------------------------------ */static void recv_handler(void *dummy){ struct sk_buff *skb; while ((skb = skb_dequeue(&recv_queue)) != 0) { __u16 appl = CAPIMSG_APPID(skb->data); struct avmb1_ncci *np; if (!VALID_APPLID(appl)) { printk(KERN_ERR "b1capi: recv_handler: applid %d ? (%s)\n", appl, capi_message2str(skb->data)); kfree_skb(skb, FREE_READ); continue; } if (APPL(appl)->signal == 0) { printk(KERN_ERR "b1capi: recv_handler: applid %d has no signal function\n", appl); kfree_skb(skb, FREE_READ); continue; } if ( CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3 && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_CONF && (np = find_ncci(APPL(appl), CAPIMSG_NCCI(skb->data))) != 0 && mq_dequeue(np, CAPIMSG_MSGID(skb->data)) == 0) { printk(KERN_ERR "b1capi: msgid %hu ncci 0x%x not on queue\n", CAPIMSG_MSGID(skb->data), np->ncci); } skb_queue_tail(&APPL(appl)->recv_queue, skb); (APPL(appl)->signal) (APPL(appl)->applid, APPL(appl)->param); }}void avmb1_handle_capimsg(avmb1_card * card, __u16 appl, struct sk_buff *skb){ if (card->cardstate != CARD_RUNNING) { printk(KERN_INFO "b1capi: controller %d not active, got: %s", card->cnr, capi_message2str(skb->data)); goto error; return; } skb_queue_tail(&recv_queue, skb); queue_task(&tq_recv_notify, &tq_immediate); mark_bh(IMMEDIATE_BH); return; error: kfree_skb(skb, FREE_READ);}void avmb1_interrupt(int interrupt, void *devptr, struct pt_regs *regs){ avmb1_card *card; card = (avmb1_card *) devptr; if (!card) { printk(KERN_WARNING "avmb1_interrupt: wrong device\n"); return; } if (card->interrupt) { printk(KERN_ERR "avmb1_interrupt: reentering interrupt hander\n"); return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -