diff options
author | hvozda <hvozda@cvs.openbsd.org> | 1996-04-29 14:17:54 +0000 |
---|---|---|
committer | hvozda <hvozda@cvs.openbsd.org> | 1996-04-29 14:17:54 +0000 |
commit | 7a9ddc83f934914d39af72bf24b67290a9e5700f (patch) | |
tree | d4e40de8eec73b77be31c346455984224213ff31 /sys/arch | |
parent | fdecada6f88b495c1afc81ad3a15c0cedffa2338 (diff) |
Pull in John Kohl's [jtk@netbsd.org] most recent (15Apr96) APM and PCMCIA work
(original PCMCIA framework by Stefan Grefen [grefen@convex.com]).
Diffstat (limited to 'sys/arch')
25 files changed, 2431 insertions, 30 deletions
diff --git a/sys/arch/i386/apm_init/Makefile b/sys/arch/i386/apm_init/Makefile new file mode 100644 index 00000000000..44e521eba13 --- /dev/null +++ b/sys/arch/i386/apm_init/Makefile @@ -0,0 +1,56 @@ +# +# LP (Laptop Package) +# +# (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp> +# +# This software may be used, modified, copied, and distributed in +# both source and binary form provided that the above copyright and +# these terms are retained. Under no circumstances is the author +# responsible for the proper functioning of this software, nor does +# the author assume any responsibility for damages incurred with its +# use. +# +# Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) +# Oct., 1994 NetBSD port (1.0 BETA 10/2) by ukai +# Dec., 1995 NetBSD 1.1 kernel build retrofit, jtk@netbsd.org +# + +DIR=${APMREL}${APMDIR} + +.if exists (${DIR}/arch/${MACHINE_ARCH}/Makefile.inc) +.PATH: ${DIR}/arch/${MACHINE_ARCH} +.include "${DIR}/arch/${MACHINE_ARCH}/Makefile.inc" +.endif + +.PATH: ${DIR} + +CC = ${APMCC} +CFLAGS += -DINITIALIZER -I${DIR} -DKERNEL \ + ${APMCFLAGS:S@-I.@-I${KERNREL}.@g} + +OBJS = apm_init.o real_prot.o table.o + +#.SUFFIXES: .c .S .o +# +#.c.o: +# $(CC) $(CFLAGS) $(OPTFLAGS) $(INC) -c $< +# +.S.o: + $(CC) $(CFLAGS) $(INC) -c $< + +apm_init.inc: apm_init + sh ${DIR}/bin2asm.sh apm_init > apm_init.inc + +apm_init: $(OBJS) + $(LD) -Bstatic -N -T 0 -o apm_init $(OBJS) + cp apm_init apm_init.sym + @strip apm_init + @sh ${DIR}/rmaouthdr apm_init apm_init.tmp + @mv -f apm_init.tmp apm_init + +#allclean: clean +# @rm -f apm_init.inc +clean: + rm -f *.o apm_init apm_init.sym apm_init.inc + +#.include <bsd.prog.mk> diff --git a/sys/arch/i386/apm_init/Makefile.inc b/sys/arch/i386/apm_init/Makefile.inc new file mode 100644 index 00000000000..715da6093c5 --- /dev/null +++ b/sys/arch/i386/apm_init/Makefile.inc @@ -0,0 +1,39 @@ +# $NetBSD: Makefile.inc,v 1.12 1995/10/07 09:56:55 mycroft Exp $ +# +# NOTE: $S must correspond to the top of the 'sys' tree + +APMDIR= ${I386}/apm_init + +APMDST= lib/apm_init +APMREL?= ../../ +APMINC?= ${APMDST}/apm_init.inc + +APMDEPS= \ + ${APMDIR}/Makefile \ + ${APMDIR}/apm_bios.h \ + ${APMDIR}/apm_init.S \ + ${APMDIR}/apm_segments.h \ + ${APMDIR}/bin2asm.sh \ + ${APMDIR}/real_prot.S \ + ${APMDIR}/real_prot.h \ + ${APMDIR}/rmaouthdr \ + ${APMDIR}/table.c + +${APMINC}: ${APMDEPS} ${APMDST} + @echo making sure the apm grappling hook is up to date... + @(cd ${APMDST} && ${MAKE} -f ${APMREL}${APMDIR}/Makefile \ + APMCC="${CC}" \ + APMCFLAGS="${CFLAGS}" \ + APMREL="${APMREL}" \ + APMDIR="${APMDIR}" apm_init.inc) + +clean:: .NOTMAIN __always_make_apmlib + @echo cleaning the apm grappling hook objects + @(cd ${APMDST} && ${MAKE} -f ${APMREL}${APMDIR}/Makefile \ + APMCC="${CC}" \ + APMCFLAGS="${CFLAGS}" \ + APMREL="${APMREL}" \ + APMDIR="${APMDIR}" clean) + +${APMDST} __always_make_apmlib: .NOTMAIN + @([ -d ${APMDST} ] || mkdir -p ${APMDST}) diff --git a/sys/arch/i386/apm_init/apm_bios.h b/sys/arch/i386/apm_init/apm_bios.h new file mode 100644 index 00000000000..5354b9ccfb7 --- /dev/null +++ b/sys/arch/i386/apm_init/apm_bios.h @@ -0,0 +1,185 @@ +/* + * Advanced Power Management (APM) BIOS driver for laptop PCs. + * + * Copyright (c) 1994 by HOSOKAWA Tatsumi <hosokawa@mt.cs.keio.ac.jp> + * + * This software may be used, modified, copied, and distributed, in + * both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + * + * Aug, 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) + * Oct, 1994 NetBSD port (1.0 BETA 10/2) by ukai + */ + +#ifndef APM_BIOS_H +#define APM_BIOS_H 1 + +#ifdef KERNEL + +/* BIOS id */ +#define APM_BIOS 0x53 +#define SYSTEM_BIOS 0x15 + +/* APM flags */ +#define APM_16BIT_SUPPORT 0x01 +#define APM_32BIT_SUPPORT 0x02 +#define APM_CPUIDLE_SLOW 0x04 +#define APM_DISABLED 0x08 +#define APM_DISENGAGED 0x10 + +/* APM initializer physical address */ +#define APM_OURADDR 0x00080000 + +/* Error code of APM initializer */ +#define APMINI_CANTFIND 0xffffffff +#define APMINI_NOT32BIT 0xfffffffe +#define APMINI_CONNECTERR 0xfffffffd +#define APMINI_BADVER 0xfffffffc + +/* APM functions */ +#define APM_INSTCHECK 0x00 +#define APM_REALCONNECT 0x01 +#define APM_PROT16CONNECT 0x02 +#define APM_PROT32CONNECT 0x03 +#define APM_DISCONNECT 0x04 +#define APM_CPUIDLE 0x05 +#define APM_CPUBUSY 0x06 +#define APM_SETPWSTATE 0x07 +#define APM_ENABLEDISABLEPM 0x08 +#define APM_RESTOREDEFAULT 0x09 +#define APM_GETPWSTATUS 0x0a +#define APM_GETPMEVENT 0x0b +#define APM_GETPWSTATE 0x0c +#define APM_ENABLEDISABLEDPM 0x0d +#define APM_DRVVERSION 0x0e +#define APM_ENGAGEDISENGAGEPM 0x0f +#define APM_OEMFUNC 0x80 + +/* error code */ +#define APME_OK 0x00 +#define APME_PMDISABLED 0x01 +#define APME_REALESTABLISHED 0x02 +#define APME_NOTCONNECTED 0x03 +#define APME_PROT16ESTABLISHED 0x05 +#define APME_PROT16NOTSUPPORTED 0x06 +#define APME_PROT32ESTABLISHED 0x07 +#define APME_PROT32NOTDUPPORTED 0x08 +#define APME_UNKNOWNDEVICEID 0x09 +#define APME_OUTOFRANGE 0x0a +#define APME_NOTENGAGED 0x0b +#define APME_CANTENTERSTATE 0x60 +#define APME_NOPMEVENT 0x80 +#define APME_NOAPMPRESENT 0x86 + + +/* device code */ +#define PMDV_APMBIOS 0x0000 +#define PMDV_ALLDEV 0x0001 +#define PMDV_DISP0 0x0100 +#define PMDV_DISP1 0x0101 +#define PMDV_2NDSTORAGE0 0x0200 +#define PMDV_2NDSTORAGE1 0x0201 +#define PMDV_2NDSTORAGE2 0x0202 +#define PMDV_2NDSTORAGE3 0x0203 +#define PMDV_PARALLEL0 0x0300 +#define PMDV_PARALLEL1 0x0301 +#define PMDV_SERIAL0 0x0400 +#define PMDV_SERIAL1 0x0401 +#define PMDV_SERIAL2 0x0402 +#define PMDV_SERIAL3 0x0403 +#define PMDV_SERIAL4 0x0404 +#define PMDV_SERIAL5 0x0405 +#define PMDV_SERIAL6 0x0406 +#define PMDV_SERIAL7 0x0407 +#define PMDV_NET0 0x0500 +#define PMDV_NET1 0x0501 +#define PMDV_NET2 0x0502 +#define PMDV_NET3 0x0503 +#define PMDV_PCMCIA0 0x0600 +#define PMDV_PCMCIA1 0x0601 +#define PMDV_PCMCIA2 0x0602 +#define PMDV_PCMCIA3 0x0603 +/* 0x0700 - 0xdfff Reserved */ +/* 0xe000 - 0xefff OEM-defined power device IDs */ +/* 0xf000 - 0xffff Reserved */ + +/* Power state */ +#define PMST_APMENABLED 0x0000 +#define PMST_STANDBY 0x0001 +#define PMST_SUSPEND 0x0002 +#define PMST_OFF 0x0003 +#define PMST_LASTREQNOTIFY 0x0004 +#define PMST_LASTREQREJECT 0x0005 +/* 0x0006 - 0x001f Reserved system states */ +/* 0x0020 - 0x003f OEM-defined system states */ +/* 0x0040 - 0x007f OEM-defined device states */ +/* 0x0080 - 0xffff Reserved device states */ + +#if !defined(ASM) && !defined(INITIALIZER) + +/* C definitions */ +typedef struct apm_hook_func { + struct apm_hook_func *next; /* Linked list */ + int (*func)(void); + const char *name; + int order; +} *apm_hook_func_t; + +apm_hook_func_t apm_resume_hook_init(int (*func)(void), char *name, int order); +void apm_resume_hook_delete(apm_hook_func_t delete_func); +apm_hook_func_t apm_suspend_hook_init(int (*func)(void), char *name, int order); +void apm_suspend_hook_delete(apm_hook_func_t delete_func); +void apm_suspend_resume(void); +void apm_cpu_idle(void); +void apm_cpu_busy(void); + +#endif /* !ASM && !INITIALIZER */ + +#define APM_MIN_ORDER 0x00 +#define APM_MID_ORDER 0x80 +#define APM_MAX_ORDER 0xff + +#endif /* KERNEL */ + +/* power management event code */ +#define PMEV_NOEVENT 0x0000 +#define PMEV_STANDBYREQ 0x0001 +#define PMEV_SUSPENDREQ 0x0002 +#define PMEV_NORMRESUME 0x0003 +#define PMEV_CRITRESUME 0x0004 +#define PMEV_BATTERYLOW 0x0005 +#define PMEV_POWERSTATECHANGE 0x0006 +#define PMEV_UPDATETIME 0x0007 +#define PMEV_CRITSUSPEND 0x0008 +#define PMEV_USERSTANDBYREQ 0x0009 +#define PMEV_USERSUSPENDREQ 0x000a +#define PMEV_STANDBYRESUME 0x000b +/* 0x000c - 0x00ff Reserved system events */ +/* 0x0100 - 0x01ff Reserved device events */ +/* 0x0200 - 0x02ff OEM-defined APM events */ +/* 0x0300 - 0xffff Reserved */ +#define PMEV_DEFAULT 0xffffffff /* used for customization */ + +#if !defined(ASM) && !defined(INITIALIZER) + +typedef struct apm_info { + u_int ai_major; /* APM major version */ + u_int ai_minor; /* APM minor version */ + u_int ai_acline; /* AC line status */ + u_int ai_batt_stat; /* Battery status */ + u_int ai_batt_life; /* Remaining battery life */ +} *apm_info_t; + +#define APMIO_SUSPEND _IO('P', 1) +#define APMIO_GETINFO _IOR('P', 2, struct apm_info) +#define APMIO_ENABLE _IO('P', 3) +#define APMIO_DISABLE _IO('P', 4) +#define APMIO_HALTCPU _IO('P', 5) +#define APMIO_NOTHALTCPU _IO('P', 6) + +#endif /* !ASM && !INITIALIZER */ + +#endif /* APM_BIOS_H */ diff --git a/sys/arch/i386/apm_init/apm_init.S b/sys/arch/i386/apm_init/apm_init.S new file mode 100644 index 00000000000..945c251446a --- /dev/null +++ b/sys/arch/i386/apm_init/apm_init.S @@ -0,0 +1,215 @@ +/* + * LP (Laptop Package) + * + * Copyright (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp> + * + * This software may be used, modified, copied, and distributed, in + * both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + * + * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) + * Oct., 1994 NetBSD port (1.0 BETA 10/2) by ukai + */ + +/* + * If you want to know the specification of APM BIOS, see the following + * documentations, + * + * [1] Intel Corporation and Microsoft Corporation, "Advanced Power + * Management, The Next Generation, Version 1.0", Feb.,1992. + * + * [2] Intel Corporation and Microsoft Corporation, "Advanced Power + * Management (APM) BIOS Interface Specification Revision 1.1", + * Sep.,1993, Intel Order Number: 241704-001, Microsoft Part + * Number: 781-110-X01 + * + * or contact + * + * APM Support Desk (Intel Corporation, US) + * TEL: (800)628-8686 + * FAX: (916)356-6100. + */ + + .file "apm_init.S" + +#define ASM + +#include "real_prot.h" +#include <apm_bios.h> +#include <apm_segments.h> + +/* + * APM BIOS initializer + * + * Return value: + * %eax 0xfffffff Can't find APM BIOS + * 0xffffffe Don't support 32bit connection + * 0xffffffd Connection error + * otherwise APM version (16bit BCD format) + * %ebx APM cs entry offset (32bit) + * %ecx lower 16bit APM 16bit cs base (real mode segment) + * upper 16bit APM 32bit cs base (real mode segment) + * %edx lower 16bit APM ds limit (real mode segment) + * upper 16bit [Reserved] + * %esi lower 16bit APM cs limit (APM 1.1 or later) + * upper 16bit APM ds limit (APM 1.1 or later) + * %edi bit0 = 1 16bit protected mode interface supported + * bit1 = 1 32bit protected mode interface supported + * bit2 = 1 "CPU idle" call slows processor clock speed + * bit3 = 1 APM BIOS Power Management disabled + * bit4 = 1 APM BIOS Power Management disengaged + */ + + .text +ENTRY(apm_init) + cli /* disable interrupt */ + push %ebp /* save original base pointer */ + /* ebp is used as a register variable */ + /* + * save old data segments: We assume that %ds == %es && %ds == %ss + */ + push %fs + movw %ds, %ax + movw %ax, %fs + movw $(APM_INIT_DS_SEL), %ax /* initializer data segment */ + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + movl %esp, old_esp /* save original stack pointer */ + movl $0xf000, %esp /* setup temporary stack */ + /* (note that it isn't 0x00000000) */ + + sidt EXT(Idtr_prot) /* save current IDT */ + call EXT(prot_to_real) /* return to real mode */ + + /* + * APM installation check + */ + movb $(APM_BIOS), %ah + movb $(APM_INSTCHECK), %al + data32 + movl $(PMDV_APMBIOS), %ebx + sti + int $(SYSTEM_BIOS) /* call system BIOS */ + cli + + jnc 1f /* if found, goto 1f */ + + data32 + call EXT(real_to_prot) /* come back again to protected mode */ + movl $(APMINI_CANTFIND), apm_version + /* can't find APM BIOS */ + jmp finish + +1: + movl %eax, %edx /* actually, movw %ax, %dx */ + /* save the value of %ax */ + data32 + call EXT(real_to_prot) /* come back again to protected mode */ + cmpb $0x50, %bh /* %bh == 'P'? */ + jnz 1f + cmpb $0x4d, %bl /* %bl == 'M'? */ + jz 2f + +1: + movl $(APMINI_BADVER), apm_version + /* can't find APM BIOS */ + jmp finish + +2: + testl $(APM_32BIT_SUPPORT), %ecx + /* supports 32bit connection? */ + jnz 1f + + movl $(APMINI_NOT32BIT), apm_version + /* don't support 32bit connection */ + jmp finish +1: + movl %edx, apm_version + andl $0x0000ffff, %ecx + movl %ecx, apm_flags + + /* + * APM Protected Mode 32-bit Interface Connect + */ + call EXT(prot_to_real) /* return to real mode */ + + movb $(APM_BIOS), %ah + movb $(APM_DISCONNECT), %al /* just in case bootloader connected*/ + data32 + movl $(PMDV_APMBIOS), %ebx + sti + int $(SYSTEM_BIOS) + cli + movb $(APM_BIOS), %ah + movb $(APM_PROT32CONNECT), %al + data32 + movl $(PMDV_APMBIOS), %ebx + sti + int $(SYSTEM_BIOS) + cli + jnc 1f /* if successed, go to 1f */ + data32 + call EXT(real_to_prot) + movl $(APMINI_CONNECTERR), apm_version + /* connection error */ + jmp finish +1: + /* save PM 32bit code segment into %bp */ + movl %eax, %ebp /* actually, movw %ax, %bp */ + data32 + call EXT(real_to_prot) + movl $0x0000ffff, %eax + andl %eax, %ebp /* 32bit cs base */ + andl %eax, %ecx /* 16bit cs base */ + andl %eax, %edx /* ds base */ + andl %eax, %esi /* cs length (APM 1.1 or later) */ + andl %eax, %edi /* ds length (APM 1.1 or later) */ + /* %ebx is code offset */ + /* pack 32bit cs and 16bit cs into %ecx */ + shll $16, %ebp + orl %ebp, %ecx + /* pack cs length and ds length into %esi */ + shll $16, %edi + orl %edi, %esi +finish: + cli + lidt EXT(Idtr_prot) /* restore old IDTR */ + movl old_esp, %esp /* restore old stack pointer */ + movl apm_version, %ebp /* stored to %eax later */ + movl apm_flags, %edi +#if 0 + movw $(BOOTSTRAP_DS_SEL), %ax + /* restore old data segments */ +#else + movw %fs, %ax +#endif + movw %ax, %ss + movw %ax, %es + movw %ax, %ds + movl %ebp, %eax + pop %fs + popl %ebp /* restore old base pointer */ + lret /* restore old code segment */ + + .data + + .globl EXT(ouraddr) +LEXT(ouraddr) + .long APM_OURADDR + +old_esp: + .long 0 +apm_version: + .long 0 +apm_flags: + .long 0 +old_ds: + .word 0 +old_es: + .word 0 +old_ss: + .word 0 diff --git a/sys/arch/i386/apm_init/apm_segments.h b/sys/arch/i386/apm_init/apm_segments.h new file mode 100644 index 00000000000..5e5fcdbe7e4 --- /dev/null +++ b/sys/arch/i386/apm_init/apm_segments.h @@ -0,0 +1,30 @@ +/* + * LP (Laptop Package) + * + * Copyright (C) 1994 by HOSOKAWA Tatsumi <hosokawa@mt.cs.keio.ac.jp> + * + * This software may be used, modified, copied, and distributed, in + * both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + * + * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) + */ + +#define SIZEOF_GDT 8 +#define BOOTSTRAP_GDT_NUM 9 + +#define APM_INIT_CS_INDEX (BOOTSTRAP_GDT_NUM - 3) +#define APM_INIT_DS_INDEX (BOOTSTRAP_GDT_NUM - 2) +#define APM_INIT_CS16_INDEX (BOOTSTRAP_GDT_NUM - 1) +#define APM_INIT_CS_SEL (APM_INIT_CS_INDEX << 3) +#define APM_INIT_DS_SEL (APM_INIT_DS_INDEX << 3) +#define APM_INIT_CS16_SEL (APM_INIT_CS16_INDEX << 3) + +#define CS32_ATTRIB 0x4F9e +#define CS16_ATTRIB 0x009e +#define DS32_ATTRIB 0x4F92 + +#define BOOTSTRAP_DS_SEL 0x10 diff --git a/sys/arch/i386/apm_init/apm_setup.h b/sys/arch/i386/apm_init/apm_setup.h new file mode 100644 index 00000000000..fdc380e50be --- /dev/null +++ b/sys/arch/i386/apm_init/apm_setup.h @@ -0,0 +1,24 @@ +/* + * LP (Laptop Package) + * + * Copyright (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp> + * + * This software may be used, modified, copied, distributed, and sold, + * in both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + * + * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) + * Oct., 1994 NetBSD port (1.0 BETA 10/2) by ukai + */ + +extern u_long apm_version; +extern u_long apm_cs_entry; +extern u_short apm_cs32_base; +extern u_short apm_cs16_base; +extern u_short apm_ds_base; +extern u_short apm_cs_limit; +extern u_short apm_ds_limit; +extern u_short apm_flags; diff --git a/sys/arch/i386/apm_init/bin2asm.sh b/sys/arch/i386/apm_init/bin2asm.sh new file mode 100644 index 00000000000..6694b49d9b5 --- /dev/null +++ b/sys/arch/i386/apm_init/bin2asm.sh @@ -0,0 +1,21 @@ +#!/bin/sh - +# bin2asm (binary to asm) shell script version by ukai +# +# +if [ $# -lt 1 ]; then + echo 'usage: $0 [in]' + exit 1 +fi +in=$1 +size=`ls -l ${in} | awk '{print $5}'` +# Oops, must 8 byte align +len=`expr \( $size + 8 \) / 8 \* 8` + +echo "/* This file is automatically generated by bin2asm.sh */" +echo "/* Original file is '${in}' */" +echo +dd if=${in} bs=${len} conv=sync |\ + hexdump -v -e '" .byte " 7/1 "0x%02x, " 1/1 " 0x%02x" "\n"' +echo +echo "/* Total size = $size -> $len */" +echo "/* End of File */" diff --git a/sys/arch/i386/apm_init/real_prot.S b/sys/arch/i386/apm_init/real_prot.S new file mode 100644 index 00000000000..5f9e97ecf68 --- /dev/null +++ b/sys/arch/i386/apm_init/real_prot.S @@ -0,0 +1,186 @@ +/* + * Mach Operating System + * Copyright (c) 1992, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + * + * from: Mach, Revision 2.2 92/04/04 11:34:13 rpd + * $Id: real_prot.S,v 1.1 1996/04/29 14:15:43 hvozda Exp $ + */ + + +/* + Copyright 1988, 1989, 1990, 1991, 1992 + by Intel Corporation, Santa Clara, California. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appears in all +copies and that both the copyright notice and this permission notice +appear in supporting documentation, and that the name of Intel +not be used in advertising or publicity pertaining to distribution +of the software without specific, written prior permission. + +INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, +IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, +NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION +WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +/* + * LP (Laptop Package) + * + * Copyright (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp> + * + * This software may be used, modified, copied, and distributed, in + * both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + * + * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) + * Oct., 1994 NetBSD port (1.0 BETA 10/2) by ukai + */ + +/* + * Modified for APM BIOS initializer by HOSOKAWA Tatsumi + * + * See also locore.s. It supports these functions works correctly. + */ + + .file "real_prot.S" + +#include "real_prot.h" +#include "apm_segments.h" + +CR0_PE_ON = 0x1 +CR0_PE_OFF = 0xfffffffe + +.globl _ouraddr + .text + +/* + * + * real_to_prot() + * transfer from real mode to protected mode. + */ + +ENTRY(real_to_prot) + /* guarantee that interrupt is disabled when in prot mode */ + cli + + /* + * deleted for APM initializer by HOSOKAWA Tatsumi + * <hosoakwa@mt.cs.keio.ac.jp> + */ +#if 0 + /* load the gdtr */ + addr32 + data32 + lgdt EXT(Gdtr) +#endif + + /* set the PE bit of CR0 */ + mov %cr0, %eax + + data32 + or $CR0_PE_ON, %eax + mov %eax, %cr0 + + /* + * make intrasegment jump to flush the processor pipeline and + * reload CS register + */ + data32 + ljmp $(APM_INIT_CS_SEL), $xprot + +xprot: + /* + * we are in USE32 mode now + * set up the protected mode segment registers : DS, SS, ES + */ + mov $(APM_INIT_DS_SEL), %eax + movw %ax, %ds + movw %ax, %ss + movw %ax, %es + + /* load idtr so we can debug */ + lidt EXT(Idtr_prot) + + ret + +/* + * + * prot_to_real() + * transfer from protected mode to real mode + * + */ + +ENTRY(prot_to_real) + + /* set up a dummy stack frame for the second seg change. */ + movl _ouraddr, %eax + sarl $4, %eax + pushw %ax + movw $xreal, %ax /* gas botches pushw $xreal - extra bytes 0, 0*/ + pushw %ax /* decode to add %al, (%eax) (%al usually 0) */ + + /* Change to use16 mode. */ + ljmp $(APM_INIT_CS16_SEL), $x16 + +x16: + /* clear the PE bit of CR0 */ + mov %cr0, %eax + data32 + and $CR0_PE_OFF, %eax + mov %eax, %cr0 + + /* + * make intersegment jmp to flush the processor pipeline + * using the fake stack frame set up earlier + * and reload CS register + */ + lret + +xreal: + /* + * we are in real mode now + * set up the real mode segment registers : DS, SS, ES + */ + movw %cs, %ax + movw %ax, %ds + movw %ax, %ss + movw %ax, %es + + /* load idtr so we can debug */ + addr32 + data32 + lidt EXT(Idtr_real) + + data32 + ret diff --git a/sys/arch/i386/apm_init/real_prot.h b/sys/arch/i386/apm_init/real_prot.h new file mode 100644 index 00000000000..51e91cf05d9 --- /dev/null +++ b/sys/arch/i386/apm_init/real_prot.h @@ -0,0 +1,57 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + * + * from: Mach, Revision 2.7 92/02/29 15:33:41 rpd + * $Id: real_prot.h,v 1.1 1996/04/29 14:15:14 hvozda Exp $ + */ + +/* + * LP (Laptop Package) + * + * Copyright (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp> + * + * This software may be used, modified, copied, and distributed, in + * both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + * + * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) + * Oct., 1994 NetBSD port (1.0 BETA 10/2) by ukai + */ + +/* + * Modified to APM BIOS initializer by HOSOKAWA, Tatsumi + */ + +#define ALIGN 4 +#define EXT(x) _ ## x +#define LEXT(x) _ ## x ## : + +#define addr32 .byte 0x67 +#define data32 .byte 0x66 + +#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x) diff --git a/sys/arch/i386/apm_init/rmaouthdr b/sys/arch/i386/apm_init/rmaouthdr new file mode 100644 index 00000000000..608715015fe --- /dev/null +++ b/sys/arch/i386/apm_init/rmaouthdr @@ -0,0 +1,6 @@ +#!/bin/csh -f +# +# from: Mach, Revision 2.2 92/04/04 11:36:01 rpd +# $Id: rmaouthdr,v 1.1 1996/04/29 14:15:35 hvozda Exp $ +# +dd if=$1 of=$2 ibs=32 skip=1 obs=1024b diff --git a/sys/arch/i386/apm_init/table.c b/sys/arch/i386/apm_init/table.c new file mode 100644 index 00000000000..d3cc1d98670 --- /dev/null +++ b/sys/arch/i386/apm_init/table.c @@ -0,0 +1,25 @@ +/* + * LP (Laptop Package) + * + * Copyright (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp> + * + * This software may be used, modified, copied, and distributed, in + * both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + * + * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) + * Oct., 1994 NetBSD port (1.0 BETA 10/2) by ukai + */ + +#include <apm_bios.h> + +struct pseudo_desc { + unsigned short limit; + unsigned long base __attribute__ ((packed)); +}; + +struct pseudo_desc Idtr_prot = { 0, 0 }; /* filled on run time */ +struct pseudo_desc Idtr_real = { 0x400 - 1, 0x0 }; diff --git a/sys/arch/i386/conf/HELIOS_PCMCIA b/sys/arch/i386/conf/HELIOS_PCMCIA index b412cdfb0ad..2b91d0e76f8 100644 --- a/sys/arch/i386/conf/HELIOS_PCMCIA +++ b/sys/arch/i386/conf/HELIOS_PCMCIA @@ -1,4 +1,4 @@ -# $OpenBSD: HELIOS_PCMCIA,v 1.3 1996/04/18 18:55:35 niklas Exp $ +# $OpenBSD: HELIOS_PCMCIA,v 1.4 1996/04/29 14:12:01 hvozda Exp $ # # HELIOS_PCMCIA -- Eric Hvozda's notebook # @@ -25,6 +25,7 @@ options KTRACE # system call tracing, a la ktrace(1) options COMPAT_NOMID # compatibility with 386BSD, BSDI, NetBSD 0.8, options COMPAT_09 # NetBSD 0.9, options COMPAT_10 # NetBSD 1.0, +options COMPAT_11 # NetBSD 1.1, options COMPAT_43 # and 4.3BSD options LKM # loadable kernel modules @@ -48,26 +49,46 @@ options FDSCRIPTS # secure setuid scripts options INET # IP + ICMP + TCP + UDP -config bsd root on wd0a swap on wd0b and vnd0b dumps on wd0b +config bsd root on wd0a swap on wd0b dumps on wd0b mainbus0 at root isa0 at mainbus0 pci0 at mainbus0 +#apm0 at mainbus0 npx0 at isa? port 0xf0 irq 13 # math coprocessor pc0 at isa? port 0x60 irq 1 # generic PC console device - -pcic0 at isa? port 0x3E0 flags 0 -pcmcia0 at pcic? iomem 0xd4000 iosiz 4096 -com2 at pcmcia? port 0x3e8 irq 12 -ed2 at pcmcia? port 0x300 iomem 0xcc000 irq 10 +#spkr0 at pckbd? port 0x61 # PC speaker + +# Multiple controllers need some testing. Some laptops have multiple PCIC +# controllers instead of two-slot controllers. +# The i82365 (pcic) controller uses the same ports for the first two +# controllers and for the second two controllers. + +# IRQ 2/9 doesn't seem to work for status change interrupts, so use one +# of the higher ones. +pcicmaster0 at isa? port 0x3E0 size 2 +pcic0 at pcicmaster0 irq 11 iomem 0xd4000 iosiz 4096 +pcic1 at pcicmaster0 irq 12 iomem 0xd5000 iosiz 4096 +pcicmaster1 at isa? port 0x3E2 size 2 +pcic2 at pcicmaster1 irq 11 iomem 0xd6000 iosiz 4096 +pcic3 at pcicmaster1 irq 12 iomem 0xd7000 iosiz 4096 + +pcmcia* at pcic? + +#ed0 at pcmcia? port 0x300 iomem 0xd8000 iosiz 8192 irq 10 +ed0 at pcmcia? port 0x300 size 0x20 irq 10 slot ? +#ep0 at pcmcia? port 0x300 size 0x10 irq 10 slot ? +#com1 at pcmcia? port 0x2f8 size 8 irq 5 slot ? +com2 at pcmcia? port 0x3e8 size 8 irq 5 slot ? +#com3 at pcmcia? port 0x2e8 size 8 irq 3 slot ? com0 at isa? port 0x3f8 irq 4 # standard PC serial ports com1 at isa? port 0x2f8 irq 3 -lpt0 at isa? port 0x378 irq 7 # standard PC parallel ports +lpt0 at isa? port 0x378 # standard PC parallel ports fdc0 at isa? port 0x3f0 irq 6 drq 2 # standard PC floppy controllers fd0 at fdc? drive 0 @@ -75,7 +96,7 @@ fd0 at fdc? drive 0 wdc0 at isa? port 0x1f0 irq 14 # ST506, ESDI, and IDE controllers wd0 at wdc? drive 0 -sb0 at isa? port 0x240 irq 5 drq 1 # SoundBlaster +sb0 at isa? port 0x240 irq 7 drq 1 # SoundBlaster pseudo-device loop 1 # network loopback pseudo-device bpfilter 8 # packet filter diff --git a/sys/arch/i386/conf/Makefile.i386 b/sys/arch/i386/conf/Makefile.i386 index aee08091430..0edf4047ae1 100644 --- a/sys/arch/i386/conf/Makefile.i386 +++ b/sys/arch/i386/conf/Makefile.i386 @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile.i386,v 1.8 1996/04/24 12:05:17 mickey Exp $ +# $OpenBSD: Makefile.i386,v 1.9 1996/04/29 14:12:10 hvozda Exp $ # $NetBSD: Makefile.i386,v 1.66 1996/02/29 20:56:16 cgd Exp $ # Makefile for OpenBSD @@ -145,10 +145,14 @@ links: sed 's,../.*/\(.*.o\),rm -f \1; ln -s ../GENERIC/\1 \1,' > makelinks sh makelinks && rm -f dontlink +# depend on APM +.include "${I386}/apm_init/Makefile.inc" +locore.o: ${APMINC} + SRCS= ${I386}/i386/locore.s \ param.c ioconf.c ${CFILES} ${SFILES} depend: .depend -.depend: ${SRCS} assym.h param.c +.depend: ${SRCS} assym.h param.c ${APMINC} mkdep ${AFLAGS} ${CPPFLAGS} ${I386}/i386/locore.s mkdep -a ${CFLAGS} ${CPPFLAGS} param.c ioconf.c ${CFILES} mkdep -a ${AFLAGS} ${CPPFLAGS} ${SFILES} diff --git a/sys/arch/i386/conf/PCMCIA b/sys/arch/i386/conf/PCMCIA new file mode 100644 index 00000000000..2544e06c62c --- /dev/null +++ b/sys/arch/i386/conf/PCMCIA @@ -0,0 +1,138 @@ +# $Id: PCMCIA,v 1.1 1996/04/29 14:12:24 hvozda Exp $ +# $Source: /cvs/OpenBSD/src/sys/arch/i386/conf/Attic/PCMCIA,v $ +# +# ATHENA-AHA -- ATHENA kernel for Adaptec & others... +# +# from: GENERIC -- everything that's currently supported +# NetBSD: GENERIC,v 1.12 1995/02/21 01:43:02 brezak Exp +# + +machine i386 # architecture, used by config; REQUIRED + +options I586_CPU +options I486_CPU +options I386_CPU +options INSECURE +options MATH_EMULATE + +options DUMMY_NOPS # speed hack; recommanded +options XSERVER,UCONSOLE +options MACHINE_NONCONTIG + +maxusers 32 # estimated number of users +options TIMEZONE=300 # time zone to adjust RTC time by +options DST=1 # daylight savings time used by RTC + +options SWAPPAGER # paging; REQUIRED +options VNODEPAGER # mmap() of files +options DEVPAGER # mmap() of devices + +options DDB # in-kernel debugger +#makeoptions DEBUG="-g" # compile full symbol table +#options DIAGNOSTIC # internally consistency checks +options KTRACE # system call tracing, a la ktrace(1) + +options SYSVMSG # System V-like message queues +options SYSVSEM # System V-like semaphores +options SYSVSHM # System V-like memory sharing +#options SHMMAXPGS=1024 # 1024 pages is the default + +options COMPAT_NOMID # compatibility with 386BSD, BSDI, NetBSD 0.8, +options COMPAT_09 # NetBSD 0.9, +options COMPAT_10 # NetBSD 1.0, +options COMPAT_43 # and 4.3BSD +options TCP_COMPAT_42 # TCP bug compatibility with 4.2BSD + +options COMPAT_SVR4 # binary compatibility with SVR4 +options COMPAT_IBCS2 # binary compatibility with SCO and ISC +options COMPAT_LINUX # binary compatibility with Linux + +options USER_LDT # user-settable LDT; used by WINE +options LKM # loadable kernel modules + +options FFS #,QUOTA # UFS and quotas +#options LFS # log-structured file system +options MFS # memory file system + +options NFSCLIENT # Network File System client +options NFSSERVER # Network File System server +options HAS_VOPLEASE # XXX + +options APM_NOIDLE +#options PCIVERBOSE +#options PCMCIA_DEBUG +#options PCMCIA_ISA_DEBUG + +### SCSI: +#options CD9660 # ISO 9660 + Rock Ridge file system +### +options MSDOSFS # MS-DOS file system +options FIFO # FIFOs; RECOMMENDED +options PROCFS # /proc + +#options GATEWAY # packet forwarding +options INET # IP + ICMP + TCP + UDP +#options NS # XNS +#options ISO,TPIP # OSI +#options EON # OSI tunneling over IP +#options CCITT,LLC,HDLC # X.25 + +config netbsd swap generic +options GENERIC + +# Local Athena options + +options PCVT_CTRL_ALT_DEL # For screwed-over Linux weenies + +mainbus0 at root +isa0 at mainbus0 +pci0 at mainbus0 bus 0 + +npx0 at isa? port 0xf0 irq 13 # math coprocessor + +vt0 at isa? port 0x60 irq 1 + +com0 at isa? port 0x3f8 irq 4 # standard PC serial ports +com1 at isa? port 0x2f8 irq 3 +com2 at isa? port 0x3e8 irq 5 + +lpt0 at isa? port 0x378 irq 7 # standard PC parallel ports + +pms0 at pckbd? irq 12 # PS/2 auxiliary port mouse + +fdc0 at isa? port 0x3f0 irq 6 drq 2 # standard PC floppy controllers +fd0 at fdc0 drive 0 + +wdc0 at isa? port 0x1f0 irq 14 # ST506, ESDI, and IDE controllers +wd0 at wdc0 drive 0 + +spkr0 at pckbd? port 0x61 +#apm0 at mainbus? + +# Multiple controllers need some testing. Some laptops have multiple PCIC +# controllers instead of two-slot controllers. +# The i82365 (pcic) controller uses the same ports for the first two +# controllers and for the second two controllers. + +# IRQ 2/9 doesn't seem to work for status change interrupts, so use one +# of the higher ones. +pcicmaster0 at isa? port 0x3E0 size 2 +pcic0 at pcicmaster0 irq 11 iomem 0xd4000 iosiz 4096 +pcic1 at pcicmaster0 irq 12 iomem 0xd5000 iosiz 4096 +pcicmaster1 at isa? port 0x3E2 size 2 +pcic2 at pcicmaster1 irq 11 iomem 0xd6000 iosiz 4096 +pcic3 at pcicmaster1 irq 12 iomem 0xd7000 iosiz 4096 + +pcmcia* at pcic? + +#ed0 at pcmcia? port 0x300 iomem 0xd8000 iosiz 8192 irq 10 +ed0 at pcmcia? port 0x300 size 0x20 irq 10 slot ? +ep0 at pcmcia? port 0x300 size 0x10 irq 10 slot ? +#com1 at pcmcia? port 0x2f8 size 8 irq 5 slot ? +#com2 at pcmcia? port 0x3e8 size 8 irq 5 slot ? +com3 at pcmcia? port 0x2e8 size 8 irq 3 slot ? + +pseudo-device loop 1 # network loopback +pseudo-device bpfilter 4 # packet filter +pseudo-device ppp 2 # PPP +pseudo-device pty 64 # pseudo-terminals diff --git a/sys/arch/i386/conf/files.i386 b/sys/arch/i386/conf/files.i386 index c434f132f04..2bd8ee7cb59 100644 --- a/sys/arch/i386/conf/files.i386 +++ b/sys/arch/i386/conf/files.i386 @@ -1,4 +1,4 @@ -# $OpenBSD: files.i386,v 1.13 1996/04/28 17:02:01 mickey Exp $ +# $OpenBSD: files.i386,v 1.14 1996/04/29 14:12:16 hvozda Exp $ # $NetBSD: files.i386,v 1.72 1996/04/09 22:59:03 cgd Exp $ # # new style config file for i386 architecture @@ -52,7 +52,8 @@ major {rd = 17} # System bus types # -device mainbus: isabus, eisabus, pcibus +define mainbus { } +device mainbus: isabus, eisabus, pcibus, mainbus attach mainbus at root file arch/i386/i386/mainbus.c mainbus @@ -69,6 +70,12 @@ file arch/i386/pci/pci_machdep.c pci file arch/i386/pci/pci_compat.c pci # XXX compatibility # +# Pcmcia, before ISA (to define device stuff) +# + +include "../../../dev/pcmcia/files.pcmcia" + +# # ISA and mixed ISA+EISA or ISA+PCI or ISA+PCMCIA drivers # @@ -77,10 +84,6 @@ major {mcd = 7} major {wd = 0} major {wt = 3} -#define pcic here until config issues are resolved -#device pcic at isa: pcmciabus -#file dev/isa/pcmcia_pcic.c pcic - include "../../../dev/isa/files.isa" file arch/i386/isa/isa_machdep.c isabus @@ -138,9 +141,9 @@ file arch/i386/isa/spkr.c spkr needs-flag # National Semiconductor DS8390/WD83C690-based boards # (WD/SMC 80x3 family, SMC Ultra [8216], 3Com 3C503, NE[12]000, and clones) # XXX conflicts with other ports; can't be in files.isa -device ed: ether, ifnet -attach ed at isa -file dev/isa/if_ed.c ed +#device ed: ether, ifnet +#attach ed at isa +#file dev/isa/if_ed.c ed # AMD am7990 (Lance) -based boards # (BICC Isolan, NE2100, DEPCA) @@ -183,3 +186,7 @@ file arch/i386/i386/linux_machdep.c compat_linux # FreeBSD binary compatibility (COMPAT_FREEBSD) include "../../../compat/freebsd/files.freebsd" file arch/i386/i386/freebsd_machdep.c compat_freebsd + +device apm +attach apm at mainbus +file arch/i386/i386/apm.c apm needs-count diff --git a/sys/arch/i386/i386/apm.c b/sys/arch/i386/i386/apm.c new file mode 100644 index 00000000000..03483c7a868 --- /dev/null +++ b/sys/arch/i386/i386/apm.c @@ -0,0 +1,844 @@ +/* $NetBSD $ */ + +/*- + * Copyright (c) 1995 John T. Kohl. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + */ + +#include "apm.h" +#if NAPM > 0 + +#if NAPM > 1 +#error only one APM device may be configured +#endif + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/signalvar.h> +#include <sys/kernel.h> +#include <sys/map.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/malloc.h> +#include <sys/device.h> +#include <sys/fcntl.h> +#include <sys/ioctl.h> + +#include <machine/cpu.h> +#include <machine/cpufunc.h> +#include <machine/gdt.h> +#include <machine/psl.h> + +#include <dev/isa/isareg.h> +#include <i386/isa/isa_machdep.h> +#include <i386/isa/nvram.h> +#include <dev/isa/isavar.h> + +#include <machine/apmvar.h> + +#if defined(DEBUG) || defined(APMDEBUG) +#define DPRINTF(x) printf x +#define STATIC /**/ +#else +#define DPRINTF(x) /**/ +#define STATIC static +#endif + +int apmprobe __P((struct device *, void *, void *)); +void apmattach __P((struct device *, struct device *, void *)); + +#define APM_NEVENTS 16 + +struct apm_softc { + struct device sc_dev; + struct selinfo sc_rsel; + struct selinfo sc_xsel; + int sc_flags; + int event_count; + int event_ptr; + struct apm_event_info event_list[APM_NEVENTS]; +}; +#define SCFLAG_OREAD 0x0000001 +#define SCFLAG_OWRITE 0x0000002 +#define SCFLAG_OPEN (SCFLAG_OREAD|SCFLAG_OWRITE) + +#define APMUNIT(dev) (minor(dev)&0xf0) +#define APMDEV(dev) (minor(dev)&0x0f) +#define APMDEV_NORMAL 0 +#define APMDEV_CTL 8 + +struct cfattach apm_ca = { + sizeof(struct apm_softc), apmprobe, apmattach +}; + +struct cfdriver apm_cd = { + NULL, "apm", DV_DULL +}; + +struct apm_connect_info apminfo = { 0 }; +u_char apm_majver; +u_char apm_minver; +u_short apminited; +int apm_dobusy; + +STATIC int apm_get_powstat __P((struct apmregs *)); +STATIC void apm_power_print __P((struct apm_softc *, struct apmregs *)); +STATIC void apm_event_handle __P((struct apm_softc *, struct apmregs *)); +STATIC int apm_get_event __P((struct apmregs *)); +STATIC void apm_set_ver __P((struct apm_softc *)); +STATIC void apm_periodic_check __P((void *)); +STATIC void apm_disconnect __P((void *)); +STATIC void apm_perror __P((const char *, struct apmregs *)); +STATIC void apm_powmgt_enable __P((int onoff)); +STATIC void apm_powmgt_engage __P((int onoff, u_int devid)); +STATIC void apm_devpowmgt_enable __P((int onoff, u_int devid)); +STATIC void apm_suspend __P((void)); +STATIC void apm_standby __P((void)); +STATIC int apm_record_event __P((struct apm_softc *sc, u_int event_type)); + +STATIC const char * +apm_err_translate(code) +int code; +{ + switch(code) { + case APM_ERR_PM_DISABLED: + return "power management disabled"; + case APM_ERR_REALALREADY: + return "real mode interface already connected"; + case APM_ERR_NOTCONN: + return "interface not connected"; + case APM_ERR_16ALREADY: + return "16-bit interface already connected"; + case APM_ERR_16NOTSUPP: + return "16-bit interface not supported"; + case APM_ERR_32ALREADY: + return "32-bit interface already connected"; + case APM_ERR_32NOTSUPP: + return "32-bit interface not supported"; + case APM_ERR_UNRECOG_DEV: + return "unrecognized device ID"; + case APM_ERR_ERANGE: + return "parameter out of range"; + case APM_ERR_NOTENGAGED: + return "interface not engaged"; + case APM_ERR_UNABLE: + return "unable to enter requested state"; + case APM_ERR_NOEVENTS: + return "No pending events"; + case APM_ERR_NOT_PRESENT: + return "No APM present"; + default: + return "unknown error code?"; + } +} + +STATIC void +apm_perror(str, regs) +const char *str; +struct apmregs *regs; +{ + printf("APM %s: %s (%d)\n", str, + apm_err_translate(APM_ERR_CODE(regs)), + APM_ERR_CODE(regs)); +} + +STATIC void +apm_power_print (sc, regs) +struct apm_softc *sc; +struct apmregs *regs; +{ + if (BATT_LIFE(regs) != APM_BATT_LIFE_UNKNOWN) { + printf("%s: battery life expectancy %d%%\n", + sc->sc_dev.dv_xname, + BATT_LIFE(regs)); + } + printf("%s: A/C state: ", sc->sc_dev.dv_xname); + switch (AC_STATE(regs)) { + case APM_AC_OFF: + printf("off\n"); + break; + case APM_AC_ON: + printf("on\n"); + break; + case APM_AC_BACKUP: + printf("backup power\n"); + break; + default: + case APM_AC_UNKNOWN: + printf("unknown\n"); + break; + } + printf("%s: battery charge state:", sc->sc_dev.dv_xname); + if (apm_minver == 0) + switch (BATT_STATE(regs)) { + case APM_BATT_HIGH: + printf("high\n"); + break; + case APM_BATT_LOW: + printf("low\n"); + break; + case APM_BATT_CRITICAL: + printf("critical\n"); + break; + case APM_BATT_CHARGING: + printf("charging\n"); + break; + case APM_BATT_UNKNOWN: + printf("unknown\n"); + break; + default: + printf("undecoded state %x\n", BATT_STATE(regs)); + break; + } + else if (apm_minver >= 1) { + if (BATT_FLAGS(regs) & APM_BATT_FLAG_NOBATTERY) + printf(" no battery"); + else { + if (BATT_FLAGS(regs) & APM_BATT_FLAG_HIGH) + printf(" high"); + if (BATT_FLAGS(regs) & APM_BATT_FLAG_LOW) + printf(" low"); + if (BATT_FLAGS(regs) & APM_BATT_FLAG_CRITICAL) + printf(" critical"); + if (BATT_FLAGS(regs) & APM_BATT_FLAG_CHARGING) + printf(" charging"); + } + printf("\n"); + if (BATT_REM_VALID(regs)) + printf("%s: estimated %d:%02d minutes\n", + sc->sc_dev.dv_xname, + BATT_REMAINING(regs) / 60, + BATT_REMAINING(regs)%60); + } + return; +} + +int apm_standbys = 0; +int apm_userstandbys = 0; +int apm_suspends = 0; +int apm_battlow = 0; + +STATIC void +apm_get_powstate(dev) +u_int dev; +{ + struct apmregs regs; + int rval; + regs.bx = dev; + rval = apmcall(APM_GET_POWER_STATE, ®s); + if (rval == 0) { + printf("apm dev %04x state %04x\n", dev, regs.cx); + } +} + +STATIC void +apm_suspend() +{ + (void) apm_set_powstate(APM_DEV_ALLDEVS, APM_SYS_SUSPEND); +} + +STATIC void +apm_standby() +{ + (void) apm_set_powstate(APM_DEV_ALLDEVS, APM_SYS_STANDBY); +} + +static int apm_evindex = 0; + +STATIC int +apm_record_event(sc, event_type) +struct apm_softc *sc; +u_int event_type; +{ + struct apm_event_info *evp; + + if ((sc->sc_flags & SCFLAG_OPEN) == 0) + return 1; /* no user waiting */ + if (sc->event_count == APM_NEVENTS) + return 1; /* overflow */ + evp = &sc->event_list[sc->event_ptr]; + sc->event_count++; + sc->event_ptr++; + sc->event_ptr %= APM_NEVENTS; + evp->type = event_type; + evp->index = ++apm_evindex; + selwakeup(&sc->sc_rsel); + return (sc->sc_flags & SCFLAG_OWRITE) ? 0 : 1; /* user may handle */ +} + +STATIC void +apm_event_handle(sc, regs) +struct apm_softc *sc; +struct apmregs *regs; +{ + int error; + struct apmregs nregs; + + switch(regs->bx) { + case APM_USER_STANDBY_REQ: + DPRINTF(("user wants STANDBY--fat chance\n")); + (void) apm_set_powstate(APM_DEV_ALLDEVS, APM_LASTREQ_REJECTED); + (void) apm_record_event(sc, regs->bx); + apm_userstandbys++; + break; + case APM_STANDBY_REQ: + DPRINTF(("standby requested\n")); + if (apm_standbys || apm_suspends) + DPRINTF(("damn fool BIOS did not wait for answer\n")); + if (apm_record_event(sc, regs->bx)) { + (void) apm_set_powstate(APM_DEV_ALLDEVS, + APM_LASTREQ_INPROG); + apm_standbys++; + } else + (void) apm_set_powstate(APM_DEV_ALLDEVS, + APM_LASTREQ_REJECTED); + break; + case APM_USER_SUSPEND_REQ: + DPRINTF(("user wants suspend--fat chance!\n")); + (void) apm_set_powstate(APM_DEV_ALLDEVS, + APM_LASTREQ_REJECTED); + apm_suspends++; + apm_record_event(sc, regs->bx); + break; + case APM_SUSPEND_REQ: + DPRINTF(("suspend requested\n")); + if (apm_standbys || apm_suspends) + DPRINTF(("damn fool BIOS did not wait for answer\n")); + if (apm_record_event(sc, regs->bx)) { + (void) apm_set_powstate(APM_DEV_ALLDEVS, + APM_LASTREQ_INPROG); + apm_suspends++; + } else + (void) apm_set_powstate(APM_DEV_ALLDEVS, + APM_LASTREQ_REJECTED); + break; + case APM_POWER_CHANGE: + DPRINTF(("power status change\n")); + error = apm_get_powstat(&nregs); + if (error == 0) + apm_power_print(sc, &nregs); + apm_record_event(sc, regs->bx); + break; + case APM_NORMAL_RESUME: + DPRINTF(("system resumed\n")); + inittodr(time.tv_sec); + apm_record_event(sc, regs->bx); + break; + case APM_CRIT_RESUME: + DPRINTF(("system resumed without us!\n")); + inittodr(time.tv_sec); + apm_record_event(sc, regs->bx); + break; + case APM_SYS_STANDBY_RESUME: + DPRINTF(("system standby resume\n")); + inittodr(time.tv_sec); + apm_record_event(sc, regs->bx); + break; + case APM_UPDATE_TIME: + DPRINTF(("update time, please\n")); + inittodr(time.tv_sec); + apm_record_event(sc, regs->bx); + break; + case APM_CRIT_SUSPEND_REQ: + DPRINTF(("suspend required immediately\n")); + apm_record_event(sc, regs->bx); + apm_suspend(); + break; + case APM_BATTERY_LOW: + DPRINTF(("Battery low!\n")); + apm_battlow++; + apm_record_event(sc, regs->bx); + break; + default: + printf("APM nonstandard event code %x\n", regs->bx); + } +} + +STATIC int +apm_get_event(regs) +struct apmregs *regs; +{ + return apmcall(APM_GET_PM_EVENT, regs); +} + +STATIC void +apm_periodic_check(arg) +void *arg; +{ + struct apmregs regs; + struct apm_softc *sc = arg; + while (apm_get_event(®s) == 0) { + apm_event_handle(sc, ®s); + }; + if (APM_ERR_CODE(®s) != APM_ERR_NOEVENTS) + apm_perror("get event", ®s); + if (apm_suspends /*|| (apm_battlow && apm_userstandbys)*/) { + /* stupid TI TM5000! */ + apm_suspend(); + } else if (apm_standbys || apm_userstandbys) { + apm_standby(); + } + apm_suspends = apm_standbys = apm_battlow = apm_userstandbys =0; + timeout(apm_periodic_check, sc, hz); +} + +STATIC void +apm_powmgt_enable(onoff) +int onoff; +{ + struct apmregs regs; + regs.bx = apm_minver == 0 ? APM_MGT_ALL : APM_DEV_APM_BIOS; + regs.cx = onoff ? APM_MGT_ENABLE : APM_MGT_DISABLE; + if (apmcall(APM_PWR_MGT_ENABLE, ®s) != 0) + apm_perror("power management enable", ®s); +} + +STATIC void +apm_powmgt_engage(onoff, dev) +int onoff; +u_int dev; +{ + struct apmregs regs; + if (apm_minver == 0) + return; + regs.bx = dev; + regs.cx = onoff ? APM_MGT_ENGAGE : APM_MGT_DISENGAGE; + if (apmcall(APM_PWR_MGT_ENGAGE, ®s) != 0) + printf("APM power mgmt engage (device %x): %s (%d)\n", + dev, apm_err_translate(APM_ERR_CODE(®s)), + APM_ERR_CODE(®s)); +} + +STATIC void +apm_devpowmgt_enable(onoff, dev) +int onoff; +u_int dev; +{ + struct apmregs regs; + if (apm_minver == 0) + return; + regs.bx = dev; + /* enable is auto BIOS managment. + * disable is program control. + */ + regs.cx = onoff ? APM_MGT_ENABLE : APM_MGT_DISABLE; + if (apmcall(APM_DEVICE_MGMT_ENABLE, ®s) != 0) + printf("APM device engage (device %x): %s (%d)\n", + dev, apm_err_translate(APM_ERR_CODE(®s)), + APM_ERR_CODE(®s)); +} + +int +apm_set_powstate(dev, state) +u_int dev, state; +{ + struct apmregs regs; + if (!apminited || (apm_minver == 0 && state > APM_SYS_OFF)) + return EINVAL; + regs.bx = dev; + regs.cx = state; + if (apmcall(APM_SET_PWR_STATE, ®s) != 0) { + apm_perror("set power state", ®s); + return EIO; + } + return 0; +} + +#ifdef APM_NOIDLE +int apmidleon = 0; +#else +int apmidleon = 1; +#endif + +void +apm_cpu_busy() +{ + struct apmregs regs; + if (!apminited) + return; + if ((apminfo.apm_detail & APM_IDLE_SLOWS) && + apmcall(APM_CPU_BUSY, ®s) != 0) + apm_perror("set CPU busy", ®s); +} + +void +apm_cpu_idle() +{ + struct apmregs regs; + if (!apminited || !apmidleon) + return; + if (apmcall(APM_CPU_IDLE, ®s) != 0) + apm_perror("set CPU idle", ®s); +} + +void *apm_sh; + +#ifdef APM_V10_ONLY +int apm_v11_enabled = 0; +#else +int apm_v11_enabled = 1; +#endif + +STATIC void +apm_set_ver(self) +struct apm_softc *self; +{ + struct apmregs regs; + int error; + + regs.cx = 0x0101; /* APM Version 1.1 */ + regs.bx = APM_DEV_APM_BIOS; + + if (apm_v11_enabled && + (error = apmcall(APM_DRIVER_VERSION, ®s)) == 0) { + apm_majver = APM_CONN_MAJOR(®s); + apm_minver = APM_CONN_MINOR(®s); + } else { + apm_majver = 1; + apm_minver = 0; + } + printf(": Power Management spec V%d.%d", + apm_majver, apm_minver); + apminited = 1; + if (apminfo.apm_detail & APM_IDLE_SLOWS) { +#ifdef DEBUG + /* not relevant much */ + printf(" (slowidle)"); +#endif + apm_dobusy = 1; + } else + apm_dobusy = 0; +#ifdef DIAGNOSTIC + if (apminfo.apm_detail & APM_BIOS_PM_DISABLED) + printf(" (BIOS mgmt disabled)"); + if (apminfo.apm_detail & APM_BIOS_PM_DISENGAGED) + printf(" (BIOS managing devices)"); +#endif + printf("\n"); +} + +STATIC int +apm_get_powstat(regs) +struct apmregs *regs; +{ + regs->bx = APM_DEV_ALLDEVS; + return apmcall(APM_POWER_STATUS, regs); +} + +STATIC void +apm_disconnect(xxx) +void *xxx; +{ + struct apmregs regs; + regs.bx = apm_minver == 1 ? APM_DEV_ALLDEVS : APM_DEFAULTS_ALL; + if (apmcall(APM_SYSTEM_DEFAULTS, ®s)) + apm_perror("system defaults failed", ®s); + + regs.bx = APM_DEV_APM_BIOS; + if (apmcall(APM_DISCONNECT, ®s)) + apm_perror("disconnect failed", ®s); + else + printf("APM disconnected\n"); +} + +int +apmprobe(parent, match, aux) + struct device *parent; + void *match, *aux; +{ + struct apm_attach_args *aaa = aux; + + if (apminited) + return 0; + if ((apminfo.apm_detail & APM_32BIT_SUPPORTED) && + strcmp(aaa->aaa_busname, "apm") == 0) { + return 1; + } + return 0; +} + +void +apmattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct apm_softc *apmsc = (void *)self; + struct apmregs regs; + int error; + /* + * set up GDT descriptors for APM + */ + if (apminfo.apm_detail & APM_32BIT_SUPPORTED) { + apminfo.apm_segsel = GSEL(GAPM32CODE_SEL,SEL_KPL); + apminfo.apm_code32_seg_base <<= 4; + apminfo.apm_code16_seg_base <<= 4; + apminfo.apm_data_seg_base <<= 4; + /* something is still amiss in the limit-fetch in the boot + loader; it returns incorrect (too small) limits. + for now, force them to max size. */ + apminfo.apm_code32_seg_len = 65536; + apminfo.apm_data_seg_len = 65536; +#if 0 + switch ((APM_MAJOR_VERS(apminfo.apm_detail) << 8) + + APM_MINOR_VERS(apminfo.apm_detail)) { + case 0x0100: + apminfo.apm_code32_seg_len = 65536; + apminfo.apm_data_seg_len = 65536; + break; + default: + if (apminfo.apm_data_seg_len == 0) + apminfo.apm_data_seg_len = 65536; + break; + } +#endif + setsegment(&dynamic_gdt[GAPM32CODE_SEL].sd, + (void *)ISA_HOLE_VADDR(apminfo.apm_code32_seg_base), + apminfo.apm_code32_seg_len-1, + SDT_MEMERA, SEL_KPL, 1, 0); + setsegment(&dynamic_gdt[GAPM16CODE_SEL].sd, + (void *)ISA_HOLE_VADDR(apminfo.apm_code16_seg_base), + 65536-1, /* just in case */ + SDT_MEMERA, SEL_KPL, 0, 0); + setsegment(&dynamic_gdt[GAPMDATA_SEL].sd, + (void *)ISA_HOLE_VADDR(apminfo.apm_data_seg_base), + apminfo.apm_data_seg_len-1, + SDT_MEMRWA, SEL_KPL, 1, 0); +#if defined(DEBUG) || defined(APMDEBUG) + printf(": detail %x 32b:%x/%x/%x 16b:%x/%x data %x/%x/%x ep %x (%x:%x)\n%s", + apminfo.apm_detail, + apminfo.apm_code32_seg_base, + ISA_HOLE_VADDR(apminfo.apm_code32_seg_base), + apminfo.apm_code32_seg_len, + apminfo.apm_code16_seg_base, + ISA_HOLE_VADDR(apminfo.apm_code16_seg_base), + apminfo.apm_data_seg_base, + ISA_HOLE_VADDR(apminfo.apm_data_seg_base), + apminfo.apm_data_seg_len, + apminfo.apm_entrypt, + apminfo.apm_segsel, + apminfo.apm_entrypt+ISA_HOLE_VADDR(apminfo.apm_code32_seg_base), + apmsc->sc_dev.dv_xname); +#endif + apm_set_ver(apmsc); + /* + * Engage cooperative power mgt (we get to do it) + * on all devices (v1.1). + */ + apm_powmgt_engage(1, APM_DEV_ALLDEVS); +#if 0 + /* doesn't seem to work, sigh. */ + apm_powmgt_engage(1, APM_DEV_DISPLAY(APM_DEV_ALLUNITS)); + apm_powmgt_engage(1, APM_DEV_DISK(APM_DEV_ALLUNITS)); + apm_powmgt_engage(1, APM_DEV_PARALLEL(APM_DEV_ALLUNITS)); + apm_powmgt_engage(1, APM_DEV_NETWORK(APM_DEV_ALLUNITS)); + apm_powmgt_engage(1, APM_DEV_PCMCIA(APM_DEV_ALLUNITS)); +#endif + error = apm_get_powstat(®s); + if (error == 0) { + apm_power_print(apmsc, ®s); + } else + apm_perror("get power status", ®s); + apm_cpu_busy(); + apm_periodic_check(apmsc); + } else { + dynamic_gdt[GAPM32CODE_SEL] = dynamic_gdt[GNULL_SEL]; + dynamic_gdt[GAPM16CODE_SEL] = dynamic_gdt[GNULL_SEL]; + dynamic_gdt[GAPMDATA_SEL] = dynamic_gdt[GNULL_SEL]; + } +} + +int +apmopen(dev, flag, mode, p) + dev_t dev; + int flag, mode; + struct proc *p; +{ + int unit = APMUNIT(dev); + int ctl = APMDEV(dev); + struct apm_softc *sc; + + if (unit >= apm_cd.cd_ndevs) + return ENXIO; + sc = apm_cd.cd_devs[unit]; + if (!sc) + return ENXIO; + + switch (ctl) { + case APMDEV_CTL: + if (!(flag & FWRITE)) + return EINVAL; + if (sc->sc_flags & SCFLAG_OWRITE) + return EBUSY; + sc->sc_flags |= SCFLAG_OWRITE; + break; + case APMDEV_NORMAL: + if (!(flag & FREAD) || (flag & FWRITE)) + return EINVAL; + sc->sc_flags |= SCFLAG_OREAD; + break; + default: + return ENXIO; + break; + } + return 0; +} + +int +apmclose(dev, flag, mode, p) + dev_t dev; + int flag, mode; + struct proc *p; +{ + struct apm_softc *sc = apm_cd.cd_devs[APMUNIT(dev)]; + int ctl = APMDEV(dev); + + DPRINTF(("apmclose: pid %d flag %x mode %x\n", p->p_pid, flag, mode)); + switch (ctl) { + case APMDEV_CTL: + sc->sc_flags &= ~SCFLAG_OWRITE; + break; + case APMDEV_NORMAL: + sc->sc_flags &= ~SCFLAG_OREAD; + break; + } + if ((sc->sc_flags & SCFLAG_OPEN) == 0) { + sc->event_count = 0; + sc->event_ptr = 0; + } + return 0; +} + +int +apmioctl(dev, cmd, data, flag, p) + dev_t dev; + u_long cmd; + caddr_t data; + int flag; + struct proc *p; +{ + int error; + struct apm_softc *sc = apm_cd.cd_devs[APMUNIT(dev)]; + struct apm_power_info *powerp; + struct apm_event_info *evp; + struct apmregs regs; + register int i; + struct apm_ctl *actl; + + switch (cmd) { + /* some ioctl names from linux */ + case APM_IOC_STANDBY: + if ((flag & FWRITE) == 0) + return EBADF; + apm_userstandbys++; + return 0; + case APM_IOC_SUSPEND: + if ((flag & FWRITE) == 0) + return EBADF; + apm_suspends++; + return 0; + case APM_IOC_DEV_CTL: + actl = (struct apm_ctl *)data; + if ((flag & FWRITE) == 0) + return EBADF; + apm_get_powstate(actl->dev); /* XXX */ + return apm_set_powstate(actl->dev, actl->mode); + case APM_IOC_NEXTEVENT: + if (sc->event_count) { + evp = (struct apm_event_info *)data; + i = sc->event_ptr + APM_NEVENTS - sc->event_count; + i %= APM_NEVENTS; + *evp = sc->event_list[i]; + sc->event_count--; + return 0; + } else + return EAGAIN; + case APM_IOC_GETPOWER: + powerp = (struct apm_power_info *)data; + error = apm_get_powstat(®s); + if (error == 0) { + bzero(powerp, sizeof(*powerp)); + if (BATT_LIFE(®s) != APM_BATT_LIFE_UNKNOWN) + powerp->battery_life = BATT_LIFE(®s); + powerp->ac_state = AC_STATE(®s); + switch (apm_minver) { + case 0: + powerp->battery_state = BATT_STATE(®s); + break; + case 1: + default: + powerp->battery_state = APM_BATT_UNKNOWN; + if (BATT_FLAGS(®s) & APM_BATT_FLAG_HIGH) + powerp->battery_state = APM_BATT_HIGH; + else if (BATT_FLAGS(®s) & APM_BATT_FLAG_LOW) + powerp->battery_state = APM_BATT_LOW; + else if (BATT_FLAGS(®s) & APM_BATT_FLAG_CRITICAL) + powerp->battery_state = APM_BATT_CRITICAL; + else if (BATT_FLAGS(®s) & APM_BATT_FLAG_CHARGING) + powerp->battery_state = APM_BATT_CHARGING; + else if (BATT_FLAGS(®s) & APM_BATT_FLAG_NOBATTERY) + powerp->battery_state = APM_BATTERY_ABSENT; + if (BATT_REM_VALID(®s)) + powerp->minutes_left = BATT_REMAINING(®s); + } + } else { + apm_perror("ioctl get power status", ®s); + error = EIO; + } + break; + + default: + return ENOTTY; + } + return 0; +} + +int +apmselect(dev, rw, p) + dev_t dev; + int rw; + struct proc *p; +{ + struct apm_softc *sc = apm_cd.cd_devs[APMUNIT(dev)]; + + switch (rw) { + case FREAD: + if (sc->event_count) + return 1; + selrecord(p, &sc->sc_rsel); + break; + case FWRITE: + case 0: + return 0; + } + return 0; +} + +#endif /* NAPM > 0 */ diff --git a/sys/arch/i386/i386/conf.c b/sys/arch/i386/i386/conf.c index c56ad7712fd..9b68b21902b 100644 --- a/sys/arch/i386/i386/conf.c +++ b/sys/arch/i386/i386/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.12 1996/04/21 22:16:23 deraadt Exp $ */ +/* $OpenBSD: conf.c,v 1.13 1996/04/29 14:12:41 hvozda Exp $ */ /* $NetBSD: conf.c,v 1.74 1996/03/30 07:30:33 mycroft Exp $ */ /* @@ -124,6 +124,13 @@ int nblkdev = sizeof(bdevsw) / sizeof(bdevsw[0]); (dev_type_mmap((*))) enodev } #define cdev_joy_init cdev_ss_init +/* open, close, ioctl, select -- XXX should be a generic device */ +#define cdev_ocis_init(c,n) { \ + dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \ + (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \ + (dev_type_stop((*))) enodev, 0, dev_init(c,n,select), \ + (dev_type_mmap((*))) enodev, 0 } + cdev_decl(cn); cdev_decl(ctty); #define mmread mmrw @@ -161,6 +168,8 @@ cdev_decl(ch); dev_decl(filedesc,open); #include "bpfilter.h" cdev_decl(bpf); +#include "pcmcia.h" +cdev_decl(pcmcia); #include "spkr.h" cdev_decl(spkr); #ifdef LKM @@ -187,6 +196,8 @@ cdev_decl(svr4_net); cdev_decl(ccd); #include "joy.h" cdev_decl(joy); +#include "apm.h" +cdev_decl(apm); #include "rnd.h" cdev_decl(rnd); @@ -222,11 +233,11 @@ struct cdevsw cdevsw[] = cdev_disk_init(NCCD,ccd), /* 18: concatenated disk driver */ cdev_ss_init(NSS,ss), /* 19: SCSI scanner */ cdev_notdef(), /* 20 */ - cdev_notdef(), /* 21 */ + cdev_ocis_init(NAPM,apm), /* 21: Advancded Power Management */ cdev_fd_init(1,filedesc), /* 22: file descriptor pseudo-device */ cdev_bpftun_init(NBPFILTER,bpf),/* 23: Berkeley packet filter */ cdev_notdef(), /* 24 */ - cdev_notdef(), /* 25 */ + cdev_ocis_init(NPCMCIA,pcmcia), /* 25: PCMCIA Bus */ cdev_joy_init(NJOY,joy), /* 26: joystick */ cdev_spkr_init(NSPKR,spkr), /* 27: PC speaker */ cdev_lkm_init(NLKM,lkm), /* 28: loadable module driver */ diff --git a/sys/arch/i386/i386/gdt.c b/sys/arch/i386/i386/gdt.c index a511ab550b7..37361fba4a2 100644 --- a/sys/arch/i386/i386/gdt.c +++ b/sys/arch/i386/i386/gdt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: gdt.c,v 1.7 1996/04/18 19:18:08 niklas Exp $ */ +/* $OpenBSD: gdt.c,v 1.8 1996/04/29 14:12:48 hvozda Exp $ */ /* $NetBSD: gdt.c,v 1.7 1996/02/27 22:45:01 jtc Exp $ */ /*- @@ -214,6 +214,16 @@ gdt_get_slot() if (gdt_next != gdt_count) panic("gdt_get_slot botch 1"); if (gdt_next >= gdt_size) { + /* + * gdt_size is clamped by maxproc, set in + * /sys/conf/param.c and clamped in init386(). + * It's held there to (MAXGDTSIZ - NGDT) if no + * user LDTs, or half that if user LDTs are + * allowed. It's important to count that + * correctly, because by the time we get here, + * it's too late to abort the fork operation + * -- we must have a GDT slot available. + */ if (gdt_size >= MAXGDTSIZ) panic("gdt_get_slot botch 2"); if (dynamic_gdt == gdt) diff --git a/sys/arch/i386/i386/genassym.c b/sys/arch/i386/i386/genassym.c index d3e01c4094d..8bba187b0d9 100644 --- a/sys/arch/i386/i386/genassym.c +++ b/sys/arch/i386/i386/genassym.c @@ -51,6 +51,11 @@ #include <machine/pmap.h> #include <machine/vmparam.h> +#include "apm.h" +#if NAPM > 0 +#include <machine/apmvar.h> +#endif + #ifdef COMPAT_SVR4 #include <compat/svr4/svr4_ucontext.h> #endif @@ -150,6 +155,21 @@ main() off("IH_COUNT", struct intrhand, ih_count); off("IH_NEXT", struct intrhand, ih_next); #endif +#if NAPM > 0 + off("APM_CODE32", struct apm_connect_info, apm_code32_seg_base); + off("APM_CODE16", struct apm_connect_info, apm_code16_seg_base); + off("APM_DATA", struct apm_connect_info, apm_data_seg_base); + off("APM_CODE32_LEN", struct apm_connect_info, apm_code32_seg_len); + off("APM_DATA_LEN", struct apm_connect_info, apm_data_seg_len); + off("APM_ENTRY", struct apm_connect_info, apm_entrypt); + off("APM_DETAIL", struct apm_connect_info, apm_detail); + off("APM_CALL", struct apm_connect_info, apm_entrypt); + def("APM_SIZE", sizeof(struct apm_connect_info)); + off("APMREG_AX", struct apmregs, ax); + off("APMREG_BX", struct apmregs, bx); + off("APMREG_CX", struct apmregs, cx); + off("APMREG_DX", struct apmregs, dx); +#endif exit(0); } diff --git a/sys/arch/i386/i386/locore.s b/sys/arch/i386/i386/locore.s index e7af2889ce0..65f33efa92e 100644 --- a/sys/arch/i386/i386/locore.s +++ b/sys/arch/i386/i386/locore.s @@ -41,6 +41,7 @@ #include "npx.h" #include "assym.h" +#include "apm.h" #include <sys/errno.h> #include <sys/syscall.h> @@ -142,6 +143,16 @@ .globl _cpu,_cpu_vendor,_cold,_esym,_boothowto,_bootdev,_atdevbase .globl _cyloffset,_proc0paddr,_curpcb,_PTDpaddr,_dynamic_gdt +#if NAPM > 0 +#include <machine/apmvar.h> + .globl _apminfo + .globl _apm_current_gdt_pdesc /* current GDT pseudo desc. */ + .globl _bootstrap_gdt +_apm_current_gdt_pdesc: + .word 0, 0, 0 +_bootstrap_gdt: + .space SIZEOF_GDTE * BOOTSTRAP_GDT_NUM +#endif _cpu: .long 0 # are we 386, 386sx, or 486 _cpu_vendor: .space 16 # vendor string returned by `cpuid' instruction _cold: .long 1 # cold till we are not @@ -178,6 +189,102 @@ start: movw $0x1234,0x472 # warm boot addl $KERNBASE,%eax 1: movl %eax,RELOC(_esym) +#if NAPM > 0 + + /* + * Setup APM BIOS: + * + * APM BIOS initialization should be done from real mode or V86 mode. + * + * (by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp>) + */ + + /* + * Cleanup %fs and %gs: + * + * Some BIOS bootstrap routine store junk value into %fs + * and %gs. + */ + + xorl %eax, %eax + movw %ax, %fs + movw %ax, %gs + + /* get GDT base */ + sgdt RELOC(_apm_current_gdt_pdesc) + + /* copy GDT to _bootstrap_gdt */ + xorl %ecx, %ecx + movw RELOC(_apm_current_gdt_pdesc), %cx + movl RELOC(_apm_current_gdt_pdesc)+2, %esi + lea RELOC(_bootstrap_gdt), %edi + cld + rep + movsb + + /* setup GDT pseudo descriptor */ + movw $(SIZEOF_GDTE*BOOTSTRAP_GDT_NUM), %ax + movw %ax, RELOC(_apm_current_gdt_pdesc) + leal RELOC(_bootstrap_gdt), %eax + movl %eax, RELOC(_apm_current_gdt_pdesc)+2 + + /* load new GDTR */ + lgdt RELOC(_apm_current_gdt_pdesc) + + /* + * Copy APM initializer under 1MB boundary: + * + * APM initializer program must switch the CPU to real mode. + * But NetBSD kernel runs above 1MB boundary. So we must + * copy the initializer code to conventional memory. + */ + movl RELOC(_apm_init_image_size), %ecx /* size */ + lea RELOC(_apm_init_image), %esi /* source */ + movl $ APM_OURADDR, %edi /* destination */ + cld + rep + movsb + + /* setup GDT for APM initializer */ + lea RELOC(_bootstrap_gdt), %ecx + movl $(APM_OURADDR), %eax /* use %ax for 15..0 */ + movl %eax, %ebx + shrl $16, %ebx /* use %bl for 23..16 */ + /* use %bh for 31..24 */ +#define APM_SETUP_GDT(index, attrib) \ + movl $(index), %si ; \ + lea 0(%ecx,%esi,8), %edx ; \ + movw $0xffff, (%edx) ; \ + movw %ax, 2(%edx) ; \ + movb %bl, 4(%edx) ; \ + movw $(attrib), 5(%edx) ; \ + movb %bh, 7(%edx) + + APM_SETUP_GDT(APM_INIT_CS_INDEX , CS32_ATTRIB) + APM_SETUP_GDT(APM_INIT_DS_INDEX , DS32_ATTRIB) + APM_SETUP_GDT(APM_INIT_CS16_INDEX, CS16_ATTRIB) + + /* + * Call the initializer: + * + * direct intersegment call to conventional memory code + */ + .byte 0x9a /* actually, lcall $APM_INIT_CS_SEL, $0 */ + .long 0 + .word APM_INIT_CS_SEL + + movw %ax,RELOC(_apminfo+APM_DETAIL) + movw %di,RELOC(_apminfo+APM_DETAIL)+2 + movl %ebx,RELOC(_apminfo+APM_ENTRY) + movw %cx,RELOC(_apminfo+APM_CODE32) + shrl $16, %ecx + movw %cx,RELOC(_apminfo+APM_CODE16) + movw %dx,RELOC(_apminfo+APM_DATA) + movw %si,RELOC(_apminfo+APM_CODE32_LEN) + shrl $16, %esi + movw %si,RELOC(_apminfo+APM_DATA_LEN) +#endif /* APM */ + /* First, reset the PSL. */ pushl $PSL_MBO popfl @@ -363,7 +470,7 @@ try586: /* Use the `cpuid' instruction. */ #endif /* Calculate where to start the bootstrap tables. */ - movl %edi,%esi # edi = esym ?: end + movl %edi,%esi # edi = esym ? esym : end addl $PGOFSET,%esi # page align up andl $~PGOFSET,%esi @@ -1481,6 +1588,9 @@ ENTRY(remrq) 3: .asciz "remrq" #endif /* DIAGNOSTIC */ +#if NAPM > 0 + .globl _apm_cpu_idle,_apm_cpu_busy,_apm_dobusy +#endif /* * When no processes are on the runq, cpu_switch() branches to here to wait for * something to come ready. @@ -1491,7 +1601,16 @@ ENTRY(idle) testl %ecx,%ecx jnz sw1 sti +#if NAPM > 0 + call _apm_cpu_idle +#endif hlt +#if NAPM > 0 + cmpl $0,_apm_dobusy + je 1f + call _apm_cpu_busy +1: +#endif jmp _idle #ifdef DIAGNOSTIC @@ -2075,3 +2194,78 @@ ENTRY(bzero) popl %edi ret + +#if NAPM > 0 +/* + * int apmcall(int function, struct apmregs *regs): + * call the APM protected mode bios function FUNCTION for BIOS selection + * WHICHBIOS. + * Fills in *regs with registers as returned by APM. + * returns nonzero if error returned by APM. + */ +apmstatus: .long 0 +ENTRY(apmcall) + pushl %ebp + movl %esp,%ebp + pushl %esi + pushl %edi + pushl %ebx + +#if defined(DEBUG) || defined(DIAGNOSTIC) + pushl %ds + pushl %es + pushl %fs + pushl %gs + xorl %ax,%ax +/* movl %ax,%ds # can't toss %ds, we need it for apmstatus*/ + movl %ax,%es + movl %ax,%fs + movl %ax,%gs +#endif + movb %cs:8(%ebp),%al + movb $0x53,%ah + movl %cs:12(%ebp),%ebx + movw %cs:APMREG_CX(%ebx),%cx + movw %cs:APMREG_DX(%ebx),%dx + movw %cs:APMREG_BX(%ebx),%bx + pushfl + cli + pushl %ds + lcall %cs:(_apminfo+APM_CALL) + popl %ds + setc apmstatus + popfl +#if defined(DEBUG) || defined(DIAGNOSTIC) + popl %gs + popl %fs + popl %es + popl %ds # see above +#endif + movl 12(%ebp),%esi + movw %ax,APMREG_AX(%esi) + movw %bx,APMREG_BX(%esi) + movw %cx,APMREG_CX(%esi) + movw %dx,APMREG_DX(%esi) +/* todo: do something with %edi? */ + cmpl $0,apmstatus + jne 1f + xorl %eax,%eax +1: + popl %ebx + popl %edi + popl %esi + popl %ebp + ret + +_apm_init_image: + .globl _apm_init_image + +8: +#include "lib/apm_init/apm_init.inc" +9: + +_apm_init_image_size: + .globl _apm_init_image_size + .long 9b - 8b + +#endif /* APM */ diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c index e3bdb4ad24b..27438f0608e 100644 --- a/sys/arch/i386/i386/machdep.c +++ b/sys/arch/i386/i386/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.13 1996/04/21 22:16:31 deraadt Exp $ */ +/* $OpenBSD: machdep.c,v 1.14 1996/04/29 14:13:15 hvozda Exp $ */ /* $NetBSD: machdep.c,v 1.197 1996/04/12 08:44:40 mycroft Exp $ */ /*- @@ -93,6 +93,12 @@ #include <i386/isa/isa_machdep.h> #include <i386/isa/nvram.h> +#include "apm.h" + +#if NAPM > 0 +#include <machine/apmvar.h> +#endif + #ifdef VM86 #include <machine/vm86.h> #endif @@ -736,6 +742,16 @@ haltsys: doshutdownhooks(); if (howto & RB_HALT) { +#if NAPM > 0 && !defined(APM_NO_POWEROFF) + /* turn off, if we can. But try to turn disk off and + * wait a bit first--some disk drives are slow to clean up + * and users have reported disk corruption. + */ + delay(500000); + apm_set_powstate(APM_DEV_DISK(0xff), APM_SYS_OFF); + delay(500000); + apm_set_powstate(APM_DEV_ALLDEVS, APM_SYS_OFF); +#endif printf("\n"); printf("The operating system has halted.\n"); printf("Please press any key to reboot.\n\n"); @@ -1169,6 +1185,16 @@ init386(first_avail) /* call pmap initialization to make new kernel address space */ pmap_bootstrap((vm_offset_t)atdevbase + IOM_SIZE); +#ifdef USER_LDT +#define MAXPROC ((MAXGDTSIZ-NGDT)/2) +#else +#define MAXPROC (MAXGDTSIZ-NGDT) +#endif + if (maxproc > MAXPROC) { + printf("reducing maxproc to %d to fit into gdt\n", MAXPROC); + maxproc = MAXPROC; + } + #ifdef DDB ddb_init(); if (boothowto & RB_KDB) diff --git a/sys/arch/i386/i386/mainbus.c b/sys/arch/i386/i386/mainbus.c index 5de4b476180..c20a774c307 100644 --- a/sys/arch/i386/i386/mainbus.c +++ b/sys/arch/i386/i386/mainbus.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mainbus.c,v 1.2 1996/04/21 22:16:32 deraadt Exp $ */ +/* $OpenBSD: mainbus.c,v 1.3 1996/04/29 14:13:25 hvozda Exp $ */ /* $NetBSD: mainbus.c,v 1.8 1996/04/11 22:13:37 cgd Exp $ */ /* @@ -45,6 +45,11 @@ #include <i386/isa/isa_machdep.h> #include "pci.h" +#include "apm.h" + +#if NAPM > 0 +#include <machine/apmvar.h> +#endif int mainbus_match __P((struct device *, void *, void *)); void mainbus_attach __P((struct device *, struct device *, void *)); @@ -64,6 +69,9 @@ union mainbus_attach_args { struct pcibus_attach_args mba_pba; struct eisabus_attach_args mba_eba; struct isabus_attach_args mba_iba; +#if NAPM > 0 + struct apm_attach_args mba_aaa; +#endif }; /* @@ -118,7 +126,12 @@ mainbus_attach(parent, self, aux) config_found(self, &mba.mba_pba, mainbus_print); } #endif - +#if NAPM > 0 + { + mba.mba_aaa.aaa_busname = "apm"; + config_found(self, &mba.mba_aaa, mainbus_print); + } +#endif } int diff --git a/sys/arch/i386/include/apmvar.h b/sys/arch/i386/include/apmvar.h new file mode 100644 index 00000000000..75dfd2c155d --- /dev/null +++ b/sys/arch/i386/include/apmvar.h @@ -0,0 +1,263 @@ +/* $NetBSD$ */ +/* + * Copyright (c) 1995 John T. Kohl + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `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 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. + * + */ +#ifndef __I386_APM_H__ +#define __I386_APM_H__ + +/* Advanced Power Management (v1.0 and v1.1 specification) + * functions/defines/etc. + */ +#define APM_BIOS_FNCODE (0x53) +#define APM_SYSTEM_BIOS (0x15) +#define APM_BIOS_FN(x) ((APM_BIOS_FNCODE<<8)|(x)) +/* + * APM info word from boot loader + */ +#define APM_MAJOR_VERS(info) (((info)&0xff00)>>8) +#define APM_MINOR_VERS(info) ((info)&0xff) +#define APM_16BIT_SUPPORTED 0x00010000 +#define APM_32BIT_SUPPORTED 0x00020000 +#define APM_IDLE_SLOWS 0x00040000 +#define APM_BIOS_PM_DISABLED 0x00080000 +#define APM_BIOS_PM_DISENGAGED 0x00100000 + +#define APM_ERR_CODE(regs) (((regs)->ax & 0xff00) >> 8) +#define APM_ERR_PM_DISABLED 0x01 +#define APM_ERR_REALALREADY 0x02 +#define APM_ERR_NOTCONN 0x03 +#define APM_ERR_16ALREADY 0x05 +#define APM_ERR_16NOTSUPP 0x06 +#define APM_ERR_32ALREADY 0x07 +#define APM_ERR_32NOTSUPP 0x08 +#define APM_ERR_UNRECOG_DEV 0x09 +#define APM_ERR_ERANGE 0x0A +#define APM_ERR_NOTENGAGED 0x0B +#define APM_ERR_UNABLE 0x60 +#define APM_ERR_NOEVENTS 0x80 +#define APM_ERR_NOT_PRESENT 0x86 + +#define APM_DEV_APM_BIOS 0x0000 +#define APM_DEV_ALLDEVS 0x0001 +/* device classes are high byte; device IDs go in low byte */ +#define APM_DEV_DISPLAY(x) (0x0100|((x)&0xff)) +#define APM_DEV_DISK(x) (0x0200|((x)&0xff)) +#define APM_DEV_PARALLEL(x) (0x0300|((x)&0xff)) +#define APM_DEV_SERIAL(x) (0x0400|((x)&0xff)) +#define APM_DEV_NETWORK(x) (0x0500|((x)&0xff)) +#define APM_DEV_PCMCIA(x) (0x0600|((x)&0xff)) +#define APM_DEV_ALLUNITS 0xff + +#define APM_INSTALLATION_CHECK 0x00 /* int15 only */ +#define APM_REALMODE_CONNECT 0x01 /* int15 only */ +#define APM_16BIT_CONNECT 0x02 /* int15 only */ +#define APM_32BIT_CONNECT 0x03 /* int15 only */ +#define APM_DISCONNECT 0x04 /* %bx = APM_DEV_APM_BIOS */ +#define APM_CPU_IDLE 0x05 +#define APM_CPU_BUSY 0x06 +#define APM_SET_PWR_STATE 0x07 +#define APM_SYS_READY 0x0000 /* %cx */ +#define APM_SYS_STANDBY 0x0001 +#define APM_SYS_SUSPEND 0x0002 +#define APM_SYS_OFF 0x0003 +#define APM_LASTREQ_INPROG 0x0004 +#define APM_LASTREQ_REJECTED 0x0005 + +/* system standby is device ID (%bx) 0x0001, APM_SYS_STANDBY */ +/* system suspend is device ID (%bx) 0x0001, APM_SYS_SUSPEND */ + +#define APM_PWR_MGT_ENABLE 0x08 +#define APM_MGT_ALL 0xffff /* %bx */ +#define APM_MGT_DISABLE 0x0 /* %cx */ +#define APM_MGT_ENABLE 0x1 + +#define APM_SYSTEM_DEFAULTS 0x09 +#define APM_DEFAULTS_ALL 0xffff /* %bx */ + +#define APM_POWER_STATUS 0x0a +#define APM_AC_OFF 0x00 +#define APM_AC_ON 0x01 +#define APM_AC_BACKUP 0x02 +#define APM_AC_UNKNOWN 0xff +#define APM_BATT_HIGH 0x00 +#define APM_BATT_LOW 0x01 +#define APM_BATT_CRITICAL 0x02 +#define APM_BATT_CHARGING 0x03 +#define APM_BATT_UNKNOWN 0xff +#define APM_BATT_FLAG_HIGH 0x01 +#define APM_BATT_FLAG_LOW 0x02 +#define APM_BATT_FLAG_CRITICAL 0x04 +#define APM_BATT_FLAG_CHARGING 0x08 +#define APM_BATT_FLAG_NOBATTERY 0x80 +#define APM_BATT_LIFE_UNKNOWN 0xff +#define BATT_STATE(regp) ((regp)->bx & 0xff) +#define BATT_FLAGS(regp) (((regp)->cx & 0xff00) >> 8) +#define AC_STATE(regp) (((regp)->bx & 0xff00) >> 8) +#define BATT_LIFE(regp) ((regp)->cx & 0xff) /* in % */ +#define BATT_REMAINING(regp) (((regp)->dx & 0x8000) ? \ + ((regp)->dx & 0x7fff)*60 : \ + ((regp)->dx & 0x7fff)) +#define BATT_REM_VALID(regp) (((regp)->dx & 0xffff) != 0xffff) +#define APM_GET_PM_EVENT 0x0b +#define APM_STANDBY_REQ 0x0001 /* %bx on return */ +#define APM_SUSPEND_REQ 0x0002 +#define APM_NORMAL_RESUME 0x0003 +#define APM_CRIT_RESUME 0x0004 /* suspend/resume happened + without us */ +#define APM_BATTERY_LOW 0x0005 +#define APM_POWER_CHANGE 0x0006 +#define APM_UPDATE_TIME 0x0007 +#define APM_CRIT_SUSPEND_REQ 0x0008 +#define APM_USER_STANDBY_REQ 0x0009 +#define APM_USER_SUSPEND_REQ 0x000A +#define APM_SYS_STANDBY_RESUME 0x000B + +#define APM_GET_POWER_STATE 0x0c +#define APM_DEVICE_MGMT_ENABLE 0x0d + +#define APM_DRIVER_VERSION 0x0e +/* %bx should be DEV value (APM_DEV_APM_BIOS) + %ch = driver major vno + %cl = driver minor vno + return: %ah = conn major; %al = conn minor + */ +#define APM_CONN_MINOR(regp) ((regp)->ax & 0xff) +#define APM_CONN_MAJOR(regp) (((regp)->ax & 0xff00) >> 8) + +#define APM_PWR_MGT_ENGAGE 0x0F +#define APM_MGT_DISENGAGE 0x0 /* %cx */ +#define APM_MGT_ENGAGE 0x1 + +#define APM_OEM 0x80 + +#ifdef _LOCORE +/* + * LP (Laptop Package) + * + * Copyright (C) 1994 by HOSOKAWA Tatsumi <hosokawa@mt.cs.keio.ac.jp> + * + * This software may be used, modified, copied, and distributed, in + * both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + * + * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) + */ + +/* Error code of APM initializer */ +#define APMINI_CANTFIND 0xffffffff +#define APMINI_NOT32BIT 0xfffffffe +#define APMINI_CONNECTERR 0xfffffffd + +#define SIZEOF_GDTE 8 +#define BOOTSTRAP_GDT_NUM 9 /* see i386/boot/table.c */ + +#define APM_INIT_CS_INDEX (BOOTSTRAP_GDT_NUM - 3) +#define APM_INIT_DS_INDEX (BOOTSTRAP_GDT_NUM - 2) +#define APM_INIT_CS16_INDEX (BOOTSTRAP_GDT_NUM - 1) +#define APM_INIT_CS_SEL (APM_INIT_CS_INDEX << 3) +#define APM_INIT_DS_SEL (APM_INIT_DS_INDEX << 3) +#define APM_INIT_CS16_SEL (APM_INIT_CS16_INDEX << 3) + +#define CS32_ATTRIB 0xCF9e +#define CS16_ATTRIB 0x0F9e +#define DS32_ATTRIB 0xCF92 + +#define BOOTSTRAP_DS_SEL 0x10 +/* APM initializer physical address */ +#define APM_OURADDR 0x00080000 +#define APM_RELOC(x) ((x) - _apm_init_image) + +#else /* !_LOCORE */ + +/* filled in by apmcall */ +struct apmregs { + u_short ax; + u_short bx; + u_short cx; + u_short dx; +}; + +struct apm_connect_info { + u_int apm_code32_seg_base; /* real-mode style segment selector */ + u_int apm_code16_seg_base; + u_int apm_data_seg_base; + u_int apm_entrypt; + u_short apm_segsel; /* segment selector for APM */ + u_short _pad1; + u_int apm_code32_seg_len; + u_int apm_data_seg_len; + u_int apm_detail; +}; + +struct apm_event_info { + u_int type; + u_int index; + u_int spare[8]; +}; + +#define APM_BATTERY_ABSENT 4 + +struct apm_power_info { + u_char battery_state; + u_char ac_state; + u_char battery_life; + u_char spare1; + u_int minutes_left; /* estimate */ + u_int spare2[6]; +}; + +struct apm_ctl { + u_int dev; + u_int mode; +}; + +#define APM_IOC_REJECT _IOW('A', 0, struct apm_event_info) /* reject request # */ +#define APM_IOC_STANDBY _IO('A', 1) /* put system into standby */ +#define APM_IOC_SUSPEND _IO('A', 2) /* put system into suspend */ +#define APM_IOC_GETPOWER _IOR('A', 3, struct apm_power_info) /* fetch battery state */ +#define APM_IOC_NEXTEVENT _IOR('A', 4, struct apm_event_info) /* fetch event */ +#define APM_IOC_DEV_CTL _IOW('A', 5, struct apm_ctl) /* put device into mode */ + +struct apm_attach_args { + char *aaa_busname; +}; + +#ifdef _KERNEL +extern struct apm_connect_info apminfo; /* in locore */ +extern int apmpresent; +extern int apmcall __P((int function, struct apmregs *regs)); +extern void apm_cpu_busy __P((void)); +extern void apm_cpu_idle __P((void)); +extern void apminit __P((void)); +int apm_set_powstate __P((u_int devid, u_int powstate)); +#endif /* _KERNEL */ +#endif /* _LOCORE */ +#endif /* __i386_apm_h__ */ diff --git a/sys/arch/i386/include/gdt.h b/sys/arch/i386/include/gdt.h index ebb8d5b0d57..7b7a6ea5ac5 100644 --- a/sys/arch/i386/include/gdt.h +++ b/sys/arch/i386/include/gdt.h @@ -1,4 +1,4 @@ -/* $OpenBSD: gdt.h,v 1.2 1996/04/18 19:21:37 niklas Exp $ */ +/* $OpenBSD: gdt.h,v 1.3 1996/04/29 14:13:48 hvozda Exp $ */ /* $NetBSD: gdt.h,v 1.3 1996/02/27 22:32:11 jtc Exp $ */ /*- @@ -37,6 +37,9 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#define MAXGDTSIZ 8192 /* max # entries in an i386 GDT */ +extern union descriptor *dynamic_gdt; + void tss_alloc __P((struct pcb *)); void tss_free __P((struct pcb *)); void ldt_alloc __P((struct pcb *, union descriptor *, size_t)); diff --git a/sys/arch/i386/include/segments.h b/sys/arch/i386/include/segments.h index a1a332e23f3..4558ccce6aa 100644 --- a/sys/arch/i386/include/segments.h +++ b/sys/arch/i386/include/segments.h @@ -217,7 +217,10 @@ void setsegment __P((struct segment_descriptor *, void *, size_t, int, int, #define GLDT_SEL 3 /* Default LDT descriptor */ #define GUCODE_SEL 4 /* User code descriptor */ #define GUDATA_SEL 5 /* User data descriptor */ -#define NGDT 6 +#define GAPM32CODE_SEL 6 +#define GAPM16CODE_SEL 7 +#define GAPMDATA_SEL 8 +#define NGDT 9 /* * Entries in the Local Descriptor Table (LDT) |