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

📄 isapnp.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
			index--;		}	}	return NULL;}struct isapnp_mem32 *isapnp_find_mem32(struct pci_dev *dev, int index){	struct isapnp_resources *res;	struct isapnp_mem32 *mem32;		if (!dev || index < 0 || index > 7)		return NULL;	for (res = (struct isapnp_resources *)dev->sysdata; res; res = res->next) {		for (mem32 = res->mem32; mem32; mem32 = mem32->next) {			if (!index)				return mem32;			index--;		}	}	return NULL;}/* *  Device manager. */struct pci_bus *isapnp_find_card(unsigned short vendor,				 unsigned short device,				 struct pci_bus *from){	struct list_head *list;	list = isapnp_cards.next;	if (from)		list = from->node.next;	while (list != &isapnp_cards) {		struct pci_bus *card = pci_bus_b(list);		if (card->vendor == vendor && card->device == device)			return card;		list = list->next;	}	return NULL;}struct pci_dev *isapnp_find_dev(struct pci_bus *card,				unsigned short vendor,				unsigned short function,				struct pci_dev *from){	if (card == NULL) {	/* look for a logical device from all cards */		struct list_head *list;		list = isapnp_devices.next;		if (from)			list = from->global_list.next;		while (list != &isapnp_devices) {			int idx;			struct pci_dev *dev = pci_dev_g(list);			if (dev->vendor == vendor && dev->device == function)				return dev;			for (idx = 0; idx < DEVICE_COUNT_COMPATIBLE; idx++)				if (dev->vendor_compatible[idx] == vendor &&				    dev->device_compatible[idx] == function)					return dev;			list = list->next;		}	} else {		struct list_head *list;		list = card->devices.next;		if (from) {			list = from->bus_list.next;			if (from->bus != card)	/* something is wrong */				return NULL;		}		while (list != &card->devices) {			int idx;			struct pci_dev *dev = pci_dev_b(list);			if (dev->vendor == vendor && dev->device == function)				return dev;			for (idx = 0; idx < DEVICE_COUNT_COMPATIBLE; idx++)				if (dev->vendor_compatible[idx] == vendor &&				    dev->device_compatible[idx] == function)					return dev;			list = list->next;		}	}	return NULL;}static const struct isapnp_card_id *isapnp_match_card(const struct isapnp_card_id *ids, struct pci_bus *card){	int idx;	while (ids->card_vendor || ids->card_device) {		if ((ids->card_vendor == ISAPNP_ANY_ID || ids->card_vendor == card->vendor) &&		    (ids->card_device == ISAPNP_ANY_ID || ids->card_device == card->device)) {			for (idx = 0; idx < ISAPNP_CARD_DEVS; idx++) {				if (ids->devs[idx].vendor == 0 &&				    ids->devs[idx].function == 0)					return ids;				if (isapnp_find_dev(card,						    ids->devs[idx].vendor,						    ids->devs[idx].function,						    NULL) == NULL)					goto __next;			}			return ids;		}	      __next:		ids++;	}	return NULL;}int isapnp_probe_cards(const struct isapnp_card_id *ids,		       int (*probe)(struct pci_bus *_card,		       		    const struct isapnp_card_id *_id)){	struct pci_bus *card;		const struct isapnp_card_id *id;	int count = 0;	if (ids == NULL || probe == NULL)		return -EINVAL;	isapnp_for_each_card(card) {		id = isapnp_match_card(ids, card);		if (id != NULL && probe(card, id) >= 0)			count++;	}	return count;}static const struct isapnp_device_id *isapnp_match_dev(const struct isapnp_device_id *ids, struct pci_dev *dev){	while (ids->card_vendor || ids->card_device) {		if ((ids->card_vendor == ISAPNP_ANY_ID || ids->card_vendor == dev->bus->vendor) &&		    (ids->card_device == ISAPNP_ANY_ID || ids->card_device == dev->bus->device) &&                    (ids->vendor == ISAPNP_ANY_ID || ids->vendor == dev->vendor) &&                    (ids->function == ISAPNP_ANY_ID || ids->function == dev->device))			return ids;		ids++;	}	return NULL;}int isapnp_probe_devs(const struct isapnp_device_id *ids,		      int (*probe)(struct pci_dev *dev,		                   const struct isapnp_device_id *id)){		struct pci_dev *dev;	const struct isapnp_device_id *id;	int count = 0;	if (ids == NULL || probe == NULL)		return -EINVAL;	isapnp_for_each_dev(dev) {		id = isapnp_match_dev(ids, dev);		if (id != NULL && probe(dev, id) >= 0)			count++;	}	return count;}int isapnp_activate_dev(struct pci_dev *dev, const char *name){	int err;		/* Device already active? Let's use it and inform the caller */	if (dev->active)		return -EBUSY;	if ((err = dev->activate(dev)) < 0) {		printk(KERN_ERR "isapnp: config of %s failed (out of resources?)[%d]\n", name, err);		dev->deactivate(dev);		return err;	}	return 0;}static unsigned int isapnp_dma_resource_flags(struct isapnp_dma *dma){	return dma->flags | IORESOURCE_DMA | IORESOURCE_AUTO;}static unsigned int isapnp_mem_resource_flags(struct isapnp_mem *mem){	unsigned int result;	result = mem->flags | IORESOURCE_MEM | IORESOURCE_AUTO;	if (!(mem->flags & IORESOURCE_MEM_WRITEABLE))		result |= IORESOURCE_READONLY;	if (mem->flags & IORESOURCE_MEM_CACHEABLE)		result |= IORESOURCE_CACHEABLE;	if (mem->flags & IORESOURCE_MEM_RANGELENGTH)		result |= IORESOURCE_RANGELENGTH;	if (mem->flags & IORESOURCE_MEM_SHADOWABLE)		result |= IORESOURCE_SHADOWABLE;	return result;}static unsigned int isapnp_irq_resource_flags(struct isapnp_irq *irq){	return irq->flags | IORESOURCE_IRQ | IORESOURCE_AUTO;}static unsigned int isapnp_port_resource_flags(struct isapnp_port *port){	return port->flags | IORESOURCE_IO | IORESOURCE_AUTO;}static int isapnp_config_prepare(struct pci_dev *dev){	struct isapnp_resources *res, *resa;	struct isapnp_port *port;	struct isapnp_irq *irq;	struct isapnp_dma *dma;	struct isapnp_mem *mem;	int port_count, port_count1;	int irq_count, irq_count1;	int dma_count, dma_count1;	int mem_count, mem_count1;	int idx;	if (dev == NULL)		return -EINVAL;	if (dev->active || dev->ro)		return -EBUSY;	for (idx = 0; idx < DEVICE_COUNT_IRQ; idx++) {		dev->irq_resource[idx].name = NULL;		dev->irq_resource[idx].start = 0;		dev->irq_resource[idx].end = 0;		dev->irq_resource[idx].flags = 0;	}	for (idx = 0; idx < DEVICE_COUNT_DMA; idx++) {		dev->dma_resource[idx].name = NULL;		dev->dma_resource[idx].start = 0;		dev->dma_resource[idx].end = 0;		dev->dma_resource[idx].flags = 0;	}	for (idx = 0; idx < DEVICE_COUNT_RESOURCE; idx++) {		dev->resource[idx].name = NULL;		dev->resource[idx].start = 0;		dev->resource[idx].end = 0;		dev->resource[idx].flags = 0;	}	port_count = irq_count = dma_count = mem_count = 0;	for (res = (struct isapnp_resources *)dev->sysdata; res; res = res->next) {		port_count1 = irq_count1 = dma_count1 = mem_count1 = 0;		for (resa = res; resa; resa = resa->alt) {			for (port = resa->port, idx = 0; port; port = port->next, idx++) {				if (dev->resource[port_count + idx].flags == 0) {					dev->resource[port_count + idx].flags = isapnp_port_resource_flags(port);					dev->resource[port_count + idx].end = port->size;				}			}			if (port_count1 < idx)				port_count1 = idx;			for (irq = resa->irq, idx = 0; irq; irq = irq->next, idx++) {				int count = irq_count + idx;				if (count < DEVICE_COUNT_IRQ) {					if (dev->irq_resource[count].flags == 0) {						dev->irq_resource[count].flags = isapnp_irq_resource_flags(irq);					}				}							}			if (irq_count1 < idx)				irq_count1 = idx;			for (dma = resa->dma, idx = 0; dma; dma = dma->next, idx++)				if (dev->dma_resource[idx].flags == 0) {					dev->dma_resource[idx].flags = isapnp_dma_resource_flags(dma);				}			if (dma_count1 < idx)				dma_count1 = idx;			for (mem = resa->mem, idx = 0; mem; mem = mem->next, idx++)				if (dev->resource[mem_count + idx + 8].flags == 0) {					dev->resource[mem_count + idx + 8].flags = isapnp_mem_resource_flags(mem);				}			if (mem_count1 < idx)				mem_count1 = idx;		}		port_count += port_count1;		irq_count += irq_count1;		dma_count += dma_count1;		mem_count += mem_count1;	}	return 0;}struct isapnp_cfgtmp {	struct isapnp_port *port[8];	struct isapnp_irq *irq[2];	struct isapnp_dma *dma[2];	struct isapnp_mem *mem[4];	struct pci_dev *request;	struct pci_dev result;};static int isapnp_alternative_switch(struct isapnp_cfgtmp *cfg,				     struct isapnp_resources *from,				     struct isapnp_resources *to){	int tmp, tmp1;	struct isapnp_port *port;	struct isapnp_irq *irq;	struct isapnp_dma *dma;	struct isapnp_mem *mem;	if (!cfg)		return -EINVAL;	/* process port settings */	for (tmp = 0; tmp < 8; tmp++) {		if (!(cfg->request->resource[tmp].flags & IORESOURCE_AUTO))			continue;		/* don't touch */		port = cfg->port[tmp];		if (!port) {			cfg->port[tmp] = port = isapnp_find_port(cfg->request, tmp);			if (!port)				return -EINVAL;		}		if (from && port->res == from) {			while (port->res != to) {				if (!port->res->alt)					return -EINVAL;				port = port->res->alt->port;				for (tmp1 = tmp; tmp1 > 0 && port; tmp1--)					port = port->next;				cfg->port[tmp] = port;				if (!port)					return -ENOENT;				cfg->result.resource[tmp].flags = isapnp_port_resource_flags(port);			}		}	}	/* process irq settings */	for (tmp = 0; tmp < 2; tmp++) {		if (!(cfg->request->irq_resource[tmp].flags & IORESOURCE_AUTO))			continue;		/* don't touch */		irq = cfg->irq[tmp];		if (!irq) {			cfg->irq[tmp] = irq = isapnp_find_irq(cfg->request, tmp);			if (!irq)				return -EINVAL;		}		if (from && irq->res == from) {			while (irq->res != to) {				if (!irq->res->alt)					return -EINVAL;				irq = irq->res->alt->irq;				for (tmp1 = tmp; tmp1 > 0 && irq; tmp1--)					irq = irq->next;				cfg->irq[tmp] = irq;				if (!irq)					return -ENOENT;				cfg->result.irq_resource[tmp].flags = isapnp_irq_resource_flags(irq);			}		}	}	/* process dma settings */	for (tmp = 0; tmp < 2; tmp++) {		if (!(cfg->request->dma_resource[tmp].flags & IORESOURCE_AUTO))			continue;		/* don't touch */		dma = cfg->dma[tmp];		if (!dma) {			cfg->dma[tmp] = dma = isapnp_find_dma(cfg->request, tmp);			if (!dma)				return -EINVAL;		}		if (from && dma->res == from) {			while (dma->res != to) {				if (!dma->res->alt)					return -EINVAL;				dma = dma->res->alt->dma;				for (tmp1 = tmp; tmp1 > 0 && dma; tmp1--)					dma = dma->next;				cfg->dma[tmp] = dma;				if (!dma)					return -ENOENT;				cfg->result.dma_resource[tmp].flags = isapnp_dma_resource_flags(dma);			}		}	}	/* process memory settings */	for (tmp = 0; tmp < 4; tmp++) {		if (!(cfg->request->resource[tmp + 8].flags & IORESOURCE_AUTO))			continue;		/* don't touch */		mem = cfg->mem[tmp];		if (!mem) {			cfg->mem[tmp] = mem = isapnp_find_mem(cfg->request, tmp);			if (!mem)				return -EINVAL;		}		if (from && mem->res == from) {			while (mem->res != to) {				if (!mem->res->alt)					return -EINVAL;				mem = mem->res->alt->mem;				for (tmp1 = tmp; tmp1 > 0 && mem; tmp1--)					mem = mem->next;				cfg->mem[tmp] = mem;				if (!mem)					return -ENOENT;				cfg->result.resource[tmp + 8].flags = isapnp_mem_resource_flags(mem);			}		}	}	return 0;}static int isapnp_check_port(struct isapnp_cfgtmp *cfg, int port, int size, int idx){	int i, tmp, rport, rsize;	struct isapnp_port *xport;	struct pci_dev *dev;	if (check_region(port, size))		return 1;	for (i = 0; i < 8; i++) {		rport = isapnp_reserve_io[i << 1];		rsize = isapnp_reserve_io[(i << 1) + 1];		if (port >= rport && port < rport + rsize)			return 1;		if (port + size > rport && port + size < (rport + rsize) - 1)			return 1;	}	isapnp_for_each_dev(dev) {		if (dev->active) {			for (tmp = 0; tmp < 8; tmp++) {				if (dev->resource[tmp].flags) {					rport = dev->resource[tmp].start;					rsize = (dev->resource[tmp].end - rport) + 1;					if (port >= rport && port < rport + rsize)						return 1;					if (port + size > rport && port + size < (rport + rsize) - 1)						return 1;				}			}		}	}	for (i = 0; i < 8; i++) {		unsigned int flags;		if (i == idx)			continue;		flags = cfg->request->resource[i].flags;		if (!flags)			continue;		tmp = cfg->request->resource[i].start;		if (flags & IORESOURCE_AUTO) {		/* auto */			xport = cfg->port[i];			if (!xport)				return 1;			if (cfg->result.resource[i].flags & IORESOURCE_AUTO)				continue;			tmp = cfg->result.resource[i].start;			if (tmp + xport->size >= port && tmp <= port + xport->size)				return 1;			continue;		}		if (port == tmp)			return 1;		xport = isapnp_find_port(cfg->request, i);		if (!xport)			return 1;		if (tmp + xport->size >= port && tmp <= port + xport->size)			return 1;	}	return 0;}static int isapnp_valid_port(struct isapnp_cfgtmp *cfg, int idx){	int err;	unsigned long *value1, *value2;	struct isapnp_port *port;	if (!cfg || idx < 0 || idx > 7)		return -EINVAL;	if (!(cfg->result.resource[idx].flags & IORESOURCE_AUTO)) /* don't touch */		return 0;      __again:      	port = cfg->port[idx];      	if (!port)      		return -EINVAL;      	value1 = &cfg->result.resource[idx].start;      	value2 = &cfg->result.resource[idx].end;	if (cfg->result.resource[idx].flags & IORESOURCE_AUTO) {		cfg->result.resource[idx].flags &= ~IORESOURCE_AUTO;		*value1 = port->min;		*value2 = port->min + port->size - 1;		if (!isapnp_check_port(cfg, *value1, port->size, idx))			return 0;	}	do {		*value1 += port->align;		*value2 = *value1 + port->size - 1;		if (*value1 > port->max || !port->align) {			if (port->res && port->res->alt) {				if ((err = isapnp_alternative_switch(cfg, port->res, port->res->alt))<0)					return err;				goto __again;			}			return -ENOENT;		}	} while (isapnp_check_port(cfg, *value1, port->size, idx));	return 0;}static void isapnp_test_handler(int irq, void *dev_id, struct pt_regs *regs){}static int isapnp_check_interrupt(struct isapnp_cfgtmp *cfg, int irq, int idx){	int i;	struct pci_dev *dev;	if (irq < 0 || irq > 15)		return 1;	for (i = 0; i < 16; i++) {		if (isapnp_reserve_irq[i] == irq)			return 1;	}	isapnp_for_each_dev(dev) {		if (dev->active) {			if (dev->irq_resource[0].start == irq ||			    dev->irq_resource[1].start == irq)				return 1;		}	}#ifdef CONFIG_PCI	if (!isapnp_skip_pci_scan) {		pci_for_each_dev(dev) {			if (dev->irq == irq)				return 1;		}	}#endif	if (request_irq(irq, isapnp_test_handler, SA_INTERRUPT, "isapnp", NULL))		return 1;	free_irq(irq, NULL);	for (i = 0; i < DEVICE_COUNT_IRQ; i++) {		if (i == idx)			continue;		if (!cfg->result.irq_resource[i].flags)			continue;		if (cfg->result.irq_resource[i].flags & IORESOURCE_AUTO)			continue;		if (cfg->result.irq_resource[i].start == irq)			return 1;	}	return 0;}static int isapnp_valid_irq(struct isapnp_cfgtmp *cfg, int idx){

⌨️ 快捷键说明

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