Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

toshiba_acpi: Add /dev/toshiba_acpi device

There were previous attempts to "merge" the toshiba SMM module to the
toshiba_acpi one, they were trying to imitate what the old toshiba
module does, however, some models (TOS1900 devices) come with a
"crippled" implementation and do not provide all the "features" a
"genuine" Toshiba BIOS does.

This patch adds a new device called toshiba_acpi, which aim is to
enable userspace to access the SMM on Toshiba laptops via ACPI calls.

Creating a new convenience _IOWR command to access the SCI functions
by opening/closing the SCI internally to avoid buggy BIOS, while at
the same time providing backwards compatibility.

Older programs (and new) who wish to access the SMM on newer models
can do it by pointing their path to /dev/toshiba_acpi (instead of
/dev/toshiba) as the toshiba.h header was modified to reflect these
changes as well as adds all the toshiba_acpi paths and command,
however, it is strongly recommended to use the new IOCTL for any
SCI command to avoid any buggy BIOS.

Signed-off-by: Azael Avalos <coproscefalo@gmail.com>
Signed-off-by: Darren Hart <dvhart@linux.intel.com>

authored by

Azael Avalos and committed by
Darren Hart
fc5462f8 7deef550

+121 -4
+1 -1
Documentation/ioctl/ioctl-number.txt
··· 263 263 's' all linux/cdk.h 264 264 't' 00-7F linux/ppp-ioctl.h 265 265 't' 80-8F linux/isdn_ppp.h 266 - 't' 90 linux/toshiba.h 266 + 't' 90-91 linux/toshiba.h toshiba and toshiba_acpi SMM 267 267 'u' 00-1F linux/smb_fs.h gone 268 268 'u' 20-3F linux/uvcvideo.h USB video class host driver 269 269 'v' 00-1F linux/ext2_fs.h conflict!
+91
drivers/platform/x86/toshiba_acpi.c
··· 50 50 #include <linux/acpi.h> 51 51 #include <linux/dmi.h> 52 52 #include <linux/uaccess.h> 53 + #include <linux/miscdevice.h> 54 + #include <linux/toshiba.h> 53 55 #include <acpi/video.h> 54 56 55 57 MODULE_AUTHOR("John Belmonte"); ··· 172 170 struct led_classdev led_dev; 173 171 struct led_classdev kbd_led; 174 172 struct led_classdev eco_led; 173 + struct miscdevice miscdev; 175 174 176 175 int force_fan; 177 176 int last_key_event; ··· 2243 2240 }; 2244 2241 2245 2242 /* 2243 + * Misc device 2244 + */ 2245 + static int toshiba_acpi_smm_bridge(SMMRegisters *regs) 2246 + { 2247 + u32 in[TCI_WORDS] = { regs->eax, regs->ebx, regs->ecx, 2248 + regs->edx, regs->esi, regs->edi }; 2249 + u32 out[TCI_WORDS]; 2250 + acpi_status status; 2251 + 2252 + status = tci_raw(toshiba_acpi, in, out); 2253 + if (ACPI_FAILURE(status)) { 2254 + pr_err("ACPI call to query SMM registers failed\n"); 2255 + return -EIO; 2256 + } 2257 + 2258 + /* Fillout the SMM struct with the TCI call results */ 2259 + regs->eax = out[0]; 2260 + regs->ebx = out[1]; 2261 + regs->ecx = out[2]; 2262 + regs->edx = out[3]; 2263 + regs->esi = out[4]; 2264 + regs->edi = out[5]; 2265 + 2266 + return 0; 2267 + } 2268 + 2269 + static long toshiba_acpi_ioctl(struct file *fp, unsigned int cmd, 2270 + unsigned long arg) 2271 + { 2272 + SMMRegisters __user *argp = (SMMRegisters __user *)arg; 2273 + SMMRegisters regs; 2274 + int ret; 2275 + 2276 + if (!argp) 2277 + return -EINVAL; 2278 + 2279 + switch (cmd) { 2280 + case TOSH_SMM: 2281 + if (copy_from_user(&regs, argp, sizeof(SMMRegisters))) 2282 + return -EFAULT; 2283 + ret = toshiba_acpi_smm_bridge(&regs); 2284 + if (ret) 2285 + return ret; 2286 + if (copy_to_user(argp, &regs, sizeof(SMMRegisters))) 2287 + return -EFAULT; 2288 + break; 2289 + case TOSHIBA_ACPI_SCI: 2290 + if (copy_from_user(&regs, argp, sizeof(SMMRegisters))) 2291 + return -EFAULT; 2292 + /* Ensure we are being called with a SCI_{GET, SET} register */ 2293 + if (regs.eax != SCI_GET && regs.eax != SCI_SET) 2294 + return -EINVAL; 2295 + if (!sci_open(toshiba_acpi)) 2296 + return -EIO; 2297 + ret = toshiba_acpi_smm_bridge(&regs); 2298 + sci_close(toshiba_acpi); 2299 + if (ret) 2300 + return ret; 2301 + if (copy_to_user(argp, &regs, sizeof(SMMRegisters))) 2302 + return -EFAULT; 2303 + break; 2304 + default: 2305 + return -EINVAL; 2306 + } 2307 + 2308 + return 0; 2309 + } 2310 + 2311 + static const struct file_operations toshiba_acpi_fops = { 2312 + .owner = THIS_MODULE, 2313 + .unlocked_ioctl = toshiba_acpi_ioctl, 2314 + .llseek = noop_llseek, 2315 + }; 2316 + 2317 + /* 2246 2318 * Hotkeys 2247 2319 */ 2248 2320 static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev) ··· 2618 2540 { 2619 2541 struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 2620 2542 2543 + misc_deregister(&dev->miscdev); 2544 + 2621 2545 remove_toshiba_proc_entries(dev); 2622 2546 2623 2547 if (dev->sysfs_created) ··· 2691 2611 return -ENOMEM; 2692 2612 dev->acpi_dev = acpi_dev; 2693 2613 dev->method_hci = hci_method; 2614 + dev->miscdev.minor = MISC_DYNAMIC_MINOR; 2615 + dev->miscdev.name = "toshiba_acpi"; 2616 + dev->miscdev.fops = &toshiba_acpi_fops; 2617 + 2618 + ret = misc_register(&dev->miscdev); 2619 + if (ret) { 2620 + pr_err("Failed to register miscdevice\n"); 2621 + kfree(dev); 2622 + return ret; 2623 + } 2624 + 2694 2625 acpi_dev->driver_data = dev; 2695 2626 dev_set_drvdata(&acpi_dev->dev, dev); 2696 2627
+29 -3
include/uapi/linux/toshiba.h
··· 1 1 /* toshiba.h -- Linux driver for accessing the SMM on Toshiba laptops 2 2 * 3 3 * Copyright (c) 1996-2000 Jonathan A. Buzzard (jonathan@buzzard.org.uk) 4 + * Copyright (c) 2015 Azael Avalos <coproscefalo@gmail.com> 4 5 * 5 6 * Thanks to Juergen Heinzl <juergen@monocerus.demon.co.uk> for the pointers 6 7 * on making sure the structure is aligned and packed. ··· 21 20 #ifndef _UAPI_LINUX_TOSHIBA_H 22 21 #define _UAPI_LINUX_TOSHIBA_H 23 22 24 - #define TOSH_PROC "/proc/toshiba" 25 - #define TOSH_DEVICE "/dev/toshiba" 26 - #define TOSH_SMM _IOWR('t', 0x90, int) /* broken: meant 24 bytes */ 23 + /* 24 + * Toshiba modules paths 25 + */ 26 + 27 + #define TOSH_PROC "/proc/toshiba" 28 + #define TOSH_DEVICE "/dev/toshiba" 29 + #define TOSHIBA_ACPI_PROC "/proc/acpi/toshiba" 30 + #define TOSHIBA_ACPI_DEVICE "/dev/toshiba_acpi" 31 + 32 + /* 33 + * Toshiba SMM structure 34 + */ 27 35 28 36 typedef struct { 29 37 unsigned int eax; ··· 42 32 unsigned int esi __attribute__ ((packed)); 43 33 unsigned int edi __attribute__ ((packed)); 44 34 } SMMRegisters; 35 + 36 + /* 37 + * IOCTLs (0x90 - 0x91) 38 + */ 39 + 40 + #define TOSH_SMM _IOWR('t', 0x90, SMMRegisters) 41 + /* 42 + * Convenience toshiba_acpi command. 43 + * 44 + * The System Configuration Interface (SCI) is opened/closed internally 45 + * to avoid userspace of buggy BIOSes. 46 + * 47 + * The toshiba_acpi module checks whether the eax register is set with 48 + * SCI_GET (0xf300) or SCI_SET (0xf400), returning -EINVAL if not. 49 + */ 50 + #define TOSHIBA_ACPI_SCI _IOWR('t', 0x91, SMMRegisters) 45 51 46 52 47 53 #endif /* _UAPI_LINUX_TOSHIBA_H */