📄 capi.c
字号:
/* * $Id: capi.c,v 1.45 2000/12/02 19:47:29 kai Exp $ * * CAPI 2.0 Interface for Linux * * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capi.c,v $ * Revision 1.45 2000/12/02 19:47:29 kai * Change the Makefiles to new style. * There may be problems there that I missed, so this shouldn't go into * an offical kernel any time soon. * However, if I didn't commit it, we wouldn't find the bugs... * * Revision 1.44 2000/11/25 17:00:59 kai * compatibility cleanup - final part for the time being * * Revision 1.43 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.42 2000/11/19 17:03:55 kai * compatibility cleanup - part 5 * * Revision 1.41 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.40 2000/10/24 15:15:04 calle * Workaround: pppd calls restoretty before reseting the ldisc and * ldisc "ppp_sync" didn't support this. So we call n_tty_ioctl * in the driver ioctl function. (remember: driver ioctl function is * only called if ldisc ioctl function did not handle the call) * * Revision 1.39 2000/07/24 13:42:50 calle * - lock_kernel/unlock_kernel for _release functions. (from 2.4) * * Revision 1.38 2000/07/24 08:49:09 calle * - Bugfix: capiminor_del_all_ack completely wrong :-( * * Revision 1.37 2000/07/20 10:22:27 calle * - Made procfs function cleaner and removed variable "begin". * * Revision 1.36 2000/06/29 13:59:35 calle * - call to devfs_register was wrong * * Revision 1.35 2000/06/19 15:11:24 keil * avoid use of freed structs * changes from 2.4.0-ac21 * * Revision 1.34 2000/06/18 16:09:54 keil * more changes for 2.4 * * Revision 1.33 2000/05/18 16:35:43 calle * Uaaahh. Bad memory leak fixed. * * Revision 1.32 2000/04/21 12:38:42 calle * Bugfix: error in proc_ functions, begin-off => off-begin * * Revision 1.31 2000/04/03 13:29:24 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.30 2000/03/19 12:31:36 calle * PPP over CAPI raw driver disabled for now, ppp_generic has been changed. * * Revision 1.29 2000/03/13 17:48:13 calle * removed unused variable. * * Revision 1.28 2000/03/08 17:06:33 calle * - changes for devfs and 2.3.49 * - capifs now configurable (no need with devfs) * - New Middleware ioctl CAPI_NCCI_GETUNIT * - Middleware again tested with 2.2.14 and 2.3.49 (with and without devfs) * * Revision 1.27 2000/03/06 18:00:23 calle * - Middleware extention now working with 2.3.49 (capifs). * - Fixed typos in debug section of capi.c * - Bugfix: Makefile corrected for b1pcmcia.c * * Revision 1.26 2000/03/03 16:48:38 calle * - Added CAPI2.0 Middleware support (CONFIG_ISDN_CAPI) * It is now possible to create a connection with a CAPI2.0 applikation * and than to handle the data connection from /dev/capi/ (capifs) and also * using async or sync PPP on this connection. * The two major device number 190 and 191 are not confirmed yet, * but I want to save the code in cvs, before I go on. * * Revision 1.25 2000/03/03 16:37:11 kai * incorporated some cosmetic changes from the official kernel tree back * into CVS * * Revision 1.24 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.23 2000/02/26 01:00:53 keil * changes from 2.3.47 * * Revision 1.22 1999/11/13 21:27:16 keil * remove KERNELVERSION * * Revision 1.21 1999/09/10 17:24:18 calle * Changes for proposed standard for CAPI2.0: * - AK148 "Linux Exention" * * Revision 1.20 1999/09/07 09:02:53 calle * SETDATA removed. Now inside the kernel the datapart of DATA_B3_REQ and * DATA_B3_IND is always directly after the CAPI message. The "Data" member * ist never used inside the kernel. * * Revision 1.19 1999/07/09 15:05:42 keil * compat.h is now isdn_compat.h * * Revision 1.18 1999/07/06 07:42:01 calle * - changes in /proc interface * - check and changed calls to [dev_]kfree_skb and [dev_]alloc_skb. * * Revision 1.17 1999/07/01 15:26:30 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. * * Revision 1.16 1999/07/01 08:22:57 keil * compatibility macros now in <linux/isdn_compat.h> * * Revision 1.15 1999/06/21 15:24:11 calle * extend information in /proc. * * Revision 1.14 1999/06/10 16:51:03 calle * Bugfix: open/release of control device was not handled correct. * * Revision 1.13 1998/08/28 04:32:25 calle * Added patch send by Michael.Mueller4@post.rwth-aachen.de, to get AVM B1 * driver running with 2.1.118. * * Revision 1.12 1998/05/26 22:39:34 he * sync'ed with 2.1.102 where appropriate (CAPABILITY changes) * concap typo * cleared dev.tbusy in isdn_net BCONN status callback * * Revision 1.11 1998/03/09 17:46:37 he * merged in 2.1.89 changes * * Revision 1.10 1998/02/13 07:09:13 calle * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * * Revision 1.9 1998/01/31 11:14:44 calle * merged changes to 2.0 tree, prepare 2.1.82 to work. * * Revision 1.8 1997/11/04 06:12:08 calle * capi.c: new read/write in file_ops since 2.1.60 * capidrv.c: prepared isdnlog interface for d2-trace in newer firmware. * capiutil.c: needs config.h (CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON) * compat.h: added #define LinuxVersionCode * * Revision 1.7 1997/10/11 10:29:34 calle * llseek() parameters changed in 2.1.56. * * Revision 1.6 1997/10/01 09:21:15 fritz * Removed old compatibility stuff for 2.0.X kernels. * From now on, this code is for 2.1.X ONLY! * Old stuff is still in the separate branch. * * Revision 1.5 1997/08/21 23:11:55 fritz * Added changes for kernels >= 2.1.45 * * Revision 1.4 1997/05/27 15:17:50 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:14 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:17:59 fritz * Added capi_poll for compiling under 2.1.27 * * Revision 1.1 1997/03/04 21:50:29 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/config.h>#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/smp_lock.h>#include <linux/timer.h>#include <linux/wait.h>#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE#include <linux/tty.h>#ifdef CONFIG_PPP#include <linux/netdevice.h>#include <linux/ppp_defs.h>#include <linux/if_ppp.h>#undef CAPI_PPP_ON_RAW_DEVICE#endif /* CONFIG_PPP */#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */#include <linux/skbuff.h>#include <linux/proc_fs.h>#include <linux/poll.h>#include <linux/capi.h>#include <linux/kernelcapi.h>#include <linux/init.h>#include <linux/devfs_fs_kernel.h>#include "capiutil.h"#include "capicmd.h"#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)#include "capifs.h"#endif#include <linux/slab.h>static char *revision = "$Revision: 1.45 $";MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)");#undef _DEBUG_REFCOUNT /* alloc/free and open/close debug */#undef _DEBUG_TTYFUNCS /* call to tty_driver */#undef _DEBUG_DATAFLOW /* data flow *//* -------- driver information -------------------------------------- */int capi_major = 68; /* allocated */#ifdef CONFIG_ISDN_CAPI_MIDDLEWAREint capi_rawmajor = 190;int capi_ttymajor = 191;#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */MODULE_PARM(capi_major, "i");#ifdef CONFIG_ISDN_CAPI_MIDDLEWAREMODULE_PARM(capi_rawmajor, "i");MODULE_PARM(capi_ttymajor, "i");#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE *//* -------- defines ------------------------------------------------- */#define CAPINC_MAX_RECVQUEUE 10#define CAPINC_MAX_SENDQUEUE 10#define CAPI_MAX_BLKSIZE 2048/* -------- data structures ----------------------------------------- */struct capidev;struct capincci;#ifdef CONFIG_ISDN_CAPI_MIDDLEWAREstruct capiminor;struct capiminor { struct capiminor *next; struct capincci *nccip; unsigned int minor; __u16 applid; __u32 ncci; __u16 datahandle; __u16 msgid; struct file *file; struct tty_struct *tty; int ttyinstop; int ttyoutstop; struct sk_buff *ttyskb; atomic_t ttyopencount; struct sk_buff_head inqueue; int inbytes; struct sk_buff_head outqueue; int outbytes; /* for raw device */ struct sk_buff_head recvqueue; wait_queue_head_t recvwait; wait_queue_head_t sendwait; /* transmit path */ struct datahandle_queue { struct datahandle_queue *next; __u16 datahandle; } *ackqueue; int nack;};#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */struct capincci { struct capincci *next; __u32 ncci; struct capidev *cdev;#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE struct capiminor *minorp;#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */};struct capidev { struct capidev *next; struct file *file; __u16 applid; __u16 errcode; unsigned int minor; unsigned userflags; struct sk_buff_head recvqueue; wait_queue_head_t recvwait; /* Statistic */ unsigned long nrecvctlpkt; unsigned long nrecvdatapkt; unsigned long nsentctlpkt; unsigned long nsentdatapkt; struct capincci *nccis;};/* -------- global variables ---------------------------------------- */static struct capi_interface *capifuncs = 0;static struct capidev *capidev_openlist = 0;#ifdef CONFIG_ISDN_CAPI_MIDDLEWAREstatic struct capiminor *minors = 0;#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */static kmem_cache_t *capidev_cachep = 0;static kmem_cache_t *capincci_cachep = 0;#ifdef CONFIG_ISDN_CAPI_MIDDLEWAREstatic kmem_cache_t *capiminor_cachep = 0;static kmem_cache_t *capidh_cachep = 0;#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE/* -------- datahandles --------------------------------------------- */int capincci_add_ack(struct capiminor *mp, __u16 datahandle){ struct datahandle_queue *n, **pp; n = (struct datahandle_queue *) kmem_cache_alloc(capidh_cachep, GFP_ATOMIC); if (!n) { printk(KERN_ERR "capi: alloc datahandle failed\n"); return -1; } n->next = 0; n->datahandle = datahandle; for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) ; *pp = n; mp->nack++; return 0;}int capiminor_del_ack(struct capiminor *mp, __u16 datahandle){ struct datahandle_queue **pp, *p; for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) { if ((*pp)->datahandle == datahandle) { p = *pp; *pp = (*pp)->next; kmem_cache_free(capidh_cachep, p); mp->nack--; return 0; } } return -1;}void capiminor_del_all_ack(struct capiminor *mp){ struct datahandle_queue **pp, *p; pp = &mp->ackqueue; while (*pp) { p = *pp; *pp = (*pp)->next; kmem_cache_free(capidh_cachep, p); mp->nack--; }}/* -------- struct capiminor ---------------------------------------- */struct capiminor *capiminor_alloc(__u16 applid, __u32 ncci){ struct capiminor *mp, **pp; unsigned int minor = 0; MOD_INC_USE_COUNT; mp = (struct capiminor *)kmem_cache_alloc(capiminor_cachep, GFP_ATOMIC); if (!mp) { MOD_DEC_USE_COUNT; printk(KERN_ERR "capi: can't alloc capiminor\n"); return 0; }#ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capiminor_alloc %d\n", GET_USE_COUNT(THIS_MODULE));#endif memset(mp, 0, sizeof(struct capiminor)); mp->applid = applid; mp->ncci = ncci; mp->msgid = 0; atomic_set(&mp->ttyopencount,0); skb_queue_head_init(&mp->inqueue); skb_queue_head_init(&mp->outqueue); skb_queue_head_init(&mp->recvqueue); init_waitqueue_head(&mp->recvwait); init_waitqueue_head(&mp->sendwait); for (pp = &minors; *pp; pp = &(*pp)->next) { if ((*pp)->minor < minor) continue; if ((*pp)->minor > minor) break; minor++; } mp->minor = minor; mp->next = *pp; *pp = mp; return mp;}void capiminor_free(struct capiminor *mp){ struct capiminor **pp; struct sk_buff *skb; pp = &minors; while (*pp) { if (*pp == mp) { *pp = (*pp)->next; if (mp->ttyskb) kfree_skb(mp->ttyskb); mp->ttyskb = 0; while ((skb = skb_dequeue(&mp->recvqueue)) != 0) kfree_skb(skb); while ((skb = skb_dequeue(&mp->inqueue)) != 0) kfree_skb(skb); while ((skb = skb_dequeue(&mp->outqueue)) != 0) kfree_skb(skb); capiminor_del_all_ack(mp); kmem_cache_free(capiminor_cachep, mp); MOD_DEC_USE_COUNT;#ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capiminor_free %d\n", GET_USE_COUNT(THIS_MODULE));#endif return; } else { pp = &(*pp)->next; } }}struct capiminor *capiminor_find(unsigned int minor){ struct capiminor *p; for (p = minors; p && p->minor != minor; p = p->next) ; return p;}#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE *//* -------- struct capincci ----------------------------------------- */static struct capincci *capincci_alloc(struct capidev *cdev, __u32 ncci){ struct capincci *np, **pp;#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE struct capiminor *mp = 0; kdev_t kdev;#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ np = (struct capincci *)kmem_cache_alloc(capincci_cachep, GFP_ATOMIC); if (!np) return 0; memset(np, 0, sizeof(struct capincci)); np->ncci = ncci; np->cdev = cdev; for (pp=&cdev->nccis; *pp; pp = &(*pp)->next) ; *pp = np;#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE mp = 0; if (cdev->userflags & CAPIFLAG_HIGHJACKING) mp = np->minorp = capiminor_alloc(cdev->applid, ncci); if (mp) { mp->nccip = np;#ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "set mp->nccip\n");#endif#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE) kdev = MKDEV(capi_rawmajor, mp->minor); capifs_new_ncci('r', mp->minor, kdev); kdev = MKDEV(capi_ttymajor, mp->minor); capifs_new_ncci(0, mp->minor, kdev);#endif }#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ return np;}static void capincci_free(struct capidev *cdev, __u32 ncci){ struct capincci *np, **pp;#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE struct capiminor *mp;#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ pp=&cdev->nccis; while (*pp) { np = *pp; if (ncci == 0xffffffff || np->ncci == ncci) { *pp = (*pp)->next;#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE if ((mp = np->minorp) != 0) {#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE) capifs_free_ncci('r', mp->minor);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -