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

📄 eicon_isa.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
字号:
/* $Id: eicon_isa.c,v 1.16 2000/06/12 12:44:02 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * Hardware-specific code for old ISA cards. * * Copyright 1998      by Fritz Elfert (fritz@isdn4linux.de) * Copyright 1998-2000 by Armin Schindler (mac@melware.de) * Copyright 1999,2000 Cytronics & Melware (info@melware.de) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  * */#include <linux/config.h>#include "eicon.h"#include "eicon_isa.h"#define check_shmem   check_region#define release_shmem release_region#define request_shmem request_regionchar *eicon_isa_revision = "$Revision: 1.16 $";#undef EICON_MCA_DEBUG#ifdef CONFIG_ISDN_DRV_EICON_ISA/* Mask for detecting invalid IRQ parameter */static int eicon_isa_valid_irq[] = {	0x1c1c, /* 2, 3, 4, 10, 11, 12 (S)*/	0x1c1c, /* 2, 3, 4, 10, 11, 12 (SX) */	0x1cbc, /* 2, 3, 4, 5, 7, 10, 11, 12 (SCOM) */	0x1cbc, /* 2, 3, 4, 5, 6, 10, 11, 12 (Quadro) */	0x1cbc  /* 2, 3, 4, 5, 7, 10, 11, 12 (S2M) */};static voideicon_isa_release_shmem(eicon_isa_card *card) {	if (card->mvalid) {		iounmap(card->shmem);		release_mem_region(card->physmem, card->ramsize);	}	card->mvalid = 0;}static voideicon_isa_release_irq(eicon_isa_card *card) {	if (!card->master)		return;	if (card->ivalid)		free_irq(card->irq, card);	card->ivalid = 0;}voideicon_isa_release(eicon_isa_card *card) {	eicon_isa_release_irq(card);	eicon_isa_release_shmem(card);}voideicon_isa_printpar(eicon_isa_card *card) {	switch (card->type) {		case EICON_CTYPE_S:		case EICON_CTYPE_SX:		case EICON_CTYPE_SCOM:		case EICON_CTYPE_QUADRO:		case EICON_CTYPE_S2M:			printk(KERN_INFO "Eicon %s at 0x%lx, irq %d.\n",			       eicon_ctype_name[card->type],			       card->physmem,			       card->irq);	}}inteicon_isa_find_card(int Mem, int Irq, char * Id){	int primary = 1;	unsigned long amem;	if (!strlen(Id))		return -1;	if (Mem == -1)		return -1;	/* Check for valid membase address */	if ((Mem < 0x0c0000) ||	    (Mem > 0x0fc000) ||	    (Mem & 0xfff)) { 		printk(KERN_WARNING "eicon_isa: illegal membase 0x%x for %s\n",			 Mem, Id);		return -1;	}	if (check_mem_region(Mem, RAMSIZE)) {		printk(KERN_WARNING "eicon_isa_boot: memory at 0x%x already in use.\n", Mem);		return -1;	}	amem = (unsigned long) ioremap(Mem, RAMSIZE);        writew(0x55aa, amem + 0x402);        if (readw(amem + 0x402) != 0x55aa) primary = 0;	writew(0, amem + 0x402);	if (readw(amem + 0x402) != 0) primary = 0;	printk(KERN_INFO "Eicon: Driver-ID: %s\n", Id);	if (primary) {		printk(KERN_INFO "Eicon: assuming pri card at 0x%x\n", Mem);		writeb(0, amem + 0x3ffe);		iounmap((unsigned char *)amem);		return EICON_CTYPE_ISAPRI;	} else {		printk(KERN_INFO "Eicon: assuming bri card at 0x%x\n", Mem);		writeb(0, amem + 0x400);		iounmap((unsigned char *)amem);		return EICON_CTYPE_ISABRI;	}	return -1;}inteicon_isa_bootload(eicon_isa_card *card, eicon_isa_codebuf *cb) {	int	tmp;	int               timeout;	eicon_isa_codebuf cbuf;	unsigned char     *code;	eicon_isa_boot    *boot;	if (copy_from_user(&cbuf, cb, sizeof(eicon_isa_codebuf)))		return -EFAULT;	/* Allocate code-buffer and copy code from userspace */	if (cbuf.bootstrap_len > 1024) {		printk(KERN_WARNING "eicon_isa_boot: Invalid startup-code size %ld\n",		       cbuf.bootstrap_len);		return -EINVAL;	}	if (!(code = kmalloc(cbuf.bootstrap_len, GFP_KERNEL))) {		printk(KERN_WARNING "eicon_isa_boot: Couldn't allocate code buffer\n");		return -ENOMEM;	}	if (copy_from_user(code, &cb->code, cbuf.bootstrap_len)) {		kfree(code);		return -EFAULT;	}	if (card->type == EICON_CTYPE_ISAPRI)		card->ramsize  = RAMSIZE_P;	else		card->ramsize  = RAMSIZE;	if (check_mem_region(card->physmem, card->ramsize)) {		printk(KERN_WARNING "eicon_isa_boot: memory at 0x%lx already in use.\n",			card->physmem);		kfree(code);		return -EBUSY;	}	request_mem_region(card->physmem, card->ramsize, "Eicon ISA ISDN");	card->shmem = (eicon_isa_shmem *) ioremap(card->physmem, card->ramsize);#ifdef EICON_MCA_DEBUG	printk(KERN_INFO "eicon_isa_boot: card->ramsize = %d.\n", card->ramsize);#endif	card->mvalid = 1;	switch(card->type) {		case EICON_CTYPE_S:		case EICON_CTYPE_SX:		case EICON_CTYPE_SCOM:		case EICON_CTYPE_QUADRO:		case EICON_CTYPE_ISABRI:			card->intack   = (__u8 *)card->shmem + INTACK;			card->startcpu = (__u8 *)card->shmem + STARTCPU;			card->stopcpu  = (__u8 *)card->shmem + STOPCPU;			break;		case EICON_CTYPE_S2M:		case EICON_CTYPE_ISAPRI:			card->intack   = (__u8 *)card->shmem + INTACK_P;			card->startcpu = (__u8 *)card->shmem + STARTCPU_P;			card->stopcpu  = (__u8 *)card->shmem + STOPCPU_P;			break;		default:			printk(KERN_WARNING "eicon_isa_boot: Invalid card type %d\n", card->type);			eicon_isa_release_shmem(card);			kfree(code);			return -EINVAL;	}	/* clear any pending irq's */	readb(card->intack);#ifdef CONFIG_MCA	if (MCA_bus) {		if (card->type == EICON_CTYPE_SCOM) {			outb_p(0,card->io+1);		}		else {			printk(KERN_WARNING "eicon_isa_boot: Card type not supported yet.\n");			eicon_isa_release_shmem(card);			return -EINVAL;		};#ifdef EICON_MCA_DEBUG	printk(KERN_INFO "eicon_isa_boot: card->io      = %x.\n", card->io);	printk(KERN_INFO "eicon_isa_boot: card->irq     = %d.\n", (int)card->irq);#endif	}#else	/* set reset-line active */	writeb(0, card->stopcpu); #endif  /* CONFIG_MCA */	/* clear irq-requests */	writeb(0, card->intack);	readb(card->intack);	/* Copy code into card */	memcpy_toio(&card->shmem->c, code, cbuf.bootstrap_len);	/* Check for properly loaded code */	if (!check_signature((unsigned long)&card->shmem->c, code, 1020)) {		printk(KERN_WARNING "eicon_isa_boot: Could not load startup-code\n");		eicon_isa_release_shmem(card);		kfree(code);		return -EIO;	}	/* if 16k-ramsize, duplicate the reset-jump-code */	if (card->ramsize == RAMSIZE_P)		memcpy_toio((__u8 *)card->shmem + 0x3ff0, &code[0x3f0], 12);	kfree(code);	boot = &card->shmem->boot;	/* Delay 0.2 sec. */	SLEEP(20);	/* Start CPU */	writeb(cbuf.boot_opt, &boot->ctrl);#ifdef CONFIG_MCA	if (MCA_bus) {		outb_p(0, card->io);	}#else 	writeb(0, card->startcpu); #endif /* CONFIG_MCA */	/* Delay 0.2 sec. */	SLEEP(20);	timeout = jiffies + (HZ * 22);	while (timeout > jiffies) {		if (readb(&boot->ctrl) == 0)			break;		SLEEP(10);	}	if (readb(&boot->ctrl) != 0) {		printk(KERN_WARNING "eicon_isa_boot: CPU test failed.\n");#ifdef EICON_MCA_DEBUG		printk(KERN_INFO "eicon_isa_boot: &boot->ctrl = %d.\n",			readb(&boot->ctrl));#endif		eicon_isa_release_shmem(card);		return -EIO;	}	/* Check for memory-test errors */	if (readw(&boot->ebit)) {		printk(KERN_WARNING "eicon_isa_boot: memory test failed (bit 0x%04x at 0x%08x)\n",		       readw(&boot->ebit), readl(&boot->eloc));		eicon_isa_release_shmem(card);		return -EIO;	}        /* Check card type and memory size */        tmp = readb(&boot->card);	if ((tmp < 0) || (tmp > 4)) {		printk(KERN_WARNING "eicon_isa_boot: Type detect failed\n");		eicon_isa_release_shmem(card);		return -EIO;	}	card->type = tmp;	((eicon_card *)card->card)->type = tmp;        tmp = readb(&boot->msize);        if (tmp != 8 && tmp != 16 && tmp != 24 &&            tmp != 32 && tmp != 48 && tmp != 60) {                printk(KERN_WARNING "eicon_isa_boot: invalid memsize\n");		eicon_isa_release_shmem(card);                return -EIO;        }	printk(KERN_INFO "%s: startup-code loaded\n", eicon_ctype_name[card->type]); 	if ((card->type == EICON_CTYPE_QUADRO) && (card->master)) {		tmp = eicon_addcard(card->type, card->physmem, card->irq, 				((eicon_card *)card->card)->regname, 0);		printk(KERN_INFO "Eicon: %d adapters added\n", tmp);	}	return 0;}inteicon_isa_load(eicon_isa_card *card, eicon_isa_codebuf *cb) {	eicon_isa_boot    *boot;	int               tmp;	int               timeout;	int 		  j;	eicon_isa_codebuf cbuf;	unsigned char     *code;	unsigned char     *p;	if (copy_from_user(&cbuf, cb, sizeof(eicon_isa_codebuf)))		return -EFAULT;	if (!(code = kmalloc(cbuf.firmware_len, GFP_KERNEL))) {		printk(KERN_WARNING "eicon_isa_load: Couldn't allocate code buffer\n");		return -ENOMEM;	}	if (copy_from_user(code, &cb->code, cbuf.firmware_len)) {		kfree(code);		return -EFAULT;	}	boot = &card->shmem->boot;	if ((!card->ivalid) && card->master) {		card->irqprobe = 1;		/* Check for valid IRQ */		if ((card->irq < 0) || (card->irq > 15) || 		    (!((1 << card->irq) & eicon_isa_valid_irq[card->type & 0x0f]))) {			printk(KERN_WARNING "eicon_isa_load: illegal irq: %d\n", card->irq);			eicon_isa_release_shmem(card);			kfree(code);			return -EINVAL;		}		/* Register irq */		if (!request_irq(card->irq, &eicon_irq, 0, "Eicon ISA ISDN", card))			card->ivalid = 1;		else {			printk(KERN_WARNING "eicon_isa_load: irq %d already in use.\n",			       card->irq);			eicon_isa_release_shmem(card);			kfree(code);			return -EBUSY;		}	}        tmp = readb(&boot->msize);        if (tmp != 8 && tmp != 16 && tmp != 24 &&            tmp != 32 && tmp != 48 && tmp != 60) {                printk(KERN_WARNING "eicon_isa_load: invalid memsize\n");		eicon_isa_release_shmem(card);                return -EIO;        }	eicon_isa_printpar(card);	/* Download firmware */	printk(KERN_INFO "%s %dkB, loading firmware ...\n", 	       eicon_ctype_name[card->type],	       tmp * 16);	tmp = cbuf.firmware_len >> 8;	p = code;	while (tmp--) {		memcpy_toio(&boot->b, p, 256);		writeb(1, &boot->ctrl);		timeout = jiffies + 10;		while (timeout > jiffies) {			if (readb(&boot->ctrl) == 0)				break;			SLEEP(2);		}		if (readb(&boot->ctrl)) {			printk(KERN_WARNING "eicon_isa_load: download timeout at 0x%x\n", p-code);			eicon_isa_release(card);			kfree(code);			return -EIO;		}		p += 256;	}	kfree(code);	/* Initialize firmware parameters */	memcpy_toio(&card->shmem->c[8], &cbuf.tei, 14);	memcpy_toio(&card->shmem->c[32], &cbuf.oad, 96);	memcpy_toio(&card->shmem->c[128], &cbuf.oad, 96);		/* Start firmware, wait for signature */	writeb(2, &boot->ctrl);	timeout = jiffies + (5*HZ);	while (timeout > jiffies) {		if (readw(&boot->signature) == 0x4447)			break;		SLEEP(2);	}	if (readw(&boot->signature) != 0x4447) {		printk(KERN_WARNING "eicon_isa_load: firmware selftest failed %04x\n",		       readw(&boot->signature));		eicon_isa_release(card);		return -EIO;	}	card->channels = readb(&card->shmem->c[0x3f6]);	/* clear irq-requests, reset irq-count */	readb(card->intack);	writeb(0, card->intack);	if (card->master) {		card->irqprobe = 1;		/* Trigger an interrupt and check if it is delivered */		tmp = readb(&card->shmem->com.ReadyInt);		tmp ++;		writeb(tmp, &card->shmem->com.ReadyInt);		timeout = jiffies + 20;		while (timeout > jiffies) {			if (card->irqprobe > 1)				break;			SLEEP(2);		}		if (card->irqprobe == 1) {			printk(KERN_WARNING "eicon_isa_load: IRQ # %d test failed\n", card->irq);			eicon_isa_release(card);			return -EIO;		}	}#ifdef EICON_MCA_DEBUG	printk(KERN_INFO "eicon_isa_load: IRQ # %d test succeeded.\n", card->irq);#endif	writeb(card->irq, &card->shmem->com.Int);	/* initializing some variables */	((eicon_card *)card->card)->ReadyInt = 0;	((eicon_card *)card->card)->ref_in  = 1;	((eicon_card *)card->card)->ref_out = 1;	for(j=0; j<256; j++) ((eicon_card *)card->card)->IdTable[j] = NULL;	for(j=0; j< (card->channels + 1); j++) {		((eicon_card *)card->card)->bch[j].e.busy = 0;		((eicon_card *)card->card)->bch[j].e.D3Id = 0;		((eicon_card *)card->card)->bch[j].e.B2Id = 0;		((eicon_card *)card->card)->bch[j].e.ref = 0;		((eicon_card *)card->card)->bch[j].e.Req = 0;		((eicon_card *)card->card)->bch[j].e.complete = 1;		((eicon_card *)card->card)->bch[j].fsm_state = EICON_STATE_NULL;	}	printk(KERN_INFO "Eicon: Supported channels: %d\n", card->channels); 	printk(KERN_INFO "%s successfully started\n", eicon_ctype_name[card->type]);	/* Enable normal IRQ processing */	card->irqprobe = 0;	return 0;}#endif /* CONFIG_ISDN_DRV_EICON_ISA */

⌨️ 快捷键说明

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