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

📄 capi.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 4 页
字号:
/* $Id: capi.c,v 1.1.4.2 2001/12/09 18:45:13 kai Exp $ * * CAPI 2.0 Interface for Linux * * Copyright 1996 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/config.h>#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/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"#endifstatic char *revision = "$Revision: 1.1.4.2 $";MODULE_DESCRIPTION("CAPI4Linux: Userspace /dev/capi20 interface");MODULE_AUTHOR("Carsten Paeth");MODULE_LICENSE("GPL");#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 --------------------------------------------- */static 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;}static 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;}static 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 ---------------------------------------- */static 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;}static void capiminor_free(struct capiminor *mp){	struct capiminor **pp;	pp = &minors;	while (*pp) {		if (*pp == mp) {			*pp = (*pp)->next;			if (mp->ttyskb) kfree_skb(mp->ttyskb);			mp->ttyskb = 0;			skb_queue_purge(&mp->recvqueue);			skb_queue_purge(&mp->inqueue);			skb_queue_purge(&mp->outqueue);			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;		}	}}static 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;#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 */	for (pp=&cdev->nccis; *pp; pp = &(*pp)->next)		;	*pp = np;        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);				capifs_free_ncci(0, mp->minor);#endif				if (mp->tty) {					mp->nccip = 0;#ifdef _DEBUG_REFCOUNT					printk(KERN_DEBUG "reset mp->nccip\n");#endif					tty_hangup(mp->tty);				} else if (mp->file) {					mp->nccip = 0;#ifdef _DEBUG_REFCOUNT					printk(KERN_DEBUG "reset mp->nccip\n");#endif					wake_up_interruptible(&mp->recvwait);					wake_up_interruptible(&mp->sendwait);				} else {					capiminor_free(mp);				}			}#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */			kmem_cache_free(capincci_cachep, np);			if (*pp == 0) return;		} else {			pp = &(*pp)->next;		}	}}static struct capincci *capincci_find(struct capidev *cdev, u32 ncci){	struct capincci *p;	for (p=cdev->nccis; p ; p = p->next) {		if (p->ncci == ncci)			break;	}	return p;}/* -------- struct capidev ------------------------------------------ */static struct capidev *capidev_alloc(struct file *file){	struct capidev *cdev;	struct capidev **pp;	cdev = (struct capidev *)kmem_cache_alloc(capidev_cachep, GFP_KERNEL);	if (!cdev)		return 0;	memset(cdev, 0, sizeof(struct capidev));	cdev->file = file;	cdev->minor = MINOR(file->f_dentry->d_inode->i_rdev);	skb_queue_head_init(&cdev->recvqueue);	init_waitqueue_head(&cdev->recvwait);	pp=&capidev_openlist;	while (*pp) pp = &(*pp)->next;	*pp = cdev;        return cdev;}static void capidev_free(struct capidev *cdev){	struct capidev **pp;	if (cdev->applid)		(*capifuncs->capi_release) (cdev->applid);	cdev->applid = 0;	skb_queue_purge(&cdev->recvqueue);		pp=&capidev_openlist;	while (*pp && *pp != cdev) pp = &(*pp)->next;	if (*pp)		*pp = cdev->next;	kmem_cache_free(capidev_cachep, cdev);}static struct capidev *capidev_find(u16 applid){	struct capidev *p;	for (p=capidev_openlist; p; p = p->next) {		if (p->applid == applid)			break;	}	return p;}#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE/* -------- handle data queue --------------------------------------- */static struct sk_buff *gen_data_b3_resp_for(struct capiminor *mp, struct sk_buff *skb){	struct sk_buff *nskb;	nskb = alloc_skb(CAPI_DATA_B3_RESP_LEN, GFP_ATOMIC);	if (nskb) {		u16 datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4+4+2);		unsigned char *s = skb_put(nskb, CAPI_DATA_B3_RESP_LEN);		capimsg_setu16(s, 0, CAPI_DATA_B3_RESP_LEN);		capimsg_setu16(s, 2, mp->applid);		capimsg_setu8 (s, 4, CAPI_DATA_B3);		capimsg_setu8 (s, 5, CAPI_RESP);		capimsg_setu16(s, 6, mp->msgid++);		capimsg_setu32(s, 8, mp->ncci);		capimsg_setu16(s, 12, datahandle);	}	return nskb;}static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb){	struct sk_buff *nskb;	unsigned int datalen;	u16 errcode, datahandle;	datalen = skb->len - CAPIMSG_LEN(skb->data);	if (mp->tty) {		if (mp->tty->ldisc.receive_buf == 0) {			printk(KERN_ERR "capi: ldisc has no receive_buf function\n");			return -1;		}		if (mp->ttyinstop) {#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)			printk(KERN_DEBUG "capi: recv tty throttled\n");#endif			return -1;		}		if (mp->tty->ldisc.receive_room &&		    mp->tty->ldisc.receive_room(mp->tty) < datalen) {#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)			printk(KERN_DEBUG "capi: no room in tty\n");#endif			return -1;		}		if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) {			printk(KERN_ERR "capi: gen_data_b3_resp failed\n");			return -1;		}		datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4);		errcode = (*capifuncs->capi_put_message)(mp->applid, nskb);		if (errcode != CAPI_NOERROR) {			printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n",					errcode);			kfree_skb(nskb);			return -1;		}		(void)skb_pull(skb, CAPIMSG_LEN(skb->data));#ifdef _DEBUG_DATAFLOW		printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n",					datahandle, skb->len);

⌨️ 快捷键说明

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