177596Simp/*- 277596Simp * Copyright (c) 2000 Nikolai Saoukh 377596Simp * All rights reserved. 477596Simp * 577596Simp * Redistribution and use in source and binary forms, with or without 677596Simp * modification, are permitted provided that the following conditions 777596Simp * are met: 877596Simp * 1. Redistributions of source code must retain the above copyright 977596Simp * notice, this list of conditions and the following disclaimer. 1077596Simp * 2. Redistributions in binary form must reproduce the above copyright 1177596Simp * notice, this list of conditions and the following disclaimer in the 1277596Simp * documentation and/or other materials provided with the distribution. 1377596Simp * 1477596Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1577596Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1677596Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1777596Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1877596Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1977596Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2077596Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2177596Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2277596Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2377596Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2477596Simp * SUCH DAMAGE. 2577596Simp */ 2677596Simp 27116181Sobrien#include <sys/cdefs.h> 28116181Sobrien__FBSDID("$FreeBSD$"); 29116181Sobrien 3077596Simp/* 3177596Simp * Driver to take care of holes in ISA I/O memory occupied 3277596Simp * by option rom(s) 3377596Simp */ 3477596Simp 3577596Simp#include <sys/param.h> 3677596Simp#include <sys/systm.h> 3777596Simp#include <sys/kernel.h> 3877596Simp#include <sys/socket.h> 3977596Simp 4077596Simp#include <sys/module.h> 4177596Simp#include <sys/bus.h> 4277596Simp 4377596Simp#include <machine/bus.h> 4477596Simp#include <machine/resource.h> 4577596Simp#include <sys/rman.h> 4677596Simp 4777596Simp#include <isa/isavar.h> 4877596Simp#include <isa/pnpvar.h> 4977596Simp 5077596Simp#define IOMEM_START 0x0a0000 5177596Simp#define IOMEM_STEP 0x000800 5277596Simp#define IOMEM_END 0x100000 5377596Simp 5477596Simp#define ORM_ID 0x00004d3e 5577596Simp 5677596Simpstatic struct isa_pnp_id orm_ids[] = { 5777596Simp { ORM_ID, NULL }, /* ORM0000 */ 5877596Simp { 0, NULL }, 5977596Simp}; 6077596Simp 6177596Simp#define MAX_ROMS 16 6277596Simp 6377596Simpstruct orm_softc { 6477596Simp int rnum; 6577596Simp int rid[MAX_ROMS]; 6677596Simp struct resource *res[MAX_ROMS]; 6777596Simp}; 6877596Simp 6977596Simpstatic int 7077596Simporm_probe(device_t dev) 7177596Simp{ 7277596Simp return (ISA_PNP_PROBE(device_get_parent(dev), dev, orm_ids)); 7377596Simp} 7477596Simp 7577596Simpstatic int 7677596Simporm_attach(device_t dev) 7777596Simp{ 7877596Simp return (0); 7977596Simp} 8077596Simp 8177596Simpstatic void 8277596Simporm_identify(driver_t* driver, device_t parent) 8377596Simp{ 8477596Simp bus_space_handle_t bh; 8577596Simp bus_space_tag_t bt; 8677596Simp device_t child; 8777596Simp u_int32_t chunk = IOMEM_START; 8877596Simp struct resource *res; 8977596Simp int rid; 9077596Simp u_int32_t rom_size; 9177596Simp struct orm_softc *sc; 9277596Simp u_int8_t buf[3]; 9377596Simp 9477596Simp child = BUS_ADD_CHILD(parent, ISA_ORDER_SENSITIVE, "orm", -1); 9577596Simp device_set_driver(child, driver); 9677596Simp isa_set_logicalid(child, ORM_ID); 9777596Simp isa_set_vendorid(child, ORM_ID); 9877596Simp sc = device_get_softc(child); 9977596Simp sc->rnum = 0; 10077596Simp while (chunk < IOMEM_END) { 10177596Simp bus_set_resource(child, SYS_RES_MEMORY, sc->rnum, chunk, 10277596Simp IOMEM_STEP); 10377596Simp rid = sc->rnum; 104127135Snjl res = bus_alloc_resource_any(child, SYS_RES_MEMORY, &rid, 105127135Snjl RF_ACTIVE); 10677596Simp if (res == NULL) { 10777596Simp bus_delete_resource(child, SYS_RES_MEMORY, sc->rnum); 10877596Simp chunk += IOMEM_STEP; 10977596Simp continue; 11077596Simp } 11177596Simp bt = rman_get_bustag(res); 11277596Simp bh = rman_get_bushandle(res); 11377596Simp bus_space_read_region_1(bt, bh, 0, buf, sizeof(buf)); 11477596Simp 11577596Simp /* 11677596Simp * We need to release and delete the resource since we're 11777596Simp * changing its size, or the rom isn't there. There 11877596Simp * is a checksum field in the ROM to prevent false 11977596Simp * positives. However, some common hardware (IBM thinkpads) 12077596Simp * neglects to put a valid checksum in the ROM, so we do 12177596Simp * not double check the checksum here. On the ISA bus 12277596Simp * areas that have no hardware read back as 0xff, so the 12377596Simp * tests to see if we have 0x55 followed by 0xaa are 12477596Simp * generally sufficient. 12577596Simp */ 12677596Simp bus_release_resource(child, SYS_RES_MEMORY, rid, res); 12777596Simp bus_delete_resource(child, SYS_RES_MEMORY, sc->rnum); 12877596Simp if (buf[0] != 0x55 || buf[1] != 0xAA || (buf[2] & 0x03) != 0) { 12977596Simp chunk += IOMEM_STEP; 13077596Simp continue; 13177596Simp } 13277596Simp rom_size = buf[2] << 9; 13377596Simp bus_set_resource(child, SYS_RES_MEMORY, sc->rnum, chunk, 13477596Simp rom_size); 13577596Simp rid = sc->rnum; 136127135Snjl res = bus_alloc_resource_any(child, SYS_RES_MEMORY, &rid, 0); 13777596Simp if (res == NULL) { 13877596Simp bus_delete_resource(child, SYS_RES_MEMORY, sc->rnum); 13977596Simp chunk += IOMEM_STEP; 14077596Simp continue; 14177596Simp } 14277596Simp sc->rid[sc->rnum] = rid; 14377596Simp sc->res[sc->rnum] = res; 14477596Simp sc->rnum++; 14577596Simp chunk += rom_size; 14677596Simp } 14777596Simp 14877596Simp if (sc->rnum == 0) 14977596Simp device_delete_child(parent, child); 15077596Simp else if (sc->rnum == 1) 151131636Simp device_set_desc(child, "ISA Option ROM"); 15277596Simp else 153131636Simp device_set_desc(child, "ISA Option ROMs"); 15477596Simp} 15577596Simp 15677596Simpstatic int 15777596Simporm_detach(device_t dev) 15877596Simp{ 15977596Simp int i; 16077596Simp struct orm_softc *sc = device_get_softc(dev); 16177596Simp 16277596Simp for (i = 0; i < sc->rnum; i++) 16377596Simp bus_release_resource(dev, SYS_RES_MEMORY, sc->rid[i], 16477596Simp sc->res[i]); 16577596Simp return (0); 16677596Simp} 16777596Simp 16877596Simpstatic device_method_t orm_methods[] = { 16977596Simp /* Device interface */ 17077596Simp DEVMETHOD(device_identify, orm_identify), 17177596Simp DEVMETHOD(device_probe, orm_probe), 17277596Simp DEVMETHOD(device_attach, orm_attach), 17377596Simp DEVMETHOD(device_detach, orm_detach), 17477596Simp { 0, 0 } 17577596Simp}; 17677596Simp 17777596Simpstatic driver_t orm_driver = { 17877596Simp "orm", 17977596Simp orm_methods, 18077596Simp sizeof (struct orm_softc) 18177596Simp}; 18277596Simp 18377596Simpstatic devclass_t orm_devclass; 18477596Simp 18577596SimpDRIVER_MODULE(orm, isa, orm_driver, orm_devclass, 0, 0); 186