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

📄 core.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  ISA Plug & Play support *  Copyright (c) by Jaroslav Kysela <perex@suse.cz> * * *   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 of the License, 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. * *  Changelog: *  2000-01-01	Added quirks handling for buggy hardware *		Peter Denison <peterd@pnd-pc.demon.co.uk> *  2000-06-14	Added isapnp_probe_devs() and isapnp_activate_dev() *		Christoph Hellwig <hch@infradead.org> *  2001-06-03  Added release_region calls to correspond with *		request_region calls when a failure occurs.  Also *		added KERN_* constants to printk() calls. *  2001-11-07  Added isapnp_{,un}register_driver calls along the lines *              of the pci driver interface *              Kai Germaschewski <kai.germaschewski@gmx.de> *  2002-06-06  Made the use of dma channel 0 configurable *              Gerald Teschl <gerald.teschl@univie.ac.at> *  2002-10-06  Ported to PnP Layer - Adam Belay <ambx1@neo.rr.com> *  2003-08-11	Resource Management Updates - Adam Belay <ambx1@neo.rr.com> */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/delay.h>#include <linux/init.h>#include <linux/isapnp.h>#include <asm/io.h>#if 0#define ISAPNP_REGION_OK#endif#if 0#define ISAPNP_DEBUG#endifint isapnp_disable;			/* Disable ISA PnP */static int isapnp_rdp;			/* Read Data Port */static int isapnp_reset = 1;		/* reset all PnP cards (deactivate) */static int isapnp_verbose = 1;		/* verbose mode */MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");MODULE_DESCRIPTION("Generic ISA Plug & Play support");module_param(isapnp_disable, int, 0);MODULE_PARM_DESC(isapnp_disable, "ISA Plug & Play disable");module_param(isapnp_rdp, int, 0);MODULE_PARM_DESC(isapnp_rdp, "ISA Plug & Play read data port");module_param(isapnp_reset, int, 0);MODULE_PARM_DESC(isapnp_reset, "ISA Plug & Play reset all cards");module_param(isapnp_verbose, int, 0);MODULE_PARM_DESC(isapnp_verbose, "ISA Plug & Play verbose mode");MODULE_LICENSE("GPL");#define _PIDXR		0x279#define _PNPWRP		0xa79/* short tags */#define _STAG_PNPVERNO		0x01#define _STAG_LOGDEVID		0x02#define _STAG_COMPATDEVID	0x03#define _STAG_IRQ		0x04#define _STAG_DMA		0x05#define _STAG_STARTDEP		0x06#define _STAG_ENDDEP		0x07#define _STAG_IOPORT		0x08#define _STAG_FIXEDIO		0x09#define _STAG_VENDOR		0x0e#define _STAG_END		0x0f/* long tags */#define _LTAG_MEMRANGE		0x81#define _LTAG_ANSISTR		0x82#define _LTAG_UNICODESTR	0x83#define _LTAG_VENDOR		0x84#define _LTAG_MEM32RANGE	0x85#define _LTAG_FIXEDMEM32RANGE	0x86static unsigned char isapnp_checksum_value;static DECLARE_MUTEX(isapnp_cfg_mutex);static int isapnp_detected;static int isapnp_csn_count;/* some prototypes */static inline void write_data(unsigned char x){	outb(x, _PNPWRP);}static inline void write_address(unsigned char x){	outb(x, _PIDXR);	udelay(20);}static inline unsigned char read_data(void){	unsigned char val = inb(isapnp_rdp);	return val;}unsigned char isapnp_read_byte(unsigned char idx){	write_address(idx);	return read_data();}static unsigned short isapnp_read_word(unsigned char idx){	unsigned short val;	val = isapnp_read_byte(idx);	val = (val << 8) + isapnp_read_byte(idx+1);	return val;}void isapnp_write_byte(unsigned char idx, unsigned char val){	write_address(idx);	write_data(val);}static void isapnp_write_word(unsigned char idx, unsigned short val){	isapnp_write_byte(idx, val >> 8);	isapnp_write_byte(idx+1, val);}static void isapnp_key(void){	unsigned char code = 0x6a, msb;	int i;	mdelay(1);	write_address(0x00);	write_address(0x00);	write_address(code);	for (i = 1; i < 32; i++) {		msb = ((code & 0x01) ^ ((code & 0x02) >> 1)) << 7;		code = (code >> 1) | msb;		write_address(code);	}}/* place all pnp cards in wait-for-key state */static void isapnp_wait(void){	isapnp_write_byte(0x02, 0x02);}static void isapnp_wake(unsigned char csn){	isapnp_write_byte(0x03, csn);}static void isapnp_device(unsigned char logdev){	isapnp_write_byte(0x07, logdev);}static void isapnp_activate(unsigned char logdev){	isapnp_device(logdev);	isapnp_write_byte(ISAPNP_CFG_ACTIVATE, 1);	udelay(250);}static void isapnp_deactivate(unsigned char logdev){	isapnp_device(logdev);	isapnp_write_byte(ISAPNP_CFG_ACTIVATE, 0);	udelay(500);}static void __init isapnp_peek(unsigned char *data, int bytes){	int i, j;	unsigned char d=0;	for (i = 1; i <= bytes; i++) {		for (j = 0; j < 20; j++) {			d = isapnp_read_byte(0x05);			if (d & 1)				break;			udelay(100);		}		if (!(d & 1)) {			if (data != NULL)				*data++ = 0xff;			continue;		}		d = isapnp_read_byte(0x04);	/* PRESDI */		isapnp_checksum_value += d;		if (data != NULL)			*data++ = d;	}}#define RDP_STEP	32	/* minimum is 4 */static int isapnp_next_rdp(void){	int rdp = isapnp_rdp;	static int old_rdp = 0;		if(old_rdp)	{		release_region(old_rdp, 1);		old_rdp = 0;	}	while (rdp <= 0x3ff) {		/*		 *	We cannot use NE2000 probe spaces for ISAPnP or we		 *	will lock up machines.		 */		if ((rdp < 0x280 || rdp >  0x380) && request_region(rdp, 1, "ISAPnP"))		{			isapnp_rdp = rdp;			old_rdp = rdp;			return 0;		}		rdp += RDP_STEP;	}	return -1;}/* Set read port address */static inline void isapnp_set_rdp(void){	isapnp_write_byte(0x00, isapnp_rdp >> 2);	udelay(100);}/* *	Perform an isolation. The port selection code now tries to avoid *	"dangerous to read" ports. */static int __init isapnp_isolate_rdp_select(void){	isapnp_wait();	isapnp_key();	/* Control: reset CSN and conditionally everything else too */	isapnp_write_byte(0x02, isapnp_reset ? 0x05 : 0x04);	mdelay(2);	isapnp_wait();	isapnp_key();	isapnp_wake(0x00);	if (isapnp_next_rdp() < 0) {		isapnp_wait();		return -1;	}	isapnp_set_rdp();	udelay(1000);	write_address(0x01);	udelay(1000);	return 0;}/* *  Isolate (assign uniqued CSN) to all ISA PnP devices. */static int __init isapnp_isolate(void){	unsigned char checksum = 0x6a;	unsigned char chksum = 0x00;	unsigned char bit = 0x00;	int data;	int csn = 0;	int i;	int iteration = 1;	isapnp_rdp = 0x213;	if (isapnp_isolate_rdp_select() < 0)		return -1;	while (1) {		for (i = 1; i <= 64; i++) {			data = read_data() << 8;			udelay(250);			data = data | read_data();			udelay(250);			if (data == 0x55aa)				bit = 0x01;			checksum = ((((checksum ^ (checksum >> 1)) & 0x01) ^ bit) << 7) | (checksum >> 1);			bit = 0x00;		}		for (i = 65; i <= 72; i++) {			data = read_data() << 8;			udelay(250);			data = data | read_data();			udelay(250);			if (data == 0x55aa)				chksum |= (1 << (i - 65));		}		if (checksum != 0x00 && checksum == chksum) {			csn++;			isapnp_write_byte(0x06, csn);			udelay(250);			iteration++;			isapnp_wake(0x00);			isapnp_set_rdp();			udelay(1000);			write_address(0x01);			udelay(1000);			goto __next;		}		if (iteration == 1) {			isapnp_rdp += RDP_STEP;			if (isapnp_isolate_rdp_select() < 0)				return -1;		} else if (iteration > 1) {			break;		}	      __next:		if (csn == 255)			break;		checksum = 0x6a;		chksum = 0x00;		bit = 0x00;	}	isapnp_wait();	isapnp_csn_count = csn;	return csn;}/* *  Read one tag from stream. */static int __init isapnp_read_tag(unsigned char *type, unsigned short *size){	unsigned char tag, tmp[2];	isapnp_peek(&tag, 1);	if (tag == 0)				/* invalid tag */		return -1;	if (tag & 0x80) {	/* large item */		*type = tag;		isapnp_peek(tmp, 2);		*size = (tmp[1] << 8) | tmp[0];	} else {		*type = (tag >> 3) & 0x0f;		*size = tag & 0x07;	}#if 0	printk(KERN_DEBUG "tag = 0x%x, type = 0x%x, size = %i\n", tag, *type, *size);#endif	if (type == 0)				/* wrong type */		return -1;	if (*type == 0xff && *size == 0xffff)	/* probably invalid data */		return -1;	return 0;}/* *  Skip specified number of bytes from stream. */static void __init isapnp_skip_bytes(int count){	isapnp_peek(NULL, count);}/* *  Parse EISA id. */static void isapnp_parse_id(struct pnp_dev * dev, unsigned short vendor, unsigned short device){	struct pnp_id * id;	if (!dev)		return;	id = kcalloc(1, sizeof(struct pnp_id), GFP_KERNEL);	if (!id)		return;	sprintf(id->id, "%c%c%c%x%x%x%x",			'A' + ((vendor >> 2) & 0x3f) - 1,			'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,			'A' + ((vendor >> 8) & 0x1f) - 1,			(device >> 4) & 0x0f,			device & 0x0f,			(device >> 12) & 0x0f,			(device >> 8) & 0x0f);	pnp_add_id(id, dev);}/* *  Parse logical device tag. */static struct pnp_dev * __init isapnp_parse_device(struct pnp_card *card, int size, int number){	unsigned char tmp[6];	struct pnp_dev *dev;	isapnp_peek(tmp, size);	dev = kcalloc(1, sizeof(struct pnp_dev), GFP_KERNEL);	if (!dev)		return NULL;	dev->number = number;	isapnp_parse_id(dev, (tmp[1] << 8) | tmp[0], (tmp[3] << 8) | tmp[2]);	dev->regs = tmp[4];	dev->card = card;	if (size > 5)		dev->regs |= tmp[5] << 8;	dev->protocol = &isapnp_protocol;	dev->capabilities |= PNP_CONFIGURABLE;	dev->capabilities |= PNP_READ;	dev->capabilities |= PNP_WRITE;	dev->capabilities |= PNP_DISABLE;	pnp_init_resource_table(&dev->res);	return dev;}/* *  Add IRQ resource to resources list. */static void __init isapnp_parse_irq_resource(struct pnp_option *option,					       int size){	unsigned char tmp[3];	struct pnp_irq *irq;	unsigned long bits;	isapnp_peek(tmp, size);	irq = kcalloc(1, sizeof(struct pnp_irq), GFP_KERNEL);	if (!irq)		return;	bits = (tmp[1] << 8) | tmp[0];	bitmap_copy(irq->map, &bits, 16);	if (size > 2)		irq->flags = tmp[2];	else		irq->flags = IORESOURCE_IRQ_HIGHEDGE;	pnp_register_irq_resource(option, irq);	return;}/* *  Add DMA resource to resources list. */static void __init isapnp_parse_dma_resource(struct pnp_option *option,                                    	       int size){	unsigned char tmp[2];	struct pnp_dma *dma;	isapnp_peek(tmp, size);	dma = kcalloc(1, sizeof(struct pnp_dma), GFP_KERNEL);	if (!dma)		return;	dma->map = tmp[0];	dma->flags = tmp[1];	pnp_register_dma_resource(option, dma);	return;}/* *  Add port resource to resources list. */static void __init isapnp_parse_port_resource(struct pnp_option *option,						int size){	unsigned char tmp[7];	struct pnp_port *port;	isapnp_peek(tmp, size);	port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);	if (!port)		return;	port->min = (tmp[2] << 8) | tmp[1];	port->max = (tmp[4] << 8) | tmp[3];	port->align = tmp[5];	port->size = tmp[6];	port->flags = tmp[0] ? PNP_PORT_FLAG_16BITADDR : 0;	pnp_register_port_resource(option,port);	return;}/* *  Add fixed port resource to resources list. */static void __init isapnp_parse_fixed_port_resource(struct pnp_option *option,						      int size){	unsigned char tmp[3];	struct pnp_port *port;	isapnp_peek(tmp, size);	port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);	if (!port)		return;	port->min = port->max = (tmp[1] << 8) | tmp[0];	port->size = tmp[2];	port->align = 0;	port->flags = PNP_PORT_FLAG_FIXED;	pnp_register_port_resource(option,port);	return;}/* *  Add memory resource to resources list. */static void __init isapnp_parse_mem_resource(struct pnp_option *option,					       int size){	unsigned char tmp[9];	struct pnp_mem *mem;	isapnp_peek(tmp, size);	mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);	if (!mem)		return;	mem->min = ((tmp[2] << 8) | tmp[1]) << 8;	mem->max = ((tmp[4] << 8) | tmp[3]) << 8;	mem->align = (tmp[6] << 8) | tmp[5];	mem->size = ((tmp[8] << 8) | tmp[7]) << 8;	mem->flags = tmp[0];	pnp_register_mem_resource(option,mem);	return;}/* *  Add 32-bit memory resource to resources list. */static void __init isapnp_parse_mem32_resource(struct pnp_option *option,						 int size){	unsigned char tmp[17];	struct pnp_mem *mem;	isapnp_peek(tmp, size);	mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);	if (!mem)		return;	mem->min = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1];	mem->max = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5];	mem->align = (tmp[12] << 24) | (tmp[11] << 16) | (tmp[10] << 8) | tmp[9];	mem->size = (tmp[16] << 24) | (tmp[15] << 16) | (tmp[14] << 8) | tmp[13];	mem->flags = tmp[0];	pnp_register_mem_resource(option,mem);}

⌨️ 快捷键说明

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