Linux Kernel 2.6.9 for OMAP1710

源代码在线查看: manager.c

软件大小: 44588 K
上传用户: huihuisasa
关键词: Kernel Linux 1710 OMAP
下载地址: 免注册下载 普通下载 VIP

相关代码

				/*				 * manager.c - Resource Management, Conflict Resolution, Activation and Disabling of Devices				 *				 * based on isapnp.c resource management (c) Jaroslav Kysela 				 * Copyright 2003 Adam Belay 				 *				 */								#include 				#include 				#include 				#include 				#include 								#ifdef CONFIG_PNP_DEBUG					#define DEBUG				#else					#undef DEBUG				#endif								#include 				#include "base.h"								DECLARE_MUTEX(pnp_res_mutex);								static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)				{					unsigned long *start, *end, *flags;									if (!dev || !rule)						return -EINVAL;									if (idx >= PNP_MAX_PORT) {						pnp_err("More than 4 ports is incompatible with pnp specifications.");						/* pretend we were successful so at least the manager won't try again */						return 1;					}									/* check if this resource has been manually set, if so skip */					if (!(dev->res.port_resource[idx].flags & IORESOURCE_AUTO))						return 1;									start = &dev->res.port_resource[idx].start;					end = &dev->res.port_resource[idx].end;					flags = &dev->res.port_resource[idx].flags;									/* set the initial values */					*flags |= rule->flags | IORESOURCE_IO;					*flags &=  ~IORESOURCE_UNSET;									if (!rule->size) {						*flags |= IORESOURCE_DISABLED;						return 1; /* skip disabled resource requests */					}									*start = rule->min;					*end = *start + rule->size - 1;									/* run through until pnp_check_port is happy */					while (!pnp_check_port(dev, idx)) {						*start += rule->align;						*end = *start + rule->size - 1;						if (*start > rule->max || !rule->align)							return 0;					}					return 1;				}								static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)				{					unsigned long *start, *end, *flags;									if (!dev || !rule)						return -EINVAL;									if (idx >= PNP_MAX_MEM) {						pnp_err("More than 8 mems is incompatible with pnp specifications.");						/* pretend we were successful so at least the manager won't try again */						return 1;					}									/* check if this resource has been manually set, if so skip */					if (!(dev->res.mem_resource[idx].flags & IORESOURCE_AUTO))						return 1;									start = &dev->res.mem_resource[idx].start;					end = &dev->res.mem_resource[idx].end;					flags = &dev->res.mem_resource[idx].flags;									/* set the initial values */					*flags |= rule->flags | IORESOURCE_MEM;					*flags &=  ~IORESOURCE_UNSET;									/* convert pnp flags to standard Linux flags */					if (!(rule->flags & IORESOURCE_MEM_WRITEABLE))						*flags |= IORESOURCE_READONLY;					if (rule->flags & IORESOURCE_MEM_CACHEABLE)						*flags |= IORESOURCE_CACHEABLE;					if (rule->flags & IORESOURCE_MEM_RANGELENGTH)						*flags |= IORESOURCE_RANGELENGTH;					if (rule->flags & IORESOURCE_MEM_SHADOWABLE)						*flags |= IORESOURCE_SHADOWABLE;									if (!rule->size) {						*flags |= IORESOURCE_DISABLED;						return 1; /* skip disabled resource requests */					}									*start = rule->min;					*end = *start + rule->size -1;									/* run through until pnp_check_mem is happy */					while (!pnp_check_mem(dev, idx)) {						*start += rule->align;						*end = *start + rule->size - 1;						if (*start > rule->max || !rule->align)							return 0;					}					return 1;				}								static int pnp_assign_irq(struct pnp_dev * dev, struct pnp_irq *rule, int idx)				{					unsigned long *start, *end, *flags;					int i;									/* IRQ priority: this table is good for i386 */					static unsigned short xtab[16] = {						5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2					};									if (!dev || !rule)						return -EINVAL;									if (idx >= PNP_MAX_IRQ) {						pnp_err("More than 2 irqs is incompatible with pnp specifications.");						/* pretend we were successful so at least the manager won't try again */						return 1;					}									/* check if this resource has been manually set, if so skip */					if (!(dev->res.irq_resource[idx].flags & IORESOURCE_AUTO))						return 1;									start = &dev->res.irq_resource[idx].start;					end = &dev->res.irq_resource[idx].end;					flags = &dev->res.irq_resource[idx].flags;									/* set the initial values */					*flags |= rule->flags | IORESOURCE_IRQ;					*flags &=  ~IORESOURCE_UNSET;									if (!rule->map) {						*flags |= IORESOURCE_DISABLED;						return 1; /* skip disabled resource requests */					}									for (i = 0; i < 16; i++) {						if(rule->map & (1							*start = *end = xtab[i];							if(pnp_check_irq(dev, idx))								return 1;						}					}					return 0;				}								static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)				{					unsigned long *start, *end, *flags;					int i;									/* DMA priority: this table is good for i386 */					static unsigned short xtab[8] = {						1, 3, 5, 6, 7, 0, 2, 4					};									if (!dev || !rule)						return -EINVAL;									if (idx >= PNP_MAX_DMA) {						pnp_err("More than 2 dmas is incompatible with pnp specifications.");						/* pretend we were successful so at least the manager won't try again */						return 1;					}									/* check if this resource has been manually set, if so skip */					if (!(dev->res.dma_resource[idx].flags & IORESOURCE_AUTO))						return 1;									start = &dev->res.dma_resource[idx].start;					end = &dev->res.dma_resource[idx].end;					flags = &dev->res.dma_resource[idx].flags;									/* set the initial values */					*flags |= rule->flags | IORESOURCE_DMA;					*flags &=  ~IORESOURCE_UNSET;									if (!rule->map) {						*flags |= IORESOURCE_DISABLED;						return 1; /* skip disabled resource requests */					}									for (i = 0; i < 8; i++) {						if(rule->map & (1							*start = *end = xtab[i];							if(pnp_check_dma(dev, idx))								return 1;						}					}					return 0;				}								/**				 * pnp_init_resources - Resets a resource table to default values.				 * @table: pointer to the desired resource table				 *				 */				void pnp_init_resource_table(struct pnp_resource_table *table)				{					int idx;					for (idx = 0; idx < PNP_MAX_IRQ; idx++) {						table->irq_resource[idx].name = NULL;						table->irq_resource[idx].start = -1;						table->irq_resource[idx].end = -1;						table->irq_resource[idx].flags = IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;					}					for (idx = 0; idx < PNP_MAX_DMA; idx++) {						table->dma_resource[idx].name = NULL;						table->dma_resource[idx].start = -1;						table->dma_resource[idx].end = -1;						table->dma_resource[idx].flags = IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;					}					for (idx = 0; idx < PNP_MAX_PORT; idx++) {						table->port_resource[idx].name = NULL;						table->port_resource[idx].start = 0;						table->port_resource[idx].end = 0;						table->port_resource[idx].flags = IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;					}					for (idx = 0; idx < PNP_MAX_MEM; idx++) {						table->mem_resource[idx].name = NULL;						table->mem_resource[idx].start = 0;						table->mem_resource[idx].end = 0;						table->mem_resource[idx].flags = IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET;					}				}								/**				 * pnp_clean_resources - clears resources that were not manually set				 * @res - the resources to clean				 *				 */				static void pnp_clean_resource_table(struct pnp_resource_table * res)				{					int idx;					for (idx = 0; idx < PNP_MAX_IRQ; idx++) {						if (!(res->irq_resource[idx].flags & IORESOURCE_AUTO))							continue;						res->irq_resource[idx].start = -1;						res->irq_resource[idx].end = -1;						res->irq_resource[idx].flags = IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;					}					for (idx = 0; idx < PNP_MAX_DMA; idx++) {						if (!(res->dma_resource[idx].flags & IORESOURCE_AUTO))							continue;						res->dma_resource[idx].start = -1;						res->dma_resource[idx].end = -1;						res->dma_resource[idx].flags = IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;					}					for (idx = 0; idx < PNP_MAX_PORT; idx++) {						if (!(res->port_resource[idx].flags & IORESOURCE_AUTO))							continue;						res->port_resource[idx].start = 0;						res->port_resource[idx].end = 0;						res->port_resource[idx].flags = IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;					}					for (idx = 0; idx < PNP_MAX_MEM; idx++) {						if (!(res->mem_resource[idx].flags & IORESOURCE_AUTO))							continue;						res->mem_resource[idx].start = 0;						res->mem_resource[idx].end = 0;						res->mem_resource[idx].flags = IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET;					}				}								/**				 * pnp_assign_resources - assigns resources to the device based on the specified dependent number				 * @dev: pointer to the desired device				 * @depnum: the dependent function number				 *				 * Only set depnum to 0 if the device does not have dependent options.				 */				int pnp_assign_resources(struct pnp_dev *dev, int depnum)				{					struct pnp_port *port;					struct pnp_mem *mem;					struct pnp_irq *irq;					struct pnp_dma *dma;					int nport = 0, nmem = 0, nirq = 0, ndma = 0;									if (!pnp_can_configure(dev))						return -ENODEV;									down(&pnp_res_mutex);					pnp_clean_resource_table(&dev->res); /* start with a fresh slate */					if (dev->independent) {						port = dev->independent->port;						mem = dev->independent->mem;						irq = dev->independent->irq;						dma = dev->independent->dma;						while (port) {							if (!pnp_assign_port(dev, port, nport))								goto fail;							nport++;							port = port->next;						}						while (mem) {							if (!pnp_assign_mem(dev, mem, nmem))								goto fail;							nmem++;							mem = mem->next;						}						while (irq) {							if (!pnp_assign_irq(dev, irq, nirq))								goto fail;							nirq++;							irq = irq->next;						}						while (dma) {							if (!pnp_assign_dma(dev, dma, ndma))								goto fail;							ndma++;							dma = dma->next;						}					}									if (depnum) {						struct pnp_option *dep;						int i;						for (i=1,dep=dev->dependent; inext)							if(!dep)								goto fail;						port =dep->port;						mem = dep->mem;						irq = dep->irq;						dma = dep->dma;						while (port) {							if (!pnp_assign_port(dev, port, nport))								goto fail;							nport++;							port = port->next;						}						while (mem) {							if (!pnp_assign_mem(dev, mem, nmem))								goto fail;							nmem++;							mem = mem->next;						}						while (irq) {							if (!pnp_assign_irq(dev, irq, nirq))								goto fail;							nirq++;							irq = irq->next;						}						while (dma) {							if (!pnp_assign_dma(dev, dma, ndma))								goto fail;							ndma++;							dma = dma->next;						}					} else if (dev->dependent)						goto fail;									up(&pnp_res_mutex);					return 1;								fail:					pnp_clean_resource_table(&dev->res);					up(&pnp_res_mutex);					return 0;				}								/**				 * pnp_manual_config_dev - Disables Auto Config and Manually sets the resource table				 * @dev: pointer to the desired device				 * @res: pointer to the new resource config				 *				 * This function can be used by drivers that want to manually set thier resources.				 */				int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table * res, int mode)				{					int i;					struct pnp_resource_table * bak;					if (!dev || !res)						return -EINVAL;					if (!pnp_can_configure(dev))						return -ENODEV;					bak = pnp_alloc(sizeof(struct pnp_resource_table));					if (!bak)						return -ENOMEM;					*bak = dev->res;									down(&pnp_res_mutex);					dev->res = *res;					if (!(mode & PNP_CONFIG_FORCE)) {						for (i = 0; i < PNP_MAX_PORT; i++) {							if(!pnp_check_port(dev,i))								goto fail;						}						for (i = 0; i < PNP_MAX_MEM; i++) {							if(!pnp_check_mem(dev,i))								goto fail;						}						for (i = 0; i < PNP_MAX_IRQ; i++) {							if(!pnp_check_irq(dev,i))								goto fail;						}						for (i = 0; i < PNP_MAX_DMA; i++) {							if(!pnp_check_dma(dev,i))								goto fail;						}					}					up(&pnp_res_mutex);									kfree(bak);					return 0;								fail:					dev->res = *bak;					up(&pnp_res_mutex);					kfree(bak);					return -EINVAL;				}								/**				 * pnp_auto_config_dev - automatically assigns resources to a device				 * @dev: pointer to the desired device				 *				 */				int pnp_auto_config_dev(struct pnp_dev *dev)				{					struct pnp_option *dep;					int i = 1;									if(!dev)						return -EINVAL;									if(!pnp_can_configure(dev)) {						pnp_info("Device %s does not support resource configuration.", dev->dev.bus_id);						return -ENODEV;					}									if (!dev->dependent) {						if (pnp_assign_resources(dev, 0))							return 0;					} else {						dep = dev->dependent;						do {							if (pnp_assign_resources(dev, i))								return 0;							dep = dep->next;							i++;						} while (dep);					}									pnp_err("Unable to assign resources to device %s.", dev->dev.bus_id);					return -EBUSY;				}								/**				 * pnp_activate_dev - activates a PnP device for use				 * @dev: pointer to the desired device				 *				 * does not validate or set resources so be careful.				 */				int pnp_activate_dev(struct pnp_dev *dev)				{					if (!dev)						return -EINVAL;					if (dev->active) {						return 0; /* the device is already active */					}									/* ensure resources are allocated */					if (pnp_auto_config_dev(dev))						return -EBUSY;									if (!pnp_can_write(dev)) {						pnp_info("Device %s does not supported activation.", dev->dev.bus_id);						return -EINVAL;					}									if (dev->protocol->set(dev, &dev->res)						pnp_err("Failed to activate device %s.", dev->dev.bus_id);						return -EIO;					}									dev->active = 1;					pnp_info("Device %s activated.", dev->dev.bus_id);									return 1;				}								/**				 * pnp_disable_dev - disables device				 * @dev: pointer to the desired device				 *				 * inform the correct pnp protocol so that resources can be used by other devices				 */				int pnp_disable_dev(struct pnp_dev *dev)				{				        if (!dev)				                return -EINVAL;					if (!dev->active) {						return 0; /* the device is already disabled */					}									if (!pnp_can_disable(dev)) {						pnp_info("Device %s does not supported disabling.", dev->dev.bus_id);						return -EINVAL;					}					if (dev->protocol->disable(dev)						pnp_err("Failed to disable device %s.", dev->dev.bus_id);						return -EIO;					}									dev->active = 0;					pnp_info("Device %s disabled.", dev->dev.bus_id);									/* release the resources so that other devices can use them */					down(&pnp_res_mutex);					pnp_clean_resource_table(&dev->res);					up(&pnp_res_mutex);									return 1;				}								/**				 * pnp_resource_change - change one resource				 * @resource: pointer to resource to be changed				 * @start: start of region				 * @size: size of region				 *				 */				void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size)				{					if (resource == NULL)						return;					resource->flags &= ~(IORESOURCE_AUTO | IORESOURCE_UNSET);					resource->start = start;					resource->end = start + size - 1;				}												EXPORT_SYMBOL(pnp_assign_resources);				EXPORT_SYMBOL(pnp_manual_config_dev);				EXPORT_SYMBOL(pnp_auto_config_dev);				EXPORT_SYMBOL(pnp_activate_dev);				EXPORT_SYMBOL(pnp_disable_dev);				EXPORT_SYMBOL(pnp_resource_change);				EXPORT_SYMBOL(pnp_init_resource_table);							

相关资源