static void quirk_awe32_resources(struct pnp_dev *dev) { struct pnp_port *port, *port2, *port3; struct pnp_option *res = dev->dependent; /* * Unfortunately the isapnp_add_port_resource is too tightly bound * into the PnP discovery sequence, and cannot be used. Link in the * two extra ports (at offset 0x400 and 0x800 from the one given) by * hand. */ for ( ; res ; res = res->next ) { port2 = pnp_alloc(sizeof(struct pnp_port)); if (!port2) return; port3 = pnp_alloc(sizeof(struct pnp_port)); if (!port3) { kfree(port2); return; } port = res->port; memcpy(port2, port, sizeof(struct pnp_port)); memcpy(port3, port, sizeof(struct pnp_port)); port->next = port2; port2->next = port3; port2->min += 0x400; port2->max += 0x400; port3->min += 0x800; port3->max += 0x800; } printk(KERN_INFO "pnp: AWE32 quirk - adding two ports\n"); }
static ssize_t pnp_show_options(struct device *dmdev, struct device_attribute *attr, char *buf) { struct pnp_dev *dev = to_pnp_dev(dmdev); struct pnp_option * independent = dev->independent; struct pnp_option * dependent = dev->dependent; int ret, dep = 1; pnp_info_buffer_t *buffer = (pnp_info_buffer_t *) pnp_alloc(sizeof(pnp_info_buffer_t)); if (!buffer) return -ENOMEM; buffer->len = PAGE_SIZE; buffer->buffer = buf; buffer->curr = buffer->buffer; if (independent) pnp_print_option(buffer, "", independent, 0); while (dependent){ pnp_print_option(buffer, " ", dependent, dep); dependent = dependent->next; dep++; } ret = (buffer->curr - buf); kfree(buffer); return ret; }
static struct pnp_option * pnp_build_option(int priority) { struct pnp_option *option = pnp_alloc(sizeof(struct pnp_option)); /* check if pnp_alloc ran out of memory */ if (!option) return NULL; option->priority = priority & 0xff; /* make sure the priority is valid */ if (option->priority > PNP_RES_PRIORITY_FUNCTIONAL) option->priority = PNP_RES_PRIORITY_INVALID; return option; }
static struct pnp_option *quirk_isapnp_mpu_options(struct pnp_dev *dev) { struct pnp_option *head = NULL; struct pnp_option *prev = NULL; struct pnp_option *res; /* * Build a functional IRQ-less variant of each MPU option. */ for (res = dev->dependent; res; res = res->next) { struct pnp_option *curr; struct pnp_port *port; struct pnp_port *copy; port = res->port; if (!port || !res->irq) continue; copy = pnp_alloc(sizeof *copy); if (!copy) break; copy->min = port->min; copy->max = port->max; copy->align = port->align; copy->size = port->size; copy->flags = port->flags; curr = pnp_build_option(PNP_RES_PRIORITY_FUNCTIONAL); if (!curr) { kfree(copy); break; } curr->port = copy; if (prev) prev->next = curr; else head = curr; prev = curr; } if (head) dev_info(&dev->dev, "adding IRQ-less MPU options\n"); return head; }
static void quirk_ad1815_mpu_resources(struct pnp_dev *dev) { struct pnp_option *res; struct pnp_irq *irq; /* * Distribute the independent IRQ over the dependent options */ res = dev->independent; if (!res) return; irq = res->irq; if (!irq || irq->next) return; res = dev->dependent; if (!res) return; while (1) { struct pnp_irq *copy; copy = pnp_alloc(sizeof *copy); if (!copy) break; memcpy(copy->map, irq->map, sizeof copy->map); copy->flags = irq->flags; copy->next = res->irq; /* Yes, this is NULL */ res->irq = copy; if (!res->next) break; res = res->next; } kfree(irq); res->next = quirk_isapnp_mpu_options(dev); res = dev->independent; res->irq = NULL; }
/** * 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 * @mode: 0 or PNP_CONFIG_FORCE * * 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; }
static ssize_t pnp_show_current_resources(struct device *dmdev, struct device_attribute *attr, char *buf) { struct pnp_dev *dev = to_pnp_dev(dmdev); int i, ret; pnp_info_buffer_t *buffer; if (!dev) return -EINVAL; buffer = (pnp_info_buffer_t *) pnp_alloc(sizeof(pnp_info_buffer_t)); if (!buffer) return -ENOMEM; buffer->len = PAGE_SIZE; buffer->buffer = buf; buffer->curr = buffer->buffer; pnp_printf(buffer,"state = "); if (dev->active) pnp_printf(buffer,"active\n"); else pnp_printf(buffer,"disabled\n"); for (i = 0; i < PNP_MAX_PORT; i++) { if (pnp_port_valid(dev, i)) { pnp_printf(buffer,"io"); if (pnp_port_flags(dev, i) & IORESOURCE_DISABLED) pnp_printf(buffer," disabled\n"); else pnp_printf(buffer," 0x%llx-0x%llx\n", (unsigned long long)pnp_port_start(dev, i), (unsigned long long)pnp_port_end(dev, i)); } } for (i = 0; i < PNP_MAX_MEM; i++) { if (pnp_mem_valid(dev, i)) { pnp_printf(buffer,"mem"); if (pnp_mem_flags(dev, i) & IORESOURCE_DISABLED) pnp_printf(buffer," disabled\n"); else pnp_printf(buffer," 0x%llx-0x%llx\n", (unsigned long long)pnp_mem_start(dev, i), (unsigned long long)pnp_mem_end(dev, i)); } } for (i = 0; i < PNP_MAX_IRQ; i++) { if (pnp_irq_valid(dev, i)) { pnp_printf(buffer,"irq"); if (pnp_irq_flags(dev, i) & IORESOURCE_DISABLED) pnp_printf(buffer," disabled\n"); else pnp_printf(buffer," %lld\n", (unsigned long long)pnp_irq(dev, i)); } } for (i = 0; i < PNP_MAX_DMA; i++) { if (pnp_dma_valid(dev, i)) { pnp_printf(buffer,"dma"); if (pnp_dma_flags(dev, i) & IORESOURCE_DISABLED) pnp_printf(buffer," disabled\n"); else pnp_printf(buffer," %lld\n", (unsigned long long)pnp_dma(dev, i)); } } ret = (buffer->curr - buf); kfree(buffer); return ret; }