📄 core.c
字号:
/* * Add 32-bit fixed memory resource to resources list. */static void __init isapnp_parse_fixed_mem32_resource(struct pnp_option *option, int size){ unsigned char tmp[9]; struct pnp_mem *mem; isapnp_peek(tmp, size); mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL); if (!mem) return; mem->min = mem->max = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1]; mem->size = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5]; mem->align = 0; mem->flags = tmp[0]; pnp_register_mem_resource(option,mem);}/* * Parse card name for ISA PnP device. */ static void __initisapnp_parse_name(char *name, unsigned int name_max, unsigned short *size){ if (name[0] == '\0') { unsigned short size1 = *size >= name_max ? (name_max - 1) : *size; isapnp_peek(name, size1); name[size1] = '\0'; *size -= size1; /* clean whitespace from end of string */ while (size1 > 0 && name[--size1] == ' ') name[size1] = '\0'; }}/* * Parse resource map for logical device. */static int __init isapnp_create_device(struct pnp_card *card, unsigned short size){ int number = 0, skip = 0, priority = 0, compat = 0; unsigned char type, tmp[17]; struct pnp_option *option; struct pnp_dev *dev; if ((dev = isapnp_parse_device(card, size, number++)) == NULL) return 1; option = pnp_register_independent_option(dev); if (!option) { kfree(dev); return 1; } pnp_add_card_device(card,dev); while (1) { if (isapnp_read_tag(&type, &size)<0) return 1; if (skip && type != _STAG_LOGDEVID && type != _STAG_END) goto __skip; switch (type) { case _STAG_LOGDEVID: if (size >= 5 && size <= 6) { if ((dev = isapnp_parse_device(card, size, number++)) == NULL) return 1; size = 0; skip = 0; option = pnp_register_independent_option(dev); if (!option) return 1; pnp_add_card_device(card,dev); } else { skip = 1; } priority = 0; compat = 0; break; case _STAG_COMPATDEVID: if (size == 4 && compat < DEVICE_COUNT_COMPATIBLE) { isapnp_peek(tmp, 4); isapnp_parse_id(dev,(tmp[1] << 8) | tmp[0], (tmp[3] << 8) | tmp[2]); compat++; size = 0; } break; case _STAG_IRQ: if (size < 2 || size > 3) goto __skip; isapnp_parse_irq_resource(option, size); size = 0; break; case _STAG_DMA: if (size != 2) goto __skip; isapnp_parse_dma_resource(option, size); size = 0; break; case _STAG_STARTDEP: if (size > 1) goto __skip; priority = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE; if (size > 0) { isapnp_peek(tmp, size); priority = 0x100 | tmp[0]; size = 0; } option = pnp_register_dependent_option(dev,priority); if (!option) return 1; break; case _STAG_ENDDEP: if (size != 0) goto __skip; priority = 0; break; case _STAG_IOPORT: if (size != 7) goto __skip; isapnp_parse_port_resource(option, size); size = 0; break; case _STAG_FIXEDIO: if (size != 3) goto __skip; isapnp_parse_fixed_port_resource(option, size); size = 0; break; case _STAG_VENDOR: break; case _LTAG_MEMRANGE: if (size != 9) goto __skip; isapnp_parse_mem_resource(option, size); size = 0; break; case _LTAG_ANSISTR: isapnp_parse_name(dev->name, sizeof(dev->name), &size); break; case _LTAG_UNICODESTR: /* silently ignore */ /* who use unicode for hardware identification? */ break; case _LTAG_VENDOR: break; case _LTAG_MEM32RANGE: if (size != 17) goto __skip; isapnp_parse_mem32_resource(option, size); size = 0; break; case _LTAG_FIXEDMEM32RANGE: if (size != 9) goto __skip; isapnp_parse_fixed_mem32_resource(option, size); size = 0; break; case _STAG_END: if (size > 0) isapnp_skip_bytes(size); return 1; default: printk(KERN_ERR "isapnp: unexpected or unknown tag type 0x%x for logical device %i (device %i), ignored\n", type, dev->number, card->number); } __skip: if (size > 0) isapnp_skip_bytes(size); } return 0;}/* * Parse resource map for ISA PnP card. */static void __init isapnp_parse_resource_map(struct pnp_card *card){ unsigned char type, tmp[17]; unsigned short size; while (1) { if (isapnp_read_tag(&type, &size)<0) return; switch (type) { case _STAG_PNPVERNO: if (size != 2) goto __skip; isapnp_peek(tmp, 2); card->pnpver = tmp[0]; card->productver = tmp[1]; size = 0; break; case _STAG_LOGDEVID: if (size >= 5 && size <= 6) { if (isapnp_create_device(card, size)==1) return; size = 0; } break; case _STAG_VENDOR: break; case _LTAG_ANSISTR: isapnp_parse_name(card->name, sizeof(card->name), &size); break; case _LTAG_UNICODESTR: /* silently ignore */ /* who use unicode for hardware identification? */ break; case _LTAG_VENDOR: break; case _STAG_END: if (size > 0) isapnp_skip_bytes(size); return; default: printk(KERN_ERR "isapnp: unexpected or unknown tag type 0x%x for device %i, ignored\n", type, card->number); } __skip: if (size > 0) isapnp_skip_bytes(size); }}/* * Compute ISA PnP checksum for first eight bytes. */static unsigned char __init isapnp_checksum(unsigned char *data){ int i, j; unsigned char checksum = 0x6a, bit, b; for (i = 0; i < 8; i++) { b = data[i]; for (j = 0; j < 8; j++) { bit = 0; if (b & (1 << j)) bit = 1; checksum = ((((checksum ^ (checksum >> 1)) & 0x01) ^ bit) << 7) | (checksum >> 1); } } return checksum;}/* * Parse EISA id for ISA PnP card. */static void isapnp_parse_card_id(struct pnp_card * card, unsigned short vendor, unsigned short device){ struct pnp_id * id = kcalloc(1, sizeof(struct pnp_id), GFP_KERNEL); if (!id) return; sprintf(id->id, "%c%c%c%x%x%x%x", 'A' + ((vendor >> 2) & 0x3f) - 1, 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1, 'A' + ((vendor >> 8) & 0x1f) - 1, (device >> 4) & 0x0f, device & 0x0f, (device >> 12) & 0x0f, (device >> 8) & 0x0f); pnp_add_card_id(id,card);}/* * Build device list for all present ISA PnP devices. */static int __init isapnp_build_device_list(void){ int csn; unsigned char header[9], checksum; struct pnp_card *card; isapnp_wait(); isapnp_key(); for (csn = 1; csn <= isapnp_csn_count; csn++) { isapnp_wake(csn); isapnp_peek(header, 9); checksum = isapnp_checksum(header);#if 0 printk(KERN_DEBUG "vendor: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", header[0], header[1], header[2], header[3], header[4], header[5], header[6], header[7], header[8]); printk(KERN_DEBUG "checksum = 0x%x\n", checksum);#endif if ((card = kcalloc(1, sizeof(struct pnp_card), GFP_KERNEL)) == NULL) continue; card->number = csn; INIT_LIST_HEAD(&card->devices); isapnp_parse_card_id(card, (header[1] << 8) | header[0], (header[3] << 8) | header[2]); card->serial = (header[7] << 24) | (header[6] << 16) | (header[5] << 8) | header[4]; isapnp_checksum_value = 0x00; isapnp_parse_resource_map(card); if (isapnp_checksum_value != 0x00) printk(KERN_ERR "isapnp: checksum for device %i is not valid (0x%x)\n", csn, isapnp_checksum_value); card->checksum = isapnp_checksum_value; card->protocol = &isapnp_protocol; pnp_add_card(card); } isapnp_wait(); return 0;}/* * Basic configuration routines. */int isapnp_present(void){ struct pnp_card *card; pnp_for_each_card(card) { if (card->protocol == &isapnp_protocol) return 1; } return 0;}int isapnp_cfg_begin(int csn, int logdev){ if (csn < 1 || csn > isapnp_csn_count || logdev > 10) return -EINVAL; down(&isapnp_cfg_mutex); isapnp_wait(); isapnp_key(); isapnp_wake(csn);#if 0 /* to avoid malfunction when the isapnptools package is used */ /* we must set RDP to our value again */ /* it is possible to set RDP only in the isolation phase */ /* Jens Thoms Toerring <Jens.Toerring@physik.fu-berlin.de> */ isapnp_write_byte(0x02, 0x04); /* clear CSN of card */ mdelay(2); /* is this necessary? */ isapnp_wake(csn); /* bring card into sleep state */ isapnp_wake(0); /* bring card into isolation state */ isapnp_set_rdp(); /* reset the RDP port */ udelay(1000); /* delay 1000us */ isapnp_write_byte(0x06, csn); /* reset CSN to previous value */ udelay(250); /* is this necessary? */#endif if (logdev >= 0) isapnp_device(logdev); return 0;}int isapnp_cfg_end(void){ isapnp_wait(); up(&isapnp_cfg_mutex); return 0;}/* * Inititialization. */EXPORT_SYMBOL(isapnp_protocol);EXPORT_SYMBOL(isapnp_present);EXPORT_SYMBOL(isapnp_cfg_begin);EXPORT_SYMBOL(isapnp_cfg_end);#if 0EXPORT_SYMBOL(isapnp_read_byte);#endifEXPORT_SYMBOL(isapnp_write_byte);static int isapnp_read_resources(struct pnp_dev *dev, struct pnp_resource_table *res){ int tmp, ret; dev->active = isapnp_read_byte(ISAPNP_CFG_ACTIVATE); if (dev->active) { for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) { ret = isapnp_read_word(ISAPNP_CFG_PORT + (tmp << 1)); if (!ret) continue; res->port_resource[tmp].start = ret; res->port_resource[tmp].flags = IORESOURCE_IO; } for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) { ret = isapnp_read_word(ISAPNP_CFG_MEM + (tmp << 3)) << 8; if (!ret) continue; res->mem_resource[tmp].start = ret; res->mem_resource[tmp].flags = IORESOURCE_MEM; } for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) { ret = (isapnp_read_word(ISAPNP_CFG_IRQ + (tmp << 1)) >> 8); if (!ret) continue; res->irq_resource[tmp].start = res->irq_resource[tmp].end = ret; res->irq_resource[tmp].flags = IORESOURCE_IRQ; } for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) { ret = isapnp_read_byte(ISAPNP_CFG_DMA + tmp); if (ret == 4) continue; res->dma_resource[tmp].start = res->dma_resource[tmp].end = ret; res->dma_resource[tmp].flags = IORESOURCE_DMA; } } return 0;}static int isapnp_get_resources(struct pnp_dev *dev, struct pnp_resource_table * res){ int ret; pnp_init_resource_table(res); isapnp_cfg_begin(dev->card->number, dev->number); ret = isapnp_read_resources(dev, res); isapnp_cfg_end(); return ret;}static int isapnp_set_resources(struct pnp_dev *dev, struct pnp_resource_table * res){ int tmp; isapnp_cfg_begin(dev->card->number, dev->number); dev->active = 1; for (tmp = 0; tmp < PNP_MAX_PORT && (res->port_resource[tmp].flags & (IORESOURCE_IO | IORESOURCE_UNSET)) == IORESOURCE_IO; tmp++) isapnp_write_word(ISAPNP_CFG_PORT+(tmp<<1), res->port_resource[tmp].start); for (tmp = 0; tmp < PNP_MAX_IRQ && (res->irq_resource[tmp].flags & (IORESOURCE_IRQ | IORESOURCE_UNSET)) == IORESOURCE_IRQ; tmp++) { int irq = res->irq_resource[tmp].start; if (irq == 2) irq = 9; isapnp_write_byte(ISAPNP_CFG_IRQ+(tmp<<1), irq); } for (tmp = 0; tmp < PNP_MAX_DMA && (res->dma_resource[tmp].flags & (IORESOURCE_DMA | IORESOURCE_UNSET)) == IORESOURCE_DMA; tmp++) isapnp_write_byte(ISAPNP_CFG_DMA+tmp, res->dma_resource[tmp].start); for (tmp = 0; tmp < PNP_MAX_MEM && (res->mem_resource[tmp].flags & (IORESOURCE_MEM | IORESOURCE_UNSET)) == IORESOURCE_MEM; tmp++) isapnp_write_word(ISAPNP_CFG_MEM+(tmp<<3), (res->mem_resource[tmp].start >> 8) & 0xffff); /* FIXME: We aren't handling 32bit mems properly here */ isapnp_activate(dev->number); isapnp_cfg_end(); return 0;}static int isapnp_disable_resources(struct pnp_dev *dev){ if (!dev || !dev->active) return -EINVAL; isapnp_cfg_begin(dev->card->number, dev->number); isapnp_deactivate(dev->number); dev->active = 0; isapnp_cfg_end(); return 0;}struct pnp_protocol isapnp_protocol = { .name = "ISA Plug and Play", .get = isapnp_get_resources, .set = isapnp_set_resources, .disable = isapnp_disable_resources,};static int __init isapnp_init(void){ int cards; struct pnp_card *card; struct pnp_dev *dev; if (isapnp_disable) { isapnp_detected = 0; printk(KERN_INFO "isapnp: ISA Plug & Play support disabled\n"); return 0; }#ifdef ISAPNP_REGION_OK if (!request_region(_PIDXR, 1, "isapnp index")) { printk(KERN_ERR "isapnp: Index Register 0x%x already used\n", _PIDXR); return -EBUSY; }#endif if (!request_region(_PNPWRP, 1, "isapnp write")) { printk(KERN_ERR "isapnp: Write Data Register 0x%x already used\n", _PNPWRP);#ifdef ISAPNP_REGION_OK release_region(_PIDXR, 1);#endif return -EBUSY; } if(pnp_register_protocol(&isapnp_protocol)<0) return -EBUSY; /* * Print a message. The existing ISAPnP code is hanging machines * so let the user know where. */ printk(KERN_INFO "isapnp: Scanning for PnP cards...\n"); if (isapnp_rdp >= 0x203 && isapnp_rdp <= 0x3ff) { isapnp_rdp |= 3; if (!request_region(isapnp_rdp, 1, "isapnp read")) { printk(KERN_ERR "isapnp: Read Data Register 0x%x already used\n", isapnp_rdp);#ifdef ISAPNP_REGION_OK release_region(_PIDXR, 1);#endif release_region(_PNPWRP, 1); 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)) {#ifdef ISAPNP_REGION_OK release_region(_PIDXR, 1);#endif release_region(_PNPWRP, 1); isapnp_detected = 0; printk(KERN_INFO "isapnp: No Plug & Play device found\n"); return 0; } request_region(isapnp_rdp, 1, "isapnp read"); } isapnp_build_device_list(); cards = 0; protocol_for_each_card(&isapnp_protocol,card) { cards++; if (isapnp_verbose) { printk(KERN_INFO "isapnp: Card '%s'\n", card->name[0]?card->name:"Unknown"); if (isapnp_verbose < 2) continue; card_for_each_dev(card,dev) { printk(KERN_INFO "isapnp: Device '%s'\n", dev->name[0]?dev->name:"Unknown"); } } } if (cards) { printk(KERN_INFO "isapnp: %i Plug & Play card%s detected total\n", cards, cards>1?"s":""); } else { printk(KERN_INFO "isapnp: No Plug & Play card found\n"); } isapnp_proc_init(); return 0;}device_initcall(isapnp_init);/* format is: noisapnp */static int __init isapnp_setup_disable(char *str){ isapnp_disable = 1; return 1;}__setup("noisapnp", isapnp_setup_disable);/* format is: isapnp=rdp,reset,skip_pci_scan,verbose */static int __init isapnp_setup_isapnp(char *str){ (void)((get_option(&str,&isapnp_rdp) == 2) && (get_option(&str,&isapnp_reset) == 2) && (get_option(&str,&isapnp_verbose) == 2)); return 1;}__setup("isapnp=", isapnp_setup_isapnp);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -