fujitsu-laptop.c 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332
  1. /*-*-linux-c-*-*/
  2. /*
  3. Copyright (C) 2007,2008 Jonathan Woithe <jwoithe@just42.net>
  4. Copyright (C) 2008 Peter Gruber <nokos@gmx.net>
  5. Copyright (C) 2008 Tony Vroon <tony@linx.net>
  6. Based on earlier work:
  7. Copyright (C) 2003 Shane Spencer <shane@bogomip.com>
  8. Adrian Yee <brewt-fujitsu@brewt.org>
  9. Templated from msi-laptop.c and thinkpad_acpi.c which is copyright
  10. by its respective authors.
  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. This program is distributed in the hope that it will be useful, but
  16. WITHOUT ANY WARRANTY; without even the implied warranty of
  17. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18. General Public License for more details.
  19. You should have received a copy of the GNU General Public License
  20. along with this program; if not, write to the Free Software
  21. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  22. 02110-1301, USA.
  23. */
  24. /*
  25. * fujitsu-laptop.c - Fujitsu laptop support, providing access to additional
  26. * features made available on a range of Fujitsu laptops including the
  27. * P2xxx/P5xxx/S6xxx/S7xxx series.
  28. *
  29. * This driver exports a few files in /sys/devices/platform/fujitsu-laptop/;
  30. * others may be added at a later date.
  31. *
  32. * lcd_level - Screen brightness: contains a single integer in the
  33. * range 0..7. (rw)
  34. *
  35. * In addition to these platform device attributes the driver
  36. * registers itself in the Linux backlight control subsystem and is
  37. * available to userspace under /sys/class/backlight/fujitsu-laptop/.
  38. *
  39. * Hotkeys present on certain Fujitsu laptops (eg: the S6xxx series) are
  40. * also supported by this driver.
  41. *
  42. * This driver has been tested on a Fujitsu Lifebook S6410, S7020 and
  43. * P8010. It should work on most P-series and S-series Lifebooks, but
  44. * YMMV.
  45. *
  46. * The module parameter use_alt_lcd_levels switches between different ACPI
  47. * brightness controls which are used by different Fujitsu laptops. In most
  48. * cases the correct method is automatically detected. "use_alt_lcd_levels=1"
  49. * is applicable for a Fujitsu Lifebook S6410 if autodetection fails.
  50. *
  51. */
  52. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  53. #include <linux/module.h>
  54. #include <linux/kernel.h>
  55. #include <linux/init.h>
  56. #include <linux/acpi.h>
  57. #include <linux/dmi.h>
  58. #include <linux/backlight.h>
  59. #include <linux/fb.h>
  60. #include <linux/input.h>
  61. #include <linux/kfifo.h>
  62. #include <linux/platform_device.h>
  63. #include <linux/slab.h>
  64. #if IS_ENABLED(CONFIG_LEDS_CLASS)
  65. #include <linux/leds.h>
  66. #endif
  67. #include <acpi/video.h>
  68. #define FUJITSU_DRIVER_VERSION "0.6.0"
  69. #define FUJITSU_LCD_N_LEVELS 8
  70. #define ACPI_FUJITSU_CLASS "fujitsu"
  71. #define ACPI_FUJITSU_HID "FUJ02B1"
  72. #define ACPI_FUJITSU_DRIVER_NAME "Fujitsu laptop FUJ02B1 ACPI brightness driver"
  73. #define ACPI_FUJITSU_DEVICE_NAME "Fujitsu FUJ02B1"
  74. #define ACPI_FUJITSU_HOTKEY_HID "FUJ02E3"
  75. #define ACPI_FUJITSU_HOTKEY_DRIVER_NAME "Fujitsu laptop FUJ02E3 ACPI hotkeys driver"
  76. #define ACPI_FUJITSU_HOTKEY_DEVICE_NAME "Fujitsu FUJ02E3"
  77. #define ACPI_FUJITSU_NOTIFY_CODE1 0x80
  78. /* FUNC interface - command values */
  79. #define FUNC_RFKILL 0x1000
  80. #define FUNC_LEDS 0x1001
  81. #define FUNC_BUTTONS 0x1002
  82. #define FUNC_BACKLIGHT 0x1004
  83. /* FUNC interface - responses */
  84. #define UNSUPPORTED_CMD 0x80000000
  85. #if IS_ENABLED(CONFIG_LEDS_CLASS)
  86. /* FUNC interface - LED control */
  87. #define FUNC_LED_OFF 0x1
  88. #define FUNC_LED_ON 0x30001
  89. #define KEYBOARD_LAMPS 0x100
  90. #define LOGOLAMP_POWERON 0x2000
  91. #define LOGOLAMP_ALWAYS 0x4000
  92. #define RADIO_LED_ON 0x20
  93. #define ECO_LED 0x10000
  94. #define ECO_LED_ON 0x80000
  95. #endif
  96. /* Hotkey details */
  97. #define KEY1_CODE 0x410 /* codes for the keys in the GIRB register */
  98. #define KEY2_CODE 0x411
  99. #define KEY3_CODE 0x412
  100. #define KEY4_CODE 0x413
  101. #define KEY5_CODE 0x420
  102. #define MAX_HOTKEY_RINGBUFFER_SIZE 100
  103. #define RINGBUFFERSIZE 40
  104. /* Debugging */
  105. #define FUJLAPTOP_DBG_ERROR 0x0001
  106. #define FUJLAPTOP_DBG_WARN 0x0002
  107. #define FUJLAPTOP_DBG_INFO 0x0004
  108. #define FUJLAPTOP_DBG_TRACE 0x0008
  109. #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
  110. #define vdbg_printk(a_dbg_level, format, arg...) \
  111. do { if (dbg_level & a_dbg_level) \
  112. printk(KERN_DEBUG pr_fmt("%s: " format), __func__, ## arg); \
  113. } while (0)
  114. #else
  115. #define vdbg_printk(a_dbg_level, format, arg...) \
  116. do { } while (0)
  117. #endif
  118. /* Device controlling the backlight and associated keys */
  119. struct fujitsu_t {
  120. acpi_handle acpi_handle;
  121. struct acpi_device *dev;
  122. struct input_dev *input;
  123. char phys[32];
  124. struct backlight_device *bl_device;
  125. struct platform_device *pf_device;
  126. int keycode1, keycode2, keycode3, keycode4, keycode5;
  127. unsigned int max_brightness;
  128. unsigned int brightness_changed;
  129. unsigned int brightness_level;
  130. };
  131. static struct fujitsu_t *fujitsu;
  132. static int use_alt_lcd_levels = -1;
  133. static int disable_brightness_adjust = -1;
  134. /* Device used to access other hotkeys on the laptop */
  135. struct fujitsu_hotkey_t {
  136. acpi_handle acpi_handle;
  137. struct acpi_device *dev;
  138. struct input_dev *input;
  139. char phys[32];
  140. struct platform_device *pf_device;
  141. struct kfifo fifo;
  142. spinlock_t fifo_lock;
  143. int rfkill_supported;
  144. int rfkill_state;
  145. int logolamp_registered;
  146. int kblamps_registered;
  147. int radio_led_registered;
  148. int eco_led_registered;
  149. };
  150. static struct fujitsu_hotkey_t *fujitsu_hotkey;
  151. static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event);
  152. #if IS_ENABLED(CONFIG_LEDS_CLASS)
  153. static enum led_brightness logolamp_get(struct led_classdev *cdev);
  154. static int logolamp_set(struct led_classdev *cdev,
  155. enum led_brightness brightness);
  156. static struct led_classdev logolamp_led = {
  157. .name = "fujitsu::logolamp",
  158. .brightness_get = logolamp_get,
  159. .brightness_set_blocking = logolamp_set
  160. };
  161. static enum led_brightness kblamps_get(struct led_classdev *cdev);
  162. static int kblamps_set(struct led_classdev *cdev,
  163. enum led_brightness brightness);
  164. static struct led_classdev kblamps_led = {
  165. .name = "fujitsu::kblamps",
  166. .brightness_get = kblamps_get,
  167. .brightness_set_blocking = kblamps_set
  168. };
  169. static enum led_brightness radio_led_get(struct led_classdev *cdev);
  170. static int radio_led_set(struct led_classdev *cdev,
  171. enum led_brightness brightness);
  172. static struct led_classdev radio_led = {
  173. .name = "fujitsu::radio_led",
  174. .brightness_get = radio_led_get,
  175. .brightness_set_blocking = radio_led_set
  176. };
  177. static enum led_brightness eco_led_get(struct led_classdev *cdev);
  178. static int eco_led_set(struct led_classdev *cdev,
  179. enum led_brightness brightness);
  180. static struct led_classdev eco_led = {
  181. .name = "fujitsu::eco_led",
  182. .brightness_get = eco_led_get,
  183. .brightness_set_blocking = eco_led_set
  184. };
  185. #endif
  186. #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
  187. static u32 dbg_level = 0x03;
  188. #endif
  189. static void acpi_fujitsu_notify(struct acpi_device *device, u32 event);
  190. /* Fujitsu ACPI interface function */
  191. static int call_fext_func(int cmd, int arg0, int arg1, int arg2)
  192. {
  193. acpi_status status = AE_OK;
  194. union acpi_object params[4] = {
  195. { .type = ACPI_TYPE_INTEGER },
  196. { .type = ACPI_TYPE_INTEGER },
  197. { .type = ACPI_TYPE_INTEGER },
  198. { .type = ACPI_TYPE_INTEGER }
  199. };
  200. struct acpi_object_list arg_list = { 4, &params[0] };
  201. unsigned long long value;
  202. acpi_handle handle = NULL;
  203. status = acpi_get_handle(fujitsu_hotkey->acpi_handle, "FUNC", &handle);
  204. if (ACPI_FAILURE(status)) {
  205. vdbg_printk(FUJLAPTOP_DBG_ERROR,
  206. "FUNC interface is not present\n");
  207. return -ENODEV;
  208. }
  209. params[0].integer.value = cmd;
  210. params[1].integer.value = arg0;
  211. params[2].integer.value = arg1;
  212. params[3].integer.value = arg2;
  213. status = acpi_evaluate_integer(handle, NULL, &arg_list, &value);
  214. if (ACPI_FAILURE(status)) {
  215. vdbg_printk(FUJLAPTOP_DBG_WARN,
  216. "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) call failed\n",
  217. cmd, arg0, arg1, arg2);
  218. return -ENODEV;
  219. }
  220. vdbg_printk(FUJLAPTOP_DBG_TRACE,
  221. "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) returned 0x%x\n",
  222. cmd, arg0, arg1, arg2, (int)value);
  223. return value;
  224. }
  225. #if IS_ENABLED(CONFIG_LEDS_CLASS)
  226. /* LED class callbacks */
  227. static int logolamp_set(struct led_classdev *cdev,
  228. enum led_brightness brightness)
  229. {
  230. if (brightness >= LED_FULL) {
  231. call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON);
  232. return call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_ON);
  233. } else if (brightness >= LED_HALF) {
  234. call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON);
  235. return call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_OFF);
  236. } else {
  237. return call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_OFF);
  238. }
  239. }
  240. static int kblamps_set(struct led_classdev *cdev,
  241. enum led_brightness brightness)
  242. {
  243. if (brightness >= LED_FULL)
  244. return call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_ON);
  245. else
  246. return call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_OFF);
  247. }
  248. static int radio_led_set(struct led_classdev *cdev,
  249. enum led_brightness brightness)
  250. {
  251. if (brightness >= LED_FULL)
  252. return call_fext_func(FUNC_RFKILL, 0x5, RADIO_LED_ON, RADIO_LED_ON);
  253. else
  254. return call_fext_func(FUNC_RFKILL, 0x5, RADIO_LED_ON, 0x0);
  255. }
  256. static int eco_led_set(struct led_classdev *cdev,
  257. enum led_brightness brightness)
  258. {
  259. int curr;
  260. curr = call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0);
  261. if (brightness >= LED_FULL)
  262. return call_fext_func(FUNC_LEDS, 0x1, ECO_LED, curr | ECO_LED_ON);
  263. else
  264. return call_fext_func(FUNC_LEDS, 0x1, ECO_LED, curr & ~ECO_LED_ON);
  265. }
  266. static enum led_brightness logolamp_get(struct led_classdev *cdev)
  267. {
  268. enum led_brightness brightness = LED_OFF;
  269. int poweron, always;
  270. poweron = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0);
  271. if (poweron == FUNC_LED_ON) {
  272. brightness = LED_HALF;
  273. always = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0);
  274. if (always == FUNC_LED_ON)
  275. brightness = LED_FULL;
  276. }
  277. return brightness;
  278. }
  279. static enum led_brightness kblamps_get(struct led_classdev *cdev)
  280. {
  281. enum led_brightness brightness = LED_OFF;
  282. if (call_fext_func(FUNC_LEDS, 0x2, KEYBOARD_LAMPS, 0x0) == FUNC_LED_ON)
  283. brightness = LED_FULL;
  284. return brightness;
  285. }
  286. static enum led_brightness radio_led_get(struct led_classdev *cdev)
  287. {
  288. enum led_brightness brightness = LED_OFF;
  289. if (call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0) & RADIO_LED_ON)
  290. brightness = LED_FULL;
  291. return brightness;
  292. }
  293. static enum led_brightness eco_led_get(struct led_classdev *cdev)
  294. {
  295. enum led_brightness brightness = LED_OFF;
  296. if (call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0) & ECO_LED_ON)
  297. brightness = LED_FULL;
  298. return brightness;
  299. }
  300. #endif
  301. /* Hardware access for LCD brightness control */
  302. static int set_lcd_level(int level)
  303. {
  304. acpi_status status = AE_OK;
  305. acpi_handle handle = NULL;
  306. vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via SBLL [%d]\n",
  307. level);
  308. if (level < 0 || level >= fujitsu->max_brightness)
  309. return -EINVAL;
  310. status = acpi_get_handle(fujitsu->acpi_handle, "SBLL", &handle);
  311. if (ACPI_FAILURE(status)) {
  312. vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBLL not present\n");
  313. return -ENODEV;
  314. }
  315. status = acpi_execute_simple_method(handle, NULL, level);
  316. if (ACPI_FAILURE(status))
  317. return -ENODEV;
  318. return 0;
  319. }
  320. static int set_lcd_level_alt(int level)
  321. {
  322. acpi_status status = AE_OK;
  323. acpi_handle handle = NULL;
  324. vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via SBL2 [%d]\n",
  325. level);
  326. if (level < 0 || level >= fujitsu->max_brightness)
  327. return -EINVAL;
  328. status = acpi_get_handle(fujitsu->acpi_handle, "SBL2", &handle);
  329. if (ACPI_FAILURE(status)) {
  330. vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBL2 not present\n");
  331. return -ENODEV;
  332. }
  333. status = acpi_execute_simple_method(handle, NULL, level);
  334. if (ACPI_FAILURE(status))
  335. return -ENODEV;
  336. return 0;
  337. }
  338. static int get_lcd_level(void)
  339. {
  340. unsigned long long state = 0;
  341. acpi_status status = AE_OK;
  342. vdbg_printk(FUJLAPTOP_DBG_TRACE, "get lcd level via GBLL\n");
  343. status =
  344. acpi_evaluate_integer(fujitsu->acpi_handle, "GBLL", NULL, &state);
  345. if (ACPI_FAILURE(status))
  346. return 0;
  347. fujitsu->brightness_level = state & 0x0fffffff;
  348. if (state & 0x80000000)
  349. fujitsu->brightness_changed = 1;
  350. else
  351. fujitsu->brightness_changed = 0;
  352. return fujitsu->brightness_level;
  353. }
  354. static int get_max_brightness(void)
  355. {
  356. unsigned long long state = 0;
  357. acpi_status status = AE_OK;
  358. vdbg_printk(FUJLAPTOP_DBG_TRACE, "get max lcd level via RBLL\n");
  359. status =
  360. acpi_evaluate_integer(fujitsu->acpi_handle, "RBLL", NULL, &state);
  361. if (ACPI_FAILURE(status))
  362. return -1;
  363. fujitsu->max_brightness = state;
  364. return fujitsu->max_brightness;
  365. }
  366. /* Backlight device stuff */
  367. static int bl_get_brightness(struct backlight_device *b)
  368. {
  369. return get_lcd_level();
  370. }
  371. static int bl_update_status(struct backlight_device *b)
  372. {
  373. int ret;
  374. if (b->props.power == FB_BLANK_POWERDOWN)
  375. ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x3);
  376. else
  377. ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x0);
  378. if (ret != 0)
  379. vdbg_printk(FUJLAPTOP_DBG_ERROR,
  380. "Unable to adjust backlight power, error code %i\n",
  381. ret);
  382. if (use_alt_lcd_levels)
  383. ret = set_lcd_level_alt(b->props.brightness);
  384. else
  385. ret = set_lcd_level(b->props.brightness);
  386. if (ret != 0)
  387. vdbg_printk(FUJLAPTOP_DBG_ERROR,
  388. "Unable to adjust LCD brightness, error code %i\n",
  389. ret);
  390. return ret;
  391. }
  392. static const struct backlight_ops fujitsubl_ops = {
  393. .get_brightness = bl_get_brightness,
  394. .update_status = bl_update_status,
  395. };
  396. /* Platform LCD brightness device */
  397. static ssize_t
  398. show_max_brightness(struct device *dev,
  399. struct device_attribute *attr, char *buf)
  400. {
  401. int ret;
  402. ret = get_max_brightness();
  403. if (ret < 0)
  404. return ret;
  405. return sprintf(buf, "%i\n", ret);
  406. }
  407. static ssize_t
  408. show_brightness_changed(struct device *dev,
  409. struct device_attribute *attr, char *buf)
  410. {
  411. int ret;
  412. ret = fujitsu->brightness_changed;
  413. if (ret < 0)
  414. return ret;
  415. return sprintf(buf, "%i\n", ret);
  416. }
  417. static ssize_t show_lcd_level(struct device *dev,
  418. struct device_attribute *attr, char *buf)
  419. {
  420. int ret;
  421. ret = get_lcd_level();
  422. if (ret < 0)
  423. return ret;
  424. return sprintf(buf, "%i\n", ret);
  425. }
  426. static ssize_t store_lcd_level(struct device *dev,
  427. struct device_attribute *attr, const char *buf,
  428. size_t count)
  429. {
  430. int level, ret;
  431. if (sscanf(buf, "%i", &level) != 1
  432. || (level < 0 || level >= fujitsu->max_brightness))
  433. return -EINVAL;
  434. if (use_alt_lcd_levels)
  435. ret = set_lcd_level_alt(level);
  436. else
  437. ret = set_lcd_level(level);
  438. if (ret < 0)
  439. return ret;
  440. ret = get_lcd_level();
  441. if (ret < 0)
  442. return ret;
  443. return count;
  444. }
  445. static ssize_t
  446. ignore_store(struct device *dev,
  447. struct device_attribute *attr, const char *buf, size_t count)
  448. {
  449. return count;
  450. }
  451. static ssize_t
  452. show_lid_state(struct device *dev,
  453. struct device_attribute *attr, char *buf)
  454. {
  455. if (!(fujitsu_hotkey->rfkill_supported & 0x100))
  456. return sprintf(buf, "unknown\n");
  457. if (fujitsu_hotkey->rfkill_state & 0x100)
  458. return sprintf(buf, "open\n");
  459. else
  460. return sprintf(buf, "closed\n");
  461. }
  462. static ssize_t
  463. show_dock_state(struct device *dev,
  464. struct device_attribute *attr, char *buf)
  465. {
  466. if (!(fujitsu_hotkey->rfkill_supported & 0x200))
  467. return sprintf(buf, "unknown\n");
  468. if (fujitsu_hotkey->rfkill_state & 0x200)
  469. return sprintf(buf, "docked\n");
  470. else
  471. return sprintf(buf, "undocked\n");
  472. }
  473. static ssize_t
  474. show_radios_state(struct device *dev,
  475. struct device_attribute *attr, char *buf)
  476. {
  477. if (!(fujitsu_hotkey->rfkill_supported & 0x20))
  478. return sprintf(buf, "unknown\n");
  479. if (fujitsu_hotkey->rfkill_state & 0x20)
  480. return sprintf(buf, "on\n");
  481. else
  482. return sprintf(buf, "killed\n");
  483. }
  484. static DEVICE_ATTR(max_brightness, 0444, show_max_brightness, ignore_store);
  485. static DEVICE_ATTR(brightness_changed, 0444, show_brightness_changed,
  486. ignore_store);
  487. static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level);
  488. static DEVICE_ATTR(lid, 0444, show_lid_state, ignore_store);
  489. static DEVICE_ATTR(dock, 0444, show_dock_state, ignore_store);
  490. static DEVICE_ATTR(radios, 0444, show_radios_state, ignore_store);
  491. static struct attribute *fujitsupf_attributes[] = {
  492. &dev_attr_brightness_changed.attr,
  493. &dev_attr_max_brightness.attr,
  494. &dev_attr_lcd_level.attr,
  495. &dev_attr_lid.attr,
  496. &dev_attr_dock.attr,
  497. &dev_attr_radios.attr,
  498. NULL
  499. };
  500. static struct attribute_group fujitsupf_attribute_group = {
  501. .attrs = fujitsupf_attributes
  502. };
  503. static struct platform_driver fujitsupf_driver = {
  504. .driver = {
  505. .name = "fujitsu-laptop",
  506. }
  507. };
  508. static void __init dmi_check_cb_common(const struct dmi_system_id *id)
  509. {
  510. pr_info("Identified laptop model '%s'\n", id->ident);
  511. if (use_alt_lcd_levels == -1) {
  512. if (acpi_has_method(NULL,
  513. "\\_SB.PCI0.LPCB.FJEX.SBL2"))
  514. use_alt_lcd_levels = 1;
  515. else
  516. use_alt_lcd_levels = 0;
  517. vdbg_printk(FUJLAPTOP_DBG_TRACE, "auto-detected usealt as "
  518. "%i\n", use_alt_lcd_levels);
  519. }
  520. }
  521. static int __init dmi_check_cb_s6410(const struct dmi_system_id *id)
  522. {
  523. dmi_check_cb_common(id);
  524. fujitsu->keycode1 = KEY_SCREENLOCK; /* "Lock" */
  525. fujitsu->keycode2 = KEY_HELP; /* "Mobility Center" */
  526. return 1;
  527. }
  528. static int __init dmi_check_cb_s6420(const struct dmi_system_id *id)
  529. {
  530. dmi_check_cb_common(id);
  531. fujitsu->keycode1 = KEY_SCREENLOCK; /* "Lock" */
  532. fujitsu->keycode2 = KEY_HELP; /* "Mobility Center" */
  533. return 1;
  534. }
  535. static int __init dmi_check_cb_p8010(const struct dmi_system_id *id)
  536. {
  537. dmi_check_cb_common(id);
  538. fujitsu->keycode1 = KEY_HELP; /* "Support" */
  539. fujitsu->keycode3 = KEY_SWITCHVIDEOMODE; /* "Presentation" */
  540. fujitsu->keycode4 = KEY_WWW; /* "Internet" */
  541. return 1;
  542. }
  543. static const struct dmi_system_id fujitsu_dmi_table[] __initconst = {
  544. {
  545. .ident = "Fujitsu Siemens S6410",
  546. .matches = {
  547. DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
  548. DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6410"),
  549. },
  550. .callback = dmi_check_cb_s6410},
  551. {
  552. .ident = "Fujitsu Siemens S6420",
  553. .matches = {
  554. DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
  555. DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6420"),
  556. },
  557. .callback = dmi_check_cb_s6420},
  558. {
  559. .ident = "Fujitsu LifeBook P8010",
  560. .matches = {
  561. DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
  562. DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P8010"),
  563. },
  564. .callback = dmi_check_cb_p8010},
  565. {}
  566. };
  567. /* ACPI device for LCD brightness control */
  568. static int acpi_fujitsu_add(struct acpi_device *device)
  569. {
  570. int state = 0;
  571. struct input_dev *input;
  572. int error;
  573. if (!device)
  574. return -EINVAL;
  575. fujitsu->acpi_handle = device->handle;
  576. sprintf(acpi_device_name(device), "%s", ACPI_FUJITSU_DEVICE_NAME);
  577. sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS);
  578. device->driver_data = fujitsu;
  579. fujitsu->input = input = input_allocate_device();
  580. if (!input) {
  581. error = -ENOMEM;
  582. goto err_stop;
  583. }
  584. snprintf(fujitsu->phys, sizeof(fujitsu->phys),
  585. "%s/video/input0", acpi_device_hid(device));
  586. input->name = acpi_device_name(device);
  587. input->phys = fujitsu->phys;
  588. input->id.bustype = BUS_HOST;
  589. input->id.product = 0x06;
  590. input->dev.parent = &device->dev;
  591. input->evbit[0] = BIT(EV_KEY);
  592. set_bit(KEY_BRIGHTNESSUP, input->keybit);
  593. set_bit(KEY_BRIGHTNESSDOWN, input->keybit);
  594. set_bit(KEY_UNKNOWN, input->keybit);
  595. error = input_register_device(input);
  596. if (error)
  597. goto err_free_input_dev;
  598. error = acpi_bus_update_power(fujitsu->acpi_handle, &state);
  599. if (error) {
  600. pr_err("Error reading power state\n");
  601. goto err_unregister_input_dev;
  602. }
  603. pr_info("ACPI: %s [%s] (%s)\n",
  604. acpi_device_name(device), acpi_device_bid(device),
  605. !device->power.state ? "on" : "off");
  606. fujitsu->dev = device;
  607. if (acpi_has_method(device->handle, METHOD_NAME__INI)) {
  608. vdbg_printk(FUJLAPTOP_DBG_INFO, "Invoking _INI\n");
  609. if (ACPI_FAILURE
  610. (acpi_evaluate_object
  611. (device->handle, METHOD_NAME__INI, NULL, NULL)))
  612. pr_err("_INI Method failed\n");
  613. }
  614. /* do config (detect defaults) */
  615. use_alt_lcd_levels = use_alt_lcd_levels == 1 ? 1 : 0;
  616. disable_brightness_adjust = disable_brightness_adjust == 1 ? 1 : 0;
  617. vdbg_printk(FUJLAPTOP_DBG_INFO,
  618. "config: [alt interface: %d], [adjust disable: %d]\n",
  619. use_alt_lcd_levels, disable_brightness_adjust);
  620. if (get_max_brightness() <= 0)
  621. fujitsu->max_brightness = FUJITSU_LCD_N_LEVELS;
  622. get_lcd_level();
  623. return 0;
  624. err_unregister_input_dev:
  625. input_unregister_device(input);
  626. input = NULL;
  627. err_free_input_dev:
  628. input_free_device(input);
  629. err_stop:
  630. return error;
  631. }
  632. static int acpi_fujitsu_remove(struct acpi_device *device)
  633. {
  634. struct fujitsu_t *fujitsu = acpi_driver_data(device);
  635. struct input_dev *input = fujitsu->input;
  636. input_unregister_device(input);
  637. fujitsu->acpi_handle = NULL;
  638. return 0;
  639. }
  640. /* Brightness notify */
  641. static void acpi_fujitsu_notify(struct acpi_device *device, u32 event)
  642. {
  643. struct input_dev *input;
  644. int keycode;
  645. int oldb, newb;
  646. input = fujitsu->input;
  647. switch (event) {
  648. case ACPI_FUJITSU_NOTIFY_CODE1:
  649. keycode = 0;
  650. oldb = fujitsu->brightness_level;
  651. get_lcd_level();
  652. newb = fujitsu->brightness_level;
  653. vdbg_printk(FUJLAPTOP_DBG_TRACE,
  654. "brightness button event [%i -> %i (%i)]\n",
  655. oldb, newb, fujitsu->brightness_changed);
  656. if (oldb < newb) {
  657. if (disable_brightness_adjust != 1) {
  658. if (use_alt_lcd_levels)
  659. set_lcd_level_alt(newb);
  660. else
  661. set_lcd_level(newb);
  662. }
  663. keycode = KEY_BRIGHTNESSUP;
  664. } else if (oldb > newb) {
  665. if (disable_brightness_adjust != 1) {
  666. if (use_alt_lcd_levels)
  667. set_lcd_level_alt(newb);
  668. else
  669. set_lcd_level(newb);
  670. }
  671. keycode = KEY_BRIGHTNESSDOWN;
  672. }
  673. break;
  674. default:
  675. keycode = KEY_UNKNOWN;
  676. vdbg_printk(FUJLAPTOP_DBG_WARN,
  677. "unsupported event [0x%x]\n", event);
  678. break;
  679. }
  680. if (keycode != 0) {
  681. input_report_key(input, keycode, 1);
  682. input_sync(input);
  683. input_report_key(input, keycode, 0);
  684. input_sync(input);
  685. }
  686. }
  687. /* ACPI device for hotkey handling */
  688. static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
  689. {
  690. int result = 0;
  691. int state = 0;
  692. struct input_dev *input;
  693. int error;
  694. int i;
  695. if (!device)
  696. return -EINVAL;
  697. fujitsu_hotkey->acpi_handle = device->handle;
  698. sprintf(acpi_device_name(device), "%s",
  699. ACPI_FUJITSU_HOTKEY_DEVICE_NAME);
  700. sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS);
  701. device->driver_data = fujitsu_hotkey;
  702. /* kfifo */
  703. spin_lock_init(&fujitsu_hotkey->fifo_lock);
  704. error = kfifo_alloc(&fujitsu_hotkey->fifo, RINGBUFFERSIZE * sizeof(int),
  705. GFP_KERNEL);
  706. if (error) {
  707. pr_err("kfifo_alloc failed\n");
  708. goto err_stop;
  709. }
  710. fujitsu_hotkey->input = input = input_allocate_device();
  711. if (!input) {
  712. error = -ENOMEM;
  713. goto err_free_fifo;
  714. }
  715. snprintf(fujitsu_hotkey->phys, sizeof(fujitsu_hotkey->phys),
  716. "%s/video/input0", acpi_device_hid(device));
  717. input->name = acpi_device_name(device);
  718. input->phys = fujitsu_hotkey->phys;
  719. input->id.bustype = BUS_HOST;
  720. input->id.product = 0x06;
  721. input->dev.parent = &device->dev;
  722. set_bit(EV_KEY, input->evbit);
  723. set_bit(fujitsu->keycode1, input->keybit);
  724. set_bit(fujitsu->keycode2, input->keybit);
  725. set_bit(fujitsu->keycode3, input->keybit);
  726. set_bit(fujitsu->keycode4, input->keybit);
  727. set_bit(fujitsu->keycode5, input->keybit);
  728. set_bit(KEY_TOUCHPAD_TOGGLE, input->keybit);
  729. set_bit(KEY_UNKNOWN, input->keybit);
  730. error = input_register_device(input);
  731. if (error)
  732. goto err_free_input_dev;
  733. error = acpi_bus_update_power(fujitsu_hotkey->acpi_handle, &state);
  734. if (error) {
  735. pr_err("Error reading power state\n");
  736. goto err_unregister_input_dev;
  737. }
  738. pr_info("ACPI: %s [%s] (%s)\n",
  739. acpi_device_name(device), acpi_device_bid(device),
  740. !device->power.state ? "on" : "off");
  741. fujitsu_hotkey->dev = device;
  742. if (acpi_has_method(device->handle, METHOD_NAME__INI)) {
  743. vdbg_printk(FUJLAPTOP_DBG_INFO, "Invoking _INI\n");
  744. if (ACPI_FAILURE
  745. (acpi_evaluate_object
  746. (device->handle, METHOD_NAME__INI, NULL, NULL)))
  747. pr_err("_INI Method failed\n");
  748. }
  749. i = 0;
  750. while (call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0
  751. && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE)
  752. ; /* No action, result is discarded */
  753. vdbg_printk(FUJLAPTOP_DBG_INFO, "Discarded %i ringbuffer entries\n", i);
  754. fujitsu_hotkey->rfkill_supported =
  755. call_fext_func(FUNC_RFKILL, 0x0, 0x0, 0x0);
  756. /* Make sure our bitmask of supported functions is cleared if the
  757. RFKILL function block is not implemented, like on the S7020. */
  758. if (fujitsu_hotkey->rfkill_supported == UNSUPPORTED_CMD)
  759. fujitsu_hotkey->rfkill_supported = 0;
  760. if (fujitsu_hotkey->rfkill_supported)
  761. fujitsu_hotkey->rfkill_state =
  762. call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0);
  763. /* Suspect this is a keymap of the application panel, print it */
  764. pr_info("BTNI: [0x%x]\n", call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0));
  765. #if IS_ENABLED(CONFIG_LEDS_CLASS)
  766. if (call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) {
  767. result = led_classdev_register(&fujitsu->pf_device->dev,
  768. &logolamp_led);
  769. if (result == 0) {
  770. fujitsu_hotkey->logolamp_registered = 1;
  771. } else {
  772. pr_err("Could not register LED handler for logo lamp, error %i\n",
  773. result);
  774. }
  775. }
  776. if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) &&
  777. (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) {
  778. result = led_classdev_register(&fujitsu->pf_device->dev,
  779. &kblamps_led);
  780. if (result == 0) {
  781. fujitsu_hotkey->kblamps_registered = 1;
  782. } else {
  783. pr_err("Could not register LED handler for keyboard lamps, error %i\n",
  784. result);
  785. }
  786. }
  787. /*
  788. * BTNI bit 24 seems to indicate the presence of a radio toggle
  789. * button in place of a slide switch, and all such machines appear
  790. * to also have an RF LED. Therefore use bit 24 as an indicator
  791. * that an RF LED is present.
  792. */
  793. if (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) & BIT(24)) {
  794. result = led_classdev_register(&fujitsu->pf_device->dev,
  795. &radio_led);
  796. if (result == 0) {
  797. fujitsu_hotkey->radio_led_registered = 1;
  798. } else {
  799. pr_err("Could not register LED handler for radio LED, error %i\n",
  800. result);
  801. }
  802. }
  803. /* Support for eco led is not always signaled in bit corresponding
  804. * to the bit used to control the led. According to the DSDT table,
  805. * bit 14 seems to indicate presence of said led as well.
  806. * Confirm by testing the status.
  807. */
  808. if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & BIT(14)) &&
  809. (call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0) != UNSUPPORTED_CMD)) {
  810. result = led_classdev_register(&fujitsu->pf_device->dev,
  811. &eco_led);
  812. if (result == 0) {
  813. fujitsu_hotkey->eco_led_registered = 1;
  814. } else {
  815. pr_err("Could not register LED handler for eco LED, error %i\n",
  816. result);
  817. }
  818. }
  819. #endif
  820. return result;
  821. err_unregister_input_dev:
  822. input_unregister_device(input);
  823. input = NULL;
  824. err_free_input_dev:
  825. input_free_device(input);
  826. err_free_fifo:
  827. kfifo_free(&fujitsu_hotkey->fifo);
  828. err_stop:
  829. return error;
  830. }
  831. static int acpi_fujitsu_hotkey_remove(struct acpi_device *device)
  832. {
  833. struct fujitsu_hotkey_t *fujitsu_hotkey = acpi_driver_data(device);
  834. struct input_dev *input = fujitsu_hotkey->input;
  835. #if IS_ENABLED(CONFIG_LEDS_CLASS)
  836. if (fujitsu_hotkey->logolamp_registered)
  837. led_classdev_unregister(&logolamp_led);
  838. if (fujitsu_hotkey->kblamps_registered)
  839. led_classdev_unregister(&kblamps_led);
  840. if (fujitsu_hotkey->radio_led_registered)
  841. led_classdev_unregister(&radio_led);
  842. if (fujitsu_hotkey->eco_led_registered)
  843. led_classdev_unregister(&eco_led);
  844. #endif
  845. input_unregister_device(input);
  846. kfifo_free(&fujitsu_hotkey->fifo);
  847. fujitsu_hotkey->acpi_handle = NULL;
  848. return 0;
  849. }
  850. static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event)
  851. {
  852. struct input_dev *input;
  853. int keycode, keycode_r;
  854. unsigned int irb = 1;
  855. int i, status;
  856. input = fujitsu_hotkey->input;
  857. if (fujitsu_hotkey->rfkill_supported)
  858. fujitsu_hotkey->rfkill_state =
  859. call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0);
  860. switch (event) {
  861. case ACPI_FUJITSU_NOTIFY_CODE1:
  862. i = 0;
  863. while ((irb =
  864. call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0
  865. && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) {
  866. switch (irb & 0x4ff) {
  867. case KEY1_CODE:
  868. keycode = fujitsu->keycode1;
  869. break;
  870. case KEY2_CODE:
  871. keycode = fujitsu->keycode2;
  872. break;
  873. case KEY3_CODE:
  874. keycode = fujitsu->keycode3;
  875. break;
  876. case KEY4_CODE:
  877. keycode = fujitsu->keycode4;
  878. break;
  879. case KEY5_CODE:
  880. keycode = fujitsu->keycode5;
  881. break;
  882. case 0:
  883. keycode = 0;
  884. break;
  885. default:
  886. vdbg_printk(FUJLAPTOP_DBG_WARN,
  887. "Unknown GIRB result [%x]\n", irb);
  888. keycode = -1;
  889. break;
  890. }
  891. if (keycode > 0) {
  892. vdbg_printk(FUJLAPTOP_DBG_TRACE,
  893. "Push keycode into ringbuffer [%d]\n",
  894. keycode);
  895. status = kfifo_in_locked(&fujitsu_hotkey->fifo,
  896. (unsigned char *)&keycode,
  897. sizeof(keycode),
  898. &fujitsu_hotkey->fifo_lock);
  899. if (status != sizeof(keycode)) {
  900. vdbg_printk(FUJLAPTOP_DBG_WARN,
  901. "Could not push keycode [0x%x]\n",
  902. keycode);
  903. } else {
  904. input_report_key(input, keycode, 1);
  905. input_sync(input);
  906. }
  907. } else if (keycode == 0) {
  908. while ((status =
  909. kfifo_out_locked(
  910. &fujitsu_hotkey->fifo,
  911. (unsigned char *) &keycode_r,
  912. sizeof(keycode_r),
  913. &fujitsu_hotkey->fifo_lock))
  914. == sizeof(keycode_r)) {
  915. input_report_key(input, keycode_r, 0);
  916. input_sync(input);
  917. vdbg_printk(FUJLAPTOP_DBG_TRACE,
  918. "Pop keycode from ringbuffer [%d]\n",
  919. keycode_r);
  920. }
  921. }
  922. }
  923. /* On some models (first seen on the Skylake-based Lifebook
  924. * E736/E746/E756), the touchpad toggle hotkey (Fn+F4) is
  925. * handled in software; its state is queried using FUNC_RFKILL
  926. */
  927. if ((fujitsu_hotkey->rfkill_supported & BIT(26)) &&
  928. (call_fext_func(FUNC_RFKILL, 0x1, 0x0, 0x0) & BIT(26))) {
  929. keycode = KEY_TOUCHPAD_TOGGLE;
  930. input_report_key(input, keycode, 1);
  931. input_sync(input);
  932. input_report_key(input, keycode, 0);
  933. input_sync(input);
  934. }
  935. break;
  936. default:
  937. keycode = KEY_UNKNOWN;
  938. vdbg_printk(FUJLAPTOP_DBG_WARN,
  939. "Unsupported event [0x%x]\n", event);
  940. input_report_key(input, keycode, 1);
  941. input_sync(input);
  942. input_report_key(input, keycode, 0);
  943. input_sync(input);
  944. break;
  945. }
  946. }
  947. /* Initialization */
  948. static const struct acpi_device_id fujitsu_device_ids[] = {
  949. {ACPI_FUJITSU_HID, 0},
  950. {"", 0},
  951. };
  952. static struct acpi_driver acpi_fujitsu_driver = {
  953. .name = ACPI_FUJITSU_DRIVER_NAME,
  954. .class = ACPI_FUJITSU_CLASS,
  955. .ids = fujitsu_device_ids,
  956. .ops = {
  957. .add = acpi_fujitsu_add,
  958. .remove = acpi_fujitsu_remove,
  959. .notify = acpi_fujitsu_notify,
  960. },
  961. };
  962. static const struct acpi_device_id fujitsu_hotkey_device_ids[] = {
  963. {ACPI_FUJITSU_HOTKEY_HID, 0},
  964. {"", 0},
  965. };
  966. static struct acpi_driver acpi_fujitsu_hotkey_driver = {
  967. .name = ACPI_FUJITSU_HOTKEY_DRIVER_NAME,
  968. .class = ACPI_FUJITSU_CLASS,
  969. .ids = fujitsu_hotkey_device_ids,
  970. .ops = {
  971. .add = acpi_fujitsu_hotkey_add,
  972. .remove = acpi_fujitsu_hotkey_remove,
  973. .notify = acpi_fujitsu_hotkey_notify,
  974. },
  975. };
  976. static const struct acpi_device_id fujitsu_ids[] __used = {
  977. {ACPI_FUJITSU_HID, 0},
  978. {ACPI_FUJITSU_HOTKEY_HID, 0},
  979. {"", 0}
  980. };
  981. MODULE_DEVICE_TABLE(acpi, fujitsu_ids);
  982. static int __init fujitsu_init(void)
  983. {
  984. int ret, result, max_brightness;
  985. if (acpi_disabled)
  986. return -ENODEV;
  987. fujitsu = kzalloc(sizeof(struct fujitsu_t), GFP_KERNEL);
  988. if (!fujitsu)
  989. return -ENOMEM;
  990. fujitsu->keycode1 = KEY_PROG1;
  991. fujitsu->keycode2 = KEY_PROG2;
  992. fujitsu->keycode3 = KEY_PROG3;
  993. fujitsu->keycode4 = KEY_PROG4;
  994. fujitsu->keycode5 = KEY_RFKILL;
  995. dmi_check_system(fujitsu_dmi_table);
  996. result = acpi_bus_register_driver(&acpi_fujitsu_driver);
  997. if (result < 0) {
  998. ret = -ENODEV;
  999. goto fail_acpi;
  1000. }
  1001. /* Register platform stuff */
  1002. fujitsu->pf_device = platform_device_alloc("fujitsu-laptop", -1);
  1003. if (!fujitsu->pf_device) {
  1004. ret = -ENOMEM;
  1005. goto fail_platform_driver;
  1006. }
  1007. ret = platform_device_add(fujitsu->pf_device);
  1008. if (ret)
  1009. goto fail_platform_device1;
  1010. ret =
  1011. sysfs_create_group(&fujitsu->pf_device->dev.kobj,
  1012. &fujitsupf_attribute_group);
  1013. if (ret)
  1014. goto fail_platform_device2;
  1015. /* Register backlight stuff */
  1016. if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
  1017. struct backlight_properties props;
  1018. memset(&props, 0, sizeof(struct backlight_properties));
  1019. max_brightness = fujitsu->max_brightness;
  1020. props.type = BACKLIGHT_PLATFORM;
  1021. props.max_brightness = max_brightness - 1;
  1022. fujitsu->bl_device = backlight_device_register("fujitsu-laptop",
  1023. NULL, NULL,
  1024. &fujitsubl_ops,
  1025. &props);
  1026. if (IS_ERR(fujitsu->bl_device)) {
  1027. ret = PTR_ERR(fujitsu->bl_device);
  1028. fujitsu->bl_device = NULL;
  1029. goto fail_sysfs_group;
  1030. }
  1031. fujitsu->bl_device->props.brightness = fujitsu->brightness_level;
  1032. }
  1033. ret = platform_driver_register(&fujitsupf_driver);
  1034. if (ret)
  1035. goto fail_backlight;
  1036. /* Register hotkey driver */
  1037. fujitsu_hotkey = kzalloc(sizeof(struct fujitsu_hotkey_t), GFP_KERNEL);
  1038. if (!fujitsu_hotkey) {
  1039. ret = -ENOMEM;
  1040. goto fail_hotkey;
  1041. }
  1042. result = acpi_bus_register_driver(&acpi_fujitsu_hotkey_driver);
  1043. if (result < 0) {
  1044. ret = -ENODEV;
  1045. goto fail_hotkey1;
  1046. }
  1047. /* Sync backlight power status (needs FUJ02E3 device, hence deferred) */
  1048. if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
  1049. if (call_fext_func(FUNC_BACKLIGHT, 0x2, 0x4, 0x0) == 3)
  1050. fujitsu->bl_device->props.power = FB_BLANK_POWERDOWN;
  1051. else
  1052. fujitsu->bl_device->props.power = FB_BLANK_UNBLANK;
  1053. }
  1054. pr_info("driver " FUJITSU_DRIVER_VERSION " successfully loaded\n");
  1055. return 0;
  1056. fail_hotkey1:
  1057. kfree(fujitsu_hotkey);
  1058. fail_hotkey:
  1059. platform_driver_unregister(&fujitsupf_driver);
  1060. fail_backlight:
  1061. backlight_device_unregister(fujitsu->bl_device);
  1062. fail_sysfs_group:
  1063. sysfs_remove_group(&fujitsu->pf_device->dev.kobj,
  1064. &fujitsupf_attribute_group);
  1065. fail_platform_device2:
  1066. platform_device_del(fujitsu->pf_device);
  1067. fail_platform_device1:
  1068. platform_device_put(fujitsu->pf_device);
  1069. fail_platform_driver:
  1070. acpi_bus_unregister_driver(&acpi_fujitsu_driver);
  1071. fail_acpi:
  1072. kfree(fujitsu);
  1073. return ret;
  1074. }
  1075. static void __exit fujitsu_cleanup(void)
  1076. {
  1077. acpi_bus_unregister_driver(&acpi_fujitsu_hotkey_driver);
  1078. kfree(fujitsu_hotkey);
  1079. platform_driver_unregister(&fujitsupf_driver);
  1080. backlight_device_unregister(fujitsu->bl_device);
  1081. sysfs_remove_group(&fujitsu->pf_device->dev.kobj,
  1082. &fujitsupf_attribute_group);
  1083. platform_device_unregister(fujitsu->pf_device);
  1084. acpi_bus_unregister_driver(&acpi_fujitsu_driver);
  1085. kfree(fujitsu);
  1086. pr_info("driver unloaded\n");
  1087. }
  1088. module_init(fujitsu_init);
  1089. module_exit(fujitsu_cleanup);
  1090. module_param(use_alt_lcd_levels, uint, 0644);
  1091. MODULE_PARM_DESC(use_alt_lcd_levels,
  1092. "Use alternative interface for lcd_levels (needed for Lifebook s6410).");
  1093. module_param(disable_brightness_adjust, uint, 0644);
  1094. MODULE_PARM_DESC(disable_brightness_adjust, "Disable brightness adjustment .");
  1095. #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
  1096. module_param_named(debug, dbg_level, uint, 0644);
  1097. MODULE_PARM_DESC(debug, "Sets debug level bit-mask");
  1098. #endif
  1099. MODULE_AUTHOR("Jonathan Woithe, Peter Gruber, Tony Vroon");
  1100. MODULE_DESCRIPTION("Fujitsu laptop extras support");
  1101. MODULE_VERSION(FUJITSU_DRIVER_VERSION);
  1102. MODULE_LICENSE("GPL");
  1103. MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1D3:*:cvrS6410:*");
  1104. MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1E6:*:cvrS6420:*");
  1105. MODULE_ALIAS("dmi:*:svnFUJITSU:*:pvr:rvnFUJITSU:rnFJNB19C:*:cvrS7020:*");