17534ac7aSMatthew N. Dodd /*- 27534ac7aSMatthew N. Dodd * Copyright (c) 2003 Matthew N. Dodd <winter@jurai.net> 37534ac7aSMatthew N. Dodd * All rights reserved. 47534ac7aSMatthew N. Dodd * 57534ac7aSMatthew N. Dodd * Redistribution and use in source and binary forms, with or without 67534ac7aSMatthew N. Dodd * modification, are permitted provided that the following conditions 77534ac7aSMatthew N. Dodd * are met: 87534ac7aSMatthew N. Dodd * 1. Redistributions of source code must retain the above copyright 97534ac7aSMatthew N. Dodd * notice, this list of conditions and the following disclaimer. 107534ac7aSMatthew N. Dodd * 2. Redistributions in binary form must reproduce the above copyright 117534ac7aSMatthew N. Dodd * notice, this list of conditions and the following disclaimer in the 127534ac7aSMatthew N. Dodd * documentation and/or other materials provided with the distribution. 137534ac7aSMatthew N. Dodd * 147534ac7aSMatthew N. Dodd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 157534ac7aSMatthew N. Dodd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 167534ac7aSMatthew N. Dodd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 177534ac7aSMatthew N. Dodd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 187534ac7aSMatthew N. Dodd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 197534ac7aSMatthew N. Dodd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 207534ac7aSMatthew N. Dodd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 217534ac7aSMatthew N. Dodd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 227534ac7aSMatthew N. Dodd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 237534ac7aSMatthew N. Dodd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 247534ac7aSMatthew N. Dodd * SUCH DAMAGE. 257534ac7aSMatthew N. Dodd * 267534ac7aSMatthew N. Dodd * $FreeBSD$ 277534ac7aSMatthew N. Dodd */ 287534ac7aSMatthew N. Dodd 297534ac7aSMatthew N. Dodd #include <sys/param.h> 307534ac7aSMatthew N. Dodd #include <sys/systm.h> 317534ac7aSMatthew N. Dodd #include <sys/kernel.h> 327534ac7aSMatthew N. Dodd 337534ac7aSMatthew N. Dodd #include <sys/module.h> 347534ac7aSMatthew N. Dodd #include <sys/bus.h> 357534ac7aSMatthew N. Dodd #include <sys/conf.h> 367534ac7aSMatthew N. Dodd 377534ac7aSMatthew N. Dodd #include <machine/bus.h> 387534ac7aSMatthew N. Dodd #include <machine/resource.h> 397534ac7aSMatthew N. Dodd #include <sys/rman.h> 407534ac7aSMatthew N. Dodd 4196aa4252SMatthew N. Dodd /* And all this for BIOS_PADDRTOVADDR() */ 4296aa4252SMatthew N. Dodd #include <vm/vm.h> 4396aa4252SMatthew N. Dodd #include <vm/pmap.h> 4496aa4252SMatthew N. Dodd #include <machine/md_var.h> 4596aa4252SMatthew N. Dodd #include <machine/pc/bios.h> 4696aa4252SMatthew N. Dodd 477534ac7aSMatthew N. Dodd #include <machine/smapi.h> 4896aa4252SMatthew N. Dodd 4996aa4252SMatthew N. Dodd #define SMAPI_START 0xf0000 5096aa4252SMatthew N. Dodd #define SMAPI_STEP 0x10 5196aa4252SMatthew N. Dodd #define SMAPI_OFF 0 5296aa4252SMatthew N. Dodd #define SMAPI_LEN 4 5396aa4252SMatthew N. Dodd #define SMAPI_SIG "$SMB" 5496aa4252SMatthew N. Dodd 5596aa4252SMatthew N. Dodd #define RES2HDR(res) ((struct smapi_bios_header *)rman_get_virtual(res)) 5696aa4252SMatthew N. Dodd #define ADDR2HDR(res) ((struct smapi_bios_header *)BIOS_PADDRTOVADDR(addr)) 5796aa4252SMatthew N. Dodd 5896aa4252SMatthew N. Dodd struct smapi_softc { 5996aa4252SMatthew N. Dodd dev_t cdev; 6096aa4252SMatthew N. Dodd device_t dev; 6196aa4252SMatthew N. Dodd struct resource * res; 6296aa4252SMatthew N. Dodd int rid; 6396aa4252SMatthew N. Dodd 6496aa4252SMatthew N. Dodd u_int32_t smapi32_entry; 6596aa4252SMatthew N. Dodd 6696aa4252SMatthew N. Dodd struct smapi_bios_header *header; 6796aa4252SMatthew N. Dodd }; 687534ac7aSMatthew N. Dodd 697534ac7aSMatthew N. Dodd u_long smapi32_offset; 707534ac7aSMatthew N. Dodd u_short smapi32_segment; 717534ac7aSMatthew N. Dodd #define SMAPI32_SEGMENT 0x18 727534ac7aSMatthew N. Dodd 737534ac7aSMatthew N. Dodd devclass_t smapi_devclass; 747534ac7aSMatthew N. Dodd 757534ac7aSMatthew N. Dodd static d_ioctl_t smapi_ioctl; 767534ac7aSMatthew N. Dodd 777534ac7aSMatthew N. Dodd static struct cdevsw smapi_cdevsw = { 7896aa4252SMatthew N. Dodd .d_open = nullopen, 7996aa4252SMatthew N. Dodd .d_close = nullclose, 807ac40f5fSPoul-Henning Kamp .d_ioctl = smapi_ioctl, 817ac40f5fSPoul-Henning Kamp .d_name = "smapi", 8296aa4252SMatthew N. Dodd .d_maj = MAJOR_AUTO, 837ac40f5fSPoul-Henning Kamp .d_flags = D_MEM, 847534ac7aSMatthew N. Dodd }; 857534ac7aSMatthew N. Dodd 8696aa4252SMatthew N. Dodd static void smapi_identify (driver_t *, device_t); 8796aa4252SMatthew N. Dodd static int smapi_probe (device_t); 8896aa4252SMatthew N. Dodd static int smapi_attach (device_t); 8996aa4252SMatthew N. Dodd static int smapi_detach (device_t); 9096aa4252SMatthew N. Dodd static int smapi_modevent (module_t, int, void *); 917534ac7aSMatthew N. Dodd 9296aa4252SMatthew N. Dodd static int smapi_header_cksum (struct smapi_bios_header *); 937534ac7aSMatthew N. Dodd 9496aa4252SMatthew N. Dodd extern int smapi32 (struct smapi_bios_parameter *, 9596aa4252SMatthew N. Dodd struct smapi_bios_parameter *); 9696aa4252SMatthew N. Dodd extern int smapi32_new (u_long, u_short, 9796aa4252SMatthew N. Dodd struct smapi_bios_parameter *, 9896aa4252SMatthew N. Dodd struct smapi_bios_parameter *); 997534ac7aSMatthew N. Dodd 1007534ac7aSMatthew N. Dodd static int 1017534ac7aSMatthew N. Dodd smapi_ioctl (dev, cmd, data, fflag, td) 1027534ac7aSMatthew N. Dodd dev_t dev; 1037534ac7aSMatthew N. Dodd u_long cmd; 1047534ac7aSMatthew N. Dodd caddr_t data; 1057534ac7aSMatthew N. Dodd int fflag; 1067534ac7aSMatthew N. Dodd d_thread_t * td; 1077534ac7aSMatthew N. Dodd { 1087534ac7aSMatthew N. Dodd struct smapi_softc *sc; 1097534ac7aSMatthew N. Dodd int error; 1107534ac7aSMatthew N. Dodd 1117534ac7aSMatthew N. Dodd error = 0; 1127534ac7aSMatthew N. Dodd sc = devclass_get_softc(smapi_devclass, minor(dev)); 1137534ac7aSMatthew N. Dodd if (sc == NULL) { 1147534ac7aSMatthew N. Dodd error = ENXIO; 1157534ac7aSMatthew N. Dodd goto fail; 1167534ac7aSMatthew N. Dodd } 1177534ac7aSMatthew N. Dodd 1187534ac7aSMatthew N. Dodd switch (cmd) { 1197534ac7aSMatthew N. Dodd case SMAPIOGHEADER: 1207534ac7aSMatthew N. Dodd bcopy((caddr_t)sc->header, data, 1217534ac7aSMatthew N. Dodd sizeof(struct smapi_bios_header)); 1227534ac7aSMatthew N. Dodd error = 0; 1237534ac7aSMatthew N. Dodd break; 1247534ac7aSMatthew N. Dodd case SMAPIOCGFUNCTION: 12595ca467aSMatthew N. Dodd #if 1 1267534ac7aSMatthew N. Dodd smapi32_segment = SMAPI32_SEGMENT; 1277534ac7aSMatthew N. Dodd smapi32_offset = sc->smapi32_entry; 12895ca467aSMatthew N. Dodd error = smapi32( 12995ca467aSMatthew N. Dodd #else 13095ca467aSMatthew N. Dodd error = smapi32_new(sc->smapi32_entry, SMAPI32_SEGMENT, 13195ca467aSMatthew N. Dodd #endif 13295ca467aSMatthew N. Dodd (struct smapi_bios_parameter *)data, 1337534ac7aSMatthew N. Dodd (struct smapi_bios_parameter *)data); 1347534ac7aSMatthew N. Dodd break; 1357534ac7aSMatthew N. Dodd default: 1367534ac7aSMatthew N. Dodd error = ENOTTY; 1377534ac7aSMatthew N. Dodd } 1387534ac7aSMatthew N. Dodd 1397534ac7aSMatthew N. Dodd fail: 1407534ac7aSMatthew N. Dodd return (error); 1417534ac7aSMatthew N. Dodd } 1427534ac7aSMatthew N. Dodd 14396aa4252SMatthew N. Dodd static int 14496aa4252SMatthew N. Dodd smapi_header_cksum (struct smapi_bios_header *header) 1457534ac7aSMatthew N. Dodd { 14696aa4252SMatthew N. Dodd u_int8_t *ptr; 14796aa4252SMatthew N. Dodd u_int8_t cksum; 14896aa4252SMatthew N. Dodd int i; 14996aa4252SMatthew N. Dodd 15096aa4252SMatthew N. Dodd ptr = (u_int8_t *)header; 15196aa4252SMatthew N. Dodd cksum = 0; 15296aa4252SMatthew N. Dodd for (i = 0; i < header->length; i++) { 15396aa4252SMatthew N. Dodd cksum += ptr[i]; 15496aa4252SMatthew N. Dodd } 15596aa4252SMatthew N. Dodd 15696aa4252SMatthew N. Dodd return (cksum); 15796aa4252SMatthew N. Dodd } 15896aa4252SMatthew N. Dodd 15996aa4252SMatthew N. Dodd static void 16096aa4252SMatthew N. Dodd smapi_identify (driver_t *driver, device_t parent) 16196aa4252SMatthew N. Dodd { 16296aa4252SMatthew N. Dodd device_t child; 16396aa4252SMatthew N. Dodd u_int32_t addr; 16496aa4252SMatthew N. Dodd int length; 16596aa4252SMatthew N. Dodd int rid; 16696aa4252SMatthew N. Dodd 16796aa4252SMatthew N. Dodd if (!device_is_alive(parent)) 16896aa4252SMatthew N. Dodd return; 16996aa4252SMatthew N. Dodd 17096aa4252SMatthew N. Dodd addr = bios_sigsearch(SMAPI_START, SMAPI_SIG, SMAPI_LEN, 17196aa4252SMatthew N. Dodd SMAPI_STEP, SMAPI_OFF); 17296aa4252SMatthew N. Dodd if (addr != 0) { 17396aa4252SMatthew N. Dodd rid = 0; 17496aa4252SMatthew N. Dodd length = ADDR2HDR(res)->length; 17596aa4252SMatthew N. Dodd 17696aa4252SMatthew N. Dodd child = BUS_ADD_CHILD(parent, 0, "smapi", -1); 17796aa4252SMatthew N. Dodd device_set_driver(child, driver); 17896aa4252SMatthew N. Dodd bus_set_resource(child, SYS_RES_MEMORY, rid, addr, length); 17996aa4252SMatthew N. Dodd device_set_desc(child, "SMAPI BIOS"); 18096aa4252SMatthew N. Dodd } 18196aa4252SMatthew N. Dodd 18296aa4252SMatthew N. Dodd return; 18396aa4252SMatthew N. Dodd } 18496aa4252SMatthew N. Dodd 18596aa4252SMatthew N. Dodd static int 18696aa4252SMatthew N. Dodd smapi_probe (device_t dev) 18796aa4252SMatthew N. Dodd { 18896aa4252SMatthew N. Dodd struct resource *res; 18996aa4252SMatthew N. Dodd int rid; 19096aa4252SMatthew N. Dodd int error; 19196aa4252SMatthew N. Dodd 19296aa4252SMatthew N. Dodd error = 0; 19396aa4252SMatthew N. Dodd rid = 0; 19496aa4252SMatthew N. Dodd res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 19596aa4252SMatthew N. Dodd 0ul, ~0ul, 1, RF_ACTIVE); 19696aa4252SMatthew N. Dodd if (res == NULL) { 19796aa4252SMatthew N. Dodd device_printf(dev, "Unable to allocate memory resource.\n"); 19896aa4252SMatthew N. Dodd error = ENOMEM; 19996aa4252SMatthew N. Dodd goto bad; 20096aa4252SMatthew N. Dodd } 20196aa4252SMatthew N. Dodd 20296aa4252SMatthew N. Dodd if (smapi_header_cksum(RES2HDR(res))) { 20396aa4252SMatthew N. Dodd device_printf(dev, "SMAPI header checksum failed.\n"); 20496aa4252SMatthew N. Dodd error = ENXIO; 20596aa4252SMatthew N. Dodd goto bad; 20696aa4252SMatthew N. Dodd } 20796aa4252SMatthew N. Dodd 20896aa4252SMatthew N. Dodd bad: 20996aa4252SMatthew N. Dodd if (res) 21096aa4252SMatthew N. Dodd bus_release_resource(dev, SYS_RES_MEMORY, rid, res); 21196aa4252SMatthew N. Dodd return (error); 21296aa4252SMatthew N. Dodd } 21396aa4252SMatthew N. Dodd 21496aa4252SMatthew N. Dodd static int 21596aa4252SMatthew N. Dodd smapi_attach (device_t dev) 21696aa4252SMatthew N. Dodd { 21796aa4252SMatthew N. Dodd struct smapi_softc *sc; 21896aa4252SMatthew N. Dodd int error; 21996aa4252SMatthew N. Dodd 22096aa4252SMatthew N. Dodd sc = device_get_softc(dev); 22196aa4252SMatthew N. Dodd error = 0; 22296aa4252SMatthew N. Dodd 22396aa4252SMatthew N. Dodd sc->dev = dev; 22496aa4252SMatthew N. Dodd sc->rid = 0; 22596aa4252SMatthew N. Dodd sc->res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->rid, 22696aa4252SMatthew N. Dodd 0ul, ~0ul, 1, RF_ACTIVE); 22796aa4252SMatthew N. Dodd if (sc->res == NULL) { 22896aa4252SMatthew N. Dodd device_printf(dev, "Unable to allocate memory resource.\n"); 22996aa4252SMatthew N. Dodd error = ENOMEM; 23096aa4252SMatthew N. Dodd goto bad; 23196aa4252SMatthew N. Dodd } 23296aa4252SMatthew N. Dodd sc->header = (struct smapi_bios_header *)rman_get_virtual(sc->res); 23396aa4252SMatthew N. Dodd sc->smapi32_entry = (u_int32_t)BIOS_PADDRTOVADDR( 23496aa4252SMatthew N. Dodd sc->header->prot32_segment + 23596aa4252SMatthew N. Dodd sc->header->prot32_offset); 2367534ac7aSMatthew N. Dodd 2377534ac7aSMatthew N. Dodd sc->cdev = make_dev(&smapi_cdevsw, 2387534ac7aSMatthew N. Dodd device_get_unit(sc->dev), 2397534ac7aSMatthew N. Dodd UID_ROOT, GID_WHEEL, 0600, 2407534ac7aSMatthew N. Dodd "%s%d", 2417534ac7aSMatthew N. Dodd smapi_cdevsw.d_name, 2427534ac7aSMatthew N. Dodd device_get_unit(sc->dev)); 2437534ac7aSMatthew N. Dodd 24496aa4252SMatthew N. Dodd device_printf(dev, "Version: %d.%02d, Length: %d, Checksum: 0x%02x\n", 24596aa4252SMatthew N. Dodd bcd2bin(sc->header->version_major), 24696aa4252SMatthew N. Dodd bcd2bin(sc->header->version_minor), 24796aa4252SMatthew N. Dodd sc->header->length, 24896aa4252SMatthew N. Dodd sc->header->checksum); 24996aa4252SMatthew N. Dodd device_printf(dev, "Information=0x%b\n", 25096aa4252SMatthew N. Dodd sc->header->information, 25196aa4252SMatthew N. Dodd "\020" 25296aa4252SMatthew N. Dodd "\001REAL_VM86" 25396aa4252SMatthew N. Dodd "\002PROTECTED_16" 25496aa4252SMatthew N. Dodd "\003PROTECTED_32"); 25596aa4252SMatthew N. Dodd 25696aa4252SMatthew N. Dodd if (bootverbose) { 25796aa4252SMatthew N. Dodd if (sc->header->information & SMAPI_REAL_VM86) 25896aa4252SMatthew N. Dodd device_printf(dev, "Real/VM86 mode: Segment 0x%04x, Offset 0x%04x\n", 25996aa4252SMatthew N. Dodd sc->header->real16_segment, 26096aa4252SMatthew N. Dodd sc->header->real16_offset); 26196aa4252SMatthew N. Dodd if (sc->header->information & SMAPI_PROT_16BIT) 26296aa4252SMatthew N. Dodd device_printf(dev, "16-bit Protected mode: Segment 0x%08x, Offset 0x%04x\n", 26396aa4252SMatthew N. Dodd sc->header->prot16_segment, 26496aa4252SMatthew N. Dodd sc->header->prot16_offset); 26596aa4252SMatthew N. Dodd if (sc->header->information & SMAPI_PROT_32BIT) 26696aa4252SMatthew N. Dodd device_printf(dev, "32-bit Protected mode: Segment 0x%08x, Offset 0x%08x\n", 26796aa4252SMatthew N. Dodd sc->header->prot32_segment, 26896aa4252SMatthew N. Dodd sc->header->prot32_offset); 2697534ac7aSMatthew N. Dodd } 2707534ac7aSMatthew N. Dodd 27196aa4252SMatthew N. Dodd return (0); 27296aa4252SMatthew N. Dodd bad: 27396aa4252SMatthew N. Dodd if (sc->res) 27496aa4252SMatthew N. Dodd bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res); 27596aa4252SMatthew N. Dodd return (error); 27696aa4252SMatthew N. Dodd } 27796aa4252SMatthew N. Dodd 27896aa4252SMatthew N. Dodd static int 27996aa4252SMatthew N. Dodd smapi_detach (device_t dev) 2807534ac7aSMatthew N. Dodd { 28196aa4252SMatthew N. Dodd struct smapi_softc *sc; 28296aa4252SMatthew N. Dodd 28396aa4252SMatthew N. Dodd sc = device_get_softc(dev); 2847534ac7aSMatthew N. Dodd 2857534ac7aSMatthew N. Dodd destroy_dev(sc->cdev); 28696aa4252SMatthew N. Dodd 28796aa4252SMatthew N. Dodd if (sc->res) 28896aa4252SMatthew N. Dodd bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res); 28996aa4252SMatthew N. Dodd 2907534ac7aSMatthew N. Dodd return (0); 2917534ac7aSMatthew N. Dodd } 29296aa4252SMatthew N. Dodd 29396aa4252SMatthew N. Dodd static int 29496aa4252SMatthew N. Dodd smapi_modevent (mod, what, arg) 29596aa4252SMatthew N. Dodd module_t mod; 29696aa4252SMatthew N. Dodd int what; 29796aa4252SMatthew N. Dodd void * arg; 29896aa4252SMatthew N. Dodd { 29996aa4252SMatthew N. Dodd device_t * devs; 30096aa4252SMatthew N. Dodd int count; 30196aa4252SMatthew N. Dodd int i; 30296aa4252SMatthew N. Dodd 30396aa4252SMatthew N. Dodd switch (what) { 30496aa4252SMatthew N. Dodd case MOD_LOAD: 30596aa4252SMatthew N. Dodd break; 30696aa4252SMatthew N. Dodd case MOD_UNLOAD: 30796aa4252SMatthew N. Dodd devclass_get_devices(smapi_devclass, &devs, &count); 30896aa4252SMatthew N. Dodd for (i = 0; i < count; i++) { 30996aa4252SMatthew N. Dodd device_delete_child(device_get_parent(devs[i]), devs[i]); 31096aa4252SMatthew N. Dodd } 31196aa4252SMatthew N. Dodd break; 31296aa4252SMatthew N. Dodd default: 31396aa4252SMatthew N. Dodd break; 31496aa4252SMatthew N. Dodd } 31596aa4252SMatthew N. Dodd 31696aa4252SMatthew N. Dodd return (0); 31796aa4252SMatthew N. Dodd } 31896aa4252SMatthew N. Dodd 31996aa4252SMatthew N. Dodd static device_method_t smapi_methods[] = { 32096aa4252SMatthew N. Dodd /* Device interface */ 32196aa4252SMatthew N. Dodd DEVMETHOD(device_identify, smapi_identify), 32296aa4252SMatthew N. Dodd DEVMETHOD(device_probe, smapi_probe), 32396aa4252SMatthew N. Dodd DEVMETHOD(device_attach, smapi_attach), 32496aa4252SMatthew N. Dodd DEVMETHOD(device_detach, smapi_detach), 32596aa4252SMatthew N. Dodd { 0, 0 } 32696aa4252SMatthew N. Dodd }; 32796aa4252SMatthew N. Dodd 32896aa4252SMatthew N. Dodd static driver_t smapi_driver = { 32996aa4252SMatthew N. Dodd "smapi", 33096aa4252SMatthew N. Dodd smapi_methods, 33196aa4252SMatthew N. Dodd sizeof(struct smapi_softc), 33296aa4252SMatthew N. Dodd }; 33396aa4252SMatthew N. Dodd 33496aa4252SMatthew N. Dodd DRIVER_MODULE(smapi, nexus, smapi_driver, smapi_devclass, smapi_modevent, 0); 33596aa4252SMatthew N. Dodd MODULE_VERSION(smapi, 1); 336