⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 kcapi.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * $Id: kcapi.c,v 1.21.6.1 2000/12/10 23:39:19 kai Exp $ *  * Kernel CAPI 2.0 Module *  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) *  * $Log: kcapi.c,v $ * Revision 1.21.6.1  2000/12/10 23:39:19  kai * in 2.4 we don't have tq_scheduler anymore. * also add one supported card to hfc_pci.c * (from main branch) * * Revision 1.21  2000/11/23 20:45:14  kai * fixed module_init/exit stuff * Note: compiled-in kernel doesn't work pre 2.2.18 anymore. * * Revision 1.20  2000/11/19 17:01:53  kai * compatibility cleanup - part 2 * * Revision 1.19  2000/11/01 14:05:02  calle * - use module_init/module_exit from linux/init.h. * - all static struct variables are initialized with "membername:" now. * - avm_cs.c, let it work with newer pcmcia-cs. * * Revision 1.18  2000/07/20 10:22:27  calle * - Made procfs function cleaner and removed variable "begin". * * Revision 1.17  2000/04/21 13:00:56  calle * Bugfix: driver_proc_info was also wrong. * * Revision 1.16  2000/04/21 12:38:42  calle * Bugfix: error in proc_ functions, begin-off => off-begin * * Revision 1.15  2000/04/06 15:01:25  calle * Bugfix: crash in capidrv.c when reseting a capi controller. * - changed code order on remove of controller. * - using tq_schedule for notifier in kcapi.c. * - now using spin_lock_irqsave() and spin_unlock_irqrestore(). * strange: sometimes even MP hang on unload of isdn.o ... * * Revision 1.14  2000/04/03 13:29:25  calle * make Tim Waugh happy (module unload races in 2.3.99-pre3). * no real problem there, but now it is much cleaner ... * * Revision 1.13  2000/03/03 15:50:42  calle * - kernel CAPI: *   - Changed parameter "param" in capi_signal from __u32 to void *. *   - rewrote notifier handling in kcapi.c *   - new notifier NCCI_UP and NCCI_DOWN * - User CAPI: *   - /dev/capi20 is now a cloning device. *   - middleware extentions prepared. * - capidrv.c *   - locking of list operations and module count updates. * * Revision 1.12  2000/01/28 16:45:39  calle * new manufacturer command KCAPI_CMD_ADDCARD (generic addcard), * will search named driver and call the add_card function if one exist. * * Revision 1.11  1999/11/23 13:29:29  calle * Bugfix: incoming capi message were never traced. * * Revision 1.10  1999/10/26 15:30:32  calle * Generate error message if user want to add card, but driver module is * not loaded. * * Revision 1.9  1999/10/11 22:04:12  keil * COMPAT_NEED_UACCESS (no include in isdn_compat.h) * * Revision 1.8  1999/09/10 17:24:18  calle * Changes for proposed standard for CAPI2.0: * - AK148 "Linux Exention" * * Revision 1.7  1999/09/04 06:20:05  keil * Changes from kernel set_current_state() * * Revision 1.6  1999/07/20 06:41:49  calle * Bugfix: After the redesign of the AVM B1 driver, the driver didn't even *         compile, if not selected as modules. * * Revision 1.5  1999/07/09 15:05:48  keil * compat.h is now isdn_compat.h * * Revision 1.4  1999/07/08 14:15:17  calle * Forgot to count down ncards in drivercb_detach_ctr. * * Revision 1.3  1999/07/06 07:42:02  calle * - changes in /proc interface * - check and changed calls to [dev_]kfree_skb and [dev_]alloc_skb. * * Revision 1.2  1999/07/05 15:09:52  calle * - renamed "appl_release" to "appl_released". * - version und profile data now cleared on controller reset * - extended /proc interface, to allow driver and controller specific *   informations to include by driver hackers. * * Revision 1.1  1999/07/01 15:26:42  calle * complete new version (I love it): * + new hardware independed "capi_driver" interface that will make it easy to: *   - support other controllers with CAPI-2.0 (i.e. USB Controller) *   - write a CAPI-2.0 for the passive cards *   - support serial link CAPI-2.0 boxes. * + wrote "capi_driver" for all supported cards. * + "capi_driver" (supported cards) now have to be configured with *   make menuconfig, in the past all supported cards where included *   at once. * + new and better informations in /proc/capi/ * + new ioctl to switch trace of capi messages per controller *   using "avmcapictrl trace [contr] on|off|...." * + complete testcircle with all supported cards and also the *   PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done. * */#define CONFIG_AVMB1_COMPAT#include <linux/config.h>#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/proc_fs.h>#include <linux/skbuff.h>#include <linux/tqueue.h>#include <linux/capi.h>#include <linux/kernelcapi.h>#include <linux/locks.h>#include <linux/init.h>#include <asm/uaccess.h>#include "capicmd.h"#include "capiutil.h"#include "capilli.h"#ifdef CONFIG_AVMB1_COMPAT#include <linux/b1lli.h>#endifstatic char *revision = "$Revision: 1.21.6.1 $";/* ------------------------------------------------------------- */#define CARD_FREE	0#define CARD_DETECTED	1#define CARD_LOADING	2#define CARD_RUNNING	3/* ------------------------------------------------------------- */int showcapimsgs = 0;MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");MODULE_PARM(showcapimsgs, "0-4i");/* ------------------------------------------------------------- */struct msgidqueue {	struct msgidqueue *next;	__u16 msgid;};struct capi_ncci {	struct capi_ncci *next;	__u16 applid;	__u32 ncci;	__u32 winsize;	int   nmsg;	struct msgidqueue *msgidqueue;	struct msgidqueue *msgidlast;	struct msgidqueue *msgidfree;	struct msgidqueue msgidpool[CAPI_MAXDATAWINDOW];};struct capi_appl {	__u16 applid;	capi_register_params rparam;	int releasing;	void *param;	void (*signal) (__u16 applid, void *param);	struct sk_buff_head recv_queue;	int nncci;	struct capi_ncci *nccilist;	unsigned long nrecvctlpkt;	unsigned long nrecvdatapkt;	unsigned long nsentctlpkt;	unsigned long nsentdatapkt;};struct capi_notifier {	struct capi_notifier *next;	unsigned int cmd;	__u32 controller;	__u16 applid;	__u32 ncci;};/* ------------------------------------------------------------- */static struct capi_version driver_version = {2, 0, 1, 1<<4};static char driver_serial[CAPI_SERIAL_LEN] = "0004711";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 struct capi_appl applications[CAPI_MAXAPPL];static struct capi_ctr cards[CAPI_MAXCONTR];static int ncards = 0;static struct sk_buff_head recv_queue;static struct capi_interface_user *capi_users = 0;static spinlock_t capi_users_lock = SPIN_LOCK_UNLOCKED;static struct capi_driver *drivers;static spinlock_t drivers_lock = SPIN_LOCK_UNLOCKED;static struct tq_struct tq_state_notify;static struct tq_struct tq_recv_notify;/* -------- util functions ------------------------------------ */static char *cardstate2str(unsigned short cardstate){	switch (cardstate) {        	default:		case CARD_FREE:		return "free";		case CARD_DETECTED:	return "detected";		case CARD_LOADING:	return "loading";		case CARD_RUNNING:	return "running";	}}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;}/* -------- /proc functions ----------------------------------- *//* * /proc/capi/applications: *      applid l3cnt dblkcnt dblklen #ncci recvqueuelen */static int proc_applications_read_proc(char *page, char **start, off_t off,                                       int count, int *eof, void *data){	struct capi_appl *ap;	int i;	int len = 0;	for (i=0; i < CAPI_MAXAPPL; i++) {		ap = &applications[i];		if (ap->applid == 0) continue;		len += sprintf(page+len, "%u %d %d %d %d %d\n",			ap->applid,			ap->rparam.level3cnt,			ap->rparam.datablkcnt,			ap->rparam.datablklen,			ap->nncci,                        skb_queue_len(&ap->recv_queue));		if (len <= off) {			off -= len;			len = 0;		} else {			if (len-off > count)				goto endloop;		}	}endloop:	*start = page+off;	if (len < count)		*eof = 1;	if (len>count) len = count;	if (len<0) len = 0;	return len;}/* * /proc/capi/ncci: *	applid ncci winsize nblk */static int proc_ncci_read_proc(char *page, char **start, off_t off,                                       int count, int *eof, void *data){	struct capi_appl *ap;	struct capi_ncci *np;	int i;	int len = 0;	for (i=0; i < CAPI_MAXAPPL; i++) {		ap = &applications[i];		if (ap->applid == 0) continue;		for (np = ap->nccilist; np; np = np->next) {			len += sprintf(page+len, "%d 0x%x %d %d\n",				np->applid,				np->ncci,				np->winsize,				np->nmsg);			if (len <= off) {				off -= len;				len = 0;			} else {				if (len-off > count)					goto endloop;			}		}	}endloop:	*start = page+off;	if (len < count)		*eof = 1;	if (len>count) len = count;	if (len<0) len = 0;	return len;}/* * /proc/capi/driver: *	driver ncontroller */static int proc_driver_read_proc(char *page, char **start, off_t off,                                       int count, int *eof, void *data){	struct capi_driver *driver;	int len = 0;	spin_lock(&drivers_lock);	for (driver = drivers; driver; driver = driver->next) {		len += sprintf(page+len, "%-32s %d %s\n",					driver->name,					driver->ncontroller,					driver->revision);		if (len <= off) {			off -= len;			len = 0;		} else {			if (len-off > count)				goto endloop;		}	}endloop:	spin_unlock(&drivers_lock);	*start = page+off;	if (len < count)		*eof = 1;	if (len>count) len = count;	if (len<0) len = 0;	return len;}/* * /proc/capi/users: *	name */static int proc_users_read_proc(char *page, char **start, off_t off,                                       int count, int *eof, void *data){        struct capi_interface_user *cp;	int len = 0;	spin_lock(&capi_users_lock);        for (cp = capi_users; cp ; cp = cp->next) {		len += sprintf(page+len, "%s\n", cp->name);		if (len <= off) {			off -= len;			len = 0;		} else {			if (len-off > count)				goto endloop;		}	}endloop:	spin_unlock(&capi_users_lock);	*start = page+off;	if (len < count)		*eof = 1;	if (len>count) len = count;	if (len<0) len = 0;	return len;}/* * /proc/capi/controller: *	cnr driver cardstate name driverinfo */static int proc_controller_read_proc(char *page, char **start, off_t off,                                       int count, int *eof, void *data){	struct capi_ctr *cp;	int i;	int len = 0;	for (i=0; i < CAPI_MAXCONTR; i++) {		cp = &cards[i];		if (cp->cardstate == CARD_FREE) continue;		len += sprintf(page+len, "%d %-10s %-8s %-16s %s\n",			cp->cnr, cp->driver->name, 			cardstate2str(cp->cardstate),			cp->name,			cp->driver->procinfo ?  cp->driver->procinfo(cp) : ""			);		if (len <= off) {			off -= len;			len = 0;		} else {			if (len-off > count)				goto endloop;		}	}endloop:	*start = page+off;	if (len < count)		*eof = 1;	if (len>count) len = count;	if (len<0) len = 0;	return len;}/* * /proc/capi/applstats: *	applid nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt */static int proc_applstats_read_proc(char *page, char **start, off_t off,                                       int count, int *eof, void *data){	struct capi_appl *ap;	int i;	int len = 0;	for (i=0; i < CAPI_MAXAPPL; i++) {		ap = &applications[i];		if (ap->applid == 0) continue;		len += sprintf(page+len, "%u %lu %lu %lu %lu\n",			ap->applid,			ap->nrecvctlpkt,			ap->nrecvdatapkt,			ap->nsentctlpkt,			ap->nsentdatapkt);		if (len <= off) {			off -= len;			len = 0;		} else {			if (len-off > count)				goto endloop;		}	}endloop:	*start = page+off;	if (len < count)		*eof = 1;	if (len>count) len = count;	if (len<0) len = 0;	return len;}/* * /proc/capi/contrstats: *	cnr nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt */static int proc_contrstats_read_proc(char *page, char **start, off_t off,                                       int count, int *eof, void *data){	struct capi_ctr *cp;	int i;	int len = 0;	for (i=0; i < CAPI_MAXCONTR; i++) {		cp = &cards[i];		if (cp->cardstate == CARD_FREE) continue;		len += sprintf(page+len, "%d %lu %lu %lu %lu\n",			cp->cnr, 			cp->nrecvctlpkt,			cp->nrecvdatapkt,			cp->nsentctlpkt,			cp->nsentdatapkt);		if (len <= off) {			off -= len;			len = 0;		} else {			if (len-off > count)				goto endloop;		}	}endloop:	*start = page+off;	if (len < count)		*eof = 1;	if (len>count) len = count;	if (len<0) len = 0;	return len;}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/applications", 0	 , proc_applications_read_proc },   { "capi/ncci", 	  0	 , proc_ncci_read_proc },   { "capi/driver",       0	 , proc_driver_read_proc },   { "capi/users", 	  0	 , proc_users_read_proc },   { "capi/controller",   0	 , proc_controller_read_proc },   { "capi/applstats",    0	 , proc_applstats_read_proc },   { "capi/contrstats",   0	 , proc_contrstats_read_proc },   { "capi/drivers",	  S_IFDIR, 0 },   { "capi/controllers",  S_IFDIR, 0 },};static void proc_capi_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, 0);	if (p->procent) p->procent->read_proc = p->read_proc;    }}static void proc_capi_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, 0);	   p->procent = 0;	}    }}/* -------- Notifier handling --------------------------------- */static struct capi_notifier_list{	struct capi_notifier *head;	struct capi_notifier *tail;} notifier_list;static spinlock_t notifier_lock = SPIN_LOCK_UNLOCKED;static inline void notify_enqueue(struct capi_notifier *np){	struct capi_notifier_list *q = &notifier_list;	unsigned long flags;	spin_lock_irqsave(&notifier_lock, flags);	if (q->tail) {		q->tail->next = np;		q->tail = np;	} else {		q->head = q->tail = np;	}	spin_unlock_irqrestore(&notifier_lock, flags);}static inline struct capi_notifier *notify_dequeue(void){	struct capi_notifier_list *q = &notifier_list;	struct capi_notifier *np = 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -