?? isapnp.c
字號:
kfree(dma); return; } } dma->map = tmp[0]; dma->flags = tmp[1]; dma->res = *res; ptr = (*res)->dma; while (ptr && ptr->next) ptr = ptr->next; if (ptr) ptr->next = dma; else (*res)->dma = dma;}/* * Add port resource to resources list. */static void __init isapnp_add_port_resource(struct pnp_dev *dev, struct isapnp_resources **res, int dependent, int size){ unsigned char tmp[7]; struct isapnp_port *port, *ptr; isapnp_peek(tmp, size); port = isapnp_alloc(sizeof(struct isapnp_port)); if (!port) return; if (*res == NULL) { *res = isapnp_build_resources(dev, dependent); if (*res == NULL) { kfree(port); return; } } port->min = (tmp[2] << 8) | tmp[1]; port->max = (tmp[4] << 8) | tmp[3]; port->align = tmp[5]; port->size = tmp[6]; port->flags = tmp[0] ? ISAPNP_PORT_FLAG_16BITADDR : 0; port->res = *res; ptr = (*res)->port; while (ptr && ptr->next) ptr = ptr->next; if (ptr) ptr->next = port; else (*res)->port = port;}/* * Add fixed port resource to resources list. */static void __init isapnp_add_fixed_port_resource(struct pnp_dev *dev, struct isapnp_resources **res, int dependent, int size){ unsigned char tmp[3]; struct isapnp_port *port, *ptr; isapnp_peek(tmp, size); port = isapnp_alloc(sizeof(struct isapnp_port)); if (!port) return; if (*res == NULL) { *res = isapnp_build_resources(dev, dependent); if (*res == NULL) { kfree(port); return; } } port->min = port->max = (tmp[1] << 8) | tmp[0]; port->size = tmp[2]; port->align = 0; port->flags = ISAPNP_PORT_FLAG_FIXED; port->res = *res; ptr = (*res)->port; while (ptr && ptr->next) ptr = ptr->next; if (ptr) ptr->next = port; else (*res)->port = port;}/* * Add memory resource to resources list. */static void __init isapnp_add_mem_resource(struct pnp_dev *dev, struct isapnp_resources **res, int dependent, int size){ unsigned char tmp[9]; struct isapnp_mem *mem, *ptr; isapnp_peek(tmp, size); mem = isapnp_alloc(sizeof(struct isapnp_mem)); if (!mem) return; if (*res == NULL) { *res = isapnp_build_resources(dev, dependent); if (*res == NULL) { kfree(mem); return; } } mem->min = ((tmp[2] << 8) | tmp[1]) << 8; mem->max = ((tmp[4] << 8) | tmp[3]) << 8; mem->align = (tmp[6] << 8) | tmp[5]; mem->size = ((tmp[8] << 8) | tmp[7]) << 8; mem->flags = tmp[0]; mem->res = *res; ptr = (*res)->mem; while (ptr && ptr->next) ptr = ptr->next; if (ptr) ptr->next = mem; else (*res)->mem = mem;}/* * Add 32-bit memory resource to resources list. */static void __init isapnp_add_mem32_resource(struct pnp_dev *dev, struct isapnp_resources **res, int dependent, int size){ unsigned char tmp[17]; struct isapnp_mem32 *mem32, *ptr; isapnp_peek(tmp, size); mem32 = isapnp_alloc(sizeof(struct isapnp_mem32)); if (!mem32) return; if (*res == NULL) { *res = isapnp_build_resources(dev, dependent); if (*res == NULL) { kfree(mem32); return; } } memcpy(mem32->data, tmp, 17); mem32->res = *res; ptr = (*res)->mem32; while (ptr && ptr->next) ptr = ptr->next; if (ptr) ptr->next = mem32; else (*res)->mem32 = mem32;}/* * Add 32-bit fixed memory resource to resources list. */static void __init isapnp_add_fixed_mem32_resource(struct pnp_dev *dev, struct isapnp_resources **res, int dependent, int size){ unsigned char tmp[17]; struct isapnp_mem32 *mem32, *ptr; isapnp_peek(tmp, size); mem32 = isapnp_alloc(sizeof(struct isapnp_mem32)); if (!mem32) return; if (*res == NULL) { *res = isapnp_build_resources(dev, dependent); if (*res == NULL) { kfree(mem32); return; } } memcpy(mem32->data, tmp, 17); mem32->res = *res; ptr = (*res)->mem32; while (ptr && ptr->next) ptr = ptr->next; if (ptr) ptr->next = mem32; else (*res)->mem32 = mem32;}/* * Parse resource map for logical device. */static int __init isapnp_create_device(struct pnp_bus *card, unsigned short size){ int number = 0, skip = 0, dependent = 0, compat = 0; unsigned char type, tmp[17]; struct pnp_dev *dev, *prev_dev; struct isapnp_resources *res = NULL; if ((dev = isapnp_parse_device(card, size, number++)) == NULL) return 1; card->devices = dev; if (isapnp_last_device) { isapnp_last_device->next = dev; isapnp_last_device = dev; } else { isapnp_devices = isapnp_last_device = 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) { prev_dev = dev; isapnp_config_prepare(dev); if ((dev = isapnp_parse_device(card, size, number++)) == NULL) return 1; prev_dev->sibling = dev; isapnp_last_device->next = dev; isapnp_last_device = dev; size = 0; skip = 0; } else { skip = 1; } res = NULL; dependent = 0; compat = 0; break; case _STAG_COMPATDEVID: if (size == 4 && compat < DEVICE_COUNT_COMPATIBLE) { isapnp_peek(tmp, 4); dev->vendor_compatible[compat] = (tmp[1] << 8) | tmp[0]; dev->device_compatible[compat] = (tmp[3] << 8) | tmp[2]; compat++; size = 0; } break; case _STAG_IRQ: if (size < 2 || size > 3) goto __skip; isapnp_add_irq_resource(dev, &res, dependent, size); size = 0; break; case _STAG_DMA: if (size != 2) goto __skip; isapnp_add_dma_resource(dev, &res, dependent, size); size = 0; break; case _STAG_STARTDEP: if (size > 1) goto __skip; res = NULL; dependent = 0x100 | ISAPNP_RES_PRIORITY_ACCEPTABLE; if (size > 0) { isapnp_peek(tmp, size); dependent = 0x100 | tmp[0]; size = 0; } break; case _STAG_ENDDEP: if (size != 0) goto __skip; res = NULL; dependent = 0; break; case _STAG_IOPORT: if (size != 7) goto __skip; isapnp_add_port_resource(dev, &res, dependent, size); size = 0; break; case _STAG_FIXEDIO: if (size != 3) goto __skip; isapnp_add_fixed_port_resource(dev, &res, dependent, size); size = 0; break; case _STAG_VENDOR: break; case _LTAG_MEMRANGE: if (size != 9) goto __skip; isapnp_add_mem_resource(dev, &res, dependent, size); size = 0; break; case _LTAG_ANSISTR: if (dev->name[0] == '\0') { unsigned short size1 = size > 47 ? 47 : size; isapnp_peek(dev->name, size1); dev->name[size1] = '\0'; size -= size1; } 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_add_mem32_resource(dev, &res, dependent, size); size = 0; break; case _LTAG_FIXEDMEM32RANGE: if (size != 17) goto __skip; isapnp_add_fixed_mem32_resource(dev, &res, dependent, size); size = 0; break; case _STAG_END: if (size > 0) isapnp_skip_bytes(size); return 1; default: printk("isapnp: unexpected or unknown tag type 0x%x for logical device %i (device %i), ignored\n", type, dev->devfn, card->number); } __skip: if (size > 0) isapnp_skip_bytes(size); } isapnp_config_prepare(dev); return 0;}/* * Parse resource map for ISA PnP card. */ static void __init isapnp_parse_resource_map(struct pnp_bus *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: if (card->name[0] == '\0') { unsigned short size1 = size > 47 ? 47 : size; isapnp_peek(card->name, size1); card->name[size1] = '\0'; size -= size1; } 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("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;}/* * 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_bus *card, *prev = NULL; isapnp_wait(); isapnp_key(); for (csn = 1; csn <= 10; csn++) { isapnp_wake(csn); isapnp_peek(header, 9); checksum = isapnp_checksum(header);#if 0 printk("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("checksum = 0x%x\n", checksum);#endif if (checksum == 0x00 || checksum != header[8]) /* not valid CSN */ continue; if ((card = isapnp_alloc(sizeof(struct pnp_bus))) == NULL) continue; card->number = csn; card->vendor = (header[1] << 8) | header[0]; card->device = (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("isapnp: checksum for device %i is not valid (0x%x)\n", csn, isapnp_checksum_value); card->checksum = isapnp_checksum_value; if (!isapnp_cards) isapnp_cards = card; else prev->next = card; prev = card; } return 0;}/* * Basic configuration routines. */int isapnp_present(void){ if (isapnp_devices) return 1; return 0;}int isapnp_cfg_begin(int csn, int logdev){ if (csn < 1 || csn > 10 || logdev > 10) return -EINVAL; MOD_INC_USE_COUNT; down(&isapnp_cfg_mutex); isapnp_wait(); isapnp_key(); isapnp_wake(csn);#if 1 /* to avoid malfunction when the isapnptools package is used */ isapnp_set_rdp(); udelay(1000); /* delay 1000us */ write_address(0x01); udelay(1000); /* delay 1000us */#endif if (logdev >= 0) isapnp_device(logdev); return 0;}int isapnp_cfg_end(void){ isapnp_wait(); up(&isapnp_cfg_mutex); MOD_DEC_USE_COUNT; return 0;}/* * Resource manager. */static struct isapnp_port *isapnp_find_port(struct pnp_dev *dev, int index){ struct isapnp_resources *res; struct isapnp_port *port; if (!dev || index < 0 || index > 7) return NULL; for (res = (struct isapnp_resources *)dev->sysdata; res; res = res->next) { for (port = res->port; port; port = port->next) { if (!index) return port; index--; } } return NULL;}struct isapnp_irq *isapnp_find_irq(struct pnp_dev *dev, int index){ struct isapnp_resources *res, *resa; struct isapnp_irq *irq; int index1, index2, index3; if (!dev || index < 0 || index > 7) return NULL; for (res = (struct isapnp_resources *)dev->sysdata; res; res = res->next) { index3 = 0; for (resa = res; resa; resa = resa->alt) { index1 = index; index2 = 0; for (irq = resa->irq; irq; irq = irq->next) { if (!index1) return irq; index1--; index2++; } if (index3 < index2) index3 = index2; } index -= index3; } return NULL;}struct isapnp_dma *isapnp_find_dma(struct pnp_dev *dev, int index){ struct isapnp_resources *res; struct isapnp_dma *dma; if (!dev || index < 0 || index > 7) return NULL; for (res = (struct isapnp_resources *)dev->sysdata; res; res = res->next) {
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -