core.c

来自「linux 内核源代码」· C语言 代码 · 共 1,176 行 · 第 1/2 页

C
1,176
字号
		*size -= size1;		/* clean whitespace from end of string */		while (size1 > 0 && name[--size1] == ' ')			name[size1] = '\0';	}}/* *  Parse resource map for logical device. */static int __init isapnp_create_device(struct pnp_card *card,				       unsigned short size){	int number = 0, skip = 0, priority = 0, compat = 0;	unsigned char type, tmp[17];	struct pnp_option *option;	struct pnp_dev *dev;	if ((dev = isapnp_parse_device(card, size, number++)) == NULL)		return 1;	option = pnp_register_independent_option(dev);	if (!option) {		kfree(dev);		return 1;	}	pnp_add_card_device(card, dev);	while (1) {		if (isapnp_read_tag(&type, &size) < 0)			return 1;		if (skip && type != _STAG_LOGDEVID && type != _STAG_END)			goto __skip;		switch (type) {		case _STAG_LOGDEVID:			if (size >= 5 && size <= 6) {				if ((dev =				     isapnp_parse_device(card, size,							 number++)) == NULL)					return 1;				size = 0;				skip = 0;				option = pnp_register_independent_option(dev);				if (!option) {					kfree(dev);					return 1;				}				pnp_add_card_device(card, dev);			} else {				skip = 1;			}			priority = 0;			compat = 0;			break;		case _STAG_COMPATDEVID:			if (size == 4 && compat < DEVICE_COUNT_COMPATIBLE) {				isapnp_peek(tmp, 4);				isapnp_parse_id(dev, (tmp[1] << 8) | tmp[0],						(tmp[3] << 8) | tmp[2]);				compat++;				size = 0;			}			break;		case _STAG_IRQ:			if (size < 2 || size > 3)				goto __skip;			isapnp_parse_irq_resource(option, size);			size = 0;			break;		case _STAG_DMA:			if (size != 2)				goto __skip;			isapnp_parse_dma_resource(option, size);			size = 0;			break;		case _STAG_STARTDEP:			if (size > 1)				goto __skip;			priority = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE;			if (size > 0) {				isapnp_peek(tmp, size);				priority = 0x100 | tmp[0];				size = 0;			}			option = pnp_register_dependent_option(dev, priority);			if (!option)				return 1;			break;		case _STAG_ENDDEP:			if (size != 0)				goto __skip;			priority = 0;			break;		case _STAG_IOPORT:			if (size != 7)				goto __skip;			isapnp_parse_port_resource(option, size);			size = 0;			break;		case _STAG_FIXEDIO:			if (size != 3)				goto __skip;			isapnp_parse_fixed_port_resource(option, size);			size = 0;			break;		case _STAG_VENDOR:			break;		case _LTAG_MEMRANGE:			if (size != 9)				goto __skip;			isapnp_parse_mem_resource(option, size);			size = 0;			break;		case _LTAG_ANSISTR:			isapnp_parse_name(dev->name, sizeof(dev->name), &size);			break;		case _LTAG_UNICODESTR:			/* silently ignore */			/* who use unicode for hardware identification? */			break;		case _LTAG_VENDOR:			break;		case _LTAG_MEM32RANGE:			if (size != 17)				goto __skip;			isapnp_parse_mem32_resource(option, size);			size = 0;			break;		case _LTAG_FIXEDMEM32RANGE:			if (size != 9)				goto __skip;			isapnp_parse_fixed_mem32_resource(option, size);			size = 0;			break;		case _STAG_END:			if (size > 0)				isapnp_skip_bytes(size);			return 1;		default:			printk(KERN_ERR			       "isapnp: unexpected or unknown tag type 0x%x for logical device %i (device %i), ignored\n",			       type, dev->number, card->number);		}__skip:		if (size > 0)			isapnp_skip_bytes(size);	}	return 0;}/* *  Parse resource map for ISA PnP card. */static void __init isapnp_parse_resource_map(struct pnp_card *card){	unsigned char type, tmp[17];	unsigned short size;	while (1) {		if (isapnp_read_tag(&type, &size) < 0)			return;		switch (type) {		case _STAG_PNPVERNO:			if (size != 2)				goto __skip;			isapnp_peek(tmp, 2);			card->pnpver = tmp[0];			card->productver = tmp[1];			size = 0;			break;		case _STAG_LOGDEVID:			if (size >= 5 && size <= 6) {				if (isapnp_create_device(card, size) == 1)					return;				size = 0;			}			break;		case _STAG_VENDOR:			break;		case _LTAG_ANSISTR:			isapnp_parse_name(card->name, sizeof(card->name),					  &size);			break;		case _LTAG_UNICODESTR:			/* silently ignore */			/* who use unicode for hardware identification? */			break;		case _LTAG_VENDOR:			break;		case _STAG_END:			if (size > 0)				isapnp_skip_bytes(size);			return;		default:			printk(KERN_ERR			       "isapnp: unexpected or unknown tag type 0x%x for device %i, ignored\n",			       type, card->number);		}__skip:		if (size > 0)			isapnp_skip_bytes(size);	}}/* *  Compute ISA PnP checksum for first eight bytes. */static unsigned char __init isapnp_checksum(unsigned char *data){	int i, j;	unsigned char checksum = 0x6a, bit, b;	for (i = 0; i < 8; i++) {		b = data[i];		for (j = 0; j < 8; j++) {			bit = 0;			if (b & (1 << j))				bit = 1;			checksum =			    ((((checksum ^ (checksum >> 1)) & 0x01) ^ bit) << 7)			    | (checksum >> 1);		}	}	return checksum;}/* *  Parse EISA id for ISA PnP card. */static void isapnp_parse_card_id(struct pnp_card *card, unsigned short vendor,				 unsigned short device){	struct pnp_id *id = kzalloc(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_card_id(id, card);}/* *  Build device list for all present ISA PnP devices. */static int __init isapnp_build_device_list(void){	int csn;	unsigned char header[9], checksum;	struct pnp_card *card;	isapnp_wait();	isapnp_key();	for (csn = 1; csn <= isapnp_csn_count; csn++) {		isapnp_wake(csn);		isapnp_peek(header, 9);		checksum = isapnp_checksum(header);#if 0		printk(KERN_DEBUG		       "vendor: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",		       header[0], header[1], header[2], header[3], header[4],		       header[5], header[6], header[7], header[8]);		printk(KERN_DEBUG "checksum = 0x%x\n", checksum);#endif		if ((card =		     kzalloc(sizeof(struct pnp_card), GFP_KERNEL)) == NULL)			continue;		card->number = csn;		INIT_LIST_HEAD(&card->devices);		isapnp_parse_card_id(card, (header[1] << 8) | header[0],				     (header[3] << 8) | header[2]);		card->serial =		    (header[7] << 24) | (header[6] << 16) | (header[5] << 8) |		    header[4];		isapnp_checksum_value = 0x00;		isapnp_parse_resource_map(card);		if (isapnp_checksum_value != 0x00)			printk(KERN_ERR			       "isapnp: checksum for device %i is not valid (0x%x)\n",			       csn, isapnp_checksum_value);		card->checksum = isapnp_checksum_value;		card->protocol = &isapnp_protocol;		pnp_add_card(card);	}	isapnp_wait();	return 0;}/* *  Basic configuration routines. */int isapnp_present(void){	struct pnp_card *card;	pnp_for_each_card(card) {		if (card->protocol == &isapnp_protocol)			return 1;	}	return 0;}int isapnp_cfg_begin(int csn, int logdev){	if (csn < 1 || csn > isapnp_csn_count || logdev > 10)		return -EINVAL;	mutex_lock(&isapnp_cfg_mutex);	isapnp_wait();	isapnp_key();	isapnp_wake(csn);#if 0	/* to avoid malfunction when the isapnptools package is used */	/* we must set RDP to our value again */	/* it is possible to set RDP only in the isolation phase */	/*   Jens Thoms Toerring <Jens.Toerring@physik.fu-berlin.de> */	isapnp_write_byte(0x02, 0x04);	/* clear CSN of card */	mdelay(2);		/* is this necessary? */	isapnp_wake(csn);	/* bring card into sleep state */	isapnp_wake(0);		/* bring card into isolation state */	isapnp_set_rdp();	/* reset the RDP port */	udelay(1000);		/* delay 1000us */	isapnp_write_byte(0x06, csn);	/* reset CSN to previous value */	udelay(250);		/* is this necessary? */#endif	if (logdev >= 0)		isapnp_device(logdev);	return 0;}int isapnp_cfg_end(void){	isapnp_wait();	mutex_unlock(&isapnp_cfg_mutex);	return 0;}/* *  Initialization. */EXPORT_SYMBOL(isapnp_protocol);EXPORT_SYMBOL(isapnp_present);EXPORT_SYMBOL(isapnp_cfg_begin);EXPORT_SYMBOL(isapnp_cfg_end);EXPORT_SYMBOL(isapnp_write_byte);static int isapnp_read_resources(struct pnp_dev *dev,				 struct pnp_resource_table *res){	int tmp, ret;	dev->active = isapnp_read_byte(ISAPNP_CFG_ACTIVATE);	if (dev->active) {		for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) {			ret = isapnp_read_word(ISAPNP_CFG_PORT + (tmp << 1));			if (!ret)				continue;			res->port_resource[tmp].start = ret;			res->port_resource[tmp].flags = IORESOURCE_IO;		}		for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) {			ret =			    isapnp_read_word(ISAPNP_CFG_MEM + (tmp << 3)) << 8;			if (!ret)				continue;			res->mem_resource[tmp].start = ret;			res->mem_resource[tmp].flags = IORESOURCE_MEM;		}		for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) {			ret =			    (isapnp_read_word(ISAPNP_CFG_IRQ + (tmp << 1)) >>			     8);			if (!ret)				continue;			res->irq_resource[tmp].start =			    res->irq_resource[tmp].end = ret;			res->irq_resource[tmp].flags = IORESOURCE_IRQ;		}		for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) {			ret = isapnp_read_byte(ISAPNP_CFG_DMA + tmp);			if (ret == 4)				continue;			res->dma_resource[tmp].start =			    res->dma_resource[tmp].end = ret;			res->dma_resource[tmp].flags = IORESOURCE_DMA;		}	}	return 0;}static int isapnp_get_resources(struct pnp_dev *dev,				struct pnp_resource_table *res){	int ret;	pnp_init_resource_table(res);	isapnp_cfg_begin(dev->card->number, dev->number);	ret = isapnp_read_resources(dev, res);	isapnp_cfg_end();	return ret;}static int isapnp_set_resources(struct pnp_dev *dev,				struct pnp_resource_table *res){	int tmp;	isapnp_cfg_begin(dev->card->number, dev->number);	dev->active = 1;	for (tmp = 0;	     tmp < PNP_MAX_PORT	     && (res->port_resource[tmp].		 flags & (IORESOURCE_IO | IORESOURCE_UNSET)) == IORESOURCE_IO;	     tmp++)		isapnp_write_word(ISAPNP_CFG_PORT + (tmp << 1),				  res->port_resource[tmp].start);	for (tmp = 0;	     tmp < PNP_MAX_IRQ	     && (res->irq_resource[tmp].		 flags & (IORESOURCE_IRQ | IORESOURCE_UNSET)) == IORESOURCE_IRQ;	     tmp++) {		int irq = res->irq_resource[tmp].start;		if (irq == 2)			irq = 9;		isapnp_write_byte(ISAPNP_CFG_IRQ + (tmp << 1), irq);	}	for (tmp = 0;	     tmp < PNP_MAX_DMA	     && (res->dma_resource[tmp].		 flags & (IORESOURCE_DMA | IORESOURCE_UNSET)) == IORESOURCE_DMA;	     tmp++)		isapnp_write_byte(ISAPNP_CFG_DMA + tmp,				  res->dma_resource[tmp].start);	for (tmp = 0;	     tmp < PNP_MAX_MEM	     && (res->mem_resource[tmp].		 flags & (IORESOURCE_MEM | IORESOURCE_UNSET)) == IORESOURCE_MEM;	     tmp++)		isapnp_write_word(ISAPNP_CFG_MEM + (tmp << 3),				  (res->mem_resource[tmp].start >> 8) & 0xffff);	/* FIXME: We aren't handling 32bit mems properly here */	isapnp_activate(dev->number);	isapnp_cfg_end();	return 0;}static int isapnp_disable_resources(struct pnp_dev *dev){	if (!dev->active)		return -EINVAL;	isapnp_cfg_begin(dev->card->number, dev->number);	isapnp_deactivate(dev->number);	dev->active = 0;	isapnp_cfg_end();	return 0;}struct pnp_protocol isapnp_protocol = {	.name = "ISA Plug and Play",	.get = isapnp_get_resources,	.set = isapnp_set_resources,	.disable = isapnp_disable_resources,};static int __init isapnp_init(void){	int cards;	struct pnp_card *card;	struct pnp_dev *dev;	if (isapnp_disable) {		printk(KERN_INFO "isapnp: ISA Plug & Play support disabled\n");		return 0;	}#ifdef CONFIG_PPC_MERGE	if (check_legacy_ioport(_PIDXR) || check_legacy_ioport(_PNPWRP))		return -EINVAL;#endif#ifdef ISAPNP_REGION_OK	if (!request_region(_PIDXR, 1, "isapnp index")) {		printk(KERN_ERR "isapnp: Index Register 0x%x already used\n",		       _PIDXR);		return -EBUSY;	}#endif	if (!request_region(_PNPWRP, 1, "isapnp write")) {		printk(KERN_ERR		       "isapnp: Write Data Register 0x%x already used\n",		       _PNPWRP);#ifdef ISAPNP_REGION_OK		release_region(_PIDXR, 1);#endif		return -EBUSY;	}	if (pnp_register_protocol(&isapnp_protocol) < 0)		return -EBUSY;	/*	 *      Print a message. The existing ISAPnP code is hanging machines	 *      so let the user know where.	 */	printk(KERN_INFO "isapnp: Scanning for PnP cards...\n");	if (isapnp_rdp >= 0x203 && isapnp_rdp <= 0x3ff) {		isapnp_rdp |= 3;		if (!request_region(isapnp_rdp, 1, "isapnp read")) {			printk(KERN_ERR			       "isapnp: Read Data Register 0x%x already used\n",			       isapnp_rdp);#ifdef ISAPNP_REGION_OK			release_region(_PIDXR, 1);#endif			release_region(_PNPWRP, 1);			return -EBUSY;		}		isapnp_set_rdp();	}	if (isapnp_rdp < 0x203 || isapnp_rdp > 0x3ff) {		cards = isapnp_isolate();		if (cards < 0 || (isapnp_rdp < 0x203 || isapnp_rdp > 0x3ff)) {#ifdef ISAPNP_REGION_OK			release_region(_PIDXR, 1);#endif			release_region(_PNPWRP, 1);			printk(KERN_INFO			       "isapnp: No Plug & Play device found\n");			return 0;		}		request_region(isapnp_rdp, 1, "isapnp read");	}	isapnp_build_device_list();	cards = 0;	protocol_for_each_card(&isapnp_protocol, card) {		cards++;		if (isapnp_verbose) {			printk(KERN_INFO "isapnp: Card '%s'\n",			       card->name[0] ? card->name : "Unknown");			if (isapnp_verbose < 2)				continue;			card_for_each_dev(card, dev) {				printk(KERN_INFO "isapnp:   Device '%s'\n",				       dev->name[0] ? dev->name : "Unknown");			}		}	}	if (cards)		printk(KERN_INFO		       "isapnp: %i Plug & Play card%s detected total\n", cards,		       cards > 1 ? "s" : "");	else		printk(KERN_INFO "isapnp: No Plug & Play card found\n");	isapnp_proc_init();	return 0;}device_initcall(isapnp_init);/* format is: noisapnp */static int __init isapnp_setup_disable(char *str){	isapnp_disable = 1;	return 1;}__setup("noisapnp", isapnp_setup_disable);/* format is: isapnp=rdp,reset,skip_pci_scan,verbose */static int __init isapnp_setup_isapnp(char *str){	(void)((get_option(&str, &isapnp_rdp) == 2) &&	       (get_option(&str, &isapnp_reset) == 2) &&	       (get_option(&str, &isapnp_verbose) == 2));	return 1;}__setup("isapnp=", isapnp_setup_isapnp);

⌨️ 快捷键说明

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