📄 isapnp.c
字号:
for (dma = res->dma; dma; dma = dma->next) { if (!index) return dma; index--; } } return NULL;}struct isapnp_mem *isapnp_find_mem(struct pnp_dev *dev, int index){ struct isapnp_resources *res; struct isapnp_mem *mem; if (!dev || index < 0 || index > 7) return NULL; for (res = (struct isapnp_resources *)dev->sysdata; res; res = res->next) { for (mem = res->mem; mem; mem = mem->next) { if (!index) return mem; index--; } } return NULL;}struct isapnp_mem32 *isapnp_find_mem32(struct pnp_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 pnp_bus *isapnp_find_card(unsigned short vendor, unsigned short device, struct pnp_bus *from){ struct pnp_bus *card; if (from == NULL) { from = isapnp_cards; } else { from = from->next; } for (card = from; card; card = card->next) { if (card->vendor == vendor && card->device == device) return card; } return NULL;}struct pnp_dev *isapnp_find_dev(struct pnp_bus *card, unsigned short vendor, unsigned short function, struct pnp_dev *from){ struct pnp_dev *dev; int idx; if (card == NULL) { /* look for a logical device from all cards */ if (from == NULL) { from = isapnp_devices; } else { from = from->next; } for (dev = from; dev; dev = dev->next) { 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; } } else { if (from == NULL) { from = card->devices; } else { from = from->next; } if (from->bus != card) /* something is wrong */ return NULL; for (dev = from; dev; dev = dev->sibling) { 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; } } return NULL;}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 pnp_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 pnp_dev *request; struct pnp_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 pnp_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; } for (dev = isapnp_devices; dev; dev = dev->next) { 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 pnp_dev *dev; if (irq < 0 || irq > 15) return 1; for (i = 0; i < 16; i++) { if (isapnp_reserve_irq[i] == irq) return 1; } for (dev = isapnp_devices; dev; dev = dev->next) { if (dev->active) { if (dev->irq_resource[0].start == irq || dev->irq_resource[1].start == irq) return 1; } } 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){ /* 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 }; int err, i; unsigned long *value1, *value2; struct isapnp_irq *irq; if (!cfg || idx < 0 || idx > 1) return -EINVAL; if (!(cfg->result.irq_resource[idx].flags & IORESOURCE_AUTO)) return 0; __again: irq = cfg->irq[idx]; if (!irq) return -EINVAL; value1 = &cfg->result.irq_resource[idx].start; value2 = &cfg->result.irq_resource[idx].end; if (cfg->result.irq_resource[idx].flags & IORESOURCE_AUTO) { for (i = 0; i < 16 && !(irq->map & (1<<xtab[i])); i++); if (i >= 16) return -ENOENT; cfg->result.irq_resource[idx].flags &= ~IORESOURCE_AUTO; if (!isapnp_check_interrupt(cfg, *value1 = *value2 = xtab[i], idx)) return 0; } do { for (i = 0; i < 16 && xtab[i] != *value1; i++); for (i++; i < 16 && !(irq->map & (1<<xtab[i])); i++); if (i >= 16) { if (irq->res && irq->res->alt) { if ((err = isapnp_alternative_switch(cfg, irq->res, irq->res->alt))<0) return err; goto __again; } return -ENOENT; } else { *value1 = *value2 = xtab[i]; } } while (isapnp_check_interrupt(cfg, *value1, idx)); return 0;}static int isapnp_check_dma(struct isapnp_cfgtmp *cfg, int dma, int idx){ int i; struct pnp_dev *dev; if (dma < 0 || dma == 4 || dma > 7) return 1; for (i = 0; i < 8; i++) { if (isapnp_reserve_dma[i] == dma) return 1; } for (dev = isapnp_devices; dev; dev = dev->next) { if (dev->active) { if (dev->dma_resource[0].start == dma || dev->dma_resource[1].start == dma) return 1; } } if (request_dma(dma, "isapnp")) return 1; free_dma(dma); for (i = 0; i < 2; i++) { if (i == idx) continue; if (!cfg->result.dma_resource[i].flags || (cfg->result.dma_resource[i].flags & IORESOURCE_AUTO)) continue; if (cfg->result.dma_resource[i].start == dma) return 1; } return 0;}static int isapnp_valid_dma(struct isapnp_cfgtmp *cfg, int idx){ int err, i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -