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