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

📄 icn.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		card = card->next;	}	restore_flags(flags);}static inticn_command(isdn_ctrl * c, icn_card * card){	ulong a;	ulong flags;	int i;	char cbuf[60];	isdn_ctrl cmd;	icn_cdef cdef;	switch (c->command) {		case ISDN_CMD_IOCTL:			memcpy(&a, c->parm.num, sizeof(ulong));			switch (c->arg) {				case ICN_IOCTL_SETMMIO:					if ((unsigned long) dev.shmem != (a & 0x0ffc000)) {						if (check_shmem((ulong) (a & 0x0ffc000), 0x4000)) {							printk(KERN_WARNING							       "icn: memory at 0x%08lx in use.\n",							       (ulong) (a & 0x0ffc000));							return -EINVAL;						}						icn_stopallcards();						save_flags(flags);						cli();						if (dev.mvalid)							release_shmem((ulong) dev.shmem, 0x4000);						dev.mvalid = 0;						dev.shmem = (icn_shmem *) (a & 0x0ffc000);						restore_flags(flags);						printk(KERN_INFO						       "icn: (%s) mmio set to 0x%08lx\n",						       CID,						       (unsigned long) dev.shmem);					}					break;				case ICN_IOCTL_GETMMIO:					return (long) dev.shmem;				case ICN_IOCTL_SETPORT:					if (a == 0x300 || a == 0x310 || a == 0x320 || a == 0x330					    || a == 0x340 || a == 0x350 || a == 0x360 ||					    a == 0x308 || a == 0x318 || a == 0x328 || a == 0x338					    || a == 0x348 || a == 0x358 || a == 0x368) {						if (card->port != (unsigned short) a) {							if (check_region((unsigned short) a, ICN_PORTLEN)) {								printk(KERN_WARNING								       "icn: (%s) ports 0x%03x-0x%03x in use.\n",								       CID, (int) a, (int) a + ICN_PORTLEN);								return -EINVAL;							}							icn_stopcard(card);							save_flags(flags);							cli();							if (card->rvalid)								release_region(card->port, ICN_PORTLEN);							card->port = (unsigned short) a;							card->rvalid = 0;							if (card->doubleS0) {								card->other->port = (unsigned short) a;								card->other->rvalid = 0;							}							restore_flags(flags);							printk(KERN_INFO							       "icn: (%s) port set to 0x%03x\n",							CID, card->port);						}					} else						return -EINVAL;					break;				case ICN_IOCTL_GETPORT:					return (int) card->port;				case ICN_IOCTL_GETDOUBLE:					return (int) card->doubleS0;				case ICN_IOCTL_DEBUGVAR:					if ((i = copy_to_user((char *) a,					  (char *) &card, sizeof(ulong))))						return i;					a += sizeof(ulong);					{						ulong l = (ulong) & dev;						if ((i = copy_to_user((char *) a,							     (char *) &l, sizeof(ulong))))							return i;					}					return 0;				case ICN_IOCTL_LOADBOOT:					if (dev.firstload) {						icn_disable_cards();						dev.firstload = 0;					}					icn_stopcard(card);					return (icn_loadboot((u_char *) a, card));				case ICN_IOCTL_LOADPROTO:					icn_stopcard(card);					if ((i = (icn_loadproto((u_char *) a, card))))						return i;					if (card->doubleS0)						i = icn_loadproto((u_char *) (a + ICN_CODE_STAGE2), card->other);					return i;					break;				case ICN_IOCTL_ADDCARD:					if (!dev.firstload)						return -EBUSY;					if ((i = copy_from_user((char *) &cdef, (char *) a, sizeof(cdef))))						return i;					return (icn_addcard(cdef.port, cdef.id1, cdef.id2));					break;				case ICN_IOCTL_LEASEDCFG:					if (a) {						if (!card->leased) {							card->leased = 1;							while (card->ptype == ISDN_PTYPE_UNKNOWN) {								schedule_timeout(ICN_BOOT_TIMEOUT1);							}							schedule_timeout(ICN_BOOT_TIMEOUT1);							sprintf(cbuf, "00;FV2ON\n01;EAZ%c\n02;EAZ%c\n",								(a & 1)?'1':'C', (a & 2)?'2':'C');							i = icn_writecmd(cbuf, strlen(cbuf), 0, card);							printk(KERN_INFO							       "icn: (%s) Leased-line mode enabled\n",							       CID);							cmd.command = ISDN_STAT_RUN;							cmd.driver = card->myid;							cmd.arg = 0;							card->interface.statcallb(&cmd);						}					} else {						if (card->leased) {							card->leased = 0;							sprintf(cbuf, "00;FV2OFF\n");							i = icn_writecmd(cbuf, strlen(cbuf), 0, card);							printk(KERN_INFO							       "icn: (%s) Leased-line mode disabled\n",							       CID);							cmd.command = ISDN_STAT_RUN;							cmd.driver = card->myid;							cmd.arg = 0;							card->interface.statcallb(&cmd);						}					}					return 0;				default:					return -EINVAL;			}			break;		case ISDN_CMD_DIAL:			if (!card->flags & ICN_FLAGS_RUNNING)				return -ENODEV;			if (card->leased)				break;			if ((c->arg & 255) < ICN_BCH) {				char *p;				char dial[50];				char dcode[4];				a = c->arg;				p = c->parm.setup.phone;				if (*p == 's' || *p == 'S') {					/* Dial for SPV */					p++;					strcpy(dcode, "SCA");				} else					/* Normal Dial */					strcpy(dcode, "CAL");				strcpy(dial, p);				sprintf(cbuf, "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1),					dcode, dial, c->parm.setup.si1,				c->parm.setup.si2, c->parm.setup.eazmsn);				i = icn_writecmd(cbuf, strlen(cbuf), 0, card);			}			break;		case ISDN_CMD_ACCEPTD:			if (!card->flags & ICN_FLAGS_RUNNING)				return -ENODEV;			if (c->arg < ICN_BCH) {				a = c->arg + 1;				if (card->fw_rev >= 300) {					switch (card->l2_proto[a - 1]) {						case ISDN_PROTO_L2_X75I:							sprintf(cbuf, "%02d;BX75\n", (int) a);							break;						case ISDN_PROTO_L2_HDLC:							sprintf(cbuf, "%02d;BTRA\n", (int) a);							break;					}					i = icn_writecmd(cbuf, strlen(cbuf), 0, card);				}				sprintf(cbuf, "%02d;DCON_R\n", (int) a);				i = icn_writecmd(cbuf, strlen(cbuf), 0, card);			}			break;		case ISDN_CMD_ACCEPTB:			if (!card->flags & ICN_FLAGS_RUNNING)				return -ENODEV;			if (c->arg < ICN_BCH) {				a = c->arg + 1;				if (card->fw_rev >= 300)					switch (card->l2_proto[a - 1]) {						case ISDN_PROTO_L2_X75I:							sprintf(cbuf, "%02d;BCON_R,BX75\n", (int) a);							break;						case ISDN_PROTO_L2_HDLC:							sprintf(cbuf, "%02d;BCON_R,BTRA\n", (int) a);							break;				} else					sprintf(cbuf, "%02d;BCON_R\n", (int) a);				i = icn_writecmd(cbuf, strlen(cbuf), 0, card);			}			break;		case ISDN_CMD_HANGUP:			if (!card->flags & ICN_FLAGS_RUNNING)				return -ENODEV;			if (c->arg < ICN_BCH) {				a = c->arg + 1;				sprintf(cbuf, "%02d;BDIS_R\n%02d;DDIS_R\n", (int) a, (int) a);				i = icn_writecmd(cbuf, strlen(cbuf), 0, card);			}			break;		case ISDN_CMD_SETEAZ:			if (!card->flags & ICN_FLAGS_RUNNING)				return -ENODEV;			if (card->leased)				break;			if (c->arg < ICN_BCH) {				a = c->arg + 1;				if (card->ptype == ISDN_PTYPE_EURO) {					sprintf(cbuf, "%02d;MS%s%s\n", (int) a,						c->parm.num[0] ? "N" : "ALL", c->parm.num);				} else					sprintf(cbuf, "%02d;EAZ%s\n", (int) a,						c->parm.num[0] ? (char *)(c->parm.num) : "0123456789");				i = icn_writecmd(cbuf, strlen(cbuf), 0, card);			}			break;		case ISDN_CMD_CLREAZ:			if (!card->flags & ICN_FLAGS_RUNNING)				return -ENODEV;			if (card->leased)				break;			if (c->arg < ICN_BCH) {				a = c->arg + 1;				if (card->ptype == ISDN_PTYPE_EURO)					sprintf(cbuf, "%02d;MSNC\n", (int) a);				else					sprintf(cbuf, "%02d;EAZC\n", (int) a);				i = icn_writecmd(cbuf, strlen(cbuf), 0, card);			}			break;		case ISDN_CMD_SETL2:			if (!card->flags & ICN_FLAGS_RUNNING)				return -ENODEV;			if ((c->arg & 255) < ICN_BCH) {				a = c->arg;				switch (a >> 8) {					case ISDN_PROTO_L2_X75I:						sprintf(cbuf, "%02d;BX75\n", (int) (a & 255) + 1);						break;					case ISDN_PROTO_L2_HDLC:						sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1);						break;					default:						return -EINVAL;				}				i = icn_writecmd(cbuf, strlen(cbuf), 0, card);				card->l2_proto[a & 255] = (a >> 8);			}			break;		case ISDN_CMD_GETL2:			if (!card->flags & ICN_FLAGS_RUNNING)				return -ENODEV;			if ((c->arg & 255) < ICN_BCH)				return card->l2_proto[c->arg & 255];			else				return -ENODEV;		case ISDN_CMD_SETL3:			if (!card->flags & ICN_FLAGS_RUNNING)				return -ENODEV;			return 0;		case ISDN_CMD_GETL3:			if (!card->flags & ICN_FLAGS_RUNNING)				return -ENODEV;			if ((c->arg & 255) < ICN_BCH)				return ISDN_PROTO_L3_TRANS;			else				return -ENODEV;		case ISDN_CMD_GETEAZ:			if (!card->flags & ICN_FLAGS_RUNNING)				return -ENODEV;			break;		case ISDN_CMD_SETSIL:			if (!card->flags & ICN_FLAGS_RUNNING)				return -ENODEV;			break;		case ISDN_CMD_GETSIL:			if (!card->flags & ICN_FLAGS_RUNNING)				return -ENODEV;			break;		case ISDN_CMD_LOCK:			MOD_INC_USE_COUNT;			break;		case ISDN_CMD_UNLOCK:			MOD_DEC_USE_COUNT;			break;		default:			return -EINVAL;	}	return 0;}/* * Find card with given driverId */static inline icn_card *icn_findcard(int driverid){	icn_card *p = cards;	while (p) {		if (p->myid == driverid)			return p;		p = p->next;	}	return (icn_card *) 0;}/* * Wrapper functions for interface to linklevel */static intif_command(isdn_ctrl * c){	icn_card *card = icn_findcard(c->driver);	if (card)		return (icn_command(c, card));	printk(KERN_ERR	       "icn: if_command %d called with invalid driverId %d!\n",	       c->command, c->driver);	return -ENODEV;}static intif_writecmd(const u_char * buf, int len, int user, int id, int channel){	icn_card *card = icn_findcard(id);	if (card) {		if (!card->flags & ICN_FLAGS_RUNNING)			return -ENODEV;		return (icn_writecmd(buf, len, user, card));	}	printk(KERN_ERR	       "icn: if_writecmd called with invalid driverId!\n");	return -ENODEV;}static intif_readstatus(u_char * buf, int len, int user, int id, int channel){	icn_card *card = icn_findcard(id);	if (card) {		if (!card->flags & ICN_FLAGS_RUNNING)			return -ENODEV;		return (icn_readstatus(buf, len, user, card));	}	printk(KERN_ERR	       "icn: if_readstatus called with invalid driverId!\n");	return -ENODEV;}static intif_sendbuf(int id, int channel, int ack, struct sk_buff *skb){	icn_card *card = icn_findcard(id);	if (card) {		if (!card->flags & ICN_FLAGS_RUNNING)			return -ENODEV;		return (icn_sendbuf(channel, ack, skb, card));	}	printk(KERN_ERR	       "icn: if_sendbuf called with invalid driverId!\n");	return -ENODEV;}/* * Allocate a new card-struct, initialize it * link it into cards-list and register it at linklevel. */static icn_card *icn_initcard(int port, char *id){	icn_card *card;	int i;	if (!(card = (icn_card *) kmalloc(sizeof(icn_card), GFP_KERNEL))) {		printk(KERN_WARNING		       "icn: (%s) Could not allocate card-struct.\n", id);		return (icn_card *) 0;	}	memset((char *) card, 0, sizeof(icn_card));	card->port = port;	card->interface.hl_hdrlen = 1;	card->interface.channels = ICN_BCH;	card->interface.maxbufsize = 4000;	card->interface.command = if_command;	card->interface.writebuf_skb = if_sendbuf;	card->interface.writecmd = if_writecmd;	card->interface.readstat = if_readstatus;	card->interface.features = ISDN_FEATURE_L2_X75I |	    ISDN_FEATURE_L2_HDLC |	    ISDN_FEATURE_L3_TRANS |	    ISDN_FEATURE_P_UNKNOWN;	card->ptype = ISDN_PTYPE_UNKNOWN;	strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);	card->msg_buf_write = card->msg_buf;	card->msg_buf_read = card->msg_buf;	card->msg_buf_end = &card->msg_buf[sizeof(card->msg_buf) - 1];	for (i = 0; i < ICN_BCH; i++) {		card->l2_proto[i] = ISDN_PROTO_L2_X75I;		skb_queue_head_init(&card->spqueue[i]);	}	card->next = cards;	cards = card;	if (!register_isdn(&card->interface)) {		cards = cards->next;		printk(KERN_WARNING		       "icn: Unable to register %s\n", id);		kfree(card);		return (icn_card *) 0;	}	card->myid = card->interface.channels;	sprintf(card->regname, "icn-isdn (%s)", card->interface.id);	return card;}static inticn_addcard(int port, char *id1, char *id2){	ulong flags;	icn_card *card;	icn_card *card2;	save_flags(flags);	cli();	if (!(card = icn_initcard(port, id1))) {		restore_flags(flags);		return -EIO;	}	if (!strlen(id2)) {		restore_flags(flags);		printk(KERN_INFO		       "icn: (%s) ICN-2B, port 0x%x added\n",		       card->interface.id, port);		return 0;	}	if (!(card2 = icn_initcard(port, id2))) {		restore_flags(flags);		printk(KERN_INFO		       "icn: (%s) half ICN-4B, port 0x%x added\n",		       card2->interface.id, port);		return 0;	}	card->doubleS0 = 1;	card->secondhalf = 0;	card->other = card2;	card2->doubleS0 = 1;	card2->secondhalf = 1;	card2->other = card;	restore_flags(flags);	printk(KERN_INFO	       "icn: (%s and %s) ICN-4B, port 0x%x added\n",	       card->interface.id, card2->interface.id, port);	return 0;}#ifdef MODULE#define icn_init init_module#else#include <linux/init.h>static int __initicn_setup(char *line){	char *p, *str;	int	ints[3];	static char sid[20];	static char sid2[20];	str = get_options(line, 2, ints);	if (ints[0])		portbase = ints[1];	if (ints[0] > 1)		membase = ints[2];	if (str && *str) {		strcpy(sid, str);		icn_id = sid;		if ((p = strchr(sid, ','))) {			*p++ = 0;			strcpy(sid2, p);			icn_id2 = sid2;		}	}	return(1);}__setup("icn=", icn_setup);#endif /* MODULES */inticn_init(void){	char *p;	char rev[10];	memset(&dev, 0, sizeof(icn_dev));	dev.shmem = (icn_shmem *) ((unsigned long) membase & 0x0ffc000);	dev.channel = -1;	dev.mcard = NULL;	dev.firstload = 1;	/* No symbols to export, hide all symbols */	EXPORT_NO_SYMBOLS;	if ((p = strchr(revision, ':'))) {		strcpy(rev, p + 1);		p = strchr(rev, '$');		*p = 0;	} else		strcpy(rev, " ??? ");	printk(KERN_NOTICE "ICN-ISDN-driver Rev%smem=0x%08lx\n", rev,	       (ulong) dev.shmem);	return (icn_addcard(portbase, icn_id, icn_id2));}#ifdef MODULEvoidcleanup_module(void){	isdn_ctrl cmd;	icn_card *card = cards;	icn_card *last;	int i;	icn_stopallcards();	while (card) {		cmd.command = ISDN_STAT_UNLOAD;		cmd.driver = card->myid;		card->interface.statcallb(&cmd);		if (card->rvalid) {			OUTB_P(0, ICN_RUN);	/* Reset Controller     */			OUTB_P(0, ICN_MAPRAM);	/* Disable RAM          */			if (card->secondhalf || (!card->doubleS0)) {				release_region(card->port, ICN_PORTLEN);				card->rvalid = 0;			}			for (i = 0; i < ICN_BCH; i++)				icn_free_queue(card, i);		}		card = card->next;	}	card = cards;	while (card) {		last = card;		card = card->next;		kfree(last);	}	if (dev.mvalid)		release_shmem((ulong) dev.shmem, 0x4000);	printk(KERN_NOTICE "ICN-ISDN-driver unloaded\n");}#endif

⌨️ 快捷键说明

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