static int aic7770_attach(device_t dev) { struct aic7770_identity *entry; struct ahc_softc *ahc; char *name; int error; entry = aic7770_find_device(eisa_get_id(dev)); if (entry == NULL) return (ENXIO); /* * Allocate a softc for this card and * set it up for attachment by our * common detect routine. */ name = malloc(strlen(device_get_nameunit(dev)) + 1, M_DEVBUF, M_NOWAIT); if (name == NULL) return (ENOMEM); strcpy(name, device_get_nameunit(dev)); ahc = ahc_alloc(dev, name); if (ahc == NULL) return (ENOMEM); ahc_set_unit(ahc, device_get_unit(dev)); /* Allocate a dmatag for our SCB DMA maps */ /* XXX Should be a child of the PCI bus dma tag */ error = aic_dma_tag_create(ahc, /*parent*/bus_get_dma_tag(dev), /*alignment*/1, /*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, /*highaddr*/BUS_SPACE_MAXADDR, /*filter*/NULL, /*filterarg*/NULL, /*maxsize*/BUS_SPACE_MAXSIZE_32BIT, /*nsegments*/AHC_NSEG, /*maxsegsz*/AHC_MAXTRANSFER_SIZE, /*flags*/0, &ahc->parent_dmat); if (error != 0) { printf("ahc_eisa_attach: Could not allocate DMA tag " "- error %d\n", error); ahc_free(ahc); return (ENOMEM); } ahc->dev_softc = dev; error = aic7770_config(ahc, entry, /*unused ioport arg*/0); if (error != 0) { ahc_free(ahc); return (error); } ahc_attach(ahc); return (0); }
/* * Perform an EISA probe of the address with the addition * of a "priming" step. The 284X requires priming (a write * to offset 0x80, the first EISA ID register) to ensure it * is not mistaken as an EISA card. Once we have the ID, * lookup the controller in the aic7770 table of supported * devices. */ static struct aic7770_identity * ahc_isa_find_device(bus_space_tag_t tag, bus_space_handle_t bsh) { uint32_t id; u_int id_size; int i; id = 0; id_size = sizeof(id); for (i = 0; i < id_size; i++) { bus_space_write_1(tag, bsh, 0x80, 0x80 + i); id |= bus_space_read_1(tag, bsh, 0x80 + i) << ((id_size - i - 1) * CHAR_BIT); } return (aic7770_find_device(id)); }
static int aic7770_probe(device_t dev) { struct aic7770_identity *entry; struct resource *regs; uint32_t iobase; bus_space_handle_t bsh; bus_space_tag_t tag; u_int irq; u_int intdef; u_int hcntrl; int shared; int rid; int error; entry = aic7770_find_device(eisa_get_id(dev)); if (entry == NULL) return (ENXIO); device_set_desc(dev, entry->name); iobase = (eisa_get_slot(dev) * EISA_SLOT_SIZE) + AHC_EISA_SLOT_OFFSET; eisa_add_iospace(dev, iobase, AHC_EISA_IOSIZE, RESVADDR_NONE); rid = 0; regs = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); if (regs == NULL) { device_printf(dev, "Unable to map I/O space?!\n"); return ENOMEM; } tag = rman_get_bustag(regs); bsh = rman_get_bushandle(regs); error = 0; /* Pause the card preseving the IRQ type */ hcntrl = bus_space_read_1(tag, bsh, HCNTRL) & IRQMS; bus_space_write_1(tag, bsh, HCNTRL, hcntrl | PAUSE); while ((bus_space_read_1(tag, bsh, HCNTRL) & PAUSE) == 0) ; /* Make sure we have a valid interrupt vector */ intdef = bus_space_read_1(tag, bsh, INTDEF); shared = (intdef & EDGE_TRIG) ? EISA_TRIGGER_EDGE : EISA_TRIGGER_LEVEL; irq = intdef & VECTOR; switch (irq) { case 9: case 10: case 11: case 12: case 14: case 15: break; default: printf("aic7770 at slot %d: illegal irq setting %d\n", eisa_get_slot(dev), intdef); error = ENXIO; } if (error == 0) eisa_add_intr(dev, irq, shared); bus_release_resource(dev, SYS_RES_IOPORT, rid, regs); return (error); }
void ahc_linux_eisa_init(void) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) struct eisa_device_id *eid; struct aic7770_identity *id; int i; if (aic7xxx_probe_eisa_vl == 0) return; /* * Linux requires the EISA IDs to be specified in * the EISA ID string format. Perform the conversion * and setup a table with a NUL terminal entry. */ aic7770_driver.id_table = malloc(sizeof(struct eisa_device_id) * (ahc_num_aic7770_devs + 1), M_DEVBUF, M_NOWAIT); if (aic7770_driver.id_table == NULL) return; for (eid = (struct eisa_device_id *)aic7770_driver.id_table, id = aic7770_ident_table, i = 0; i < ahc_num_aic7770_devs; eid++, id++, i++) { sprintf(eid->sig, "%c%c%c%03X%01X", EISA_MFCTR_CHAR0(id->full_id), EISA_MFCTR_CHAR1(id->full_id), EISA_MFCTR_CHAR2(id->full_id), EISA_PRODUCT_ID(id->full_id), EISA_REVISION_ID(id->full_id)); eid->driver_data = i; } eid->sig[0] = 0; eisa_driver_register(&aic7770_driver); #else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) */ struct aic7770_identity *entry; u_int slot; u_int eisaBase; u_int i; if (aic7xxx_probe_eisa_vl == 0) return; eisaBase = 0x1000 + AHC_EISA_SLOT_OFFSET; for (slot = 1; slot < NUMSLOTS; eisaBase+=0x1000, slot++) { uint32_t eisa_id; size_t id_size; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) if (check_region(eisaBase, AHC_EISA_IOSIZE) != 0) continue; request_region(eisaBase, AHC_EISA_IOSIZE, "aic7xxx"); #else if (request_region(eisaBase, AHC_EISA_IOSIZE, "aic7xxx") == 0) continue; #endif eisa_id = 0; id_size = sizeof(eisa_id); for (i = 0; i < 4; i++) { /* VLcards require priming*/ outb(0x80 + i, eisaBase + IDOFFSET); eisa_id |= inb(eisaBase + IDOFFSET + i) << ((id_size-i-1) * 8); } release_region(eisaBase, AHC_EISA_IOSIZE); if (eisa_id & 0x80000000) continue; /* no EISA card in slot */ entry = aic7770_find_device(eisa_id); if (entry != NULL) aic7770_linux_config(entry, NULL, eisaBase); } #endif }