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

📄 divasi.c

📁 优龙2410linux2.6.8内核源代码
💻 C
字号:
/* $Id: divasi.c,v 1.25 2003/09/09 06:46:29 schindler Exp $ * * Driver for Eicon DIVA Server ISDN cards. * User Mode IDI Interface  * * Copyright 2000-2003 by Armin Schindler (mac@melware.de) * Copyright 2000-2003 Cytronics & Melware (info@melware.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/init.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/smp_lock.h>#include <linux/poll.h>#include <linux/proc_fs.h>#include <linux/skbuff.h>#include <linux/devfs_fs_kernel.h>#include "platform.h"#include "di_defs.h"#include "divasync.h"#include "um_xdi.h"#include "um_idi.h"static char *main_revision = "$Revision: 1.25 $";static int major;MODULE_DESCRIPTION("User IDI Interface for Eicon ISDN cards");MODULE_AUTHOR("Cytronics & Melware, Eicon Networks");MODULE_SUPPORTED_DEVICE("DIVA card driver");MODULE_LICENSE("GPL");typedef struct _diva_um_idi_os_context {	wait_queue_head_t read_wait;	wait_queue_head_t close_wait;	struct timer_list diva_timer_id;	int aborted;	int adapter_nr;} diva_um_idi_os_context_t;static char *DRIVERNAME = "Eicon DIVA - User IDI (http://www.melware.net)";static char *DRIVERLNAME = "diva_idi";static char *DEVNAME = "DivasIDI";char *DRIVERRELEASE_IDI = "2.0";extern int idifunc_init(void);extern void idifunc_finit(void);/* *  helper functions */static char *getrev(const char *revision){	char *rev;	char *p;	if ((p = strchr(revision, ':'))) {		rev = p + 2;		p = strchr(rev, '$');		*--p = 0;	} else		rev = "1.0";	return rev;}/* *  LOCALS */static ssize_t um_idi_read(struct file *file, char __user *buf, size_t count,			   loff_t * offset);static ssize_t um_idi_write(struct file *file, const char __user *buf,			    size_t count, loff_t * offset);static unsigned int um_idi_poll(struct file *file, poll_table * wait);static int um_idi_open(struct inode *inode, struct file *file);static int um_idi_release(struct inode *inode, struct file *file);static int remove_entity(void *entity);static void diva_um_timer_function(unsigned long data);/* * proc entry */extern struct proc_dir_entry *proc_net_eicon;static struct proc_dir_entry *um_idi_proc_entry = NULL;static intum_idi_proc_read(char *page, char **start, off_t off, int count, int *eof,		 void *data){	int len = 0;	char tmprev[32];	len += sprintf(page + len, "%s\n", DRIVERNAME);	len += sprintf(page + len, "name     : %s\n", DRIVERLNAME);	len += sprintf(page + len, "release  : %s\n", DRIVERRELEASE_IDI);	strcpy(tmprev, main_revision);	len += sprintf(page + len, "revision : %s\n", getrev(tmprev));	len += sprintf(page + len, "build    : %s\n", DIVA_BUILD);	len += sprintf(page + len, "major    : %d\n", major);	if (off + count >= len)		*eof = 1;	if (len < off)		return 0;	*start = page + off;	return ((count < len - off) ? count : len - off);}static int DIVA_INIT_FUNCTION create_um_idi_proc(void){	um_idi_proc_entry = create_proc_entry(DRIVERLNAME,					      S_IFREG | S_IRUGO | S_IWUSR,					      proc_net_eicon);	if (!um_idi_proc_entry)		return (0);	um_idi_proc_entry->read_proc = um_idi_proc_read;	um_idi_proc_entry->owner = THIS_MODULE;	return (1);}static void remove_um_idi_proc(void){	if (um_idi_proc_entry) {		remove_proc_entry(DRIVERLNAME, proc_net_eicon);		um_idi_proc_entry = NULL;	}}static struct file_operations divas_idi_fops = {	.owner   = THIS_MODULE,	.llseek  = no_llseek,	.read    = um_idi_read,	.write   = um_idi_write,	.poll    = um_idi_poll,	.open    = um_idi_open,	.release = um_idi_release};static void divas_idi_unregister_chrdev(void){	devfs_remove(DEVNAME);	unregister_chrdev(major, DEVNAME);}static int DIVA_INIT_FUNCTION divas_idi_register_chrdev(void){	if ((major = register_chrdev(0, DEVNAME, &divas_idi_fops)) < 0)	{		printk(KERN_ERR "%s: failed to create /dev entry.\n",		       DRIVERLNAME);		return (0);	}	devfs_mk_cdev(MKDEV(major, 0), S_IFCHR|S_IRUSR|S_IWUSR, DEVNAME);	return (1);}/*** Driver Load*/static int DIVA_INIT_FUNCTION divasi_init(void){	char tmprev[50];	int ret = 0;	printk(KERN_INFO "%s\n", DRIVERNAME);	printk(KERN_INFO "%s: Rel:%s  Rev:", DRIVERLNAME, DRIVERRELEASE_IDI);	strcpy(tmprev, main_revision);	printk("%s  Build: %s\n", getrev(tmprev), DIVA_BUILD);	if (!divas_idi_register_chrdev()) {		ret = -EIO;		goto out;	}	if (!create_um_idi_proc()) {		divas_idi_unregister_chrdev();		printk(KERN_ERR "%s: failed to create proc entry.\n",		       DRIVERLNAME);		ret = -EIO;		goto out;	}	if (!(idifunc_init())) {		remove_um_idi_proc();		divas_idi_unregister_chrdev();		printk(KERN_ERR "%s: failed to connect to DIDD.\n",		       DRIVERLNAME);		ret = -EIO;		goto out;	}	printk(KERN_INFO "%s: started with major %d\n", DRIVERLNAME, major);      out:	return (ret);}/*** Driver Unload*/static void DIVA_EXIT_FUNCTION divasi_exit(void){	idifunc_finit();	remove_um_idi_proc();	divas_idi_unregister_chrdev();	printk(KERN_INFO "%s: module unloaded.\n", DRIVERLNAME);}module_init(divasi_init);module_exit(divasi_exit);/* *  FILE OPERATIONS */static intdivas_um_idi_copy_to_user(void *os_handle, void *dst, const void *src,			  int length){	memcpy(dst, src, length);	return (length);}static ssize_tum_idi_read(struct file *file, char __user *buf, size_t count, loff_t * offset){	diva_um_idi_os_context_t *p_os;	int ret = -EINVAL;	void *data;	if (!file->private_data) {		return (-ENODEV);	}	if (!	    (p_os =	     (diva_um_idi_os_context_t *) diva_um_id_get_os_context(file->								    private_data)))	{		return (-ENODEV);	}	if (p_os->aborted) {		return (-ENODEV);	}	if (!(data = diva_os_malloc(0, count))) {		return (-ENOMEM);	}	ret = diva_um_idi_read(file->private_data,			       file, data, count,			       divas_um_idi_copy_to_user);	switch (ret) {	case 0:		/* no message available */		ret = (-EAGAIN);		break;	case (-1):		/* adapter was removed */		ret = (-ENODEV);		break;	case (-2):		/* message_length > length of user buffer */		ret = (-EFAULT);		break;	}	if (ret > 0) {		if (copy_to_user(buf, data, ret)) {			ret = (-EFAULT);		}	}	diva_os_free(0, data);	DBG_TRC(("read: ret %d", ret));	return (ret);}static intdivas_um_idi_copy_from_user(void *os_handle, void *dst, const void *src,			    int length){	memcpy(dst, src, length);	return (length);}static int um_idi_open_adapter(struct file *file, int adapter_nr){	diva_um_idi_os_context_t *p_os;	void *e =	    divas_um_idi_create_entity((dword) adapter_nr, (void *) file);	if (!(file->private_data = e)) {		return (0);	}	p_os = (diva_um_idi_os_context_t *) diva_um_id_get_os_context(e);	init_waitqueue_head(&p_os->read_wait);	init_waitqueue_head(&p_os->close_wait);	init_timer(&p_os->diva_timer_id);	p_os->diva_timer_id.function = (void *) diva_um_timer_function;	p_os->diva_timer_id.data = (unsigned long) p_os;	p_os->aborted = 0;	p_os->adapter_nr = adapter_nr;	return (1);}static ssize_tum_idi_write(struct file *file, const char __user *buf, size_t count,	     loff_t * offset){	diva_um_idi_os_context_t *p_os;	int ret = -EINVAL;	void *data;	int adapter_nr = 0;	if (!file->private_data) {		/* the first write() selects the adapter_nr */		if (count == sizeof(int)) {			if (copy_from_user			    ((void *) &adapter_nr, buf,			     count)) return (-EFAULT);			if (!(um_idi_open_adapter(file, adapter_nr)))				return (-ENODEV);			return (count);		} else			return (-ENODEV);	}	if (!(p_os =	     (diva_um_idi_os_context_t *) diva_um_id_get_os_context(file->								    private_data)))	{		return (-ENODEV);	}	if (p_os->aborted) {		return (-ENODEV);	}	if (!(data = diva_os_malloc(0, count))) {		return (-ENOMEM);	}	if (copy_from_user(data, buf, count)) {		ret = -EFAULT;	} else {		ret = diva_um_idi_write(file->private_data,					file, data, count,					divas_um_idi_copy_from_user);		switch (ret) {		case 0:	/* no space available */			ret = (-EAGAIN);			break;		case (-1):	/* adapter was removed */			ret = (-ENODEV);			break;		case (-2):	/* length of user buffer > max message_length */			ret = (-EFAULT);			break;		}	}	diva_os_free(0, data);	DBG_TRC(("write: ret %d", ret));	return (ret);}static unsigned int um_idi_poll(struct file *file, poll_table * wait){	diva_um_idi_os_context_t *p_os;	if (!file->private_data) {		return (POLLERR);	}	if ((!(p_os =	       (diva_um_idi_os_context_t *)	       diva_um_id_get_os_context(file->private_data)))	    || p_os->aborted) {		return (POLLERR);	}	poll_wait(file, &p_os->read_wait, wait);	if (p_os->aborted) {		return (POLLERR);	}	switch (diva_user_mode_idi_ind_ready(file->private_data, file)) {	case (-1):		return (POLLERR);	case 0:		return (0);	}	return (POLLIN | POLLRDNORM);}static int um_idi_open(struct inode *inode, struct file *file){	return (0);}static int um_idi_release(struct inode *inode, struct file *file){	diva_um_idi_os_context_t *p_os;	unsigned int adapter_nr;	int ret = 0;	if (!(file->private_data)) {		ret = -ENODEV;		goto out;	}	if (!(p_os =		(diva_um_idi_os_context_t *) diva_um_id_get_os_context(file->private_data))) {		ret = -ENODEV;		goto out;	}	adapter_nr = p_os->adapter_nr;	if ((ret = remove_entity(file->private_data))) {		goto out;	}	if (divas_um_idi_delete_entity	    ((int) adapter_nr, file->private_data)) {		ret = -ENODEV;		goto out;	}      out:	return (ret);}int diva_os_get_context_size(void){	return (sizeof(diva_um_idi_os_context_t));}void diva_os_wakeup_read(void *os_context){	diva_um_idi_os_context_t *p_os =	    (diva_um_idi_os_context_t *) os_context;	wake_up_interruptible(&p_os->read_wait);}void diva_os_wakeup_close(void *os_context){	diva_um_idi_os_context_t *p_os =	    (diva_um_idi_os_context_t *) os_context;	wake_up_interruptible(&p_os->close_wait);}staticvoid diva_um_timer_function(unsigned long data){	diva_um_idi_os_context_t *p_os = (diva_um_idi_os_context_t *) data;	p_os->aborted = 1;	wake_up_interruptible(&p_os->read_wait);	wake_up_interruptible(&p_os->close_wait);	DBG_ERR(("entity removal watchdog"))}/***  If application exits without entity removal this function will remove**  entity and block until removal is complete*/static int remove_entity(void *entity){	struct task_struct *curtask = current;	diva_um_idi_os_context_t *p_os;	diva_um_idi_stop_wdog(entity);	if (!entity) {		DBG_FTL(("Zero entity on remove"))		return (0);	}	if (!(p_os =	     (diva_um_idi_os_context_t *)	     diva_um_id_get_os_context(entity))) {		DBG_FTL(("Zero entity os context on remove"))		return (0);	}	if (!divas_um_idi_entity_assigned(entity) || p_os->aborted) {		/*		   Entity is not assigned, also can be removed		 */		return (0);	}	DBG_TRC(("E(%08x) check remove", entity))	/*	   If adapter not answers on remove request inside of	   10 Sec, then adapter is dead	 */	diva_um_idi_start_wdog(entity);	{		DECLARE_WAITQUEUE(wait, curtask);		add_wait_queue(&p_os->close_wait, &wait);		for (;;) {			set_current_state(TASK_INTERRUPTIBLE);			if (!divas_um_idi_entity_start_remove(entity)			    || p_os->aborted) {				break;			}			schedule();		}		set_current_state(TASK_RUNNING);		remove_wait_queue(&p_os->close_wait, &wait);	}	DBG_TRC(("E(%08x) start remove", entity))	{		DECLARE_WAITQUEUE(wait, curtask);		add_wait_queue(&p_os->close_wait, &wait);		for (;;) {			set_current_state(TASK_INTERRUPTIBLE);			if (!divas_um_idi_entity_assigned(entity)			    || p_os->aborted) {				break;			}			schedule();		}		set_current_state(TASK_RUNNING);		remove_wait_queue(&p_os->close_wait, &wait);	}	DBG_TRC(("E(%08x) remove complete, aborted:%d", entity,		 p_os->aborted))	diva_um_idi_stop_wdog(entity);	p_os->aborted = 0;	return (0);}/* * timer watchdog */void diva_um_idi_start_wdog(void *entity){	diva_um_idi_os_context_t *p_os;	if (entity &&	    ((p_os =	      (diva_um_idi_os_context_t *)	      diva_um_id_get_os_context(entity)))) {		mod_timer(&p_os->diva_timer_id, jiffies + 10 * HZ);	}}void diva_um_idi_stop_wdog(void *entity){	diva_um_idi_os_context_t *p_os;	if (entity &&	    ((p_os =	      (diva_um_idi_os_context_t *)	      diva_um_id_get_os_context(entity)))) {		del_timer(&p_os->diva_timer_id);	}}

⌨️ 快捷键说明

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