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

📄 drv.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * PCBIT-D interface with isdn4linux * * Copyright (C) 1996 Universidade de Lisboa *  * Written by Pedro Roque Marques (roque@di.fc.ul.pt) * * This software may be used and distributed according to the terms of  * the GNU General Public License, incorporated herein by reference. *//* *	Fixes: * *	Nuno Grilo	<l38486@alfa.ist.utl.pt> *      fixed msn_list NULL pointer dereference. *		 */#include <linux/module.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/slab.h>#include <linux/mm.h>#include <linux/interrupt.h>#include <linux/string.h>#include <linux/skbuff.h>#include <linux/isdnif.h>#include <asm/string.h>#include <asm/io.h>#include <linux/ioport.h>#include "pcbit.h"#include "edss1.h"#include "layer2.h"#include "capi.h"extern ushort last_ref_num;static int pcbit_ioctl(isdn_ctrl* ctl);static char* pcbit_devname[MAX_PCBIT_CARDS] = {	"pcbit0",	"pcbit1",	"pcbit2",	"pcbit3"};/* * prototypes */static int pcbit_command(isdn_ctrl* ctl);static int pcbit_stat(u_char __user * buf, int len, int, int);static int pcbit_xmit(int driver, int chan, int ack, struct sk_buff *skb);static int pcbit_writecmd(const u_char __user *, int, int, int);static int set_protocol_running(struct pcbit_dev * dev);static void pcbit_clear_msn(struct pcbit_dev *dev);static void pcbit_set_msn(struct pcbit_dev *dev, char *list);static int pcbit_check_msn(struct pcbit_dev *dev, char *msn);extern void pcbit_deliver(void * data);int pcbit_init_dev(int board, int mem_base, int irq){	struct pcbit_dev *dev;	isdn_if *dev_if;	if ((dev=kmalloc(sizeof(struct pcbit_dev), GFP_KERNEL)) == NULL)	{		printk("pcbit_init: couldn't malloc pcbit_dev struct\n");		return -ENOMEM;	}	dev_pcbit[board] = dev;	memset(dev, 0, sizeof(struct pcbit_dev));	init_waitqueue_head(&dev->set_running_wq);	spin_lock_init(&dev->lock);	if (mem_base >= 0xA0000 && mem_base <= 0xFFFFF ) {		dev->ph_mem = mem_base;		if (!request_mem_region(dev->ph_mem, 4096, "PCBIT mem")) {			printk(KERN_WARNING				"PCBIT: memory region %lx-%lx already in use\n",				dev->ph_mem, dev->ph_mem + 4096);			kfree(dev);			dev_pcbit[board] = NULL;			return -EACCES;		}		dev->sh_mem = ioremap(dev->ph_mem, 4096);	}	else 	{		printk("memory address invalid");		kfree(dev);		dev_pcbit[board] = NULL;		return -EACCES;	}	dev->b1 = kmalloc(sizeof(struct pcbit_chan), GFP_KERNEL);	if (!dev->b1) {		printk("pcbit_init: couldn't malloc pcbit_chan struct\n");		iounmap(dev->sh_mem);		release_mem_region(dev->ph_mem, 4096);		kfree(dev);		return -ENOMEM;	}    	dev->b2 = kmalloc(sizeof(struct pcbit_chan), GFP_KERNEL);	if (!dev->b2) {		printk("pcbit_init: couldn't malloc pcbit_chan struct\n");		kfree(dev->b1);		iounmap(dev->sh_mem);		release_mem_region(dev->ph_mem, 4096);		kfree(dev);		return -ENOMEM;	}	memset(dev->b1, 0, sizeof(struct pcbit_chan));	memset(dev->b2, 0, sizeof(struct pcbit_chan));	dev->b2->id = 1;	INIT_WORK(&dev->qdelivery, pcbit_deliver, dev);	/*	 *  interrupts	 */	if (request_irq(irq, &pcbit_irq_handler, 0, pcbit_devname[board], dev) != 0) 	{		kfree(dev->b1);		kfree(dev->b2);		iounmap(dev->sh_mem);		release_mem_region(dev->ph_mem, 4096);		kfree(dev);		dev_pcbit[board] = NULL;		return -EIO;	}	dev->irq = irq;	/* next frame to be received */	dev->rcv_seq = 0;	dev->send_seq = 0;	dev->unack_seq = 0;	dev->hl_hdrlen = 16;	dev_if = kmalloc(sizeof(isdn_if), GFP_KERNEL);	if (!dev_if) {		free_irq(irq, dev);		kfree(dev->b1);		kfree(dev->b2);		iounmap(dev->sh_mem);		release_mem_region(dev->ph_mem, 4096);		kfree(dev);		dev_pcbit[board] = NULL;		return -EIO;	}	dev->dev_if = dev_if;	dev_if->owner = THIS_MODULE;	dev_if->channels = 2;		dev_if->features = (ISDN_FEATURE_P_EURO  | ISDN_FEATURE_L3_TRANS | 			    ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L2_TRANS );	dev_if->writebuf_skb = pcbit_xmit;	dev_if->hl_hdrlen = 16;	dev_if->maxbufsize = MAXBUFSIZE;	dev_if->command  = pcbit_command;		dev_if->writecmd = pcbit_writecmd;	dev_if->readstat = pcbit_stat;	strcpy(dev_if->id, pcbit_devname[board]);	if (!register_isdn(dev_if)) {		free_irq(irq, dev);		kfree(dev->b1);		kfree(dev->b2);		iounmap(dev->sh_mem);		release_mem_region(dev->ph_mem, 4096);		kfree(dev);		dev_pcbit[board] = NULL;		return -EIO;	}	dev->id = dev_if->channels;	dev->l2_state = L2_DOWN;	dev->free = 511;	/*	 * set_protocol_running(dev);	 */	return 0;}#ifdef MODULEvoid pcbit_terminate(int board){	struct pcbit_dev * dev;	dev = dev_pcbit[board];	if (dev) {	     /* unregister_isdn(dev->dev_if); */		free_irq(dev->irq, dev);		pcbit_clear_msn(dev);		kfree(dev->dev_if);		if (dev->b1->fsm_timer.function)			del_timer(&dev->b1->fsm_timer);		if (dev->b2->fsm_timer.function)			del_timer(&dev->b2->fsm_timer);		kfree(dev->b1);		kfree(dev->b2);		iounmap(dev->sh_mem);		release_mem_region(dev->ph_mem, 4096);		kfree(dev);	}}#endifstatic int pcbit_command(isdn_ctrl* ctl){	struct pcbit_dev  *dev;	struct pcbit_chan *chan;	struct callb_data info;	dev = finddev(ctl->driver);	if (!dev)	{		printk("pcbit_command: unknown device\n");		return -1;	}	chan = (ctl->arg & 0x0F) ? dev->b2 : dev->b1;	switch(ctl->command) {	case ISDN_CMD_IOCTL:		return pcbit_ioctl(ctl);		break;	case ISDN_CMD_DIAL:		info.type = EV_USR_SETUP_REQ;		info.data.setup.CalledPN = (char *) &ctl->parm.setup.phone;		pcbit_fsm_event(dev, chan, EV_USR_SETUP_REQ, &info);		break;	case ISDN_CMD_ACCEPTD:		pcbit_fsm_event(dev, chan, EV_USR_SETUP_RESP, NULL);		break;	case ISDN_CMD_ACCEPTB:		printk("ISDN_CMD_ACCEPTB - not really needed\n");		break;	case ISDN_CMD_HANGUP:		pcbit_fsm_event(dev, chan, EV_USR_RELEASE_REQ, NULL);		break;	case ISDN_CMD_SETL2:		chan->proto = (ctl->arg >> 8);		break;	case ISDN_CMD_CLREAZ:		pcbit_clear_msn(dev);		break;	case ISDN_CMD_SETEAZ:		pcbit_set_msn(dev, ctl->parm.num);		break;	case ISDN_CMD_SETL3:		if ((ctl->arg >> 8) != ISDN_PROTO_L3_TRANS)			printk(KERN_DEBUG "L3 protocol unknown\n");		break;	default:		printk(KERN_DEBUG "pcbit_command: unknown command\n");		break;	};	return 0;}/* * Another Hack :-( * on some conditions the board stops sending TDATA_CONFs * let's see if we can turn around the problem */#ifdef BLOCK_TIMERstatic void pcbit_block_timer(unsigned long data){	struct pcbit_chan *chan;	struct pcbit_dev * dev;	isdn_ctrl ictl;	chan = (struct pcbit_chan *) data;	dev = chan2dev(chan);	if (dev == NULL) {		printk(KERN_DEBUG "pcbit: chan2dev failed\n");		return;	}	del_timer(&chan->block_timer);	chan->block_timer.function = NULL;#ifdef DEBUG	printk(KERN_DEBUG "pcbit_block_timer\n");#endif		chan->queued = 0;	ictl.driver = dev->id;	ictl.command = ISDN_STAT_BSENT;	ictl.arg = chan->id;	dev->dev_if->statcallb(&ictl);     }#endifstatic int pcbit_xmit(int driver, int chnum, int ack, struct sk_buff *skb){	ushort hdrlen;	int refnum, len;	struct pcbit_chan * chan;	struct pcbit_dev *dev;	dev = finddev(driver);	if (dev == NULL)	{		printk("finddev returned NULL");		return -1;	}	chan = chnum ? dev->b2 : dev->b1;	if (chan->fsm_state != ST_ACTIVE)		return -1;	if (chan->queued >= MAX_QUEUED )	{#ifdef DEBUG_QUEUE		printk(KERN_DEBUG 		       "pcbit: %d packets already in queue - write fails\n",		       chan->queued);#endif		/*		 * packet stays on the head of the device queue		 * since dev_start_xmit will fail		 * see net/core/dev.c		 */#ifdef BLOCK_TIMER		if (chan->block_timer.function == NULL) {			init_timer(&chan->block_timer);			chan->block_timer.function =  &pcbit_block_timer;			chan->block_timer.data = (long) chan;			chan->block_timer.expires = jiffies + 1 * HZ;			add_timer(&chan->block_timer);		}#endif				return 0;	                 	}	chan->queued++;	        len = skb->len;	hdrlen = capi_tdata_req(chan, skb);	refnum = last_ref_num++ & 0x7fffU;	chan->s_refnum = refnum;	pcbit_l2_write(dev, MSG_TDATA_REQ, refnum, skb, hdrlen);	return len;}static int pcbit_writecmd(const u_char __user *buf, int len, int driver, int channel){	struct pcbit_dev * dev;	int i, j;	const u_char * loadbuf;	u_char * ptr = NULL;	u_char *cbuf;	int errstat;	dev = finddev(driver);	if (!dev)	{		printk("pcbit_writecmd: couldn't find device");		return -ENODEV;	}	switch(dev->l2_state) {	case L2_LWMODE:		/* check (size <= rdp_size); write buf into board */		if (len < 0 || len > BANK4 + 1 || len > 1024)		{			printk("pcbit_writecmd: invalid length %d\n", len);			return -EINVAL;		}		cbuf = kmalloc(len, GFP_KERNEL);		if (!cbuf)			return -ENOMEM;		if (copy_from_user(cbuf, buf, len)) {			kfree(cbuf);			return -EFAULT;		}		memcpy_toio(dev->sh_mem, cbuf, len);		kfree(cbuf);		return len;	case L2_FWMODE:		/* this is the hard part */		/* dumb board */		/* get it into kernel space */		if ((ptr = kmalloc(len, GFP_KERNEL))==NULL)			return -ENOMEM;		if (copy_from_user(ptr, buf, len)) {			kfree(ptr);			return -EFAULT;		}		loadbuf = ptr;    		errstat = 0;		for (i=0; i < len; i++)		{			for(j=0; j < LOAD_RETRY; j++)				if (!(readb(dev->sh_mem + dev->loadptr)))					break;			if (j == LOAD_RETRY)			{				errstat = -ETIME;				printk("TIMEOUT i=%d\n", i);				break;			}			writeb(loadbuf[i], dev->sh_mem + dev->loadptr + 1);			writeb(0x01, dev->sh_mem + dev->loadptr);			dev->loadptr += 2;			if (dev->loadptr > LOAD_ZONE_END)				dev->loadptr = LOAD_ZONE_START;		}		kfree(ptr);		return errstat ? errstat : len;	default:		return -EBUSY;	}}/* *  demultiplexing of messages * */void pcbit_l3_receive(struct pcbit_dev * dev, ulong msg, 			     struct sk_buff * skb,			     ushort hdr_len, ushort refnum){	struct pcbit_chan *chan;	struct sk_buff *skb2;	unsigned short len;	struct callb_data cbdata;	int complete, err;	isdn_ctrl ictl;	switch(msg) {	case MSG_TDATA_IND:		if (!(chan = capi_channel(dev, skb))) {			printk(KERN_WARNING 			       "CAPI header: unknown channel id\n");			break;		}		chan->r_refnum = skb->data[7];		skb_pull(skb, 8);		dev->dev_if->rcvcallb_skb(dev->id, chan->id, skb);		if (capi_tdata_resp(chan, &skb2) > 0) 			pcbit_l2_write(dev, MSG_TDATA_RESP, refnum, 				       skb2, skb2->len);		return;		break;  	case MSG_TDATA_CONF:		if (!(chan = capi_channel(dev, skb))) {			printk(KERN_WARNING 			       "CAPI header: unknown channel id\n");			break;		}#ifdef DEBUG		if ( (*((ushort *) (skb->data + 2) )) != 0) {                        printk(KERN_DEBUG "TDATA_CONF error\n");		}#endif#ifdef BLOCK_TIMER                if (chan->queued == MAX_QUEUED) {                        del_timer(&chan->block_timer);			chan->block_timer.function = NULL;		}                #endif				chan->queued--;		ictl.driver = dev->id;		ictl.command = ISDN_STAT_BSENT;		ictl.arg = chan->id;		dev->dev_if->statcallb(&ictl);		break;	case MSG_CONN_IND:		/*		 *  channel: 1st not used will do		 *           if both are used we're in trouble 		 */		if (!dev->b1->fsm_state)			chan = dev->b1;		else if (!dev->b2->fsm_state)			chan = dev->b2;		else {			printk(KERN_INFO 			       "Incoming connection: no channels available");

⌨️ 快捷键说明

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