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

Configure Feed

Select the types of activity you want to include in your feed.

at dc39455e7948ec9bc5f3f2dced5c2f5ac8a8dfd9 354 lines 8.4 kB view raw
1/*-*-linux-c-*-*/ 2 3/* 4 Copyright (C) 2007 Jonathan Woithe <jwoithe@physics.adelaide.edu.au> 5 Based on earlier work: 6 Copyright (C) 2003 Shane Spencer <shane@bogomip.com> 7 Adrian Yee <brewt-fujitsu@brewt.org> 8 9 Templated from msi-laptop.c which is copyright by its respective authors. 10 11 This program is free software; you can redistribute it and/or modify 12 it under the terms of the GNU General Public License as published by 13 the Free Software Foundation; either version 2 of the License, or 14 (at your option) any later version. 15 16 This program is distributed in the hope that it will be useful, but 17 WITHOUT ANY WARRANTY; without even the implied warranty of 18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 General Public License for more details. 20 21 You should have received a copy of the GNU General Public License 22 along with this program; if not, write to the Free Software 23 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 24 02110-1301, USA. 25 */ 26 27/* 28 * fujitsu-laptop.c - Fujitsu laptop support, providing access to additional 29 * features made available on a range of Fujitsu laptops including the 30 * P2xxx/P5xxx/S6xxx/S7xxx series. 31 * 32 * This driver exports a few files in /sys/devices/platform/fujitsu-laptop/; 33 * others may be added at a later date. 34 * 35 * lcd_level - Screen brightness: contains a single integer in the 36 * range 0..7. (rw) 37 * 38 * In addition to these platform device attributes the driver 39 * registers itself in the Linux backlight control subsystem and is 40 * available to userspace under /sys/class/backlight/fujitsu-laptop/. 41 * 42 * This driver has been tested on a Fujitsu Lifebook S7020. It should 43 * work on most P-series and S-series Lifebooks, but YMMV. 44 */ 45 46#include <linux/module.h> 47#include <linux/kernel.h> 48#include <linux/init.h> 49#include <linux/acpi.h> 50#include <linux/dmi.h> 51#include <linux/backlight.h> 52#include <linux/platform_device.h> 53 54#define FUJITSU_DRIVER_VERSION "0.3" 55 56#define FUJITSU_LCD_N_LEVELS 8 57 58#define ACPI_FUJITSU_CLASS "fujitsu" 59#define ACPI_FUJITSU_HID "FUJ02B1" 60#define ACPI_FUJITSU_DRIVER_NAME "Fujitsu laptop FUJ02B1 ACPI extras driver" 61#define ACPI_FUJITSU_DEVICE_NAME "Fujitsu FUJ02B1" 62 63struct fujitsu_t { 64 acpi_handle acpi_handle; 65 struct backlight_device *bl_device; 66 struct platform_device *pf_device; 67 68 unsigned long fuj02b1_state; 69 unsigned int brightness_changed; 70 unsigned int brightness_level; 71}; 72 73static struct fujitsu_t *fujitsu; 74 75/* Hardware access */ 76 77static int set_lcd_level(int level) 78{ 79 acpi_status status = AE_OK; 80 union acpi_object arg0 = { ACPI_TYPE_INTEGER }; 81 struct acpi_object_list arg_list = { 1, &arg0 }; 82 acpi_handle handle = NULL; 83 84 if (level < 0 || level >= FUJITSU_LCD_N_LEVELS) 85 return -EINVAL; 86 87 if (!fujitsu) 88 return -EINVAL; 89 90 status = acpi_get_handle(fujitsu->acpi_handle, "SBLL", &handle); 91 if (ACPI_FAILURE(status)) { 92 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "SBLL not present\n")); 93 return -ENODEV; 94 } 95 96 arg0.integer.value = level; 97 98 status = acpi_evaluate_object(handle, NULL, &arg_list, NULL); 99 if (ACPI_FAILURE(status)) 100 return -ENODEV; 101 102 return 0; 103} 104 105static int get_lcd_level(void) 106{ 107 unsigned long state = 0; 108 acpi_status status = AE_OK; 109 110 // Get the Brightness 111 status = 112 acpi_evaluate_integer(fujitsu->acpi_handle, "GBLL", NULL, &state); 113 if (status < 0) 114 return status; 115 116 fujitsu->fuj02b1_state = state; 117 fujitsu->brightness_level = state & 0x0fffffff; 118 119 if (state & 0x80000000) 120 fujitsu->brightness_changed = 1; 121 else 122 fujitsu->brightness_changed = 0; 123 124 return fujitsu->brightness_level; 125} 126 127/* Backlight device stuff */ 128 129static int bl_get_brightness(struct backlight_device *b) 130{ 131 return get_lcd_level(); 132} 133 134static int bl_update_status(struct backlight_device *b) 135{ 136 return set_lcd_level(b->props.brightness); 137} 138 139static struct backlight_ops fujitsubl_ops = { 140 .get_brightness = bl_get_brightness, 141 .update_status = bl_update_status, 142}; 143 144/* Platform device */ 145 146static ssize_t show_lcd_level(struct device *dev, 147 struct device_attribute *attr, char *buf) 148{ 149 150 int ret; 151 152 ret = get_lcd_level(); 153 if (ret < 0) 154 return ret; 155 156 return sprintf(buf, "%i\n", ret); 157} 158 159static ssize_t store_lcd_level(struct device *dev, 160 struct device_attribute *attr, const char *buf, 161 size_t count) 162{ 163 164 int level, ret; 165 166 if (sscanf(buf, "%i", &level) != 1 167 || (level < 0 || level >= FUJITSU_LCD_N_LEVELS)) 168 return -EINVAL; 169 170 ret = set_lcd_level(level); 171 if (ret < 0) 172 return ret; 173 174 return count; 175} 176 177static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level); 178 179static struct attribute *fujitsupf_attributes[] = { 180 &dev_attr_lcd_level.attr, 181 NULL 182}; 183 184static struct attribute_group fujitsupf_attribute_group = { 185 .attrs = fujitsupf_attributes 186}; 187 188static struct platform_driver fujitsupf_driver = { 189 .driver = { 190 .name = "fujitsu-laptop", 191 .owner = THIS_MODULE, 192 } 193}; 194 195/* ACPI device */ 196 197static int acpi_fujitsu_add(struct acpi_device *device) 198{ 199 int result = 0; 200 int state = 0; 201 202 ACPI_FUNCTION_TRACE("acpi_fujitsu_add"); 203 204 if (!device) 205 return -EINVAL; 206 207 fujitsu->acpi_handle = device->handle; 208 sprintf(acpi_device_name(device), "%s", ACPI_FUJITSU_DEVICE_NAME); 209 sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS); 210 acpi_driver_data(device) = fujitsu; 211 212 result = acpi_bus_get_power(fujitsu->acpi_handle, &state); 213 if (result) { 214 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 215 "Error reading power state\n")); 216 goto end; 217 } 218 219 printk(KERN_INFO PREFIX "%s [%s] (%s)\n", 220 acpi_device_name(device), acpi_device_bid(device), 221 !device->power.state ? "on" : "off"); 222 223 end: 224 225 return result; 226} 227 228static int acpi_fujitsu_remove(struct acpi_device *device, int type) 229{ 230 ACPI_FUNCTION_TRACE("acpi_fujitsu_remove"); 231 232 if (!device || !acpi_driver_data(device)) 233 return -EINVAL; 234 fujitsu->acpi_handle = 0; 235 236 return 0; 237} 238 239static const struct acpi_device_id fujitsu_device_ids[] = { 240 {ACPI_FUJITSU_HID, 0}, 241 {"", 0}, 242}; 243 244static struct acpi_driver acpi_fujitsu_driver = { 245 .name = ACPI_FUJITSU_DRIVER_NAME, 246 .class = ACPI_FUJITSU_CLASS, 247 .ids = fujitsu_device_ids, 248 .ops = { 249 .add = acpi_fujitsu_add, 250 .remove = acpi_fujitsu_remove, 251 }, 252}; 253 254/* Initialization */ 255 256static int __init fujitsu_init(void) 257{ 258 int ret, result; 259 260 if (acpi_disabled) 261 return -ENODEV; 262 263 fujitsu = kmalloc(sizeof(struct fujitsu_t), GFP_KERNEL); 264 if (!fujitsu) 265 return -ENOMEM; 266 memset(fujitsu, 0, sizeof(struct fujitsu_t)); 267 268 result = acpi_bus_register_driver(&acpi_fujitsu_driver); 269 if (result < 0) { 270 ret = -ENODEV; 271 goto fail_acpi; 272 } 273 274 /* Register backlight stuff */ 275 276 fujitsu->bl_device = 277 backlight_device_register("fujitsu-laptop", NULL, NULL, 278 &fujitsubl_ops); 279 if (IS_ERR(fujitsu->bl_device)) 280 return PTR_ERR(fujitsu->bl_device); 281 282 fujitsu->bl_device->props.max_brightness = FUJITSU_LCD_N_LEVELS - 1; 283 ret = platform_driver_register(&fujitsupf_driver); 284 if (ret) 285 goto fail_backlight; 286 287 /* Register platform stuff */ 288 289 fujitsu->pf_device = platform_device_alloc("fujitsu-laptop", -1); 290 if (!fujitsu->pf_device) { 291 ret = -ENOMEM; 292 goto fail_platform_driver; 293 } 294 295 ret = platform_device_add(fujitsu->pf_device); 296 if (ret) 297 goto fail_platform_device1; 298 299 ret = 300 sysfs_create_group(&fujitsu->pf_device->dev.kobj, 301 &fujitsupf_attribute_group); 302 if (ret) 303 goto fail_platform_device2; 304 305 printk(KERN_INFO "fujitsu-laptop: driver " FUJITSU_DRIVER_VERSION 306 " successfully loaded.\n"); 307 308 return 0; 309 310 fail_platform_device2: 311 312 platform_device_del(fujitsu->pf_device); 313 314 fail_platform_device1: 315 316 platform_device_put(fujitsu->pf_device); 317 318 fail_platform_driver: 319 320 platform_driver_unregister(&fujitsupf_driver); 321 322 fail_backlight: 323 324 backlight_device_unregister(fujitsu->bl_device); 325 326 fail_acpi: 327 328 kfree(fujitsu); 329 330 return ret; 331} 332 333static void __exit fujitsu_cleanup(void) 334{ 335 sysfs_remove_group(&fujitsu->pf_device->dev.kobj, 336 &fujitsupf_attribute_group); 337 platform_device_unregister(fujitsu->pf_device); 338 platform_driver_unregister(&fujitsupf_driver); 339 backlight_device_unregister(fujitsu->bl_device); 340 341 acpi_bus_unregister_driver(&acpi_fujitsu_driver); 342 343 kfree(fujitsu); 344 345 printk(KERN_INFO "fujitsu-laptop: driver unloaded.\n"); 346} 347 348module_init(fujitsu_init); 349module_exit(fujitsu_cleanup); 350 351MODULE_AUTHOR("Jonathan Woithe"); 352MODULE_DESCRIPTION("Fujitsu laptop extras support"); 353MODULE_VERSION(FUJITSU_DRIVER_VERSION); 354MODULE_LICENSE("GPL");