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

📄 capi.c

📁 arm平台上的uclinux系统全部源代码
💻 C
字号:
/* * $Id: capi.c,v 1.1.1.1 1999/11/15 13:42:17 vadim Exp $ * * CAPI 2.0 Interface for Linux * * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capi.c,v $ * Revision 1.1.1.1  1999/11/15 13:42:17  vadim * Initial import * * 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/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/timer.h>#include <linux/wait.h>#include <linux/skbuff.h>#if (LINUX_VERSION_CODE >= 0x020117)#include <asm/poll.h>#endif#include <linux/capi.h>#include <linux/kernelcapi.h>#include "compat.h"#include "capiutil.h"#include "capicmd.h"#include "capidev.h"#ifdef HAS_NEW_SYMTABMODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)");#endif/* -------- driver information -------------------------------------- */int capi_major = 68;		/* allocated */#ifdef HAS_NEW_SYMTABMODULE_PARM(capi_major, "i");#endif/* -------- global variables ---------------------------------------- */static struct capidev capidevs[CAPI_MAXMINOR + 1];struct capi_interface *capifuncs;/* -------- function called by lower level -------------------------- */static void capi_signal(__u16 applid, __u32 minor){	struct capidev *cdev;	struct sk_buff *skb = 0;	if (minor > CAPI_MAXMINOR || !capidevs[minor].is_registered) {		printk(KERN_ERR "BUG: capi_signal: illegal minor %d\n", minor);		return;	}	cdev = &capidevs[minor];	(void) (*capifuncs->capi_get_message) (applid, &skb);	if (skb) {		skb_queue_tail(&cdev->recv_queue, skb);		wake_up_interruptible(&cdev->recv_wait);	} else {		printk(KERN_ERR "BUG: capi_signal: no skb\n");	}}/* -------- file_operations ----------------------------------------- */#if LINUX_VERSION_CODE < 0x020100static int capi_lseek(struct inode *inode, struct file *file,		      off_t offset, int origin){	return -ESPIPE;}#elsestatic long long capi_llseek(struct inode *inode, struct file *file,			     long long offset, int origin){	return -ESPIPE;}#endif#if LINUX_VERSION_CODE < 0x020100static int capi_read(struct inode *inode, struct file *file,		     char *buf, int count)#elsestatic long capi_read(struct inode *inode, struct file *file,		      char *buf, unsigned long count)#endif{	unsigned int minor = MINOR(inode->i_rdev);	struct capidev *cdev;	struct sk_buff *skb;	int retval;	size_t copied;	if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)		return -ENODEV;	cdev = &capidevs[minor];	if ((skb = skb_dequeue(&cdev->recv_queue)) == 0) {		if (file->f_flags & O_NONBLOCK)			return -EAGAIN;		for (;;) {			interruptible_sleep_on(&cdev->recv_wait);			if ((skb = skb_dequeue(&cdev->recv_queue)) != 0)				break;			if (current->signal & ~current->blocked)				break;		}		if (skb == 0)			return -ERESTARTNOHAND;	}	if (skb->len > count) {		skb_queue_head(&cdev->recv_queue, skb);		return -EMSGSIZE;	}	if (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3	    && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND)		CAPIMSG_SETDATA(skb->data, buf + CAPIMSG_LEN(skb->data));	retval = copy_to_user(buf, skb->data, skb->len);	if (retval) {		skb_queue_head(&cdev->recv_queue, skb);		return retval;	}	copied = skb->len;	kfree_skb(skb, FREE_READ);	return copied;}#if LINUX_VERSION_CODE < 0x020100static int capi_write(struct inode *inode, struct file *file,		      const char *buf, int count)#elsestatic long capi_write(struct inode *inode, struct file *file,		       const char *buf, unsigned long count)#endif{	unsigned int minor = MINOR(inode->i_rdev);	struct capidev *cdev;	struct sk_buff *skb;	int retval;	__u8 cmd;	__u8 subcmd;	__u16 mlen;	if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)		return -ENODEV;	cdev = &capidevs[minor];	skb = alloc_skb(count, GFP_USER);	if ((retval = copy_from_user(skb_put(skb, count), buf, count))) {		dev_kfree_skb(skb, FREE_WRITE);		return retval;	}	cmd = CAPIMSG_COMMAND(skb->data);	subcmd = CAPIMSG_SUBCOMMAND(skb->data);	mlen = CAPIMSG_LEN(skb->data);	if (cmd == CAPI_DATA_B3 && subcmd == CAPI_REQ) {		__u16 dlen = CAPIMSG_DATALEN(skb->data);		if (mlen + dlen != count) {			dev_kfree_skb(skb, FREE_WRITE);			return -EINVAL;		}	} else if (mlen != count) {		dev_kfree_skb(skb, FREE_WRITE);		return -EINVAL;	}	CAPIMSG_SETAPPID(skb->data, cdev->applid);	cdev->errcode = (*capifuncs->capi_put_message) (cdev->applid, skb);	if (cdev->errcode) {		dev_kfree_skb(skb, FREE_WRITE);		return -EIO;	}	return count;}#if (LINUX_VERSION_CODE < 0x020117)static int capi_select(struct inode *inode, struct file *file,		       int sel_type, select_table * wait){	unsigned int minor = MINOR(inode->i_rdev);	struct capidev *cdev;	if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)		return -ENODEV;	cdev = &capidevs[minor];	switch (sel_type) {	case SEL_IN:		if (!skb_queue_empty(&cdev->recv_queue))			return 1;		/* fall througth */	case SEL_EX:		/* error conditions ? */		select_wait(&cdev->recv_wait, wait);		return 0;	case SEL_OUT:		/* 		   if (!queue_full())		   return 1;		   select_wait(&cdev->send_wait, wait);		   return 0;		 */		return 1;	}	return 1;}#elsestatic unsigned intcapi_poll(struct file *file, poll_table * wait){	unsigned int mask = 0;	unsigned int minor = MINOR(file->f_inode->i_rdev);	struct capidev *cdev;	if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)		return POLLERR;	cdev = &capidevs[minor];	poll_wait(&(cdev->recv_wait), wait);	mask = POLLOUT | POLLWRNORM;	if (!skb_queue_empty(&cdev->recv_queue))		mask |= POLLIN | POLLRDNORM;	return mask;}#endifstatic int capi_ioctl(struct inode *inode, struct file *file,		      unsigned int cmd, unsigned long arg){	unsigned int minor = MINOR(inode->i_rdev);	struct capidev *cdev;	capi_ioctl_struct data;	int retval;	if (minor >= CAPI_MAXMINOR || !capidevs[minor].is_open)		return -ENODEV;	cdev = &capidevs[minor];	switch (cmd) {	case CAPI_REGISTER:		{			if (!minor)				return -EINVAL;			retval = copy_from_user((void *) &data.rparams,						(void *) arg, sizeof(struct capi_register_params));			if (retval)				return -EFAULT;			if (cdev->is_registered)				return -EEXIST;			cdev->errcode = (*capifuncs->capi_register) (&data.rparams,							  &cdev->applid);			if (cdev->errcode)				return -EIO;			(void) (*capifuncs->capi_set_signal) (cdev->applid, capi_signal, minor);			cdev->is_registered = 1;		}		return 0;	case CAPI_GET_VERSION:		{			retval = copy_from_user((void *) &data.contr,						(void *) arg,						sizeof(data.contr));			if (retval)				return -EFAULT;		        cdev->errcode = (*capifuncs->capi_get_version) (data.contr, &data.version);			if (cdev->errcode)				return -EIO;			retval = copy_to_user((void *) arg,					      (void *) &data.version,					      sizeof(data.version));			if (retval)				return -EFAULT;		}		return 0;	case CAPI_GET_SERIAL:		{			retval = copy_from_user((void *) &data.contr,						(void *) arg,						sizeof(data.contr));			if (retval)				return -EFAULT;			cdev->errcode = (*capifuncs->capi_get_serial) (data.contr, data.serial);			if (cdev->errcode)				return -EIO;			retval = copy_to_user((void *) arg,					      (void *) data.serial,					      sizeof(data.serial));			if (retval)				return -EFAULT;		}		return 0;	case CAPI_GET_PROFILE:		{			retval = copy_from_user((void *) &data.contr,						(void *) arg,						sizeof(data.contr));			if (retval)				return -EFAULT;			if (data.contr == 0) {				cdev->errcode = (*capifuncs->capi_get_profile) (data.contr, &data.profile);				if (cdev->errcode)					return -EIO;				retval = copy_to_user((void *) arg,				      (void *) &data.profile.ncontroller,				       sizeof(data.profile.ncontroller));			} else {				cdev->errcode = (*capifuncs->capi_get_profile) (data.contr, &data.profile);				if (cdev->errcode)					return -EIO;				retval = copy_to_user((void *) arg,						  (void *) &data.profile,						   sizeof(data.profile));			}			if (retval)				return -EFAULT;		}		return 0;	case CAPI_GET_MANUFACTURER:		{			retval = copy_from_user((void *) &data.contr,						(void *) arg,						sizeof(data.contr));			if (retval)				return -EFAULT;			cdev->errcode = (*capifuncs->capi_get_manufacturer) (data.contr, data.manufacturer);			if (cdev->errcode)				return -EIO;			retval = copy_to_user((void *) arg, (void *) data.manufacturer,					      sizeof(data.manufacturer));			if (retval)				return -EFAULT;		}		return 0;	case CAPI_GET_ERRCODE:		data.errcode = cdev->errcode;		cdev->errcode = CAPI_NOERROR;		if (arg) {			retval = copy_to_user((void *) arg,					      (void *) &data.errcode,					      sizeof(data.errcode));			if (retval)				return -EFAULT;		}		return data.errcode;	case CAPI_INSTALLED:		if ((*capifuncs->capi_installed) ())			return 0;		return -ENXIO;	case CAPI_MANUFACTURER_CMD:		{			struct capi_manufacturer_cmd mcmd;			if (minor)				return -EINVAL;			if (!suser())				return -EPERM;			retval = copy_from_user((void *) &mcmd, (void *) arg,						sizeof(mcmd));			if (retval)				return -EFAULT;			return (*capifuncs->capi_manufacturer) (mcmd.cmd, mcmd.data);		}		return 0;	}	return -EINVAL;}static int capi_open(struct inode *inode, struct file *file){	unsigned int minor = MINOR(inode->i_rdev);	if (minor >= CAPI_MAXMINOR)		return -ENXIO;	if (minor) {		if (capidevs[minor].is_open)			return -EEXIST;		capidevs[minor].is_open = 1;		skb_queue_head_init(&capidevs[minor].recv_queue);		MOD_INC_USE_COUNT;	} else {		if (!capidevs[minor].is_open) {			capidevs[minor].is_open = 1;			MOD_INC_USE_COUNT;		}	}	return 0;}static CLOSETYPEcapi_release(struct inode *inode, struct file *file){	unsigned int minor = MINOR(inode->i_rdev);	struct capidev *cdev;	struct sk_buff *skb;	if (minor >= CAPI_MAXMINOR || !capidevs[minor].is_open) {		printk(KERN_ERR "capi20: release minor %d ???\n", minor);		return CLOSEVAL;	}	cdev = &capidevs[minor];	if (minor) {		if (cdev->is_registered)			(*capifuncs->capi_release) (cdev->applid);		cdev->is_registered = 0;		cdev->applid = 0;		while ((skb = skb_dequeue(&cdev->recv_queue)) != 0)			kfree_skb(skb, FREE_READ);	}	cdev->is_open = 0;	MOD_DEC_USE_COUNT;	return CLOSEVAL;}static struct file_operations capi_fops ={#if LINUX_VERSION_CODE < 0x020100	capi_lseek,#else	capi_llseek,#endif	capi_read,	capi_write,	NULL,			/* capi_readdir */#if (LINUX_VERSION_CODE < 0x020117)	capi_select,#else	capi_poll,#endif	capi_ioctl,	NULL,			/* capi_mmap */	capi_open,	capi_release,	NULL,			/* capi_fsync */	NULL,			/* capi_fasync */};/* -------- init function and module interface ---------------------- */#ifdef MODULE#define	 capi_init	init_module#endifstatic struct capi_interface_user cuser = {	"capi20",	0,};int capi_init(void){	memset(capidevs, 0, sizeof(capidevs));	if (register_chrdev(capi_major, "capi20", &capi_fops)) {		printk(KERN_ERR "capi20: unable to get major %d\n", capi_major);		return -EIO;	}	printk(KERN_NOTICE "capi20: started up with major %d\n", capi_major);	if ((capifuncs = attach_capi_interface(&cuser)) == 0) {		unregister_chrdev(capi_major, "capi20");		return -EIO;	}	return 0;}#ifdef MODULEvoid cleanup_module(void){	unregister_chrdev(capi_major, "capi20");	(void) detach_capi_interface(&cuser);}#endif

⌨️ 快捷键说明

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