diff options
author | mdodd <mdodd@FreeBSD.org> | 2003-01-17 08:10:18 +0000 |
---|---|---|
committer | mdodd <mdodd@FreeBSD.org> | 2003-01-17 08:10:18 +0000 |
commit | def7e1bda051583fcc3525070ac5429f314f7fcf (patch) | |
tree | 9569a08b4ce3cebe0d49d0bb941a139c6b6d5f61 /sys/i386/bios | |
parent | 67dc3cf7fb55dd4317169204e4235cc4b359827c (diff) | |
download | FreeBSD-src-def7e1bda051583fcc3525070ac5429f314f7fcf.zip FreeBSD-src-def7e1bda051583fcc3525070ac5429f314f7fcf.tar.gz |
A driver for the System Management Application Program
Interface (SMAPI) BIOS, which is present on some IBM
Thinkpad models (560, 600, 770 to name a few.)
The SMAPI BIOS provides access to System Information,
System Configuration, and Power Management.
Diffstat (limited to 'sys/i386/bios')
-rw-r--r-- | sys/i386/bios/smapi.c | 167 | ||||
-rw-r--r-- | sys/i386/bios/smapi_bios.S | 54 | ||||
-rw-r--r-- | sys/i386/bios/smapi_isa.c | 274 | ||||
-rw-r--r-- | sys/i386/bios/smapi_var.h | 51 |
4 files changed, 546 insertions, 0 deletions
diff --git a/sys/i386/bios/smapi.c b/sys/i386/bios/smapi.c new file mode 100644 index 0000000..e2e96ad --- /dev/null +++ b/sys/i386/bios/smapi.c @@ -0,0 +1,167 @@ +/*- + * Copyright (c) 2003 Matthew N. Dodd <winter@jurai.net> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> + +#include <sys/module.h> +#include <sys/bus.h> +#include <sys/conf.h> + +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/rman.h> + +#include <machine/smapi.h> +#include <i386/smapi/smapi_var.h> + +u_long smapi32_offset; +u_short smapi32_segment; +#define SMAPI32_SEGMENT 0x18 + +devclass_t smapi_devclass; + +static d_open_t smapi_open; +static d_close_t smapi_close; +static d_ioctl_t smapi_ioctl; + +#define CDEV_MAJOR 183 + +static struct cdevsw smapi_cdevsw = { + /* open */ smapi_open, + /* close */ smapi_close, + /* read */ noread, + /* write */ nowrite, + /* ioctl */ smapi_ioctl, + /* poll */ nopoll, + /* mmap */ nommap, + /* strategy */ nostrategy, + /* name */ "smapi", + /* maj */ CDEV_MAJOR, + /* dump */ nodump, + /* psize */ nopsize, + /* flags */ D_MEM, + /* kqfilter */ NULL, +}; + +static int +smapi_open (dev, oflags, devtype, td) + dev_t dev; + int oflags; + int devtype; + d_thread_t * td; +{ + + return (0); +} + +static int +smapi_close (dev, fflag, devtype, td) + dev_t dev; + int fflag; + int devtype; + d_thread_t * td; +{ + + return (0); +} + +static int +smapi_ioctl (dev, cmd, data, fflag, td) + dev_t dev; + u_long cmd; + caddr_t data; + int fflag; + d_thread_t * td; +{ + struct smapi_softc *sc; + int error; + + error = 0; + sc = devclass_get_softc(smapi_devclass, minor(dev)); + if (sc == NULL) { + error = ENXIO; + goto fail; + } + + switch (cmd) { + case SMAPIOGHEADER: + bcopy((caddr_t)sc->header, data, + sizeof(struct smapi_bios_header)); + error = 0; + break; + case SMAPIOCGFUNCTION: + smapi32_segment = SMAPI32_SEGMENT; + smapi32_offset = sc->smapi32_entry; + error = smapi32((struct smapi_bios_parameter *)data, + (struct smapi_bios_parameter *)data); + break; + default: + error = ENOTTY; + } + +fail: + return (error); +} + +int +smapi_attach (struct smapi_softc *sc) +{ + struct smapi_bios_parameter input_param; + struct smapi_bios_parameter output_param; + int retval; + + sc->cdev = make_dev(&smapi_cdevsw, + device_get_unit(sc->dev), + UID_ROOT, GID_WHEEL, 0600, + "%s%d", + smapi_cdevsw.d_name, + device_get_unit(sc->dev)); + + bzero(&input_param, sizeof(struct smapi_bios_parameter)); + bzero(&output_param, sizeof(struct smapi_bios_parameter)); + smapi32_segment = SMAPI32_SEGMENT; + smapi32_offset = sc->smapi32_entry; + retval = smapi32(&output_param, &output_param); + +#if 0 + retval = smapi32_new(sc->smapi32_entry, SMAPI32_SEGMENT, + &output_param, &output_param); +#endif + + return (0); +} + +int +smapi_detach (struct smapi_softc *sc) +{ + + destroy_dev(sc->cdev); + return (0); +} diff --git a/sys/i386/bios/smapi_bios.S b/sys/i386/bios/smapi_bios.S new file mode 100644 index 0000000..2ada5c6 --- /dev/null +++ b/sys/i386/bios/smapi_bios.S @@ -0,0 +1,54 @@ +/* $FreeBSD$ */ + +#include <machine/asmacros.h> + + .data +smapi32_segment_tmp: .word 0 +smapi32_offset_tmp: .long 0 + .text +/* + * smapi32(input_param, output_param) + * struct smapi_bios_parameter *input_parm; + * struct smapi_bios_parameter *output_parm; + */ +ENTRY(smapi32) + pushl %ebp /* Save frame */ + movl %esp,%ebp + + pushl %ds + pushl 0x0c(%ebp) /* Output Param */ + pushl %ds + pushl 0x08(%ebp) /* Input Param */ + + movl $0,%eax /* Clear EAX (return 0) */ + movw %cs,smapi32_segment /* Save CS */ + lcall *(smapi32_offset) + + leave + ret + +/* + * smapi32(offset, segment, input_param, output_param) + * u_int offset; + * u_short segment; + * struct smapi_bios_parameter *input_parm; + * struct smapi_bios_parameter *output_parm; + */ +ENTRY(smapi32_new) + pushl %ebp /* Save frame */ + movl 0x08(%esp),%ebp + movl %ebp,smapi32_offset_tmp + movw 0x0c(%esp),%bp + movw %bp,smapi32_segment_tmp + + pushl %ds + pushl 0x20(%ebp) /* Output Param */ + pushl %ds + pushl 0x10(%ebp) /* Input Param */ + + movl $0,%eax + movw %cs,smapi32_segment_tmp + lcall *(smapi32_offset_tmp) + + leave + ret diff --git a/sys/i386/bios/smapi_isa.c b/sys/i386/bios/smapi_isa.c new file mode 100644 index 0000000..bd6bfd3 --- /dev/null +++ b/sys/i386/bios/smapi_isa.c @@ -0,0 +1,274 @@ +/*- + * Copyright (c) 2003 Matthew N. Dodd <winter@jurai.net> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> + +#include <sys/module.h> +#include <sys/bus.h> + +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/rman.h> + +#include <isa/isavar.h> +#include <isa/pnpvar.h> + +/* And all this for BIOS_PADDRTOVADDR() */ +#include <vm/vm.h> +#include <vm/pmap.h> +#include <machine/md_var.h> +#include <machine/pc/bios.h> + +#include <machine/smapi.h> +#include <i386/smapi/smapi_var.h> + +static void smapi_isa_identify (driver_t *, device_t); +static int smapi_isa_probe (device_t); +static int smapi_isa_attach (device_t); +static int smapi_isa_detach (device_t); +static int smapi_modevent (module_t, int, void *); + +static int smapi_header_cksum (struct smapi_bios_header *); + +#define SMAPI_ID 0x0000a24d + +static struct isa_pnp_id smapi_ids[] = { + { SMAPI_ID, NULL }, /* SMB0000 */ + { 0, NULL }, +}; + +#define SMAPI_START 0xf0000 +#define SMAPI_END 0xffff0 +#define SMAPI_STEP 0x10 + +#define SMAPI_SIGNATURE(h) ((h->signature[0] == '$') && \ + (h->signature[1] == 'S') && \ + (h->signature[2] == 'M') && \ + (h->signature[3] == 'B')) + +static void +smapi_isa_identify (driver_t *driver, device_t parent) +{ + device_t child; + struct resource *res; + struct smapi_bios_header *header; + u_int32_t chunk; + int rid; + + rid = 0; + chunk = SMAPI_START; + + child = BUS_ADD_CHILD(parent, ISA_ORDER_SENSITIVE, "smapi", -1); + device_set_driver(child, driver); + isa_set_logicalid(child, SMAPI_ID); + isa_set_vendorid(child, SMAPI_ID); + + while (chunk < SMAPI_END) { + bus_set_resource(child, SYS_RES_MEMORY, rid, chunk, + sizeof(struct smapi_bios_header)); + res = bus_alloc_resource(child, SYS_RES_MEMORY, &rid, + 0ul, ~0ul, 1, RF_ACTIVE); + if (res == NULL) { + bus_delete_resource(child, SYS_RES_MEMORY, rid); + chunk += SMAPI_STEP; + continue; + } + header = (struct smapi_bios_header *)rman_get_virtual(res); + + if (SMAPI_SIGNATURE(header)) { + if (smapi_header_cksum(header)) { + device_printf(child, "SMAPI header checksum failed.\n"); + } else { + goto found; + } + } else { + bus_release_resource(child, SYS_RES_MEMORY, rid, res); + bus_delete_resource(child, SYS_RES_MEMORY, rid); + } + + chunk += SMAPI_STEP; + } + + device_delete_child(parent, child); + return; + +found: + device_set_desc(child, "SMAPI BIOS"); + return; +} + +static int +smapi_isa_probe (device_t dev) +{ + return (ISA_PNP_PROBE(device_get_parent(dev), dev, smapi_ids)); +} + +static int +smapi_isa_attach (device_t dev) +{ + struct smapi_softc *sc; + int error; + + sc = device_get_softc(dev); + error = 0; + + sc->dev = dev; + sc->rid = 0; + sc->res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->rid, + 0ul, ~0ul, 1, RF_ACTIVE); + if (sc->res == NULL) { + device_printf(dev, "Unable to allocate memory resource.\n"); + error = ENOMEM; + goto bad; + } + sc->header = (struct smapi_bios_header *)rman_get_virtual(sc->res); + sc->smapi32_entry = (u_int32_t)BIOS_PADDRTOVADDR( + sc->header->prot32_segment + + sc->header->prot32_offset); + + if (smapi_header_cksum(sc->header)) { + device_printf(dev, "SMAPI header checksum failed.\n"); + error = ENXIO; + goto bad; + } + + if (smapi_attach(sc)) { + device_printf(dev, "SMAPI attach failed.\n"); + error = ENXIO; + goto bad; + } + + device_printf(dev, "Version %02d.%02d, Length %d, Checksum 0x%02x\n", + sc->header->version_major, sc->header->version_minor, + sc->header->length, sc->header->checksum); + device_printf(dev, "Information=0x%b\n", + sc->header->information, + "\020" + "\001REAL_VM86" + "\002PROTECTED_16" + "\003PROTECTED_32"); + + if (bootverbose) { + if (sc->header->information & SMAPI_REAL_VM86) + device_printf(dev, "Real/VM86 mode: Segment 0x%04x, Offset 0x%04x\n", + sc->header->real16_segment, + sc->header->real16_offset); + if (sc->header->information & SMAPI_PROT_16BIT) + device_printf(dev, "16-bit Protected mode: Segment 0x%08x, Offset 0x%04x\n", + sc->header->prot16_segment, + sc->header->prot16_offset); + if (sc->header->information & SMAPI_PROT_32BIT) + device_printf(dev, "32-bit Protected mode: Segment 0x%08x, Offset 0x%08x\n", + sc->header->prot32_segment, + sc->header->prot32_offset); + } + + return (0); +bad: + if (sc->res) + bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res); + return (error); +} + +static int +smapi_isa_detach (device_t dev) +{ + struct smapi_softc *sc; + + sc = device_get_softc(dev); + + (void)smapi_detach(sc); + + if (sc->res) + bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res); + + return (0); +} + +static int +smapi_modevent (mod, what, arg) + module_t mod; + int what; + void * arg; +{ + device_t * devs; + int count; + int i; + + switch (what) { + case MOD_LOAD: + break; + case MOD_UNLOAD: + devclass_get_devices(smapi_devclass, &devs, &count); + for (i = 0; i < count; i++) { + device_delete_child(device_get_parent(devs[i]), devs[i]); + } + break; + default: + break; + } + + return (0); +} + +static device_method_t smapi_methods[] = { + /* Device interface */ + DEVMETHOD(device_identify, smapi_isa_identify), + DEVMETHOD(device_probe, smapi_isa_probe), + DEVMETHOD(device_attach, smapi_isa_attach), + DEVMETHOD(device_detach, smapi_isa_detach), + { 0, 0 } +}; + +static driver_t smapi_driver = { + "smapi", + smapi_methods, + sizeof(struct smapi_softc), +}; + +DRIVER_MODULE(smapi, isa, smapi_driver, smapi_devclass, smapi_modevent, 0); +MODULE_VERSION(smapi, 1); + +static int +smapi_header_cksum (struct smapi_bios_header *header) +{ + u_int8_t *ptr; + u_int8_t cksum; + int i; + + ptr = (u_int8_t *)header; + cksum = 0; + for (i = 0; i < header->length; i++) { + cksum += ptr[i]; + } + + return (cksum); +} diff --git a/sys/i386/bios/smapi_var.h b/sys/i386/bios/smapi_var.h new file mode 100644 index 0000000..c05ae8f --- /dev/null +++ b/sys/i386/bios/smapi_var.h @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 2003 Matthew N. Dodd <winter@jurai.net> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +struct smapi_softc { + dev_t cdev; + device_t dev; + struct resource * res; + int rid; + + u_int32_t smapi32_entry; + + struct smapi_bios_header *header; +}; + +extern u_long smapi32_offset; +extern u_short smapi32_segment; +extern devclass_t smapi_devclass; + +int smapi_attach (struct smapi_softc *); +int smapi_detach (struct smapi_softc *); + +extern int smapi32 (struct smapi_bios_parameter *, + struct smapi_bios_parameter *); +extern int smapi32_new (u_long, u_short, + struct smapi_bios_parameter *, + struct smapi_bios_parameter *); |