Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /* toshiba.c -- Linux driver for accessing the SMM on Toshiba laptops
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  * Copyright (c) 1996-2001  Jonathan A. Buzzard (jonathan@buzzard.org.uk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  * Valuable assistance and patches from:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  *     Tom May <tom@you-bastards.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  *     Rob Napier <rnapier@employees.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  * Fn status port numbers for machine ID's courtesy of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  *     0xfc02: Scott Eisert <scott.e@sky-eye.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12)  *     0xfc04: Steve VanDevender <stevev@efn.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13)  *     0xfc08: Garth Berry <garth@itsbruce.net>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14)  *     0xfc0a: Egbert Eich <eich@xfree86.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15)  *     0xfc10: Andrew Lofthouse <Andrew.Lofthouse@robins.af.mil>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16)  *     0xfc11: Spencer Olson <solson@novell.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17)  *     0xfc13: Claudius Frankewitz <kryp@gmx.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18)  *     0xfc15: Tom May <tom@you-bastards.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19)  *     0xfc17: Dave Konrad <konrad@xenia.it>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20)  *     0xfc1a: George Betzos <betzos@engr.colostate.edu>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21)  *     0xfc1b: Munemasa Wada <munemasa@jnovel.co.jp>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22)  *     0xfc1d: Arthur Liu <armie@slap.mine.nu>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23)  *     0xfc5a: Jacques L'helgoualc'h <lhh@free.fr>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24)  *     0xfcd1: Mr. Dave Konrad <konrad@xenia.it>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26)  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28)  *   This code is covered by the GNU GPL and you are free to make any
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29)  *   changes you wish to it under the terms of the license. However the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30)  *   code has the potential to render your computer and/or someone else's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31)  *   unusable. Please proceed with care when modifying the code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33)  * Note: Unfortunately the laptop hardware can close the System Configuration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34)  *       Interface on it's own accord. It is therefore necessary for *all*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35)  *       programs using this driver to be aware that *any* SCI call can fail at
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36)  *       *any* time. It is up to any program to be aware of this eventuality
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37)  *       and take appropriate steps.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39)  * The information used to write this driver has been obtained by reverse
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40)  * engineering the software supplied by Toshiba for their portable computers in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41)  * strict accordance with the European Council Directive 92/250/EEC on the legal
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42)  * protection of computer programs, and it's implementation into English Law by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43)  * the Copyright (Computer Programs) Regulations 1992 (S.I. 1992 No.3233).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) #define TOSH_VERSION "1.11 26/9/2001"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) #define TOSH_DEBUG 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) #include <linux/fcntl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) #include <linux/miscdevice.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) #include <linux/ioport.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) #include <linux/stat.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) #include <linux/proc_fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) #include <linux/seq_file.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) #include <linux/mutex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) #include <linux/toshiba.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) MODULE_AUTHOR("Jonathan Buzzard <jonathan@buzzard.org.uk>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) MODULE_DESCRIPTION("Toshiba laptop SMM driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) MODULE_SUPPORTED_DEVICE("toshiba");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) static DEFINE_MUTEX(tosh_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) static int tosh_fn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) module_param_named(fn, tosh_fn, int, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) MODULE_PARM_DESC(fn, "User specified Fn key detection port");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) static int tosh_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) static int tosh_bios;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) static int tosh_date;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) static int tosh_sci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) static int tosh_fan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) static long tosh_ioctl(struct file *, unsigned int,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 	unsigned long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) static const struct file_operations tosh_fops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 	.owner		= THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 	.unlocked_ioctl	= tosh_ioctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 	.llseek		= noop_llseek,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) static struct miscdevice tosh_device = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 	TOSH_MINOR_DEV,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 	"toshiba",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 	&tosh_fops
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97)  * Read the Fn key status
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) #ifdef CONFIG_PROC_FS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) static int tosh_fn_status(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)         unsigned char scan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 	if (tosh_fn!=0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 		scan = inb(tosh_fn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 		local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 		outb(0x8e, 0xe4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 		scan = inb(0xe5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 		local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)         return (int) scan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)  * For the Portage 610CT and the Tecra 700CS/700CDT emulate the HCI fan function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) static int tosh_emulate_fan(SMMRegisters *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 	unsigned long eax,ecx,flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 	unsigned char al;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 	eax = regs->eax & 0xff00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 	ecx = regs->ecx & 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 	/* Portage 610CT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 	if (tosh_id==0xfccb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 		if (eax==0xfe00) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 			/* fan status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 			local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 			outb(0xbe, 0xe4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 			al = inb(0xe5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 			local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 			regs->eax = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 			regs->ecx = (unsigned int) (al & 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 		if ((eax==0xff00) && (ecx==0x0000)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 			/* fan off */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 			local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 			outb(0xbe, 0xe4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 			al = inb(0xe5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 			outb(0xbe, 0xe4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 			outb (al | 0x01, 0xe5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 			local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 			regs->eax = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 			regs->ecx = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 		if ((eax==0xff00) && (ecx==0x0001)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 			/* fan on */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 			local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 			outb(0xbe, 0xe4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 			al = inb(0xe5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 			outb(0xbe, 0xe4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 			outb(al & 0xfe, 0xe5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 			local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 			regs->eax = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 			regs->ecx = 0x01;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 	/* Tecra 700CS/CDT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 	if (tosh_id==0xfccc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 		if (eax==0xfe00) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 			/* fan status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 			local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 			outb(0xe0, 0xe4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 			al = inb(0xe5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 			local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 			regs->eax = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 			regs->ecx = al & 0x01;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 		if ((eax==0xff00) && (ecx==0x0000)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 			/* fan off */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 			local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 			outb(0xe0, 0xe4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 			al = inb(0xe5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 			outw(0xe0 | ((al & 0xfe) << 8), 0xe4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 			local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 			regs->eax = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 			regs->ecx = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 		if ((eax==0xff00) && (ecx==0x0001)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 			/* fan on */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 			local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 			outb(0xe0, 0xe4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 			al = inb(0xe5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 			outw(0xe0 | ((al | 0x01) << 8), 0xe4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 			local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 			regs->eax = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 			regs->ecx = 0x01;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)  * Put the laptop into System Management Mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) int tosh_smm(SMMRegisters *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 	int eax;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 	asm ("# load the values into the registers\n\t" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 		"pushl %%eax\n\t" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 		"movl 0(%%eax),%%edx\n\t" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 		"push %%edx\n\t" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 		"movl 4(%%eax),%%ebx\n\t" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 		"movl 8(%%eax),%%ecx\n\t" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 		"movl 12(%%eax),%%edx\n\t" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 		"movl 16(%%eax),%%esi\n\t" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 		"movl 20(%%eax),%%edi\n\t" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 		"popl %%eax\n\t" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 		"# call the System Management mode\n\t" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 		"inb $0xb2,%%al\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 		"# fill out the memory with the values in the registers\n\t" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 		"xchgl %%eax,(%%esp)\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 		"movl %%ebx,4(%%eax)\n\t" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 		"movl %%ecx,8(%%eax)\n\t" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 		"movl %%edx,12(%%eax)\n\t" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 		"movl %%esi,16(%%eax)\n\t" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 		"movl %%edi,20(%%eax)\n\t" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 		"popl %%edx\n\t" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 		"movl %%edx,0(%%eax)\n\t" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 		"# setup the return value to the carry flag\n\t" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 		"lahf\n\t" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 		"shrl $8,%%eax\n\t" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 		"andl $1,%%eax\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 		: "=a" (eax)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 		: "a" (regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 		: "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 	return eax;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) EXPORT_SYMBOL(tosh_smm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) static long tosh_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 	SMMRegisters regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 	SMMRegisters __user *argp = (SMMRegisters __user *)arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 	unsigned short ax,bx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 	if (!argp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 	if (copy_from_user(&regs, argp, sizeof(SMMRegisters)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 		return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 	switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 		case TOSH_SMM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 			ax = regs.eax & 0xff00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 			bx = regs.ebx & 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 			/* block HCI calls to read/write memory & PCI devices */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 			if (((ax==0xff00) || (ax==0xfe00)) && (bx>0x0069))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 				return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 			/* do we need to emulate the fan ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 			mutex_lock(&tosh_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 			if (tosh_fan==1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 				if (((ax==0xf300) || (ax==0xf400)) && (bx==0x0004)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 					err = tosh_emulate_fan(&regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 					mutex_unlock(&tosh_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 					break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 				}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 			err = tosh_smm(&regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 			mutex_unlock(&tosh_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 		default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)         if (copy_to_user(argp, &regs, sizeof(SMMRegisters)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)         	return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 	return (err==0) ? 0:-EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)  * Print the information for /proc/toshiba
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) #ifdef CONFIG_PROC_FS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) static int proc_toshiba_show(struct seq_file *m, void *v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 	int key;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 	key = tosh_fn_status();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 	/* Arguments
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 	     0) Linux driver version (this will change if format changes)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 	     1) Machine ID
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 	     2) SCI version
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 	     3) BIOS version (major, minor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 	     4) BIOS date (in SCI date format)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 	     5) Fn Key status
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 	*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 	seq_printf(m, "1.1 0x%04x %d.%d %d.%d 0x%04x 0x%02x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 		tosh_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 		(tosh_sci & 0xff00)>>8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 		tosh_sci & 0xff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 		(tosh_bios & 0xff00)>>8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 		tosh_bios & 0xff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 		tosh_date,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 		key);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)  * Determine which port to use for the Fn key status
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) static void tosh_set_fn_port(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 	switch (tosh_id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 		case 0xfc02: case 0xfc04: case 0xfc09: case 0xfc0a: case 0xfc10:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 		case 0xfc11: case 0xfc13: case 0xfc15: case 0xfc1a: case 0xfc1b:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) 		case 0xfc5a:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 			tosh_fn = 0x62;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 		case 0xfc08: case 0xfc17: case 0xfc1d: case 0xfcd1: case 0xfce0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 		case 0xfce2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 			tosh_fn = 0x68;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 		default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 			tosh_fn = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) 	return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)  * Get the machine identification number of the current model
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) static int tosh_get_machine_id(void __iomem *bios)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 	int id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 	SMMRegisters regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 	unsigned short bx,cx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 	unsigned long address;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 	id = (0x100*(int) readb(bios+0xfffe))+((int) readb(bios+0xfffa));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 	/* do we have a SCTTable machine identication number on our hands */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 	if (id==0xfc2f) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) 		/* start by getting a pointer into the BIOS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 		regs.eax = 0xc000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) 		regs.ebx = 0x0000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) 		regs.ecx = 0x0000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) 		tosh_smm(&regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) 		bx = (unsigned short) (regs.ebx & 0xffff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 		/* At this point in the Toshiba routines under MS Windows
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) 		   the bx register holds 0xe6f5. However my code is producing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) 		   a different value! For the time being I will just fudge the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) 		   value. This has been verified on a Satellite Pro 430CDT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 		   Tecra 750CDT, Tecra 780DVD and Satellite 310CDT. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) #if TOSH_DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 		pr_debug("toshiba: debugging ID ebx=0x%04x\n", regs.ebx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) 		bx = 0xe6f5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) 		/* now twiddle with our pointer a bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) 		address = bx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) 		cx = readw(bios + address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) 		address = 9+bx+cx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) 		cx = readw(bios + address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) 		address = 0xa+cx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) 		cx = readw(bios + address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 		/* now construct our machine identification number */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) 		id = ((cx & 0xff)<<8)+((cx & 0xff00)>>8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) 	return id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)  * Probe for the presence of a Toshiba laptop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399)  *   returns and non-zero if unable to detect the presence of a Toshiba
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)  *   laptop, otherwise zero and determines the Machine ID, BIOS version and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)  *   date, and SCI version.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) static int tosh_probe(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) 	int i,major,minor,day,year,month,flag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) 	unsigned char signature[7] = { 0x54,0x4f,0x53,0x48,0x49,0x42,0x41 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) 	SMMRegisters regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) 	void __iomem *bios = ioremap(0xf0000, 0x10000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) 	if (!bios)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) 	/* extra sanity check for the string "TOSHIBA" in the BIOS because
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) 	   some machines that are not Toshiba's pass the next test */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) 	for (i=0;i<7;i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) 		if (readb(bios+0xe010+i)!=signature[i]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) 			pr_err("toshiba: not a supported Toshiba laptop\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) 			iounmap(bios);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) 			return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) 	/* call the Toshiba SCI support check routine */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) 	regs.eax = 0xf0f0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) 	regs.ebx = 0x0000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) 	regs.ecx = 0x0000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) 	flag = tosh_smm(&regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) 	/* if this is not a Toshiba laptop carry flag is set and ah=0x86 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) 	if ((flag==1) || ((regs.eax & 0xff00)==0x8600)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) 		pr_err("toshiba: not a supported Toshiba laptop\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) 		iounmap(bios);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) 		return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) 	/* if we get this far then we are running on a Toshiba (probably)! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) 	tosh_sci = regs.edx & 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) 	/* next get the machine ID of the current laptop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) 	tosh_id = tosh_get_machine_id(bios);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) 	/* get the BIOS version */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) 	major = readb(bios+0xe009)-'0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) 	minor = ((readb(bios+0xe00b)-'0')*10)+(readb(bios+0xe00c)-'0');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) 	tosh_bios = (major*0x100)+minor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) 	/* get the BIOS date */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) 	day = ((readb(bios+0xfff5)-'0')*10)+(readb(bios+0xfff6)-'0');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) 	month = ((readb(bios+0xfff8)-'0')*10)+(readb(bios+0xfff9)-'0');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) 	year = ((readb(bios+0xfffb)-'0')*10)+(readb(bios+0xfffc)-'0');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) 	tosh_date = (((year-90) & 0x1f)<<10) | ((month & 0xf)<<6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) 		| ((day & 0x1f)<<1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) 	/* in theory we should check the ports we are going to use for the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) 	   fn key detection (and the fan on the Portage 610/Tecra700), and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) 	   then request them to stop other drivers using them. However as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) 	   the keyboard driver grabs 0x60-0x6f and the pic driver grabs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) 	   0xa0-0xbf we can't. We just have to live dangerously and use the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) 	   ports anyway, oh boy! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) 	/* do we need to emulate the fan? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) 	if ((tosh_id==0xfccb) || (tosh_id==0xfccc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) 		tosh_fan = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) 	iounmap(bios);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) static int __init toshiba_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) 	int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) 	/* are we running on a Toshiba laptop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) 	if (tosh_probe())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) 		return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) 	pr_info("Toshiba System Management Mode driver v" TOSH_VERSION "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) 	/* set the port to use for Fn status if not specified as a parameter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) 	if (tosh_fn==0x00)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) 		tosh_set_fn_port();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) 	/* register the device file */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) 	retval = misc_register(&tosh_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) 	if (retval < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) 		return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) #ifdef CONFIG_PROC_FS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) 		struct proc_dir_entry *pde;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) 		pde = proc_create_single("toshiba", 0, NULL, proc_toshiba_show);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) 		if (!pde) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) 			misc_deregister(&tosh_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) 			return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) static void __exit toshiba_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) 	remove_proc_entry("toshiba", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) 	misc_deregister(&tosh_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) module_init(toshiba_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) module_exit(toshiba_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)