📄 isapnp.c
字号:
/* 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 pci_dev *dev; /* Some machines allow DMA 0, but others don't. In fact on some boxes DMA 0 is the memory refresh. Play safe */ if (dma < 1 || dma == 4 || dma > 7) return 1; for (i = 0; i < 8; i++) { if (isapnp_reserve_dma[i] == dma) return 1; } isapnp_for_each_dev(dev) { 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; unsigned long *value1, *value2; struct isapnp_dma *dma; if (!cfg || idx < 0 || idx > 1) return -EINVAL; if (!(cfg->result.dma_resource[idx].flags & IORESOURCE_AUTO)) /* don't touch */ return 0; __again: dma = cfg->dma[idx]; if (!dma) return -EINVAL; value1 = &cfg->result.dma_resource[idx].start; value2 = &cfg->result.dma_resource[idx].end; if (cfg->result.dma_resource[idx].flags & IORESOURCE_AUTO) { for (i = 0; i < 8 && !(dma->map & (1<<i)); i++); if (i >= 8) return -ENOENT; cfg->result.dma_resource[idx].flags &= ~IORESOURCE_AUTO; if (!isapnp_check_dma(cfg, *value1 = *value2 = i, idx)) return 0; } do { for (i = *value1 + 1; i < 8 && !(dma->map & (1<<i)); i++); if (i >= 8) { if (dma->res && dma->res->alt) { if ((err = isapnp_alternative_switch(cfg, dma->res, dma->res->alt))<0) return err; goto __again; } return -ENOENT; } else { *value1 = *value2 = i; } } while (isapnp_check_dma(cfg, *value1, idx)); return 0;}static int isapnp_check_mem(struct isapnp_cfgtmp *cfg, unsigned int addr, unsigned int size, int idx){ int i, tmp; unsigned int raddr, rsize; struct isapnp_mem *xmem; struct pci_dev *dev; for (i = 0; i < 8; i++) { raddr = (unsigned int)isapnp_reserve_mem[i << 1]; rsize = (unsigned int)isapnp_reserve_mem[(i << 1) + 1]; if (addr >= raddr && addr < raddr + rsize) return 1; if (addr + size > raddr && addr + size < (raddr + rsize) - 1) return 1; if (__check_region(&iomem_resource, addr, size)) return 1; } isapnp_for_each_dev(dev) { if (dev->active) { for (tmp = 0; tmp < 4; tmp++) { if (dev->resource[tmp].flags) { raddr = dev->resource[tmp + 8].start; rsize = (dev->resource[tmp + 8].end - raddr) + 1; if (addr >= raddr && addr < raddr + rsize) return 1; if (addr + size > raddr && addr + size < (raddr + rsize) - 1) return 1; } } } } for (i = 0; i < 4; i++) { unsigned int flags = cfg->request->resource[i + 8].flags; if (i == idx) continue; if (!flags) continue; tmp = cfg->result.resource[i + 8].start; if (flags & IORESOURCE_AUTO) { /* auto */ xmem = cfg->mem[i]; if (!xmem) return 1; if (cfg->result.resource[i + 8].flags & IORESOURCE_AUTO) continue; if (tmp + xmem->size >= addr && tmp <= addr + xmem->size) return 1; continue; } if (addr == tmp) return 1; xmem = isapnp_find_mem(cfg->request, i); if (!xmem) return 1; if (tmp + xmem->size >= addr && tmp <= addr + xmem->size) return 1; } return 0;}static int isapnp_valid_mem(struct isapnp_cfgtmp *cfg, int idx){ int err; unsigned long *value1, *value2; struct isapnp_mem *mem; if (!cfg || idx < 0 || idx > 3) return -EINVAL; if (!(cfg->result.resource[idx + 8].flags & IORESOURCE_AUTO)) /* don't touch */ return 0; __again: mem = cfg->mem[idx]; if (!mem) return -EINVAL; value1 = &cfg->result.resource[idx + 8].start; value2 = &cfg->result.resource[idx + 8].end; if (cfg->result.resource[idx + 8].flags & IORESOURCE_AUTO) { cfg->result.resource[idx + 8].flags &= ~IORESOURCE_AUTO; *value1 = mem->min; *value2 = mem->min + mem->size - 1; if (!isapnp_check_mem(cfg, *value1, mem->size, idx)) return 0; } do { *value1 += mem->align; *value2 = *value1 + mem->size - 1; if (*value1 > mem->max || !mem->align) { if (mem->res && mem->res->alt) { if ((err = isapnp_alternative_switch(cfg, mem->res, mem->res->alt))<0) return err; goto __again; } return -ENOENT; } } while (isapnp_check_mem(cfg, *value1, mem->size, idx)); return 0;}static int isapnp_check_valid(struct isapnp_cfgtmp *cfg){ int tmp; for (tmp = 0; tmp < 8; tmp++) if (cfg->result.resource[tmp].flags & IORESOURCE_AUTO) return -EAGAIN; for (tmp = 0; tmp < 2; tmp++) if (cfg->result.irq_resource[tmp].flags & IORESOURCE_AUTO) return -EAGAIN; for (tmp = 0; tmp < 2; tmp++) if (cfg->result.dma_resource[tmp].flags & IORESOURCE_AUTO) return -EAGAIN; for (tmp = 0; tmp < 4; tmp++) if (cfg->result.resource[tmp + 8].flags & IORESOURCE_AUTO) return -EAGAIN; return 0;}static int isapnp_config_activate(struct pci_dev *dev){ struct isapnp_cfgtmp cfg; int tmp, fauto, err; if (!dev) return -EINVAL; if (dev->active) return -EBUSY; memset(&cfg, 0, sizeof(cfg)); cfg.request = dev; memcpy(&cfg.result, dev, sizeof(struct pci_dev)); /* check if all values are set, otherwise try auto-configuration */ for (tmp = fauto = 0; !fauto && tmp < 8; tmp++) { if (dev->resource[tmp].flags & IORESOURCE_AUTO) fauto++; } for (tmp = 0; !fauto && tmp < 2; tmp++) { if (dev->irq_resource[tmp].flags & IORESOURCE_AUTO) fauto++; } for (tmp = 0; !fauto && tmp < 2; tmp++) { if (dev->dma_resource[tmp].flags & IORESOURCE_AUTO) fauto++; } for (tmp = 0; !fauto && tmp < 4; tmp++) { if (dev->resource[tmp + 8].flags & IORESOURCE_AUTO) fauto++; } if (!fauto) goto __skip_auto; /* set variables to initial values */ if ((err = isapnp_alternative_switch(&cfg, NULL, NULL))<0) return err; /* find first valid configuration */ fauto = 0; do { for (tmp = 0; tmp < 8 && cfg.result.resource[tmp].flags; tmp++) if ((err = isapnp_valid_port(&cfg, tmp))<0) return err; for (tmp = 0; tmp < 2 && cfg.result.irq_resource[tmp].flags; tmp++) if ((err = isapnp_valid_irq(&cfg, tmp))<0) return err; for (tmp = 0; tmp < 2 && cfg.result.dma_resource[tmp].flags; tmp++) if ((err = isapnp_valid_dma(&cfg, tmp))<0) return err; for (tmp = 0; tmp < 4 && cfg.result.resource[tmp + 8].flags; tmp++) if ((err = isapnp_valid_mem(&cfg, tmp))<0) return err; } while (isapnp_check_valid(&cfg)<0 && fauto++ < 20); if (fauto >= 20) return -EAGAIN; __skip_auto: /* we have valid configuration, try configure hardware */ isapnp_cfg_begin(dev->bus->number, dev->devfn); dev->active = 1; dev->irq_resource[0] = cfg.result.irq_resource[0]; dev->irq_resource[1] = cfg.result.irq_resource[1]; dev->dma_resource[0] = cfg.result.dma_resource[0]; dev->dma_resource[1] = cfg.result.dma_resource[1]; for (tmp = 0; tmp < 12; tmp++) { dev->resource[tmp] = cfg.result.resource[tmp]; } for (tmp = 0; tmp < 8 && dev->resource[tmp].flags; tmp++) isapnp_write_word(ISAPNP_CFG_PORT+(tmp<<1), dev->resource[tmp].start); for (tmp = 0; tmp < 2 && dev->irq_resource[tmp].flags; tmp++) { int irq = dev->irq_resource[tmp].start; if (irq == 2) irq = 9; isapnp_write_byte(ISAPNP_CFG_IRQ+(tmp<<1), irq); } for (tmp = 0; tmp < 2 && dev->dma_resource[tmp].flags; tmp++) isapnp_write_byte(ISAPNP_CFG_DMA+tmp, dev->dma_resource[tmp].start); for (tmp = 0; tmp < 4 && dev->resource[tmp+8].flags; tmp++) isapnp_write_word(ISAPNP_CFG_MEM+(tmp<<2), (dev->resource[tmp + 8].start >> 8) & 0xffff); isapnp_activate(dev->devfn); isapnp_cfg_end(); return 0;}static int isapnp_config_deactivate(struct pci_dev *dev){ if (!dev || !dev->active) return -EINVAL; isapnp_cfg_begin(dev->bus->number, dev->devfn); isapnp_deactivate(dev->devfn); dev->active = 0; isapnp_cfg_end(); return 0;}void isapnp_resource_change(struct resource *resource, unsigned long start, unsigned long size){ if (resource == NULL) return; resource->flags &= ~IORESOURCE_AUTO; resource->start = start; resource->end = start + size - 1;}/* * Inititialization. */#ifdef MODULEstatic void isapnp_free_port(struct isapnp_port *port){ struct isapnp_port *next; while (port) { next = port->next; kfree(port); port = next; }}static void isapnp_free_irq(struct isapnp_irq *irq){ struct isapnp_irq *next; while (irq) { next = irq->next; kfree(irq); irq = next; }}static void isapnp_free_dma(struct isapnp_dma *dma){ struct isapnp_dma *next; while (dma) { next = dma->next; kfree(dma); dma = next; }}static void isapnp_free_mem(struct isapnp_mem *mem){ struct isapnp_mem *next; while (mem) { next = mem->next; kfree(mem); mem = next; }}static void isapnp_free_mem32(struct isapnp_mem32 *mem32){ struct isapnp_mem32 *next; while (mem32) { next = mem32->next; kfree(mem32); mem32 = next; }}static void isapnp_free_resources(struct isapnp_resources *resources, int alt){ struct isapnp_resources *next; while (resources) { next = alt ? resources->alt : resources->next; isapnp_free_port(resources->port); isapnp_free_irq(resources->irq); isapnp_free_dma(resources->dma); isapnp_free_mem(resources->mem); isapnp_free_mem32(resources->mem32); if (!alt && resources->alt) isapnp_free_resources(resources->alt, 1); kfree(resources); resources = next; }}static void isapnp_free_card(struct pci_bus *card){ while (!list_empty(&card->devices)) { struct list_head *list = card->devices.next; struct pci_dev *dev = pci_dev_b(list); list_del(list); isapnp_free_resources((struct isapnp_resources *)dev->sysdata, 0); kfree(dev); } kfree(card);}#endif /* MODULE */static void isapnp_free_all_resources(void){#ifdef ISAPNP_REGION_OK if (pidxr_res) release_resource(pidxr_res);#endif if (pnpwrp_res) release_resource(pnpwrp_res); if (isapnp_rdp >= 0x203 && isapnp_rdp <= 0x3ff && isapnp_rdp_res) release_resource(isapnp_rdp_res);#ifdef MODULE#ifdef CONFIG_PROC_FS isapnp_proc_done();#endif while (!list_empty(&isapnp_cards)) { struct list_head *list = isapnp_cards.next; list_del(list); isapnp_free_card(pci_bus_b(list)); }#endif}EXPORT_SYMBOL(isapnp_cards);EXPORT_SYMBOL(isapnp_devices);EXPORT_SYMBOL(isapnp_present);EXPORT_SYMBOL(isapnp_cfg_begin);EXPORT_SYMBOL(isapnp_cfg_end);EXPORT_SYMBOL(isapnp_read_byte);EXPORT_SYMBOL(isapnp_read_word);EXPORT_SYMBOL(isapnp_read_dword);EXPORT_SYMBOL(isapnp_write_byte);EXPORT_SYMBOL(isapnp_write_word);EXPORT_SYMBOL(isapnp_write_dword);EXPORT_SYMBOL(isapnp_wake);EXPORT_SYMBOL(isapnp_device);EXPORT_SYMBOL(isapnp_activate);EXPORT_SYMBOL(isapnp_deactivate);EXPORT_SYMBOL(isapnp_find_card);EXPORT_SYMBOL(isapnp_find_dev);EXPORT_SYMBOL(isapnp_probe_cards);EXPORT_SYMBOL(isapnp_probe_devs);EXPORT_SYMBOL(isapnp_activate_dev);EXPORT_SYMBOL(isapnp_resource_change);int __init isapnp_init(void){ int cards; struct pci_bus *card; if (isapnp_disable) { isapnp_detected = 0; printk("isapnp: ISA Plug & Play support disabled\n"); return 0; }#ifdef ISAPNP_REGION_OK pidxr_res=request_region(_PIDXR, 1, "isapnp index"); if(!pidxr_res) { printk("isapnp: Index Register 0x%x already used\n", _PIDXR); return -EBUSY; }#endif pnpwrp_res=request_region(_PNPWRP, 1, "isapnp write"); if(!pnpwrp_res) { printk("isapnp: Write Data Register 0x%x already used\n", _PNPWRP); return -EBUSY; } /* * Print a message. The existing ISAPnP code is hanging machines * so let the user know where. */ printk("isapnp: Scanning for Pnp cards...\n"); if (isapnp_rdp >= 0x203 && isapnp_rdp <= 0x3ff) { isapnp_rdp |= 3; isapnp_rdp_res=request_region(isapnp_rdp, 1, "isapnp read"); if(!isapnp_rdp_res) { printk("isapnp: Read Data Register 0x%x already used\n", isapnp_rdp); return -EBUSY; } isapnp_set_rdp(); } isapnp_detected = 1; if (isapnp_rdp < 0x203 || isapnp_rdp > 0x3ff) { cards = isapnp_isolate(); if (cards < 0 || (isapnp_rdp < 0x203 || isapnp_rdp > 0x3ff)) { isapnp_free_all_resources(); isapnp_detected = 0; printk("isapnp: No Plug & Play device found\n"); return 0; } isapnp_rdp_res=request_region(isapnp_rdp, 1, "isapnp read"); } isapnp_build_device_list(); cards = 0; isapnp_for_each_card(card) { cards++; if (isapnp_verbose) { struct list_head *devlist; printk( "isapnp: Card '%s'\n", card->name[0]?card->name:"Unknown"); if (isapnp_verbose < 2) continue; for (devlist = card->devices.next; devlist != &card->devices; devlist = devlist->next) { struct pci_dev *dev = pci_dev_b(devlist); printk("isapnp: Device '%s'\n", dev->name[0]?card->name:"Unknown"); } } } if (cards) { printk("isapnp: %i Plug & Play card%s detected total\n", cards, cards>1?"s":""); } else { printk("isapnp: No Plug & Play card found\n"); }#ifdef CONFIG_PROC_FS isapnp_proc_init();#endif return 0;}#ifdef MODULEint init_module(void){ return isapnp_init();}void cleanup_module(void){ if (isapnp_detected) isapnp_free_all_resources();}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -