From owner-acpi-jp@jp.freebsd.org  Sat Aug  5 04:21:25 2000
Received: (from daemon@localhost)
	by castle.jp.freebsd.org (8.9.3+3.2W/8.7.3) id EAA41173;
	Sat, 5 Aug 2000 04:21:25 +0900 (JST)
	(envelope-from owner-acpi-jp@jp.FreeBSD.org)
Received: from tasogare.imasy.or.jp (daemon@tasogare.imasy.or.jp [202.227.24.5])
	by castle.jp.freebsd.org (8.9.3+3.2W/8.7.3) with ESMTP id EAA41168
	for <acpi-jp@jp.freebsd.org>; Sat, 5 Aug 2000 04:21:24 +0900 (JST)
	(envelope-from iwasaki@jp.FreeBSD.org)
Received: from localhost (iwasaki.imasy.or.jp [202.227.24.92])
	by tasogare.imasy.or.jp (8.10.1+3.3W/3.7W-tasogare/smtpfeed 1.07) with ESMTP id e74JLLp46320;
	Sat, 5 Aug 2000 04:21:21 +0900 (JST)
	(envelope-from iwasaki@jp.FreeBSD.org)
To: acpi-jp@jp.freebsd.org, keisuke-ml@keisuke.org
In-Reply-To: <20000628151612B.keisuke@csl.sony.co.jp>
References: <20000628151612B.keisuke@csl.sony.co.jp>
X-Mailer: Mew version 1.94.1 on Emacs 19.34 / Mule 2.3 (SUETSUMUHANA)
Mime-Version: 1.0
Content-Type: Text/Plain; charset=iso-2022-jp
Content-Transfer-Encoding: 7bit
Message-Id: <20000805042117E.iwasaki@jp.FreeBSD.org>
Date: Sat, 05 Aug 2000 04:21:17 +0900
From: Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
X-Dispatcher: imput version 20000228(IM140)
Lines: 423
Reply-To: acpi-jp@jp.freebsd.org
Precedence: list
X-Distribute: distribute version 2.1 (Alpha) patchlevel 24e+000315
X-Sequence: acpi-jp 516
Subject: [acpi-jp 516] Re: =?ISO-2022-JP?B?GyRCRWw8RxsoQg==?= Linux
 =?ISO-2022-JP?B?GyRCJVohPCU4JE4zK0gvPnBKcxsoQg==?= 
Errors-To: owner-acpi-jp@jp.freebsd.org
Sender: owner-acpi-jp@jp.freebsd.org
X-Originator: iwasaki@jp.freebsd.org

$B$A$g$C$H8E$$OC$G$9$,(B...

> $BEl<G(BLinux$B%f!<%6$N%Z!<%8$NCf$N3+H/>pJs(B
> http://www.tce.co.jp/linux/jpn/develop.php3
> $B$K%O%$%P%M!<%7%g%s>pJs$,$"$j$^$9!%2?$+Lr$KN)$A$^$9$G$7$g$&$+!%(B
> w3m$B$G8+$?$H$-$NH4?h$G$9!%(B

$B<B$O$\$/$b;qNA$r$b$i$C$?$s$G$9$,!"(Btoshiba $B%^%7%s8GM-$@$7(B ACPI $B$H4X78(B
$BL5$$$N$G%,%C%/%7$G$7$?!#$G$b$;$C$+$/F~<j$7$?$N$G?t;~4V$@$1:n6H$7$F(B
$B%F%9%HL$40$N$^$^J|$C$F$"$j$^$9(B (^^;
$B$\$/<+?H$O$3$l0J>e$d$k$D$b$j$O$J$$$G$9$,!"B?J,$"$H$A$g$C$H4hD%$l$P(B
$B$G$-$k$h$&$K$J$k$H;W$$$^$9$N$GN.$7$F$*$-$^$9!#(B
$B8eH>IU$12C$($?ItJ,$O(B FreeBSD, Linux, Windows (DOS?) $B$G%3%s%Q%$%k(B & $B<B9T(B
$B$G$-$k$H;W$$$^$9!#(B
$B;qNAF~<j;~$KEl<G$5$s$K$3$l$r85$K3+H/$7$?%3!<%I$N8x3+$K$D$$$FLd$$9g$o$;(B
$B$7$?$H$3$m!"!V8x3+$N<j=g$K@)Ls$OM-$j$^$;$s!#$h$C$F!"%l%S%e!<$bI,MWM-$j$^$;$s!#(B 
$B5U$K!"8x3+$5$l$?@.2L$KIU$$$F!"El<G$*$h$SJ@<R$O2?$i@UG$$rIi$o$J$$$b$N$H$7$^$9!#!W(B
$B$H2sEzD:$$$?$N$G!"$3$3$KN.$9$3$H$O2?$iLdBj$J$$$H$$$&G'<1$G$9!#(B

$B$G$O!"C/$+$d$k5$$N$"$k?M!"8e$O$h$m$7$/$*4j$$$7$^$9(B (_ _)

Index: apm.c
===================================================================
RCS file: /home/ncvs/src/sys/i386/apm/apm.c,v
retrieving revision 1.115
diff -u -r1.115 apm.c
--- apm.c	2000/07/19 06:32:00	1.115
+++ apm.c	2000/07/23 08:48:04
@@ -107,6 +107,18 @@
 SYSCTL_INT(_machdep, OID_AUTO, apm_suspend_delay, CTLFLAG_RW, &apm_suspend_delay, 1, "");
 SYSCTL_INT(_machdep, OID_AUTO, apm_standby_delay, CTLFLAG_RW, &apm_standby_delay, 1, "");
 
+#if 1
+#define TOSHIBA_BIOS_HIBERNATION
+#endif
+
+#ifdef TOSHIBA_BIOS_HIBERNATION
+static int apm_hibernation = 1;
+SYSCTL_INT(_machdep, OID_AUTO, apm_hibernation, CTLFLAG_RW, &apm_hibernation, 1, "");
+
+u_long	apm_toshiba_get_hibernation_mode(void);
+void	apm_toshiba_set_hibernation_mode(int);
+#endif
+
 /*
  * return  0 if the function successfull,
  * return  1 if the function unsuccessfull,
@@ -557,6 +580,9 @@
 apm_suspend(int state)
 {
 	struct apm_softc *sc = &apm_softc;
+#ifdef TOSHIBA_BIOS_HIBERNATION
+	static int last_hibernation_mode = -1;
+#endif
 
 	if (!sc->initialized)
 		return;
@@ -565,6 +591,15 @@
 	case PMST_SUSPEND:
 		if (sc->suspends)
 			return;
+#ifdef TOSHIBA_BIOS_HIBERNATION
+		printf("last_hibernation_mode = %ld, apm_hibernation = %d\n",
+			last_hibernation_mode, apm_hibernation);
+		if ((apm_hibernation >= 0) &&
+		    (last_hibernation_mode != apm_hibernation)) {
+			apm_toshiba_set_hibernation_mode(apm_hibernation);
+			last_hibernation_mode = apm_hibernation;
+		}
+#endif 
 		sc->suspends++;
 		sc->suspend_countdown = apm_suspend_delay;
 		break;
@@ -1372,3 +1407,349 @@
 static devclass_t apm_devclass;
 
 DRIVER_MODULE(apm, nexus, apm_driver, apm_devclass, 0, 0);
+
+
+#ifdef TOSHIBA_BIOS_HIBERNATION
+/*-
+ * Extended APM BIOS Interface for Toshiba Laptops (hibernation).
+ *
+ * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
+ * 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.
+ *
+ */
+#if defined(__linux__) || defined(__GO32__)
+#undef TOSHIBA_BIOS_USE_INT15
+#define TOSHIBA_BIOS_USE_INT15	0
+#endif
+
+#if defined(__FreeBSD__) || !defined(_KERNEL)
+#undef TOSHIBA_BIOS_USE_INT15
+#define TOSHIBA_BIOS_USE_INT15	0
+#endif
+
+/* Use INT15 call for SCI/HCI manipulation as default */
+#ifndef TOSHIBA_BIOS_USE_INT15
+#define TOSHIBA_BIOS_USE_INT15	1
+#endif
+
+/*
+ * Toshiba Laptop SCI (System Configuration Interface) modes and
+ * HCI (Hardware Configuration Interface).
+ * Following values are used for AX register.
+ */
+#if TOSHIBA_BIOS_USE_INT15 == 1
+/*
+ * Use INT15 call for SCI/HCI manipulation.
+ * These values were obtained from the technical documents provided by
+ * Toshiba Computer Engineering Co. Jan, 2000.
+ * <URL:http://www.tce.co.jp/linux/indexj.html>
+ */
+#define TOSHIBA_BIOS_SCI_EXIST	0x44f0
+#define TOSHIBA_BIOS_SCI_OPEN	0x44f1
+#define TOSHIBA_BIOS_SCI_CLOSE	0x44f2
+#define TOSHIBA_BIOS_SCI_GET	0x44f3
+#define TOSHIBA_BIOS_SCI_SET	0x44f4
+
+#define TOSHIBA_BIOS_HCI_GET	0x44fe
+#define TOSHIBA_BIOS_HCI_SET	0x44ff
+#else
+/*
+ * Use SMI Command port I/O for SCI/HCI manipulation.
+ * These values were obtained by analyzing ACPI DSDT data block of
+ * toshiba laptops by using AML interpreter for FreeBSD. 
+ * See also \_SMBR method of PORTEGE, TECRA, Dynabook and others.
+ * <URL:http://www.jp.FreeBSD.org/acpi/>
+ */
+#define TOSHIBA_BIOS_SCI_EXIST	0xf000
+#define TOSHIBA_BIOS_SCI_OPEN	0xf100
+#define TOSHIBA_BIOS_SCI_CLOSE	0xf200
+#define TOSHIBA_BIOS_SCI_GET	0xf300
+#define TOSHIBA_BIOS_SCI_SET	0xf400
+
+#define TOSHIBA_BIOS_HCI_GET	0xfe00
+#define TOSHIBA_BIOS_HCI_SET	0xff00
+#endif	/* TOSHIBA_BIOS_USE_INT15 */
+
+/*
+ * Toshiba Laptop SCI/HCI subfunction code.
+ * Following values are used for BX register.
+ */
+/* SCI subfunctions.  */
+#define TOSHIBA_BIOS_HIBERNATION_MODE	0x012d
+/* HCI subfunctions.  */
+#define TOSHIBA_BIOS_HIBERNATION_FILE	0x002e
+
+#include <sys/types.h>
+
+static u_long
+toshiba_bios_read(u_long ieax, u_long iebx)
+{
+	u_long	oecx = 0;
+#if TOSHIBA_BIOS_USE_INT15 == 1
+#if defined(__FreeBSD__)
+	struct vm86frame	vmf;
+
+	bzero(&vmf, sizeof(struct vm86frame));
+	vmf.vmf_ax = ieax;
+	vmf.vmf_bx = iebx;
+	vm86_intcall(0x15, &vmf);
+	oecx = vmf.vmf_cx;
+#else
+#error "INT15 call unsupported on this system"
+#endif	/* __FreeBSD__ */
+
+#else	/* TOSHIBA_BIOS_USE_INT15 */
+#ifdef __GNUC__
+	__asm__("pushl %%eax; pushl %%ebx; pushl %%ecx; pushl %%edx; " \
+		"movl %1,%%eax; movl %2,%%ebx; " \
+		"inb $0xb2, %%al; " \
+		"movl %%ecx, %0; " \
+		"popl %%edx; popl %%ecx; popl %%ebx; popl %%eax"
+		:"=m" (oecx) \
+		:"m" (ieax), "m" (iebx) \
+		:"memory" );
+#endif	/* __GNUC__ */
+
+#endif	/* TOSHIBA_BIOS_USE_INT15 */
+
+	return (oecx);
+}
+
+static int
+toshiba_bios_write(u_long ieax, u_long iebx, u_long iecx)
+{
+	u_long	oeax = 0;
+#if TOSHIBA_BIOS_USE_INT15 == 1
+#if defined(__FreeBSD__)
+	struct vm86frame	vmf;
+
+	bzero(&vmf, sizeof(struct vm86frame));
+	vmf.vmf_ax = ieax;
+	vmf.vmf_bx = iebx;
+	vmf.vmf_cx = iecx;
+	vm86_intcall(0x15, &vmf);
+	oeax = vmf.vmf_ax;
+#else
+#error "INT15 call unsupported on this system"
+#endif	/* __FreeBSD__ */
+
+#else	/* TOSHIBA_BIOS_USE_INT15 */
+#ifdef __GNUC__
+	__asm__("pushl %%eax; pushl %%ebx; pushl %%ecx; pushl %%edx; " \
+		"movl %1,%%eax; movl %2,%%ebx; movl %3,%%ecx; " \
+		"inb $0xb2, %%al; " \
+		"movl %%eax, %0; " \
+		"popl %%edx; popl %%ecx; popl %%ebx; popl %%eax"
+		:"=m" (oeax) \
+		:"m" (ieax), "m" (iebx), "m" (iecx) \
+		:"memory" );
+#endif	/* __GNUC__ */
+
+#endif	/* TOSHIBA_BIOS_USE_INT15 */
+	return (oeax & 0x0000ff00);	/* error code in AH register */
+}
+
+static u_long
+toshiba_bios_get_sci_mode(u_long subfunction)
+{
+	u_long	value = 0;
+
+	if (toshiba_bios_write(TOSHIBA_BIOS_SCI_EXIST, 0, 0)) {
+		printf("toshiba bios: SCI no exists\n");
+		value = -1;
+		goto out;
+	}
+
+	if (toshiba_bios_write(TOSHIBA_BIOS_SCI_OPEN, 0, 0)) {
+		printf("toshiba bios: SCI open failure\n");
+		value = -1;
+		goto out;
+	}
+
+	value = toshiba_bios_read(TOSHIBA_BIOS_SCI_GET, subfunction);
+
+out:
+	if (toshiba_bios_write(TOSHIBA_BIOS_SCI_CLOSE, 0, 0)) {
+		printf("toshiba bios: SCI close failure\n");
+	}
+
+	return (value);
+}
+
+static int
+toshiba_bios_set_sci_mode(u_long subfunction, u_long value)
+{
+	int	error = 0;
+
+	if (toshiba_bios_write(TOSHIBA_BIOS_SCI_EXIST, 0, 0)) {
+		printf("toshiba bios: SCI no exists\n");
+		error = -1;
+		goto out;
+	}
+
+	if (toshiba_bios_write(TOSHIBA_BIOS_SCI_OPEN, 0, 0)) {
+		printf("toshiba bios: SCI open failure\n");
+		error = -1;
+		goto out;
+	}
+
+	error = toshiba_bios_write(TOSHIBA_BIOS_SCI_SET, subfunction, value);
+	if (error) {
+		printf("toshiba bios: SCI set failure (0x%lx, 0x%lx) = 0x%x\n", 
+			subfunction, value, error);
+	}
+
+out:
+	if (toshiba_bios_write(TOSHIBA_BIOS_SCI_CLOSE, 0, 0)) {
+		printf("toshiba bios: SCI close failure\n");
+	}
+
+	return (error);
+}
+
+static u_long
+toshiba_bios_get_hci_mode(u_long subfunction)
+{
+	u_long	value = 0;
+
+	value = toshiba_bios_read(TOSHIBA_BIOS_HCI_GET, subfunction);
+
+	return (value);
+}
+
+static int
+toshiba_bios_set_hci_mode(u_long subfunction, u_long value)
+{
+	int	error;
+
+	error = toshiba_bios_write(TOSHIBA_BIOS_HCI_SET, subfunction, value);
+	if (error) {
+		printf("toshiba bios: HCI set failure (0x%lx, 0x%lx) = 0x%x\n", 
+			subfunction, value, error);
+	}
+
+	return (error);
+}
+
+/*
+ * Public interface for APM device driver.
+ */
+
+u_long
+apm_toshiba_get_hibernation_file(void)
+{
+	return toshiba_bios_get_hci_mode(TOSHIBA_BIOS_HIBERNATION_FILE);
+}
+
+int
+apm_toshiba_set_hibernation_file(u_long lba)
+{
+	return toshiba_bios_set_hci_mode(TOSHIBA_BIOS_HIBERNATION_FILE, lba);
+}
+
+u_long
+apm_toshiba_get_hibernation_mode(void)
+{
+	return toshiba_bios_get_sci_mode(TOSHIBA_BIOS_HIBERNATION_MODE);
+}
+
+void
+apm_toshiba_set_hibernation_mode(int enable)
+{
+	u_long	hfile_lba;
+	if (enable != 0 && enable != 1) {
+		return;
+	}
+
+	printf("apm:toshiba: changing hibernation mode to %d\n", enable);
+	toshiba_bios_set_sci_mode(TOSHIBA_BIOS_HIBERNATION_MODE, enable);
+	hfile_lba = apm_toshiba_get_hibernation_file();
+	if (hfile_lba == 0) {
+		printf("apm:toshiba: no hibernaion file installed, will suspend.\n");
+	} else {
+		printf("apm:toshiba: hibernaion file installed at %ld (LBA).\n", hfile_lba);
+	}
+}
+
+#ifndef _KERNEL
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+int
+main(int argc, char *argv[])
+{
+	char	c;
+	u_long	hfile_lba;
+
+#if defined(__FreeBSD__) || defined(__linux__)
+	setuid(0);
+#endif
+
+#if defined(__FreeBSD__)
+	open("/dev/io", O_RDWR, 0);
+#else
+#ifdef __linux__
+	ioperm(0xb2, 1, 1);
+#endif
+#endif
+	if (argc > 1 && argv[1][0] == '-') {
+		c = argv[1][1];
+		switch (c) {
+		case 'e':
+			apm_toshiba_set_hibernation_mode(1);
+			goto out;
+		case 'd':
+			apm_toshiba_set_hibernation_mode(0);
+			goto out;
+		case 'g':
+			hfile_lba = apm_toshiba_get_hibernation_file();
+			if (hfile_lba == 0) {
+				printf("apm:toshiba: no hibernaion file installed, will suspend.\n");
+			} else {
+				printf("apm:toshiba: hibernaion file installed at %ld (LBA).\n", hfile_lba);
+			}
+			goto out;
+		case 's':
+			if (argc <= 2) {
+				goto usage;
+			}
+			hfile_lba = atol(argv[2]);
+			apm_toshiba_set_hibernation_file(hfile_lba);
+			goto out;
+		default:
+			goto usage;
+		}
+	}
+usage:
+	printf("usage %s: [-e] [-d] [-g] [-s LBA]\n", argv[0]);
+
+out:
+	printf("apm:toshiba: hibernation mode = %ld\n",
+		apm_toshiba_get_hibernation_mode());
+	return 0;
+}
+#endif	/* !_KERNEL */
+
+#endif	/* TOSHIBA_BIOS_HIBERNATION */
