*** ./drivers/platform/x86/toshiba_acpi.c.orig Tue Jun 29 21:54:43 2010 --- ./drivers/platform/x86/toshiba_acpi.c Tue Jun 29 21:54:11 2010 *************** *** 29,40 **** * Yasushi Nagato - changes for linux kernel 2.4 -> 2.5 * Rob Miller - TV out and hotkeys help * * * TODO * */ ! #define TOSHIBA_ACPI_VERSION "0.19" #define PROC_INTERFACE_VERSION 1 #include --- 29,55 ---- * Yasushi Nagato - changes for linux kernel 2.4 -> 2.5 * Rob Miller - TV out and hotkeys help * + * PLEASE NOTE + * + * This is an experimental version of toshiba_acpi which includes emulation + * of the original toshiba driver's /proc/toshiba and /dev/toshiba, + * allowing Toshiba userspace utilities to work. The relevant code was + * based on toshiba.c (copyright 1996-2001 Jonathan A. Buzzard) and + * incorporated into this driver with help from Gintautas Miliauskas, + * Charles Schwieters, and Christoph Burger-Scheidlin. + * + * Caveats: + * * hotkey status in /proc/toshiba is not implemented + * * to make accesses to /dev/toshiba load this driver instead of + * the original driver, you will have to modify your module + * auto-loading configuration * * TODO * */ ! #define TOSHIBA_ACPI_VERSION "experimental-dev-toshiba-test-5" ! /*#define TOSHIBA_ACPI_VERSION "0.19"*/ #define PROC_INTERFACE_VERSION 1 #include *************** *** 43,48 **** --- 58,66 ---- #include #include #include + #include + #include + #include #include #include #include *************** *** 715,720 **** --- 733,923 ---- .release = single_release, }; + /* /dev/toshiba and /proc/toshiba handlers {{{ + * + * ISSUE: lots of magic numbers and mysterious code + */ + + #define TOSH_MINOR_DEV 181 + #define OLD_PROC_TOSHIBA "toshiba" + + static int + tosh_acpi_bridge(SMMRegisters* regs) + { + acpi_status status; + + /* assert(sizeof(SMMRegisters) == sizeof(u32)*HCI_WORDS); */ + status = hci_raw((u32*)regs, (u32*)regs); + if (status == AE_OK && (regs->eax & 0xff00) == HCI_SUCCESS) + return 0; + + return -EINVAL; + } + + static int + tosh_ioctl(struct inode* ip, struct file* fp, unsigned int cmd, + unsigned long arg) + { + SMMRegisters regs; + unsigned short ax,bx; + int err; + + if ((!arg) || (cmd != TOSH_SMM)) + return -EINVAL; + + if (copy_from_user(®s, (SMMRegisters*)arg, sizeof(SMMRegisters))) + return -EFAULT; + + ax = regs.eax & 0xff00; + bx = regs.ebx & 0xffff; + + /* block HCI calls to read/write memory & PCI devices */ + if (((ax==HCI_SET) || (ax==HCI_GET)) && (bx>0x0069)) + return -EINVAL; + + err = tosh_acpi_bridge(®s); + + if (copy_to_user((SMMRegisters*)arg, ®s, sizeof(SMMRegisters))) + return -EFAULT; + + return err; + } + + static int + tosh_get_machine_id(void __iomem *bios) + { + int id; + unsigned short bx,cx; + unsigned long address; + + id = (0x100*(int) readb(bios+0xfffe))+((int) readb(bios+0xfffa)); + + /* do we have a SCTTable machine identication number on our hands */ + if (id==0xfc2f) { + bx = 0xe6f5; /* cheat */ + /* now twiddle with our pointer a bit */ + address = 0x00000000 + bx; + cx = readw(bios + address); + address = 0x00000009 + bx + cx; + cx = readw(bios + address); + address = 0x0000000a + cx; + cx = readw(bios + address); + /* now construct our machine identification number */ + id = ((cx & 0xff)<<8)+((cx & 0xff00)>>8); + } + + return id; + } + + static int tosh_id; + static int tosh_bios; + static int tosh_date; + static int tosh_sci; + + static struct file_operations tosh_fops = { + .owner = THIS_MODULE, + .ioctl = tosh_ioctl + }; + + static struct miscdevice tosh_device = { + TOSH_MINOR_DEV, + "toshiba", + &tosh_fops + }; + + static void + setup_tosh_info(void __iomem *bios) + { + int major, minor; + int day, month, year; + + tosh_id = tosh_get_machine_id(bios); + + /* get the BIOS version */ + major = readb(bios + 0xe009)-'0'; + minor = ((readb(bios + 0xe00b)-'0')*10)+(readb(bios + 0xe00c)-'0'); + tosh_bios = (major*0x100)+minor; + + /* get the BIOS date */ + day = ((readb(bios + 0xfff5)-'0')*10)+(readb(bios + 0xfff6)-'0'); + month = ((readb(bios + 0xfff8)-'0')*10)+(readb(bios + 0xfff9)-'0'); + year = ((readb(bios + 0xfffb)-'0')*10)+(readb(bios + 0xfffc)-'0'); + tosh_date = (((year-90) & 0x1f)<<10) | ((month & 0xf)<<6) + | ((day & 0x1f)<<1); + } + + /* /proc/toshiba read handler */ + static int + tosh_proc_show(struct seq_file *m, void *v) + { + /* TODO: tosh_fn_status() */ + int key = 0; + + /* Format: + * 0) Linux driver version (this will change if format changes) + * 1) Machine ID + * 2) SCI version + * 3) BIOS version (major, minor) + * 4) BIOS date (in SCI date format) + * 5) Fn Key status + */ + + seq_printf(m, "1.1 0x%04x %d.%d %d.%d 0x%04x 0x%02x\n", + tosh_id, + (tosh_sci & 0xff00)>>8, + tosh_sci & 0xff, + (tosh_bios & 0xff00)>>8, + tosh_bios & 0xff, + tosh_date, + key); + + return 0; + } + + static int tosh_proc_open(struct inode *inode, struct file *file) + { + return single_open(file, tosh_proc_show, NULL); + } + + static const struct file_operations tosh_proc_fops = { + .owner = THIS_MODULE, + .open = tosh_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + }; + + static int __init + old_driver_emulation_init(void) + { + int status; + void __iomem *bios = ioremap(0xf0000, 0x10000); + if (!bios) + return -ENOMEM; + + if ((status = misc_register(&tosh_device))) { + printk(MY_ERR "failed to register misc device %d (\"%s\")\n", + tosh_device.minor, tosh_device.name); + return status; + } + + setup_tosh_info(bios); + proc_create(OLD_PROC_TOSHIBA, 0, NULL, &tosh_proc_fops); + + iounmap(bios); + + return 0; + } + + static void __exit + old_driver_emulation_exit(void) + { + remove_proc_entry(OLD_PROC_TOSHIBA, NULL); + misc_deregister(&tosh_device); + } + + /* }}} end of /dev/toshiba and /proc/toshiba handlers */ + /* proc and module init */ *************** *** 916,921 **** --- 1119,1126 ---- platform_device_unregister(toshiba_acpi.p_dev); + old_driver_emulation_exit(); + return; } *************** *** 924,929 **** --- 1129,1135 ---- acpi_status status = AE_OK; u32 hci_result; bool bt_present; + int status2; int ret = 0; struct backlight_properties props; *************** *** 958,963 **** --- 1164,1172 ---- return ret; } + if ((status2 = old_driver_emulation_init())) + return status2; + force_fan = 0; key_event_valid = 0;