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

📄 module.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: module.c,v 1.14.6.4 2001/09/23 22:24:32 kai Exp $ * * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000. * * Author       Fritz Elfert * Copyright    by Fritz Elfert      <fritz@isdn4linux.de> *  * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * * Thanks to Friedemann Baitinger and IBM Germany * */#include "act2000.h"#include "act2000_isa.h"#include "capi.h"#include <linux/module.h>#include <linux/init.h>static unsigned short act2000_isa_ports[] ={        0x0200, 0x0240, 0x0280, 0x02c0, 0x0300, 0x0340, 0x0380,        0xcfe0, 0xcfa0, 0xcf60, 0xcf20, 0xcee0, 0xcea0, 0xce60,};#define ISA_NRPORTS (sizeof(act2000_isa_ports)/sizeof(unsigned short))static act2000_card *cards = (act2000_card *) NULL;/* Parameters to be set by insmod */static int   act_bus  =  0;static int   act_port = -1;  /* -1 = Autoprobe  */static int   act_irq  = -1;static char *act_id   = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";MODULE_DESCRIPTION(       "ISDN4Linux: Driver for IBM Active 2000 ISDN card");MODULE_AUTHOR(            "Fritz Elfert");MODULE_LICENSE(           "GPL");MODULE_PARM_DESC(act_bus, "BusType of first card, 1=ISA, 2=MCA, 3=PCMCIA, currently only ISA");MODULE_PARM_DESC(membase, "Base port address of first card");MODULE_PARM_DESC(act_irq, "IRQ of first card");MODULE_PARM_DESC(act_id,  "ID-String of first card");module_param(act_bus,  int, 0);module_param(act_port, int, 0);module_param(act_irq, int, 0);module_param(act_id, charp, 0);static int act2000_addcard(int, int, int, char *);static act2000_chan *find_channel(act2000_card *card, int channel){	if ((channel >= 0) && (channel < ACT2000_BCH))        	return &(card->bch[channel]);	printk(KERN_WARNING "act2000: Invalid channel %d\n", channel);	return NULL;}/* * Free MSN list */static voidact2000_clear_msn(act2000_card *card){	struct msn_entry *p = card->msn_list;	struct msn_entry *q;	unsigned long flags;	spin_lock_irqsave(&card->lock, flags);	card->msn_list = NULL;	spin_unlock_irqrestore(&card->lock, flags);	while (p) {		q  = p->next;		kfree(p);		p = q;	}}/* * Find an MSN entry in the list. * If ia5 != 0, return IA5-encoded EAZ, else * return a bitmask with corresponding bit set. */static __u16act2000_find_msn(act2000_card *card, char *msn, int ia5){        struct msn_entry *p = card->msn_list;	__u8 eaz = '0';	while (p) {		if (!strcmp(p->msn, msn)) {			eaz = p->eaz;			break;		}		p = p->next;	}	if (!ia5)		return (1 << (eaz - '0'));	else		return eaz;}/* * Find an EAZ entry in the list. * return a string with corresponding msn. */char *act2000_find_eaz(act2000_card *card, char eaz){        struct msn_entry *p = card->msn_list;	while (p) {		if (p->eaz == eaz)			return(p->msn);		p = p->next;	}	return("\0");}/* * Add or delete an MSN to the MSN list * * First character of msneaz is EAZ, rest is MSN. * If length of eazmsn is 1, delete that entry. */static intact2000_set_msn(act2000_card *card, char *eazmsn){        struct msn_entry *p = card->msn_list;        struct msn_entry *q = NULL;	unsigned long flags;	int i;		if (!strlen(eazmsn))		return 0;	if (strlen(eazmsn) > 16)		return -EINVAL;	for (i = 0; i < strlen(eazmsn); i++)		if (!isdigit(eazmsn[i]))			return -EINVAL;        if (strlen(eazmsn) == 1) {		/* Delete a single MSN */		while (p) {			if (p->eaz == eazmsn[0]) {				spin_lock_irqsave(&card->lock, flags);				if (q)					q->next = p->next;				else					card->msn_list = p->next;				spin_unlock_irqrestore(&card->lock, flags);				kfree(p);				printk(KERN_DEBUG				       "Mapping for EAZ %c deleted\n",				       eazmsn[0]);				return 0;			}			q = p;			p = p->next;		}		return 0;        }	/* Add a single MSN */	while (p) {		/* Found in list, replace MSN */		if (p->eaz == eazmsn[0]) {			spin_lock_irqsave(&card->lock, flags);			strcpy(p->msn, &eazmsn[1]);			spin_unlock_irqrestore(&card->lock, flags);			printk(KERN_DEBUG			       "Mapping for EAZ %c changed to %s\n",			       eazmsn[0],			       &eazmsn[1]);			return 0;		}		p = p->next;	}	/* Not found in list, add new entry */	p = kmalloc(sizeof(msn_entry), GFP_KERNEL);	if (!p)		return -ENOMEM;	p->eaz = eazmsn[0];	strcpy(p->msn, &eazmsn[1]);	p->next = card->msn_list;	spin_lock_irqsave(&card->lock, flags);	card->msn_list = p;	spin_unlock_irqrestore(&card->lock, flags);	printk(KERN_DEBUG	       "Mapping %c -> %s added\n",	       eazmsn[0],	       &eazmsn[1]);	return 0;}static voidact2000_transmit(struct act2000_card *card){	switch (card->bus) {		case ACT2000_BUS_ISA:			act2000_isa_send(card);			break;		case ACT2000_BUS_PCMCIA:		case ACT2000_BUS_MCA:		default:			printk(KERN_WARNING			       "act2000_transmit: Illegal bustype %d\n", card->bus);	}}static voidact2000_receive(struct act2000_card *card){	switch (card->bus) {		case ACT2000_BUS_ISA:			act2000_isa_receive(card);			break;		case ACT2000_BUS_PCMCIA:		case ACT2000_BUS_MCA:		default:			printk(KERN_WARNING			       "act2000_receive: Illegal bustype %d\n", card->bus);	}}static voidact2000_poll(unsigned long data){	act2000_card * card = (act2000_card *)data;	unsigned long flags;	act2000_receive(card);	spin_lock_irqsave(&card->lock, flags);	mod_timer(&card->ptimer, jiffies+3);	spin_unlock_irqrestore(&card->lock, flags);}static intact2000_command(act2000_card * card, isdn_ctrl * c){        ulong a;        act2000_chan *chan;	act2000_cdef cdef;	isdn_ctrl cmd;	char tmp[17];	int ret;	unsigned long flags;	void __user *arg;         switch (c->command) {		case ISDN_CMD_IOCTL:			memcpy(&a, c->parm.num, sizeof(ulong));			arg = (void __user *)a;			switch (c->arg) {				case ACT2000_IOCTL_LOADBOOT:					switch (card->bus) {						case ACT2000_BUS_ISA:							ret = act2000_isa_download(card,									   arg);							if (!ret) {								card->flags |= ACT2000_FLAGS_LOADED;								if (!(card->flags & ACT2000_FLAGS_IVALID)) {									card->ptimer.expires = jiffies + 3;									card->ptimer.function = act2000_poll;									card->ptimer.data = (unsigned long)card;									add_timer(&card->ptimer);								}								actcapi_manufacturer_req_errh(card);							}							break;						default:							printk(KERN_WARNING							       "act2000: Illegal BUS type %d\n",							       card->bus);							ret = -EIO;					}					return ret;				case ACT2000_IOCTL_SETPROTO:					card->ptype = a?ISDN_PTYPE_EURO:ISDN_PTYPE_1TR6;					if (!(card->flags & ACT2000_FLAGS_RUNNING))						return 0;					actcapi_manufacturer_req_net(card);					return 0;				case ACT2000_IOCTL_SETMSN:					if (copy_from_user(tmp, arg,							   sizeof(tmp)))						return -EFAULT;					if ((ret = act2000_set_msn(card, tmp)))						return ret;					if (card->flags & ACT2000_FLAGS_RUNNING)						return(actcapi_manufacturer_req_msn(card));					return 0;				case ACT2000_IOCTL_ADDCARD:					if (copy_from_user(&cdef, arg,							   sizeof(cdef)))						return -EFAULT;					if (act2000_addcard(cdef.bus, cdef.port, cdef.irq, cdef.id))						return -EIO;					return 0;				case ACT2000_IOCTL_TEST:					if (!(card->flags & ACT2000_FLAGS_RUNNING))						return -ENODEV;					return 0;				default:					return -EINVAL;			}			break;		case ISDN_CMD_DIAL:			if (!card->flags & ACT2000_FLAGS_RUNNING)				return -ENODEV;			if (!(chan = find_channel(card, c->arg & 0x0f)))				break;			spin_lock_irqsave(&card->lock, flags);			if (chan->fsm_state != ACT2000_STATE_NULL) {				spin_unlock_irqrestore(&card->lock, flags);				printk(KERN_WARNING "Dial on channel with state %d\n",					chan->fsm_state);				return -EBUSY;			}			if (card->ptype == ISDN_PTYPE_EURO)				tmp[0] = act2000_find_msn(card, c->parm.setup.eazmsn, 1);			else				tmp[0] = c->parm.setup.eazmsn[0];			chan->fsm_state = ACT2000_STATE_OCALL;			chan->callref = 0xffff;			spin_unlock_irqrestore(&card->lock, flags);			ret = actcapi_connect_req(card, chan, c->parm.setup.phone,						  tmp[0], c->parm.setup.si1,						  c->parm.setup.si2);			if (ret) {				cmd.driver = card->myid;				cmd.command = ISDN_STAT_DHUP;				cmd.arg &= 0x0f;				card->interface.statcallb(&cmd);			}			return ret;		case ISDN_CMD_ACCEPTD:			if (!card->flags & ACT2000_FLAGS_RUNNING)				return -ENODEV;			if (!(chan = find_channel(card, c->arg & 0x0f)))				break;			if (chan->fsm_state == ACT2000_STATE_ICALL)				actcapi_select_b2_protocol_req(card, chan);			return 0;		case ISDN_CMD_ACCEPTB:			if (!card->flags & ACT2000_FLAGS_RUNNING)				return -ENODEV;			return 0;		case ISDN_CMD_HANGUP:			if (!card->flags & ACT2000_FLAGS_RUNNING)				return -ENODEV;			if (!(chan = find_channel(card, c->arg & 0x0f)))				break;			switch (chan->fsm_state) {				case ACT2000_STATE_ICALL:				case ACT2000_STATE_BSETUP:					actcapi_connect_resp(card, chan, 0x15);					break;				case ACT2000_STATE_ACTIVE:					actcapi_disconnect_b3_req(card, chan);					break;			}			return 0;		case ISDN_CMD_SETEAZ:			if (!card->flags & ACT2000_FLAGS_RUNNING)				return -ENODEV;			if (!(chan = find_channel(card, c->arg & 0x0f)))				break;			if (strlen(c->parm.num)) {				if (card->ptype == ISDN_PTYPE_EURO) {					chan->eazmask = act2000_find_msn(card, c->parm.num, 0);				}				if (card->ptype == ISDN_PTYPE_1TR6) {					int i;					chan->eazmask = 0;					for (i = 0; i < strlen(c->parm.num); i++)						if (isdigit(c->parm.num[i]))							chan->eazmask |= (1 << (c->parm.num[i] - '0'));				}			} else				chan->eazmask = 0x3ff;			actcapi_listen_req(card);			return 0;		case ISDN_CMD_CLREAZ:			if (!card->flags & ACT2000_FLAGS_RUNNING)				return -ENODEV;			if (!(chan = find_channel(card, c->arg & 0x0f)))				break;			chan->eazmask = 0;			actcapi_listen_req(card);			return 0;		case ISDN_CMD_SETL2:			if (!card->flags & ACT2000_FLAGS_RUNNING)				return -ENODEV;			if (!(chan = find_channel(card, c->arg & 0x0f)))				break;			chan->l2prot = (c->arg >> 8);			return 0;		case ISDN_CMD_SETL3:			if (!card->flags & ACT2000_FLAGS_RUNNING)				return -ENODEV;			if ((c->arg >> 8) != ISDN_PROTO_L3_TRANS) {				printk(KERN_WARNING "L3 protocol unknown\n");				return -1;			}			if (!(chan = find_channel(card, c->arg & 0x0f)))				break;

⌨️ 快捷键说明

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