diff --exclude *.rej --exclude *.orig --exclude .config -ruN linux-2.4.20/Documentation/Configure.help linux-2.4.20-patched/Documentation/Configure.help --- linux-2.4.20/Documentation/Configure.help Fri Nov 29 08:53:08 2002 +++ linux-2.4.20-patched/Documentation/Configure.help Mon Dec 30 18:21:17 2002 @@ -18453,6 +18453,30 @@ This driver handles overheating conditions on laptops. It is HIGHLY recommended, as your laptop CPU may be damaged without it. +ACPI Toshiba Laptop Extras +CONFIG_ACPI_TOSHIBA + This driver adds support for access to certain system settings + on "legacy free" Toshiba laptops. These laptops can be recognized by + their lack of a BIOS setup menu and APM support. + + On these machines, all system configuration is handled through the + ACPI. This driver is required for access to controls not covered + by the general ACPI drivers, such as LCD brightness, video output, + etc. + + This driver differs from the non-ACPI Toshiba laptop driver (located + under "Processor type and features") in several aspects. + Configuration is accessed by reading and writing text files in the + /proc tree instead of by program interface to /dev. Furthermore, no + power management functions are exposed, as those are handled by the + general ACPI drivers. + + More information about this driver is available at + . + + If you have a legacy free Toshiba laptop (such as the Libretto L1 + series), say Y. + Advanced Power Management BIOS support CONFIG_APM APM is a BIOS specification for saving power using several different diff --exclude *.rej --exclude *.orig --exclude .config -ruN linux-2.4.20/MAINTAINERS linux-2.4.20-patched/MAINTAINERS --- linux-2.4.20/MAINTAINERS Fri Nov 29 08:53:08 2002 +++ linux-2.4.20-patched/MAINTAINERS Mon Dec 30 18:21:17 2002 @@ -1609,6 +1609,12 @@ W: http://www.linuxtr.net S: Maintained +TOSHIBA ACPI EXTRAS DRIVER +P: John Belmonte +M: toshiba_acpi@memebeam.org +W: http://memebeam.org/toys/ToshibaAcpiDriver +S: Maintained + TOSHIBA SMM DRIVER P: Jonathan Buzzard M: jonathan@buzzard.org.uk diff --exclude *.rej --exclude *.orig --exclude .config -ruN linux-2.4.20/arch/i386/kernel/pci-irq.c linux-2.4.20-patched/arch/i386/kernel/pci-irq.c --- linux-2.4.20/arch/i386/kernel/pci-irq.c Fri Nov 29 08:53:09 2002 +++ linux-2.4.20-patched/arch/i386/kernel/pci-irq.c Mon Dec 30 18:25:47 2002 @@ -20,6 +20,7 @@ #include "pci-i386.h" #define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24)) +#define PIRQ_SIGNATURE2 (('_' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24)) #define PIRQ_VERSION 0x0100 int broken_hp_bios_irq9; @@ -58,7 +59,8 @@ for(addr = (u8 *) __va(0xf0000); addr < (u8 *) __va(0x100000); addr += 16) { rt = (struct irq_routing_table *) addr; - if (rt->signature != PIRQ_SIGNATURE || + if ((rt->signature != PIRQ_SIGNATURE && + rt->signature != PIRQ_SIGNATURE2 ) || rt->version != PIRQ_VERSION || rt->size % 16 || rt->size < sizeof(struct irq_routing_table)) diff --exclude *.rej --exclude *.orig --exclude .config -ruN linux-2.4.20/drivers/acpi/Config.in linux-2.4.20-patched/drivers/acpi/Config.in --- linux-2.4.20/drivers/acpi/Config.in Thu Jun 21 09:47:39 2001 +++ linux-2.4.20-patched/drivers/acpi/Config.in Mon Dec 30 18:22:32 2002 @@ -14,4 +14,6 @@ dep_tristate ' Embedded Controller' CONFIG_ACPI_EC $CONFIG_ACPI_BUSMGR $CONFIG_ACPI dep_tristate ' Control Method Battery' CONFIG_ACPI_CMBATT $CONFIG_ACPI_BUSMGR $CONFIG_ACPI $CONFIG_ACPI_EC dep_tristate ' Thermal' CONFIG_ACPI_THERMAL $CONFIG_ACPI_BUSMGR $CONFIG_ACPI $CONFIG_ACPI_EC +tristate ' Toshiba Laptop Extras' CONFIG_ACPI_TOSHIBA + #endmenu diff --exclude *.rej --exclude *.orig --exclude .config -ruN linux-2.4.20/drivers/acpi/Makefile linux-2.4.20-patched/drivers/acpi/Makefile --- linux-2.4.20/drivers/acpi/Makefile Thu Oct 25 06:06:21 2001 +++ linux-2.4.20-patched/drivers/acpi/Makefile Mon Dec 30 18:24:13 2002 @@ -38,6 +38,7 @@ obj-$(CONFIG_ACPI) += driver.o os.o acpi_ksyms.o obj-$(CONFIG_ACPI) += $(foreach dir,$(acpi-subdirs),$(dir)/$(dir).o) +obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o ifdef CONFIG_ACPI_KERNEL_CONFIG obj-$(CONFIG_ACPI) += acpiconf.o osconf.o endif diff --exclude *.rej --exclude *.orig --exclude .config -ruN linux-2.4.20/drivers/acpi/toshiba_acpi.c linux-2.4.20-patched/drivers/acpi/toshiba_acpi.c --- linux-2.4.20/drivers/acpi/toshiba_acpi.c Thu Jan 1 09:00:00 1970 +++ linux-2.4.20-patched/drivers/acpi/toshiba_acpi.c Mon Dec 30 18:21:18 2002 @@ -0,0 +1,570 @@ +/* + * toshiba_acpi.c - Toshiba Laptop ACPI Extras + * + * + * Copyright (C) 2002 John Belmonte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * The devolpment page for this driver is located at + * http://memebeam.org/toys/ToshibaAcpiDriver. + * + * Credits: + * Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse + * engineering the Windows drivers + * Yasushi Nagato - changes for linux kernel 2.4 -> 2.5 + * Rob Miller - TV out and hotkeys help + * + * + * TODO + * + */ + +#define TOSHIBA_ACPI_VERSION "0.13" +#define PROC_INTERFACE_VERSION 1 + +#include +#include +#include +#include +#include +#include + +#include +#define OLD_ACPI_INTERFACE (ACPI_CA_VERSION < 0x20020000) + +#if OLD_ACPI_INTERFACE +#include +extern struct proc_dir_entry* bm_proc_root; +#define acpi_root_dir bm_proc_root +#else +#include "acpi_drivers.h" +#endif + +MODULE_AUTHOR("John Belmonte"); +MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver"); +MODULE_LICENSE("GPL"); + +/* Toshiba ACPI method paths */ +#define METHOD_LCD_BRIGHTNESS "\\_SB_.PCI0.VGA_.LCD_._BCM" +#define METHOD_HCI "\\_SB_.VALD.GHCI" +#define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX" + +/* Toshiba HCI interface definitions + * + * HCI is Toshiba's "Hardware Control Interface" which is supposed to + * be uniform across all their models. Ideally we would just call + * dedicated ACPI methods instead of using this primitive interface. + * However the ACPI methods seem to be incomplete in some areas (for + * example they allow setting, but not reading, the LCD brightness value), + * so this is still useful. + */ + +#define HCI_WORDS 6 + +/* operations */ +#define HCI_SET 0xff00 +#define HCI_GET 0xfe00 + +/* return codes */ +#define HCI_SUCCESS 0x0000 +#define HCI_FAILURE 0x1000 +#define HCI_NOT_SUPPORTED 0x8000 +#define HCI_EMPTY 0x8c00 + +/* registers */ +#define HCI_FAN 0x0004 +#define HCI_SYSTEM_EVENT 0x0016 +#define HCI_VIDEO_OUT 0x001c +#define HCI_HOTKEY_EVENT 0x001e +#define HCI_LCD_BRIGHTNESS 0x002a + +/* field definitions */ +#define HCI_LCD_BRIGHTNESS_BITS 3 +#define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS) +#define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS) +#define HCI_VIDEO_OUT_LCD 0x1 +#define HCI_VIDEO_OUT_CRT 0x2 +#define HCI_VIDEO_OUT_TV 0x4 + +/* utility + */ + +static __inline__ void +_set_bit(u32* word, u32 mask, int value) +{ + *word = (*word & ~mask) | (mask * value); +} + +/* an sscanf that takes explicit string length */ +static int +snscanf(const char* str, int n, const char* format, ...) +{ + va_list args; + int result; + char* str2 = kmalloc(n + 1, GFP_KERNEL); + if (str2 == 0) return 0; + strncpy(str2, str, n); + str2[n] = 0; + va_start(args, format); + result = vsscanf(str2, format, args); + va_end(args); + kfree(str2); + return result; +} + +/* This is the common code at the end of every proc read handler. I don't + * understand it yet. + */ +static int +end_proc_read(const char* p, char* page, off_t off, int count, + char** start, int* eof) +{ + int len = (p - page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +/* acpi interface wrappers + */ + +static int +write_acpi_int(const char* methodName, int val) +{ + acpi_object_list params; + acpi_object in_objs[1]; + acpi_status status; + + params.count = sizeof(in_objs)/sizeof(in_objs[0]); + params.pointer = in_objs; + in_objs[0].type = ACPI_TYPE_INTEGER; + in_objs[0].integer.value = val; + + status = acpi_evaluate_object(0, (char*)methodName, ¶ms, 0); + return (status == AE_OK); +} + +#if 0 +static int +read_acpi_int(const char* methodName, int* pVal) +{ + acpi_buffer results; + acpi_object out_objs[1]; + acpi_status status; + + results.length = sizeof(out_objs); + results.pointer = out_objs; + + status = acpi_evaluate_object(0, (char*)methodName, 0, &results); + *pVal = out_objs[0].integer.value; + + return (status == AE_OK) && (out_objs[0].type == ACPI_TYPE_INTEGER); +} +#endif + +/* Perform a raw HCI call. Here we don't care about input or output buffer + * format. + */ +static acpi_status +hci_raw(const u32 in[HCI_WORDS], u32 out[HCI_WORDS]) +{ + acpi_object_list params; + acpi_object in_objs[HCI_WORDS]; + acpi_buffer results; + acpi_object out_objs[HCI_WORDS+1]; + acpi_status status; + int i; + + params.count = HCI_WORDS; + params.pointer = in_objs; + for (i = 0; i < HCI_WORDS; ++i) { + in_objs[i].type = ACPI_TYPE_INTEGER; + in_objs[i].integer.value = in[i]; + /*printk("%04x ", in[i]);*/ + } + /*printk("\n");*/ + + results.length = sizeof(out_objs); + results.pointer = out_objs; + + status = acpi_evaluate_object(0, METHOD_HCI, ¶ms, + &results); + if ((status == AE_OK) && (out_objs->package.count <= HCI_WORDS)) { + for (i = 0; i < out_objs->package.count; ++i) { + out[i] = out_objs->package.elements[i].integer.value; + /*printk("%04x ", out[i]);*/ + } + /*printk("\n");*/ + } + + return status; +} + +/* common hci tasks (get or set one value) + * + * In addition to the ACPI status, the HCI system returns a result which + * may be useful (such as "not supported"). + */ + +static acpi_status +hci_write1(u32 reg, u32 in1, u32* result) +{ + u32 in[HCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 }; + u32 out[HCI_WORDS]; + acpi_status status = hci_raw(in, out); + *result = (status == AE_OK) ? out[0] : HCI_FAILURE; + return status; +} + +static acpi_status +hci_read1(u32 reg, u32* out1, u32* result) +{ + u32 in[HCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 }; + u32 out[HCI_WORDS]; + acpi_status status = hci_raw(in, out); + *out1 = out[2]; + *result = (status == AE_OK) ? out[0] : HCI_FAILURE; + return status; +} + +#define PROC_TOSHIBA "toshiba" +#define PROC_LCD "lcd" +#define PROC_VIDEO "video" +#define PROC_FAN "fan" +#define PROC_KEYS "keys" +#define PROC_VERSION "version" + +static struct proc_dir_entry* toshiba_proc_dir = NULL; +static int force_fan; +static int last_key_event; +static int key_event_valid; + +/* proc file handlers + */ + +static int +proc_read_lcd(char* page, char** start, off_t off, int count, int* eof, + void* context) +{ + char* p = page; + u32 hci_result; + u32 value; + + if (off != 0) goto end; + + hci_read1(HCI_LCD_BRIGHTNESS, &value, &hci_result); + if (hci_result == HCI_SUCCESS) { + value = value >> HCI_LCD_BRIGHTNESS_SHIFT; + p += sprintf(p, "brightness: %d\n", value); + p += sprintf(p, "brightness_levels: %d\n", + HCI_LCD_BRIGHTNESS_LEVELS); + } else { + p += sprintf(p, "ERROR\n"); + goto end; + } + +end: + return end_proc_read(p, page, off, count, start, eof); +} + +static int +proc_write_lcd(struct file* file, const char* buffer, unsigned long count, + void* data) +{ + int value; + /*int byte_count;*/ + u32 hci_result; + + /* ISSUE: %i doesn't work with hex values as advertised */ + if (snscanf(buffer, count, " brightness : %i", &value) == 1 && + value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS) { + value = value << HCI_LCD_BRIGHTNESS_SHIFT; + hci_write1(HCI_LCD_BRIGHTNESS, value, &hci_result); + if (hci_result != HCI_SUCCESS) + return -EFAULT; + } else { + return -EINVAL; + } + + return count; +} + +static int +proc_read_video(char* page, char** start, off_t off, int count, int* eof, + void* context) +{ + char* p = page; + u32 hci_result; + u32 value; + + if (off != 0) goto end; + + hci_read1(HCI_VIDEO_OUT, &value, &hci_result); + if (hci_result == HCI_SUCCESS) { + int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0; + int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0; + int is_tv = (value & HCI_VIDEO_OUT_TV ) ? 1 : 0; + p += sprintf(p, "lcd_out: %d\n", is_lcd); + p += sprintf(p, "crt_out: %d\n", is_crt); + p += sprintf(p, "tv_out: %d\n", is_tv); + } else { + p += sprintf(p, "ERROR\n"); + goto end; + } + +end: + return end_proc_read(p, page, off, count, start, eof); +} + +static int +proc_write_video(struct file* file, const char* buffer, unsigned long count, + void* data) +{ + int value; + const char* buffer_end = buffer + count; + int lcd_out = -1; + int crt_out = -1; + int tv_out = -1; + u32 hci_result; + int video_out; + + /* scan expression. Multiple expressions may be delimited with ; */ + do { + if (snscanf(buffer, count, " lcd_out : %i", &value) == 1) + lcd_out = value & 1; + else if (snscanf(buffer, count, " crt_out : %i", &value) == 1) + crt_out = value & 1; + else if (snscanf(buffer, count, " tv_out : %i", &value) == 1) + tv_out = value & 1; + /* advance to one character past the next ; */ + do ++buffer; + while ((buffer < buffer_end) && (*(buffer-1) != ';')); + } while (buffer < buffer_end); + + hci_read1(HCI_VIDEO_OUT, &video_out, &hci_result); + if (hci_result == HCI_SUCCESS) { + int new_video_out = video_out; + if (lcd_out != -1) + _set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out); + if (crt_out != -1) + _set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out); + if (tv_out != -1) + _set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out); + /* To avoid unnecessary video disruption, only write the new + * video setting if something changed. */ + if (new_video_out != video_out) + write_acpi_int(METHOD_VIDEO_OUT, new_video_out); + } + + return count; +} + +static int +proc_read_fan(char* page, char** start, off_t off, int count, int* eof, + void* context) +{ + char* p = page; + u32 hci_result; + u32 value; + + if (off != 0) goto end; + + hci_read1(HCI_FAN, &value, &hci_result); + if (hci_result == HCI_SUCCESS) { + p += sprintf(p, "running: %d\n", (value > 0)); + p += sprintf(p, "force_on: %d\n", force_fan); + } else { + p += sprintf(p, "ERROR\n"); + goto end; + } + +end: + return end_proc_read(p, page, off, count, start, eof); +} + +static int +proc_write_fan(struct file* file, const char* buffer, unsigned long count, + void* data) +{ + int value; + u32 hci_result; + + if (snscanf(buffer, count, " force_on : %i", &value) == 1 && + value >= 0 && value <= 1) { + hci_write1(HCI_FAN, value, &hci_result); + if (hci_result != HCI_SUCCESS) + return -EFAULT; + else + force_fan = value; + } else { + return -EINVAL; + } + + return count; +} + +static int +proc_read_keys(char* page, char** start, off_t off, int count, int* eof, + void* context) +{ + char* p = page; + u32 hci_result; + u32 value; + + if (off != 0) goto end; + + if (!key_event_valid) { + hci_read1(HCI_SYSTEM_EVENT, &value, &hci_result); + if (hci_result == HCI_SUCCESS) { + key_event_valid = 1; + last_key_event = value; + } else if (hci_result == HCI_EMPTY) { + /* better luck next time */ + } else { + p += sprintf(p, "ERROR\n"); + goto end; + } + } + + p += sprintf(p, "hotkey_ready: %d\n", key_event_valid); + p += sprintf(p, "hotkey: 0x%04x\n", last_key_event); + +end: + return end_proc_read(p, page, off, count, start, eof); +} + +static int +proc_write_keys(struct file* file, const char* buffer, unsigned long count, + void* data) +{ + int value; + + if (snscanf(buffer, count, " hotkey_ready : %i", &value) == 1 && + value == 0) { + key_event_valid = 0; + } else { + return -EINVAL; + } + + return count; +} + +static int +proc_read_version(char* page, char** start, off_t off, int count, int* eof, + void* context) +{ + char* p = page; + + if (off != 0) goto end; + + p += sprintf(p, "driver: %s\n", TOSHIBA_ACPI_VERSION); + p += sprintf(p, "proc_interface: %d\n", + PROC_INTERFACE_VERSION); + +end: + return end_proc_read(p, page, off, count, start, eof); +} + +/* proc and module init + */ + +static acpi_status +add_device(void) +{ + struct proc_dir_entry* proc; + + proc = create_proc_read_entry(PROC_LCD, S_IFREG | S_IRUGO | S_IWUSR, + toshiba_proc_dir, proc_read_lcd, 0); + if (proc) proc->write_proc = proc_write_lcd; + + proc = create_proc_read_entry(PROC_VIDEO, S_IFREG | S_IRUGO | S_IWUSR, + toshiba_proc_dir, proc_read_video, 0); + if (proc) proc->write_proc = proc_write_video; + + proc = create_proc_read_entry(PROC_FAN, S_IFREG | S_IRUGO | S_IWUSR, + toshiba_proc_dir, proc_read_fan, 0); + if (proc) proc->write_proc = proc_write_fan; + + proc = create_proc_read_entry(PROC_KEYS, S_IFREG | S_IRUGO | S_IWUSR, + toshiba_proc_dir, proc_read_keys, 0); + if (proc) proc->write_proc = proc_write_keys; + + proc = create_proc_read_entry(PROC_VERSION, S_IFREG | S_IRUGO | S_IWUSR, + toshiba_proc_dir, proc_read_version, 0); + + return(AE_OK); +} + +static acpi_status +remove_device(void) +{ + remove_proc_entry(PROC_LCD, toshiba_proc_dir); + remove_proc_entry(PROC_VIDEO, toshiba_proc_dir); + remove_proc_entry(PROC_FAN, toshiba_proc_dir); + remove_proc_entry(PROC_KEYS, toshiba_proc_dir); + remove_proc_entry(PROC_VERSION, toshiba_proc_dir); + return(AE_OK); +} + +static int __init +toshiba_acpi_init(void) +{ + acpi_status status = AE_OK; + int value; + u32 hci_result; + + /* simple device detection: try reading an HCI register */ + hci_read1(HCI_LCD_BRIGHTNESS, &value, &hci_result); + if (hci_result != HCI_SUCCESS) + return -ENODEV; + + printk("Toshiba Laptop ACPI Extras version %s\n", TOSHIBA_ACPI_VERSION); + + force_fan = 0; + key_event_valid = 0; + + /* enable event fifo */ + hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result); + + toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir); + if (!toshiba_proc_dir) { + status = AE_ERROR; + } else { + status = add_device(); + if (ACPI_FAILURE(status)) + remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); + } + + return (ACPI_SUCCESS(status)) ? 0 : -ENODEV; +} + +static void __exit +toshiba_acpi_exit(void) +{ + remove_device(); + + if (toshiba_proc_dir) + remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); + + return; +} + +module_init(toshiba_acpi_init); +module_exit(toshiba_acpi_exit); diff --exclude *.rej --exclude *.orig --exclude .config -ruN linux-2.4.20/drivers/pci/pci.c linux-2.4.20-patched/drivers/pci/pci.c --- linux-2.4.20/drivers/pci/pci.c Fri Nov 29 08:53:14 2002 +++ linux-2.4.20-patched/drivers/pci/pci.c Mon Dec 30 18:25:47 2002 @@ -2079,6 +2079,29 @@ } +/* patched locally -- dancerj 30 dec 2001 -- for kernel sound */ + +static void __init pci_m5451_init(void) +{ + struct pci_dev *dev; + + /* Allocate IRQ is 4 */ + unsigned char m5451_irq = 4; + + /* for (dev = pci_devices; dev; dev = dev->next) { */ + pci_for_each_dev(dev) { + if (dev->vendor == PCI_VENDOR_ID_AL && + dev->device == PCI_DEVICE_ID_AL_M5451) { + dev->irq = m5451_irq; + printk("PCI m5451_init: Found ALi AUDIO M5451 \n"); + printk("PCI m5451_init: Allocate IRQ %0x \n", m5451_irq); + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, m5451_irq); + } + } +} + + + void __devinit pci_init(void) { struct pci_dev *dev; @@ -2092,6 +2115,9 @@ #ifdef CONFIG_PM pm_register(PM_PCI_DEV, 0, pci_pm_callback); #endif + + /* ali patch -- dancerj --30 dec 2001 */ + pci_m5451_init(); } static int __devinit pci_setup(char *str)