acer-wmi.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107
  1. /*
  2. * Acer WMI Laptop Extras
  3. *
  4. * Copyright (C) 2007-2008 Carlos Corbacho <carlos@strangeworlds.co.uk>
  5. *
  6. * Based on acer_acpi:
  7. * Copyright (C) 2005-2007 E.M. Smith
  8. * Copyright (C) 2007-2008 Carlos Corbacho <cathectic@gmail.com>
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  23. */
  24. #define ACER_WMI_VERSION "0.1"
  25. #include <linux/kernel.h>
  26. #include <linux/module.h>
  27. #include <linux/init.h>
  28. #include <linux/types.h>
  29. #include <linux/dmi.h>
  30. #include <linux/backlight.h>
  31. #include <linux/leds.h>
  32. #include <linux/platform_device.h>
  33. #include <linux/acpi.h>
  34. #include <linux/i8042.h>
  35. #include <acpi/acpi_drivers.h>
  36. MODULE_AUTHOR("Carlos Corbacho");
  37. MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver");
  38. MODULE_LICENSE("GPL");
  39. #define ACER_LOGPREFIX "acer-wmi: "
  40. #define ACER_ERR KERN_ERR ACER_LOGPREFIX
  41. #define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX
  42. #define ACER_INFO KERN_INFO ACER_LOGPREFIX
  43. /*
  44. * The following defines quirks to get some specific functions to work
  45. * which are known to not be supported over ACPI-WMI (such as the mail LED
  46. * on WMID based Acer's)
  47. */
  48. struct acer_quirks {
  49. const char *vendor;
  50. const char *model;
  51. u16 quirks;
  52. };
  53. /*
  54. * Magic Number
  55. * Meaning is unknown - this number is required for writing to ACPI for AMW0
  56. * (it's also used in acerhk when directly accessing the BIOS)
  57. */
  58. #define ACER_AMW0_WRITE 0x9610
  59. /*
  60. * Bit masks for the AMW0 interface
  61. */
  62. #define ACER_AMW0_WIRELESS_MASK 0x35
  63. #define ACER_AMW0_BLUETOOTH_MASK 0x34
  64. #define ACER_AMW0_MAILLED_MASK 0x31
  65. /*
  66. * Method IDs for WMID interface
  67. */
  68. #define ACER_WMID_GET_WIRELESS_METHODID 1
  69. #define ACER_WMID_GET_BLUETOOTH_METHODID 2
  70. #define ACER_WMID_GET_BRIGHTNESS_METHODID 3
  71. #define ACER_WMID_SET_WIRELESS_METHODID 4
  72. #define ACER_WMID_SET_BLUETOOTH_METHODID 5
  73. #define ACER_WMID_SET_BRIGHTNESS_METHODID 6
  74. #define ACER_WMID_GET_THREEG_METHODID 10
  75. #define ACER_WMID_SET_THREEG_METHODID 11
  76. /*
  77. * Acer ACPI method GUIDs
  78. */
  79. #define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB"
  80. #define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"
  81. #define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A"
  82. MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB");
  83. MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3");
  84. /* Temporary workaround until the WMI sysfs interface goes in */
  85. MODULE_ALIAS("dmi:*:*Acer*:*:");
  86. /*
  87. * Interface capability flags
  88. */
  89. #define ACER_CAP_MAILLED (1<<0)
  90. #define ACER_CAP_WIRELESS (1<<1)
  91. #define ACER_CAP_BLUETOOTH (1<<2)
  92. #define ACER_CAP_BRIGHTNESS (1<<3)
  93. #define ACER_CAP_THREEG (1<<4)
  94. #define ACER_CAP_ANY (0xFFFFFFFF)
  95. /*
  96. * Interface type flags
  97. */
  98. enum interface_flags {
  99. ACER_AMW0,
  100. ACER_AMW0_V2,
  101. ACER_WMID,
  102. };
  103. #define ACER_DEFAULT_WIRELESS 0
  104. #define ACER_DEFAULT_BLUETOOTH 0
  105. #define ACER_DEFAULT_MAILLED 0
  106. #define ACER_DEFAULT_THREEG 0
  107. static int max_brightness = 0xF;
  108. static int wireless = -1;
  109. static int bluetooth = -1;
  110. static int mailled = -1;
  111. static int brightness = -1;
  112. static int threeg = -1;
  113. static int force_series;
  114. module_param(mailled, int, 0444);
  115. module_param(wireless, int, 0444);
  116. module_param(bluetooth, int, 0444);
  117. module_param(brightness, int, 0444);
  118. module_param(threeg, int, 0444);
  119. module_param(force_series, int, 0444);
  120. MODULE_PARM_DESC(wireless, "Set initial state of Wireless hardware");
  121. MODULE_PARM_DESC(bluetooth, "Set initial state of Bluetooth hardware");
  122. MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
  123. MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
  124. MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
  125. MODULE_PARM_DESC(force_series, "Force a different laptop series");
  126. struct acer_data {
  127. int mailled;
  128. int wireless;
  129. int bluetooth;
  130. int threeg;
  131. int brightness;
  132. };
  133. /* Each low-level interface must define at least some of the following */
  134. struct wmi_interface {
  135. /* The WMI device type */
  136. u32 type;
  137. /* The capabilities this interface provides */
  138. u32 capability;
  139. /* Private data for the current interface */
  140. struct acer_data data;
  141. };
  142. /* The static interface pointer, points to the currently detected interface */
  143. static struct wmi_interface *interface;
  144. /*
  145. * Embedded Controller quirks
  146. * Some laptops require us to directly access the EC to either enable or query
  147. * features that are not available through WMI.
  148. */
  149. struct quirk_entry {
  150. u8 wireless;
  151. u8 mailled;
  152. u8 brightness;
  153. u8 bluetooth;
  154. };
  155. static struct quirk_entry *quirks;
  156. static void set_quirks(void)
  157. {
  158. if (quirks->mailled)
  159. interface->capability |= ACER_CAP_MAILLED;
  160. if (quirks->brightness)
  161. interface->capability |= ACER_CAP_BRIGHTNESS;
  162. }
  163. static int dmi_matched(const struct dmi_system_id *dmi)
  164. {
  165. quirks = dmi->driver_data;
  166. return 0;
  167. }
  168. static struct quirk_entry quirk_unknown = {
  169. };
  170. static struct quirk_entry quirk_acer_travelmate_2490 = {
  171. .mailled = 1,
  172. };
  173. /* This AMW0 laptop has no bluetooth */
  174. static struct quirk_entry quirk_medion_md_98300 = {
  175. .wireless = 1,
  176. };
  177. static struct dmi_system_id acer_quirks[] = {
  178. {
  179. .callback = dmi_matched,
  180. .ident = "Acer Aspire 3100",
  181. .matches = {
  182. DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
  183. DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3100"),
  184. },
  185. .driver_data = &quirk_acer_travelmate_2490,
  186. },
  187. {
  188. .callback = dmi_matched,
  189. .ident = "Acer Aspire 5100",
  190. .matches = {
  191. DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
  192. DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
  193. },
  194. .driver_data = &quirk_acer_travelmate_2490,
  195. },
  196. {
  197. .callback = dmi_matched,
  198. .ident = "Acer Aspire 5630",
  199. .matches = {
  200. DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
  201. DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"),
  202. },
  203. .driver_data = &quirk_acer_travelmate_2490,
  204. },
  205. {
  206. .callback = dmi_matched,
  207. .ident = "Acer Aspire 5650",
  208. .matches = {
  209. DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
  210. DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"),
  211. },
  212. .driver_data = &quirk_acer_travelmate_2490,
  213. },
  214. {
  215. .callback = dmi_matched,
  216. .ident = "Acer Aspire 5680",
  217. .matches = {
  218. DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
  219. DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"),
  220. },
  221. .driver_data = &quirk_acer_travelmate_2490,
  222. },
  223. {
  224. .callback = dmi_matched,
  225. .ident = "Acer Aspire 9110",
  226. .matches = {
  227. DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
  228. DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"),
  229. },
  230. .driver_data = &quirk_acer_travelmate_2490,
  231. },
  232. {
  233. .callback = dmi_matched,
  234. .ident = "Acer TravelMate 2490",
  235. .matches = {
  236. DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
  237. DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"),
  238. },
  239. .driver_data = &quirk_acer_travelmate_2490,
  240. },
  241. {
  242. .callback = dmi_matched,
  243. .ident = "Medion MD 98300",
  244. .matches = {
  245. DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
  246. DMI_MATCH(DMI_PRODUCT_NAME, "WAM2030"),
  247. },
  248. .driver_data = &quirk_medion_md_98300,
  249. },
  250. {}
  251. };
  252. /* Find which quirks are needed for a particular vendor/ model pair */
  253. static void find_quirks(void)
  254. {
  255. if (!force_series) {
  256. dmi_check_system(acer_quirks);
  257. } else if (force_series == 2490) {
  258. quirks = &quirk_acer_travelmate_2490;
  259. }
  260. if (quirks == NULL)
  261. quirks = &quirk_unknown;
  262. set_quirks();
  263. }
  264. /*
  265. * General interface convenience methods
  266. */
  267. static bool has_cap(u32 cap)
  268. {
  269. if ((interface->capability & cap) != 0)
  270. return 1;
  271. return 0;
  272. }
  273. /*
  274. * AMW0 (V1) interface
  275. */
  276. struct wmab_args {
  277. u32 eax;
  278. u32 ebx;
  279. u32 ecx;
  280. u32 edx;
  281. };
  282. struct wmab_ret {
  283. u32 eax;
  284. u32 ebx;
  285. u32 ecx;
  286. u32 edx;
  287. u32 eex;
  288. };
  289. static acpi_status wmab_execute(struct wmab_args *regbuf,
  290. struct acpi_buffer *result)
  291. {
  292. struct acpi_buffer input;
  293. acpi_status status;
  294. input.length = sizeof(struct wmab_args);
  295. input.pointer = (u8 *)regbuf;
  296. status = wmi_evaluate_method(AMW0_GUID1, 1, 1, &input, result);
  297. return status;
  298. }
  299. static acpi_status AMW0_get_u32(u32 *value, u32 cap,
  300. struct wmi_interface *iface)
  301. {
  302. int err;
  303. u8 result;
  304. switch (cap) {
  305. case ACER_CAP_MAILLED:
  306. switch (quirks->mailled) {
  307. default:
  308. err = ec_read(0xA, &result);
  309. if (err)
  310. return AE_ERROR;
  311. *value = (result >> 7) & 0x1;
  312. return AE_OK;
  313. }
  314. break;
  315. case ACER_CAP_WIRELESS:
  316. switch (quirks->wireless) {
  317. case 1:
  318. err = ec_read(0x7B, &result);
  319. if (err)
  320. return AE_ERROR;
  321. *value = result & 0x1;
  322. return AE_OK;
  323. default:
  324. err = ec_read(0xA, &result);
  325. if (err)
  326. return AE_ERROR;
  327. *value = (result >> 2) & 0x1;
  328. return AE_OK;
  329. }
  330. break;
  331. case ACER_CAP_BLUETOOTH:
  332. switch (quirks->bluetooth) {
  333. default:
  334. err = ec_read(0xA, &result);
  335. if (err)
  336. return AE_ERROR;
  337. *value = (result >> 4) & 0x1;
  338. return AE_OK;
  339. }
  340. break;
  341. case ACER_CAP_BRIGHTNESS:
  342. switch (quirks->brightness) {
  343. default:
  344. err = ec_read(0x83, &result);
  345. if (err)
  346. return AE_ERROR;
  347. *value = result;
  348. return AE_OK;
  349. }
  350. break;
  351. default:
  352. return AE_BAD_ADDRESS;
  353. }
  354. return AE_OK;
  355. }
  356. static acpi_status AMW0_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
  357. {
  358. struct wmab_args args;
  359. args.eax = ACER_AMW0_WRITE;
  360. args.ebx = value ? (1<<8) : 0;
  361. args.ecx = args.edx = 0;
  362. switch (cap) {
  363. case ACER_CAP_MAILLED:
  364. if (value > 1)
  365. return AE_BAD_PARAMETER;
  366. args.ebx |= ACER_AMW0_MAILLED_MASK;
  367. break;
  368. case ACER_CAP_WIRELESS:
  369. if (value > 1)
  370. return AE_BAD_PARAMETER;
  371. args.ebx |= ACER_AMW0_WIRELESS_MASK;
  372. break;
  373. case ACER_CAP_BLUETOOTH:
  374. if (value > 1)
  375. return AE_BAD_PARAMETER;
  376. args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
  377. break;
  378. case ACER_CAP_BRIGHTNESS:
  379. if (value > max_brightness)
  380. return AE_BAD_PARAMETER;
  381. switch (quirks->brightness) {
  382. default:
  383. return ec_write(0x83, value);
  384. break;
  385. }
  386. default:
  387. return AE_BAD_ADDRESS;
  388. }
  389. /* Actually do the set */
  390. return wmab_execute(&args, NULL);
  391. }
  392. static acpi_status AMW0_find_mailled(void)
  393. {
  394. struct wmab_args args;
  395. struct wmab_ret ret;
  396. acpi_status status = AE_OK;
  397. struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
  398. union acpi_object *obj;
  399. args.eax = 0x86;
  400. args.ebx = args.ecx = args.edx = 0;
  401. status = wmab_execute(&args, &out);
  402. if (ACPI_FAILURE(status))
  403. return status;
  404. obj = (union acpi_object *) out.pointer;
  405. if (obj && obj->type == ACPI_TYPE_BUFFER &&
  406. obj->buffer.length == sizeof(struct wmab_ret)) {
  407. ret = *((struct wmab_ret *) obj->buffer.pointer);
  408. } else {
  409. return AE_ERROR;
  410. }
  411. if (ret.eex & 0x1)
  412. interface->capability |= ACER_CAP_MAILLED;
  413. kfree(out.pointer);
  414. return AE_OK;
  415. }
  416. static acpi_status AMW0_set_capabilities(void)
  417. {
  418. struct wmab_args args;
  419. struct wmab_ret ret;
  420. acpi_status status = AE_OK;
  421. struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
  422. union acpi_object *obj;
  423. args.eax = ACER_AMW0_WRITE;
  424. args.ecx = args.edx = 0;
  425. args.ebx = 0xa2 << 8;
  426. args.ebx |= ACER_AMW0_WIRELESS_MASK;
  427. status = wmab_execute(&args, &out);
  428. if (ACPI_FAILURE(status))
  429. return status;
  430. obj = (union acpi_object *) out.pointer;
  431. if (obj && obj->type == ACPI_TYPE_BUFFER &&
  432. obj->buffer.length == sizeof(struct wmab_ret)) {
  433. ret = *((struct wmab_ret *) obj->buffer.pointer);
  434. } else {
  435. return AE_ERROR;
  436. }
  437. if (ret.eax & 0x1)
  438. interface->capability |= ACER_CAP_WIRELESS;
  439. args.ebx = 2 << 8;
  440. args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
  441. status = wmab_execute(&args, &out);
  442. if (ACPI_FAILURE(status))
  443. return status;
  444. obj = (union acpi_object *) out.pointer;
  445. if (obj && obj->type == ACPI_TYPE_BUFFER
  446. && obj->buffer.length == sizeof(struct wmab_ret)) {
  447. ret = *((struct wmab_ret *) obj->buffer.pointer);
  448. } else {
  449. return AE_ERROR;
  450. }
  451. if (ret.eax & 0x1)
  452. interface->capability |= ACER_CAP_BLUETOOTH;
  453. kfree(out.pointer);
  454. /*
  455. * This appears to be safe to enable, since all Wistron based laptops
  456. * appear to use the same EC register for brightness, even if they
  457. * differ for wireless, etc
  458. */
  459. interface->capability |= ACER_CAP_BRIGHTNESS;
  460. return AE_OK;
  461. }
  462. static struct wmi_interface AMW0_interface = {
  463. .type = ACER_AMW0,
  464. };
  465. static struct wmi_interface AMW0_V2_interface = {
  466. .type = ACER_AMW0_V2,
  467. };
  468. /*
  469. * New interface (The WMID interface)
  470. */
  471. static acpi_status
  472. WMI_execute_u32(u32 method_id, u32 in, u32 *out)
  473. {
  474. struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) };
  475. struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
  476. union acpi_object *obj;
  477. u32 tmp;
  478. acpi_status status;
  479. status = wmi_evaluate_method(WMID_GUID1, 1, method_id, &input, &result);
  480. if (ACPI_FAILURE(status))
  481. return status;
  482. obj = (union acpi_object *) result.pointer;
  483. if (obj && obj->type == ACPI_TYPE_BUFFER &&
  484. obj->buffer.length == sizeof(u32)) {
  485. tmp = *((u32 *) obj->buffer.pointer);
  486. } else {
  487. tmp = 0;
  488. }
  489. if (out)
  490. *out = tmp;
  491. kfree(result.pointer);
  492. return status;
  493. }
  494. static acpi_status WMID_get_u32(u32 *value, u32 cap,
  495. struct wmi_interface *iface)
  496. {
  497. acpi_status status;
  498. u8 tmp;
  499. u32 result, method_id = 0;
  500. switch (cap) {
  501. case ACER_CAP_WIRELESS:
  502. method_id = ACER_WMID_GET_WIRELESS_METHODID;
  503. break;
  504. case ACER_CAP_BLUETOOTH:
  505. method_id = ACER_WMID_GET_BLUETOOTH_METHODID;
  506. break;
  507. case ACER_CAP_BRIGHTNESS:
  508. method_id = ACER_WMID_GET_BRIGHTNESS_METHODID;
  509. break;
  510. case ACER_CAP_THREEG:
  511. method_id = ACER_WMID_GET_THREEG_METHODID;
  512. break;
  513. case ACER_CAP_MAILLED:
  514. if (quirks->mailled == 1) {
  515. ec_read(0x9f, &tmp);
  516. *value = tmp & 0x1;
  517. return 0;
  518. }
  519. default:
  520. return AE_BAD_ADDRESS;
  521. }
  522. status = WMI_execute_u32(method_id, 0, &result);
  523. if (ACPI_SUCCESS(status))
  524. *value = (u8)result;
  525. return status;
  526. }
  527. static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
  528. {
  529. u32 method_id = 0;
  530. char param;
  531. switch (cap) {
  532. case ACER_CAP_BRIGHTNESS:
  533. if (value > max_brightness)
  534. return AE_BAD_PARAMETER;
  535. method_id = ACER_WMID_SET_BRIGHTNESS_METHODID;
  536. break;
  537. case ACER_CAP_WIRELESS:
  538. if (value > 1)
  539. return AE_BAD_PARAMETER;
  540. method_id = ACER_WMID_SET_WIRELESS_METHODID;
  541. break;
  542. case ACER_CAP_BLUETOOTH:
  543. if (value > 1)
  544. return AE_BAD_PARAMETER;
  545. method_id = ACER_WMID_SET_BLUETOOTH_METHODID;
  546. break;
  547. case ACER_CAP_THREEG:
  548. if (value > 1)
  549. return AE_BAD_PARAMETER;
  550. method_id = ACER_WMID_SET_THREEG_METHODID;
  551. break;
  552. case ACER_CAP_MAILLED:
  553. if (value > 1)
  554. return AE_BAD_PARAMETER;
  555. if (quirks->mailled == 1) {
  556. param = value ? 0x92 : 0x93;
  557. i8042_command(&param, 0x1059);
  558. return 0;
  559. }
  560. break;
  561. default:
  562. return AE_BAD_ADDRESS;
  563. }
  564. return WMI_execute_u32(method_id, (u32)value, NULL);
  565. }
  566. static acpi_status WMID_set_capabilities(void)
  567. {
  568. struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
  569. union acpi_object *obj;
  570. acpi_status status;
  571. u32 devices;
  572. status = wmi_query_block(WMID_GUID2, 1, &out);
  573. if (ACPI_FAILURE(status))
  574. return status;
  575. obj = (union acpi_object *) out.pointer;
  576. if (obj && obj->type == ACPI_TYPE_BUFFER &&
  577. obj->buffer.length == sizeof(u32)) {
  578. devices = *((u32 *) obj->buffer.pointer);
  579. } else {
  580. return AE_ERROR;
  581. }
  582. /* Not sure on the meaning of the relevant bits yet to detect these */
  583. interface->capability |= ACER_CAP_WIRELESS;
  584. interface->capability |= ACER_CAP_THREEG;
  585. /* WMID always provides brightness methods */
  586. interface->capability |= ACER_CAP_BRIGHTNESS;
  587. if (devices & 0x10)
  588. interface->capability |= ACER_CAP_BLUETOOTH;
  589. if (!(devices & 0x20))
  590. max_brightness = 0x9;
  591. return status;
  592. }
  593. static struct wmi_interface wmid_interface = {
  594. .type = ACER_WMID,
  595. };
  596. /*
  597. * Generic Device (interface-independent)
  598. */
  599. static acpi_status get_u32(u32 *value, u32 cap)
  600. {
  601. acpi_status status = AE_BAD_ADDRESS;
  602. switch (interface->type) {
  603. case ACER_AMW0:
  604. status = AMW0_get_u32(value, cap, interface);
  605. break;
  606. case ACER_AMW0_V2:
  607. if (cap == ACER_CAP_MAILLED) {
  608. status = AMW0_get_u32(value, cap, interface);
  609. break;
  610. }
  611. case ACER_WMID:
  612. status = WMID_get_u32(value, cap, interface);
  613. break;
  614. }
  615. return status;
  616. }
  617. static acpi_status set_u32(u32 value, u32 cap)
  618. {
  619. if (interface->capability & cap) {
  620. switch (interface->type) {
  621. case ACER_AMW0:
  622. return AMW0_set_u32(value, cap, interface);
  623. case ACER_AMW0_V2:
  624. case ACER_WMID:
  625. return WMID_set_u32(value, cap, interface);
  626. default:
  627. return AE_BAD_PARAMETER;
  628. }
  629. }
  630. return AE_BAD_PARAMETER;
  631. }
  632. static void __init acer_commandline_init(void)
  633. {
  634. /*
  635. * These will all fail silently if the value given is invalid, or the
  636. * capability isn't available on the given interface
  637. */
  638. set_u32(mailled, ACER_CAP_MAILLED);
  639. set_u32(wireless, ACER_CAP_WIRELESS);
  640. set_u32(bluetooth, ACER_CAP_BLUETOOTH);
  641. set_u32(threeg, ACER_CAP_THREEG);
  642. set_u32(brightness, ACER_CAP_BRIGHTNESS);
  643. }
  644. /*
  645. * LED device (Mail LED only, no other LEDs known yet)
  646. */
  647. static void mail_led_set(struct led_classdev *led_cdev,
  648. enum led_brightness value)
  649. {
  650. set_u32(value, ACER_CAP_MAILLED);
  651. }
  652. static struct led_classdev mail_led = {
  653. .name = "acer-mail:green",
  654. .brightness_set = mail_led_set,
  655. };
  656. static int __devinit acer_led_init(struct device *dev)
  657. {
  658. return led_classdev_register(dev, &mail_led);
  659. }
  660. static void acer_led_exit(void)
  661. {
  662. led_classdev_unregister(&mail_led);
  663. }
  664. /*
  665. * Backlight device
  666. */
  667. static struct backlight_device *acer_backlight_device;
  668. static int read_brightness(struct backlight_device *bd)
  669. {
  670. u32 value;
  671. get_u32(&value, ACER_CAP_BRIGHTNESS);
  672. return value;
  673. }
  674. static int update_bl_status(struct backlight_device *bd)
  675. {
  676. set_u32(bd->props.brightness, ACER_CAP_BRIGHTNESS);
  677. return 0;
  678. }
  679. static struct backlight_ops acer_bl_ops = {
  680. .get_brightness = read_brightness,
  681. .update_status = update_bl_status,
  682. };
  683. static int __devinit acer_backlight_init(struct device *dev)
  684. {
  685. struct backlight_device *bd;
  686. bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops);
  687. if (IS_ERR(bd)) {
  688. printk(ACER_ERR "Could not register Acer backlight device\n");
  689. acer_backlight_device = NULL;
  690. return PTR_ERR(bd);
  691. }
  692. acer_backlight_device = bd;
  693. bd->props.max_brightness = max_brightness;
  694. bd->props.brightness = read_brightness(NULL);
  695. backlight_update_status(bd);
  696. return 0;
  697. }
  698. static void acer_backlight_exit(void)
  699. {
  700. backlight_device_unregister(acer_backlight_device);
  701. }
  702. /*
  703. * Read/ write bool sysfs macro
  704. */
  705. #define show_set_bool(value, cap) \
  706. static ssize_t \
  707. show_bool_##value(struct device *dev, struct device_attribute *attr, \
  708. char *buf) \
  709. { \
  710. u32 result; \
  711. acpi_status status = get_u32(&result, cap); \
  712. if (ACPI_SUCCESS(status)) \
  713. return sprintf(buf, "%u\n", result); \
  714. return sprintf(buf, "Read error\n"); \
  715. } \
  716. \
  717. static ssize_t \
  718. set_bool_##value(struct device *dev, struct device_attribute *attr, \
  719. const char *buf, size_t count) \
  720. { \
  721. u32 tmp = simple_strtoul(buf, NULL, 10); \
  722. acpi_status status = set_u32(tmp, cap); \
  723. if (ACPI_FAILURE(status)) \
  724. return -EINVAL; \
  725. return count; \
  726. } \
  727. static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
  728. show_bool_##value, set_bool_##value);
  729. show_set_bool(wireless, ACER_CAP_WIRELESS);
  730. show_set_bool(bluetooth, ACER_CAP_BLUETOOTH);
  731. show_set_bool(threeg, ACER_CAP_THREEG);
  732. /*
  733. * Read interface sysfs macro
  734. */
  735. static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
  736. char *buf)
  737. {
  738. switch (interface->type) {
  739. case ACER_AMW0:
  740. return sprintf(buf, "AMW0\n");
  741. case ACER_AMW0_V2:
  742. return sprintf(buf, "AMW0 v2\n");
  743. case ACER_WMID:
  744. return sprintf(buf, "WMID\n");
  745. default:
  746. return sprintf(buf, "Error!\n");
  747. }
  748. }
  749. static DEVICE_ATTR(interface, S_IWUGO | S_IRUGO | S_IWUSR,
  750. show_interface, NULL);
  751. /*
  752. * Platform device
  753. */
  754. static int __devinit acer_platform_probe(struct platform_device *device)
  755. {
  756. int err;
  757. if (has_cap(ACER_CAP_MAILLED)) {
  758. err = acer_led_init(&device->dev);
  759. if (err)
  760. goto error_mailled;
  761. }
  762. if (has_cap(ACER_CAP_BRIGHTNESS)) {
  763. err = acer_backlight_init(&device->dev);
  764. if (err)
  765. goto error_brightness;
  766. }
  767. return 0;
  768. error_brightness:
  769. acer_led_exit();
  770. error_mailled:
  771. return err;
  772. }
  773. static int acer_platform_remove(struct platform_device *device)
  774. {
  775. if (has_cap(ACER_CAP_MAILLED))
  776. acer_led_exit();
  777. if (has_cap(ACER_CAP_BRIGHTNESS))
  778. acer_backlight_exit();
  779. return 0;
  780. }
  781. static int acer_platform_suspend(struct platform_device *dev,
  782. pm_message_t state)
  783. {
  784. u32 value;
  785. struct acer_data *data = &interface->data;
  786. if (!data)
  787. return -ENOMEM;
  788. if (has_cap(ACER_CAP_WIRELESS)) {
  789. get_u32(&value, ACER_CAP_WIRELESS);
  790. data->wireless = value;
  791. }
  792. if (has_cap(ACER_CAP_BLUETOOTH)) {
  793. get_u32(&value, ACER_CAP_BLUETOOTH);
  794. data->bluetooth = value;
  795. }
  796. if (has_cap(ACER_CAP_MAILLED)) {
  797. get_u32(&value, ACER_CAP_MAILLED);
  798. data->mailled = value;
  799. }
  800. if (has_cap(ACER_CAP_BRIGHTNESS)) {
  801. get_u32(&value, ACER_CAP_BRIGHTNESS);
  802. data->brightness = value;
  803. }
  804. return 0;
  805. }
  806. static int acer_platform_resume(struct platform_device *device)
  807. {
  808. struct acer_data *data = &interface->data;
  809. if (!data)
  810. return -ENOMEM;
  811. if (has_cap(ACER_CAP_WIRELESS))
  812. set_u32(data->wireless, ACER_CAP_WIRELESS);
  813. if (has_cap(ACER_CAP_BLUETOOTH))
  814. set_u32(data->bluetooth, ACER_CAP_BLUETOOTH);
  815. if (has_cap(ACER_CAP_THREEG))
  816. set_u32(data->threeg, ACER_CAP_THREEG);
  817. if (has_cap(ACER_CAP_MAILLED))
  818. set_u32(data->mailled, ACER_CAP_MAILLED);
  819. if (has_cap(ACER_CAP_BRIGHTNESS))
  820. set_u32(data->brightness, ACER_CAP_BRIGHTNESS);
  821. return 0;
  822. }
  823. static struct platform_driver acer_platform_driver = {
  824. .driver = {
  825. .name = "acer-wmi",
  826. .owner = THIS_MODULE,
  827. },
  828. .probe = acer_platform_probe,
  829. .remove = acer_platform_remove,
  830. .suspend = acer_platform_suspend,
  831. .resume = acer_platform_resume,
  832. };
  833. static struct platform_device *acer_platform_device;
  834. static int remove_sysfs(struct platform_device *device)
  835. {
  836. if (has_cap(ACER_CAP_WIRELESS))
  837. device_remove_file(&device->dev, &dev_attr_wireless);
  838. if (has_cap(ACER_CAP_BLUETOOTH))
  839. device_remove_file(&device->dev, &dev_attr_bluetooth);
  840. if (has_cap(ACER_CAP_THREEG))
  841. device_remove_file(&device->dev, &dev_attr_threeg);
  842. device_remove_file(&device->dev, &dev_attr_interface);
  843. return 0;
  844. }
  845. static int create_sysfs(void)
  846. {
  847. int retval = -ENOMEM;
  848. if (has_cap(ACER_CAP_WIRELESS)) {
  849. retval = device_create_file(&acer_platform_device->dev,
  850. &dev_attr_wireless);
  851. if (retval)
  852. goto error_sysfs;
  853. }
  854. if (has_cap(ACER_CAP_BLUETOOTH)) {
  855. retval = device_create_file(&acer_platform_device->dev,
  856. &dev_attr_bluetooth);
  857. if (retval)
  858. goto error_sysfs;
  859. }
  860. if (has_cap(ACER_CAP_THREEG)) {
  861. retval = device_create_file(&acer_platform_device->dev,
  862. &dev_attr_threeg);
  863. if (retval)
  864. goto error_sysfs;
  865. }
  866. retval = device_create_file(&acer_platform_device->dev,
  867. &dev_attr_interface);
  868. if (retval)
  869. goto error_sysfs;
  870. return 0;
  871. error_sysfs:
  872. remove_sysfs(acer_platform_device);
  873. return retval;
  874. }
  875. static int __init acer_wmi_init(void)
  876. {
  877. int err;
  878. printk(ACER_INFO "Acer Laptop ACPI-WMI Extras version %s\n",
  879. ACER_WMI_VERSION);
  880. /*
  881. * Detect which ACPI-WMI interface we're using.
  882. */
  883. if (wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1))
  884. interface = &AMW0_V2_interface;
  885. if (!wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1))
  886. interface = &wmid_interface;
  887. if (wmi_has_guid(WMID_GUID2) && interface) {
  888. if (ACPI_FAILURE(WMID_set_capabilities())) {
  889. printk(ACER_ERR "Unable to detect available devices\n");
  890. return -ENODEV;
  891. }
  892. } else if (!wmi_has_guid(WMID_GUID2) && interface) {
  893. printk(ACER_ERR "Unable to detect available devices\n");
  894. return -ENODEV;
  895. }
  896. if (wmi_has_guid(AMW0_GUID1) && !wmi_has_guid(WMID_GUID1)) {
  897. interface = &AMW0_interface;
  898. if (ACPI_FAILURE(AMW0_set_capabilities())) {
  899. printk(ACER_ERR "Unable to detect available devices\n");
  900. return -ENODEV;
  901. }
  902. }
  903. if (wmi_has_guid(AMW0_GUID1)) {
  904. if (ACPI_FAILURE(AMW0_find_mailled()))
  905. printk(ACER_ERR "Unable to detect mail LED\n");
  906. }
  907. find_quirks();
  908. if (!interface) {
  909. printk(ACER_ERR "No or unsupported WMI interface, unable to ");
  910. printk(KERN_CONT "load.\n");
  911. return -ENODEV;
  912. }
  913. if (platform_driver_register(&acer_platform_driver)) {
  914. printk(ACER_ERR "Unable to register platform driver.\n");
  915. goto error_platform_register;
  916. }
  917. acer_platform_device = platform_device_alloc("acer-wmi", -1);
  918. platform_device_add(acer_platform_device);
  919. err = create_sysfs();
  920. if (err)
  921. return err;
  922. /* Override any initial settings with values from the commandline */
  923. acer_commandline_init();
  924. return 0;
  925. error_platform_register:
  926. return -ENODEV;
  927. }
  928. static void __exit acer_wmi_exit(void)
  929. {
  930. remove_sysfs(acer_platform_device);
  931. platform_device_del(acer_platform_device);
  932. platform_driver_unregister(&acer_platform_driver);
  933. printk(ACER_INFO "Acer Laptop WMI Extras unloaded\n");
  934. return;
  935. }
  936. module_init(acer_wmi_init);
  937. module_exit(acer_wmi_exit);