compal-laptop.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113
  1. /*-*-linux-c-*-*/
  2. /*
  3. Copyright (C) 2008 Cezary Jackiewicz <cezary.jackiewicz (at) gmail.com>
  4. based on MSI driver
  5. Copyright (C) 2006 Lennart Poettering <mzxreary (at) 0pointer (dot) de>
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful, but
  11. WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. 02110-1301, USA.
  18. */
  19. /*
  20. * compal-laptop.c - Compal laptop support.
  21. *
  22. * This driver exports a few files in /sys/devices/platform/compal-laptop/:
  23. * wake_up_XXX Whether or not we listen to such wake up events (rw)
  24. *
  25. * In addition to these platform device attributes the driver
  26. * registers itself in the Linux backlight control, power_supply, rfkill
  27. * and hwmon subsystem and is available to userspace under:
  28. *
  29. * /sys/class/backlight/compal-laptop/
  30. * /sys/class/power_supply/compal-laptop/
  31. * /sys/class/rfkill/rfkillX/
  32. * /sys/class/hwmon/hwmonX/
  33. *
  34. * Notes on the power_supply battery interface:
  35. * - the "minimum" design voltage is *the* design voltage
  36. * - the ambient temperature is the average battery temperature
  37. * and the value is an educated guess (see commented code below)
  38. *
  39. *
  40. * This driver might work on other laptops produced by Compal. If you
  41. * want to try it you can pass force=1 as argument to the module which
  42. * will force it to load even when the DMI data doesn't identify the
  43. * laptop as compatible.
  44. *
  45. * Lots of data available at:
  46. * http://service1.marasst.com/Compal/JHL90_91/Service%20Manual/
  47. * JHL90%20service%20manual-Final-0725.pdf
  48. *
  49. *
  50. *
  51. * Support for the Compal JHL90 added by Roald Frederickx
  52. * (roald.frederickx@gmail.com):
  53. * Driver got large revision. Added functionalities: backlight
  54. * power, wake_on_XXX, a hwmon and power_supply interface.
  55. *
  56. * In case this gets merged into the kernel source: I want to dedicate this
  57. * to Kasper Meerts, the awesome guy who showed me Linux and C!
  58. */
  59. /* NOTE: currently the wake_on_XXX, hwmon and power_supply interfaces are
  60. * only enabled on a JHL90 board until it is verified that they work on the
  61. * other boards too. See the extra_features variable. */
  62. #include <linux/module.h>
  63. #include <linux/kernel.h>
  64. #include <linux/init.h>
  65. #include <linux/acpi.h>
  66. #include <linux/dmi.h>
  67. #include <linux/backlight.h>
  68. #include <linux/platform_device.h>
  69. #include <linux/rfkill.h>
  70. #include <linux/hwmon.h>
  71. #include <linux/hwmon-sysfs.h>
  72. #include <linux/power_supply.h>
  73. #include <linux/fb.h>
  74. /* ======= */
  75. /* Defines */
  76. /* ======= */
  77. #define DRIVER_NAME "compal-laptop"
  78. #define DRIVER_VERSION "0.2.7"
  79. #define BACKLIGHT_LEVEL_ADDR 0xB9
  80. #define BACKLIGHT_LEVEL_MAX 7
  81. #define BACKLIGHT_STATE_ADDR 0x59
  82. #define BACKLIGHT_STATE_ON_DATA 0xE1
  83. #define BACKLIGHT_STATE_OFF_DATA 0xE2
  84. #define WAKE_UP_ADDR 0xA4
  85. #define WAKE_UP_PME (1 << 0)
  86. #define WAKE_UP_MODEM (1 << 1)
  87. #define WAKE_UP_LAN (1 << 2)
  88. #define WAKE_UP_WLAN (1 << 4)
  89. #define WAKE_UP_KEY (1 << 6)
  90. #define WAKE_UP_MOUSE (1 << 7)
  91. #define WIRELESS_ADDR 0xBB
  92. #define WIRELESS_WLAN (1 << 0)
  93. #define WIRELESS_BT (1 << 1)
  94. #define WIRELESS_WLAN_EXISTS (1 << 2)
  95. #define WIRELESS_BT_EXISTS (1 << 3)
  96. #define WIRELESS_KILLSWITCH (1 << 4)
  97. #define PWM_ADDRESS 0x46
  98. #define PWM_DISABLE_ADDR 0x59
  99. #define PWM_DISABLE_DATA 0xA5
  100. #define PWM_ENABLE_ADDR 0x59
  101. #define PWM_ENABLE_DATA 0xA8
  102. #define FAN_ADDRESS 0x46
  103. #define FAN_DATA 0x81
  104. #define FAN_FULL_ON_CMD 0x59 /* Doesn't seem to work. Just */
  105. #define FAN_FULL_ON_ENABLE 0x76 /* force the pwm signal to its */
  106. #define FAN_FULL_ON_DISABLE 0x77 /* maximum value instead */
  107. #define TEMP_CPU 0xB0
  108. #define TEMP_CPU_LOCAL 0xB1
  109. #define TEMP_CPU_DTS 0xB5
  110. #define TEMP_NORTHBRIDGE 0xB6
  111. #define TEMP_VGA 0xB4
  112. #define TEMP_SKIN 0xB2
  113. #define BAT_MANUFACTURER_NAME_ADDR 0x10
  114. #define BAT_MANUFACTURER_NAME_LEN 9
  115. #define BAT_MODEL_NAME_ADDR 0x19
  116. #define BAT_MODEL_NAME_LEN 6
  117. #define BAT_SERIAL_NUMBER_ADDR 0xC4
  118. #define BAT_SERIAL_NUMBER_LEN 5
  119. #define BAT_CHARGE_NOW 0xC2
  120. #define BAT_CHARGE_DESIGN 0xCA
  121. #define BAT_VOLTAGE_NOW 0xC6
  122. #define BAT_VOLTAGE_DESIGN 0xC8
  123. #define BAT_CURRENT_NOW 0xD0
  124. #define BAT_CURRENT_AVG 0xD2
  125. #define BAT_POWER 0xD4
  126. #define BAT_CAPACITY 0xCE
  127. #define BAT_TEMP 0xD6
  128. #define BAT_TEMP_AVG 0xD7
  129. #define BAT_STATUS0 0xC1
  130. #define BAT_STATUS1 0xF0
  131. #define BAT_STATUS2 0xF1
  132. #define BAT_STOP_CHARGE1 0xF2
  133. #define BAT_STOP_CHARGE2 0xF3
  134. #define BAT_S0_DISCHARGE (1 << 0)
  135. #define BAT_S0_DISCHRG_CRITICAL (1 << 2)
  136. #define BAT_S0_LOW (1 << 3)
  137. #define BAT_S0_CHARGING (1 << 1)
  138. #define BAT_S0_AC (1 << 7)
  139. #define BAT_S1_EXISTS (1 << 0)
  140. #define BAT_S1_FULL (1 << 1)
  141. #define BAT_S1_EMPTY (1 << 2)
  142. #define BAT_S1_LiION_OR_NiMH (1 << 7)
  143. #define BAT_S2_LOW_LOW (1 << 0)
  144. #define BAT_STOP_CHRG1_BAD_CELL (1 << 1)
  145. #define BAT_STOP_CHRG1_COMM_FAIL (1 << 2)
  146. #define BAT_STOP_CHRG1_OVERVOLTAGE (1 << 6)
  147. #define BAT_STOP_CHRG1_OVERTEMPERATURE (1 << 7)
  148. /* ======= */
  149. /* Structs */
  150. /* ======= */
  151. struct compal_data{
  152. /* Fan control */
  153. struct device *hwmon_dev;
  154. int pwm_enable; /* 0:full on, 1:set by pwm1, 2:control by moterboard */
  155. unsigned char curr_pwm;
  156. /* Power supply */
  157. struct power_supply psy;
  158. struct power_supply_info psy_info;
  159. char bat_model_name[BAT_MODEL_NAME_LEN + 1];
  160. char bat_manufacturer_name[BAT_MANUFACTURER_NAME_LEN + 1];
  161. char bat_serial_number[BAT_SERIAL_NUMBER_LEN + 1];
  162. };
  163. /* =============== */
  164. /* General globals */
  165. /* =============== */
  166. static int force;
  167. module_param(force, bool, 0);
  168. MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
  169. /* Support for the wake_on_XXX, hwmon and power_supply interface. Currently
  170. * only gets enabled on a JHL90 board. Might work with the others too */
  171. static bool extra_features;
  172. /* Nasty stuff. For some reason the fan control is very un-linear. I've
  173. * come up with these values by looping through the possible inputs and
  174. * watching the output of address 0x4F (do an ec_transaction writing 0x33
  175. * into 0x4F and read a few bytes from the output, like so:
  176. * u8 writeData = 0x33;
  177. * ec_transaction(0x4F, &writeData, 1, buffer, 32, 0);
  178. * That address is labled "fan1 table information" in the service manual.
  179. * It should be clear which value in 'buffer' changes). This seems to be
  180. * related to fan speed. It isn't a proper 'realtime' fan speed value
  181. * though, because physically stopping or speeding up the fan doesn't
  182. * change it. It might be the average voltage or current of the pwm output.
  183. * Nevertheless, it is more fine-grained than the actual RPM reading */
  184. static const unsigned char pwm_lookup_table[256] = {
  185. 0, 0, 0, 1, 1, 1, 2, 253, 254, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6,
  186. 7, 7, 7, 8, 86, 86, 9, 9, 9, 10, 10, 10, 11, 92, 92, 12, 12, 95,
  187. 13, 66, 66, 14, 14, 98, 15, 15, 15, 16, 16, 67, 17, 17, 72, 18, 70,
  188. 75, 19, 90, 90, 73, 73, 73, 21, 21, 91, 91, 91, 96, 23, 94, 94, 94,
  189. 94, 94, 94, 94, 94, 94, 94, 141, 141, 238, 223, 192, 139, 139, 139,
  190. 139, 139, 142, 142, 142, 142, 142, 78, 78, 78, 78, 78, 76, 76, 76,
  191. 76, 76, 79, 79, 79, 79, 79, 79, 79, 20, 20, 20, 20, 20, 22, 22, 22,
  192. 22, 22, 24, 24, 24, 24, 24, 24, 219, 219, 219, 219, 219, 219, 219,
  193. 219, 27, 27, 188, 188, 28, 28, 28, 29, 186, 186, 186, 186, 186,
  194. 186, 186, 186, 186, 186, 31, 31, 31, 31, 31, 32, 32, 32, 41, 33,
  195. 33, 33, 33, 33, 252, 252, 34, 34, 34, 43, 35, 35, 35, 36, 36, 38,
  196. 206, 206, 206, 206, 206, 206, 206, 206, 206, 37, 37, 37, 46, 46,
  197. 47, 47, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 48, 48,
  198. 48, 48, 48, 40, 40, 40, 49, 42, 42, 42, 42, 42, 42, 42, 42, 44,
  199. 189, 189, 189, 189, 54, 54, 45, 45, 45, 45, 45, 45, 45, 45, 251,
  200. 191, 199, 199, 199, 199, 199, 215, 215, 215, 215, 187, 187, 187,
  201. 187, 187, 193, 50
  202. };
  203. /* ========================= */
  204. /* Hardware access functions */
  205. /* ========================= */
  206. /* General access */
  207. static u8 ec_read_u8(u8 addr)
  208. {
  209. u8 value;
  210. ec_read(addr, &value);
  211. return value;
  212. }
  213. static s8 ec_read_s8(u8 addr)
  214. {
  215. return (s8)ec_read_u8(addr);
  216. }
  217. static u16 ec_read_u16(u8 addr)
  218. {
  219. int hi, lo;
  220. lo = ec_read_u8(addr);
  221. hi = ec_read_u8(addr + 1);
  222. return (hi << 8) + lo;
  223. }
  224. static s16 ec_read_s16(u8 addr)
  225. {
  226. return (s16) ec_read_u16(addr);
  227. }
  228. static void ec_read_sequence(u8 addr, u8 *buf, int len)
  229. {
  230. int i;
  231. for (i = 0; i < len; i++)
  232. ec_read(addr + i, buf + i);
  233. }
  234. /* Backlight access */
  235. static int set_backlight_level(int level)
  236. {
  237. if (level < 0 || level > BACKLIGHT_LEVEL_MAX)
  238. return -EINVAL;
  239. ec_write(BACKLIGHT_LEVEL_ADDR, level);
  240. return 1;
  241. }
  242. static int get_backlight_level(void)
  243. {
  244. return (int) ec_read_u8(BACKLIGHT_LEVEL_ADDR);
  245. }
  246. static void set_backlight_state(bool on)
  247. {
  248. u8 data = on ? BACKLIGHT_STATE_ON_DATA : BACKLIGHT_STATE_OFF_DATA;
  249. ec_transaction(BACKLIGHT_STATE_ADDR, &data, 1, NULL, 0, 0);
  250. }
  251. /* Fan control access */
  252. static void pwm_enable_control(void)
  253. {
  254. unsigned char writeData = PWM_ENABLE_DATA;
  255. ec_transaction(PWM_ENABLE_ADDR, &writeData, 1, NULL, 0, 0);
  256. }
  257. static void pwm_disable_control(void)
  258. {
  259. unsigned char writeData = PWM_DISABLE_DATA;
  260. ec_transaction(PWM_DISABLE_ADDR, &writeData, 1, NULL, 0, 0);
  261. }
  262. static void set_pwm(int pwm)
  263. {
  264. ec_transaction(PWM_ADDRESS, &pwm_lookup_table[pwm], 1, NULL, 0, 0);
  265. }
  266. static int get_fan_rpm(void)
  267. {
  268. u8 value, data = FAN_DATA;
  269. ec_transaction(FAN_ADDRESS, &data, 1, &value, 1, 0);
  270. return 100 * (int)value;
  271. }
  272. /* =================== */
  273. /* Interface functions */
  274. /* =================== */
  275. /* Backlight interface */
  276. static int bl_get_brightness(struct backlight_device *b)
  277. {
  278. return get_backlight_level();
  279. }
  280. static int bl_update_status(struct backlight_device *b)
  281. {
  282. int ret = set_backlight_level(b->props.brightness);
  283. if (ret)
  284. return ret;
  285. set_backlight_state((b->props.power == FB_BLANK_UNBLANK)
  286. && !(b->props.state & BL_CORE_SUSPENDED)
  287. && !(b->props.state & BL_CORE_FBBLANK));
  288. return 0;
  289. }
  290. static const struct backlight_ops compalbl_ops = {
  291. .get_brightness = bl_get_brightness,
  292. .update_status = bl_update_status,
  293. };
  294. /* Wireless interface */
  295. static int compal_rfkill_set(void *data, bool blocked)
  296. {
  297. unsigned long radio = (unsigned long) data;
  298. u8 result = ec_read_u8(WIRELESS_ADDR);
  299. u8 value;
  300. if (!blocked)
  301. value = (u8) (result | radio);
  302. else
  303. value = (u8) (result & ~radio);
  304. ec_write(WIRELESS_ADDR, value);
  305. return 0;
  306. }
  307. static void compal_rfkill_poll(struct rfkill *rfkill, void *data)
  308. {
  309. u8 result = ec_read_u8(WIRELESS_ADDR);
  310. bool hw_blocked = !(result & WIRELESS_KILLSWITCH);
  311. rfkill_set_hw_state(rfkill, hw_blocked);
  312. }
  313. static const struct rfkill_ops compal_rfkill_ops = {
  314. .poll = compal_rfkill_poll,
  315. .set_block = compal_rfkill_set,
  316. };
  317. /* Wake_up interface */
  318. #define SIMPLE_MASKED_STORE_SHOW(NAME, ADDR, MASK) \
  319. static ssize_t NAME##_show(struct device *dev, \
  320. struct device_attribute *attr, char *buf) \
  321. { \
  322. return sprintf(buf, "%d\n", ((ec_read_u8(ADDR) & MASK) != 0)); \
  323. } \
  324. static ssize_t NAME##_store(struct device *dev, \
  325. struct device_attribute *attr, const char *buf, size_t count) \
  326. { \
  327. int state; \
  328. u8 old_val = ec_read_u8(ADDR); \
  329. if (sscanf(buf, "%d", &state) != 1 || (state < 0 || state > 1)) \
  330. return -EINVAL; \
  331. ec_write(ADDR, state ? (old_val | MASK) : (old_val & ~MASK)); \
  332. return count; \
  333. }
  334. SIMPLE_MASKED_STORE_SHOW(wake_up_pme, WAKE_UP_ADDR, WAKE_UP_PME)
  335. SIMPLE_MASKED_STORE_SHOW(wake_up_modem, WAKE_UP_ADDR, WAKE_UP_MODEM)
  336. SIMPLE_MASKED_STORE_SHOW(wake_up_lan, WAKE_UP_ADDR, WAKE_UP_LAN)
  337. SIMPLE_MASKED_STORE_SHOW(wake_up_wlan, WAKE_UP_ADDR, WAKE_UP_WLAN)
  338. SIMPLE_MASKED_STORE_SHOW(wake_up_key, WAKE_UP_ADDR, WAKE_UP_KEY)
  339. SIMPLE_MASKED_STORE_SHOW(wake_up_mouse, WAKE_UP_ADDR, WAKE_UP_MOUSE)
  340. /* General hwmon interface */
  341. static ssize_t hwmon_name_show(struct device *dev,
  342. struct device_attribute *attr, char *buf)
  343. {
  344. return sprintf(buf, "%s\n", DRIVER_NAME);
  345. }
  346. /* Fan control interface */
  347. static ssize_t pwm_enable_show(struct device *dev,
  348. struct device_attribute *attr, char *buf)
  349. {
  350. struct compal_data *data = dev_get_drvdata(dev);
  351. return sprintf(buf, "%d\n", data->pwm_enable);
  352. }
  353. static ssize_t pwm_enable_store(struct device *dev,
  354. struct device_attribute *attr, const char *buf, size_t count)
  355. {
  356. struct compal_data *data = dev_get_drvdata(dev);
  357. long val;
  358. int err;
  359. err = strict_strtol(buf, 10, &val);
  360. if (err)
  361. return err;
  362. if (val < 0)
  363. return -EINVAL;
  364. data->pwm_enable = val;
  365. switch (val) {
  366. case 0: /* Full speed */
  367. pwm_enable_control();
  368. set_pwm(255);
  369. break;
  370. case 1: /* As set by pwm1 */
  371. pwm_enable_control();
  372. set_pwm(data->curr_pwm);
  373. break;
  374. default: /* Control by motherboard */
  375. pwm_disable_control();
  376. break;
  377. }
  378. return count;
  379. }
  380. static ssize_t pwm_show(struct device *dev, struct device_attribute *attr,
  381. char *buf)
  382. {
  383. struct compal_data *data = dev_get_drvdata(dev);
  384. return sprintf(buf, "%hhu\n", data->curr_pwm);
  385. }
  386. static ssize_t pwm_store(struct device *dev, struct device_attribute *attr,
  387. const char *buf, size_t count)
  388. {
  389. struct compal_data *data = dev_get_drvdata(dev);
  390. long val;
  391. int err;
  392. err = strict_strtol(buf, 10, &val);
  393. if (err)
  394. return err;
  395. if (val < 0 || val > 255)
  396. return -EINVAL;
  397. data->curr_pwm = val;
  398. if (data->pwm_enable != 1)
  399. return count;
  400. set_pwm(val);
  401. return count;
  402. }
  403. static ssize_t fan_show(struct device *dev, struct device_attribute *attr,
  404. char *buf)
  405. {
  406. return sprintf(buf, "%d\n", get_fan_rpm());
  407. }
  408. /* Temperature interface */
  409. #define TEMPERATURE_SHOW_TEMP_AND_LABEL(POSTFIX, ADDRESS, LABEL) \
  410. static ssize_t temp_##POSTFIX(struct device *dev, \
  411. struct device_attribute *attr, char *buf) \
  412. { \
  413. return sprintf(buf, "%d\n", 1000 * (int)ec_read_s8(ADDRESS)); \
  414. } \
  415. static ssize_t label_##POSTFIX(struct device *dev, \
  416. struct device_attribute *attr, char *buf) \
  417. { \
  418. return sprintf(buf, "%s\n", LABEL); \
  419. }
  420. /* Labels as in service guide */
  421. TEMPERATURE_SHOW_TEMP_AND_LABEL(cpu, TEMP_CPU, "CPU_TEMP");
  422. TEMPERATURE_SHOW_TEMP_AND_LABEL(cpu_local, TEMP_CPU_LOCAL, "CPU_TEMP_LOCAL");
  423. TEMPERATURE_SHOW_TEMP_AND_LABEL(cpu_DTS, TEMP_CPU_DTS, "CPU_DTS");
  424. TEMPERATURE_SHOW_TEMP_AND_LABEL(northbridge,TEMP_NORTHBRIDGE,"NorthBridge");
  425. TEMPERATURE_SHOW_TEMP_AND_LABEL(vga, TEMP_VGA, "VGA_TEMP");
  426. TEMPERATURE_SHOW_TEMP_AND_LABEL(SKIN, TEMP_SKIN, "SKIN_TEMP90");
  427. /* Power supply interface */
  428. static int bat_status(void)
  429. {
  430. u8 status0 = ec_read_u8(BAT_STATUS0);
  431. u8 status1 = ec_read_u8(BAT_STATUS1);
  432. if (status0 & BAT_S0_CHARGING)
  433. return POWER_SUPPLY_STATUS_CHARGING;
  434. if (status0 & BAT_S0_DISCHARGE)
  435. return POWER_SUPPLY_STATUS_DISCHARGING;
  436. if (status1 & BAT_S1_FULL)
  437. return POWER_SUPPLY_STATUS_FULL;
  438. return POWER_SUPPLY_STATUS_NOT_CHARGING;
  439. }
  440. static int bat_health(void)
  441. {
  442. u8 status = ec_read_u8(BAT_STOP_CHARGE1);
  443. if (status & BAT_STOP_CHRG1_OVERTEMPERATURE)
  444. return POWER_SUPPLY_HEALTH_OVERHEAT;
  445. if (status & BAT_STOP_CHRG1_OVERVOLTAGE)
  446. return POWER_SUPPLY_HEALTH_OVERVOLTAGE;
  447. if (status & BAT_STOP_CHRG1_BAD_CELL)
  448. return POWER_SUPPLY_HEALTH_DEAD;
  449. if (status & BAT_STOP_CHRG1_COMM_FAIL)
  450. return POWER_SUPPLY_HEALTH_UNKNOWN;
  451. return POWER_SUPPLY_HEALTH_GOOD;
  452. }
  453. static int bat_is_present(void)
  454. {
  455. u8 status = ec_read_u8(BAT_STATUS2);
  456. return ((status & BAT_S1_EXISTS) != 0);
  457. }
  458. static int bat_technology(void)
  459. {
  460. u8 status = ec_read_u8(BAT_STATUS1);
  461. if (status & BAT_S1_LiION_OR_NiMH)
  462. return POWER_SUPPLY_TECHNOLOGY_LION;
  463. return POWER_SUPPLY_TECHNOLOGY_NiMH;
  464. }
  465. static int bat_capacity_level(void)
  466. {
  467. u8 status0 = ec_read_u8(BAT_STATUS0);
  468. u8 status1 = ec_read_u8(BAT_STATUS1);
  469. u8 status2 = ec_read_u8(BAT_STATUS2);
  470. if (status0 & BAT_S0_DISCHRG_CRITICAL
  471. || status1 & BAT_S1_EMPTY
  472. || status2 & BAT_S2_LOW_LOW)
  473. return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
  474. if (status0 & BAT_S0_LOW)
  475. return POWER_SUPPLY_CAPACITY_LEVEL_LOW;
  476. if (status1 & BAT_S1_FULL)
  477. return POWER_SUPPLY_CAPACITY_LEVEL_FULL;
  478. return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
  479. }
  480. static int bat_get_property(struct power_supply *psy,
  481. enum power_supply_property psp,
  482. union power_supply_propval *val)
  483. {
  484. struct compal_data *data;
  485. data = container_of(psy, struct compal_data, psy);
  486. switch (psp) {
  487. case POWER_SUPPLY_PROP_STATUS:
  488. val->intval = bat_status();
  489. break;
  490. case POWER_SUPPLY_PROP_HEALTH:
  491. val->intval = bat_health();
  492. break;
  493. case POWER_SUPPLY_PROP_PRESENT:
  494. val->intval = bat_is_present();
  495. break;
  496. case POWER_SUPPLY_PROP_TECHNOLOGY:
  497. val->intval = bat_technology();
  498. break;
  499. case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: /* THE design voltage... */
  500. val->intval = ec_read_u16(BAT_VOLTAGE_DESIGN) * 1000;
  501. break;
  502. case POWER_SUPPLY_PROP_VOLTAGE_NOW:
  503. val->intval = ec_read_u16(BAT_VOLTAGE_NOW) * 1000;
  504. break;
  505. case POWER_SUPPLY_PROP_CURRENT_NOW:
  506. val->intval = ec_read_s16(BAT_CURRENT_NOW) * 1000;
  507. break;
  508. case POWER_SUPPLY_PROP_CURRENT_AVG:
  509. val->intval = ec_read_s16(BAT_CURRENT_AVG) * 1000;
  510. break;
  511. case POWER_SUPPLY_PROP_POWER_NOW:
  512. val->intval = ec_read_u8(BAT_POWER) * 1000000;
  513. break;
  514. case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
  515. val->intval = ec_read_u16(BAT_CHARGE_DESIGN) * 1000;
  516. break;
  517. case POWER_SUPPLY_PROP_CHARGE_NOW:
  518. val->intval = ec_read_u16(BAT_CHARGE_NOW) * 1000;
  519. break;
  520. case POWER_SUPPLY_PROP_CAPACITY:
  521. val->intval = ec_read_u8(BAT_CAPACITY);
  522. break;
  523. case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
  524. val->intval = bat_capacity_level();
  525. break;
  526. /* It smees that BAT_TEMP_AVG is a (2's complement?) value showing
  527. * the number of degrees, whereas BAT_TEMP is somewhat more
  528. * complicated. It looks like this is a negative nember with a
  529. * 100/256 divider and an offset of 222. Both were determined
  530. * experimentally by comparing BAT_TEMP and BAT_TEMP_AVG. */
  531. case POWER_SUPPLY_PROP_TEMP:
  532. val->intval = ((222 - (int)ec_read_u8(BAT_TEMP)) * 1000) >> 8;
  533. break;
  534. case POWER_SUPPLY_PROP_TEMP_AMBIENT: /* Ambient, Avg, ... same thing */
  535. val->intval = ec_read_s8(BAT_TEMP_AVG) * 10;
  536. break;
  537. /* Neither the model name nor manufacturer name work for me. */
  538. case POWER_SUPPLY_PROP_MODEL_NAME:
  539. val->strval = data->bat_model_name;
  540. break;
  541. case POWER_SUPPLY_PROP_MANUFACTURER:
  542. val->strval = data->bat_manufacturer_name;
  543. break;
  544. case POWER_SUPPLY_PROP_SERIAL_NUMBER:
  545. val->strval = data->bat_serial_number;
  546. break;
  547. default:
  548. break;
  549. }
  550. return 0;
  551. }
  552. /* ============== */
  553. /* Driver Globals */
  554. /* ============== */
  555. static DEVICE_ATTR(wake_up_pme,
  556. 0644, wake_up_pme_show, wake_up_pme_store);
  557. static DEVICE_ATTR(wake_up_modem,
  558. 0644, wake_up_modem_show, wake_up_modem_store);
  559. static DEVICE_ATTR(wake_up_lan,
  560. 0644, wake_up_lan_show, wake_up_lan_store);
  561. static DEVICE_ATTR(wake_up_wlan,
  562. 0644, wake_up_wlan_show, wake_up_wlan_store);
  563. static DEVICE_ATTR(wake_up_key,
  564. 0644, wake_up_key_show, wake_up_key_store);
  565. static DEVICE_ATTR(wake_up_mouse,
  566. 0644, wake_up_mouse_show, wake_up_mouse_store);
  567. static SENSOR_DEVICE_ATTR(name, S_IRUGO, hwmon_name_show, NULL, 1);
  568. static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, fan_show, NULL, 1);
  569. static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, temp_cpu, NULL, 1);
  570. static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, temp_cpu_local, NULL, 1);
  571. static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, temp_cpu_DTS, NULL, 1);
  572. static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, temp_northbridge, NULL, 1);
  573. static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, temp_vga, NULL, 1);
  574. static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, temp_SKIN, NULL, 1);
  575. static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, label_cpu, NULL, 1);
  576. static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, label_cpu_local, NULL, 1);
  577. static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, label_cpu_DTS, NULL, 1);
  578. static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, label_northbridge, NULL, 1);
  579. static SENSOR_DEVICE_ATTR(temp5_label, S_IRUGO, label_vga, NULL, 1);
  580. static SENSOR_DEVICE_ATTR(temp6_label, S_IRUGO, label_SKIN, NULL, 1);
  581. static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, pwm_show, pwm_store, 1);
  582. static SENSOR_DEVICE_ATTR(pwm1_enable,
  583. S_IRUGO | S_IWUSR, pwm_enable_show, pwm_enable_store, 0);
  584. static struct attribute *compal_attributes[] = {
  585. &dev_attr_wake_up_pme.attr,
  586. &dev_attr_wake_up_modem.attr,
  587. &dev_attr_wake_up_lan.attr,
  588. &dev_attr_wake_up_wlan.attr,
  589. &dev_attr_wake_up_key.attr,
  590. &dev_attr_wake_up_mouse.attr,
  591. /* Maybe put the sensor-stuff in a separate hwmon-driver? That way,
  592. * the hwmon sysfs won't be cluttered with the above files. */
  593. &sensor_dev_attr_name.dev_attr.attr,
  594. &sensor_dev_attr_pwm1_enable.dev_attr.attr,
  595. &sensor_dev_attr_pwm1.dev_attr.attr,
  596. &sensor_dev_attr_fan1_input.dev_attr.attr,
  597. &sensor_dev_attr_temp1_input.dev_attr.attr,
  598. &sensor_dev_attr_temp2_input.dev_attr.attr,
  599. &sensor_dev_attr_temp3_input.dev_attr.attr,
  600. &sensor_dev_attr_temp4_input.dev_attr.attr,
  601. &sensor_dev_attr_temp5_input.dev_attr.attr,
  602. &sensor_dev_attr_temp6_input.dev_attr.attr,
  603. &sensor_dev_attr_temp1_label.dev_attr.attr,
  604. &sensor_dev_attr_temp2_label.dev_attr.attr,
  605. &sensor_dev_attr_temp3_label.dev_attr.attr,
  606. &sensor_dev_attr_temp4_label.dev_attr.attr,
  607. &sensor_dev_attr_temp5_label.dev_attr.attr,
  608. &sensor_dev_attr_temp6_label.dev_attr.attr,
  609. NULL
  610. };
  611. static struct attribute_group compal_attribute_group = {
  612. .attrs = compal_attributes
  613. };
  614. static int __devinit compal_probe(struct platform_device *);
  615. static int __devexit compal_remove(struct platform_device *);
  616. static struct platform_driver compal_driver = {
  617. .driver = {
  618. .name = DRIVER_NAME,
  619. .owner = THIS_MODULE,
  620. },
  621. .probe = compal_probe,
  622. .remove = __devexit_p(compal_remove)
  623. };
  624. static enum power_supply_property compal_bat_properties[] = {
  625. POWER_SUPPLY_PROP_STATUS,
  626. POWER_SUPPLY_PROP_HEALTH,
  627. POWER_SUPPLY_PROP_PRESENT,
  628. POWER_SUPPLY_PROP_TECHNOLOGY,
  629. POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
  630. POWER_SUPPLY_PROP_VOLTAGE_NOW,
  631. POWER_SUPPLY_PROP_CURRENT_NOW,
  632. POWER_SUPPLY_PROP_CURRENT_AVG,
  633. POWER_SUPPLY_PROP_POWER_NOW,
  634. POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
  635. POWER_SUPPLY_PROP_CHARGE_NOW,
  636. POWER_SUPPLY_PROP_CAPACITY,
  637. POWER_SUPPLY_PROP_CAPACITY_LEVEL,
  638. POWER_SUPPLY_PROP_TEMP,
  639. POWER_SUPPLY_PROP_TEMP_AMBIENT,
  640. POWER_SUPPLY_PROP_MODEL_NAME,
  641. POWER_SUPPLY_PROP_MANUFACTURER,
  642. POWER_SUPPLY_PROP_SERIAL_NUMBER,
  643. };
  644. static struct backlight_device *compalbl_device;
  645. static struct platform_device *compal_device;
  646. static struct rfkill *wifi_rfkill;
  647. static struct rfkill *bt_rfkill;
  648. /* =================================== */
  649. /* Initialization & clean-up functions */
  650. /* =================================== */
  651. static int dmi_check_cb(const struct dmi_system_id *id)
  652. {
  653. printk(KERN_INFO DRIVER_NAME": Identified laptop model '%s'\n",
  654. id->ident);
  655. extra_features = false;
  656. return 0;
  657. }
  658. static int dmi_check_cb_extra(const struct dmi_system_id *id)
  659. {
  660. printk(KERN_INFO DRIVER_NAME": Identified laptop model '%s', "
  661. "enabling extra features\n",
  662. id->ident);
  663. extra_features = true;
  664. return 0;
  665. }
  666. static struct dmi_system_id __initdata compal_dmi_table[] = {
  667. {
  668. .ident = "FL90/IFL90",
  669. .matches = {
  670. DMI_MATCH(DMI_BOARD_NAME, "IFL90"),
  671. DMI_MATCH(DMI_BOARD_VERSION, "IFT00"),
  672. },
  673. .callback = dmi_check_cb
  674. },
  675. {
  676. .ident = "FL90/IFL90",
  677. .matches = {
  678. DMI_MATCH(DMI_BOARD_NAME, "IFL90"),
  679. DMI_MATCH(DMI_BOARD_VERSION, "REFERENCE"),
  680. },
  681. .callback = dmi_check_cb
  682. },
  683. {
  684. .ident = "FL91/IFL91",
  685. .matches = {
  686. DMI_MATCH(DMI_BOARD_NAME, "IFL91"),
  687. DMI_MATCH(DMI_BOARD_VERSION, "IFT00"),
  688. },
  689. .callback = dmi_check_cb
  690. },
  691. {
  692. .ident = "FL92/JFL92",
  693. .matches = {
  694. DMI_MATCH(DMI_BOARD_NAME, "JFL92"),
  695. DMI_MATCH(DMI_BOARD_VERSION, "IFT00"),
  696. },
  697. .callback = dmi_check_cb
  698. },
  699. {
  700. .ident = "FT00/IFT00",
  701. .matches = {
  702. DMI_MATCH(DMI_BOARD_NAME, "IFT00"),
  703. DMI_MATCH(DMI_BOARD_VERSION, "IFT00"),
  704. },
  705. .callback = dmi_check_cb
  706. },
  707. {
  708. .ident = "Dell Mini 9",
  709. .matches = {
  710. DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
  711. DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 910"),
  712. },
  713. .callback = dmi_check_cb
  714. },
  715. {
  716. .ident = "Dell Mini 10",
  717. .matches = {
  718. DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
  719. DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1010"),
  720. },
  721. .callback = dmi_check_cb
  722. },
  723. {
  724. .ident = "Dell Mini 10v",
  725. .matches = {
  726. DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
  727. DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1011"),
  728. },
  729. .callback = dmi_check_cb
  730. },
  731. {
  732. .ident = "Dell Mini 1012",
  733. .matches = {
  734. DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
  735. DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1012"),
  736. },
  737. .callback = dmi_check_cb
  738. },
  739. {
  740. .ident = "Dell Inspiron 11z",
  741. .matches = {
  742. DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
  743. DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1110"),
  744. },
  745. .callback = dmi_check_cb
  746. },
  747. {
  748. .ident = "Dell Mini 12",
  749. .matches = {
  750. DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
  751. DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1210"),
  752. },
  753. .callback = dmi_check_cb
  754. },
  755. {
  756. .ident = "JHL90",
  757. .matches = {
  758. DMI_MATCH(DMI_BOARD_NAME, "JHL90"),
  759. DMI_MATCH(DMI_BOARD_VERSION, "REFERENCE"),
  760. },
  761. .callback = dmi_check_cb_extra
  762. },
  763. {
  764. .ident = "KHLB2",
  765. .matches = {
  766. DMI_MATCH(DMI_BOARD_NAME, "KHLB2"),
  767. DMI_MATCH(DMI_BOARD_VERSION, "REFERENCE"),
  768. },
  769. .callback = dmi_check_cb_extra
  770. },
  771. { }
  772. };
  773. static void initialize_power_supply_data(struct compal_data *data)
  774. {
  775. data->psy.name = DRIVER_NAME;
  776. data->psy.type = POWER_SUPPLY_TYPE_BATTERY;
  777. data->psy.properties = compal_bat_properties;
  778. data->psy.num_properties = ARRAY_SIZE(compal_bat_properties);
  779. data->psy.get_property = bat_get_property;
  780. ec_read_sequence(BAT_MANUFACTURER_NAME_ADDR,
  781. data->bat_manufacturer_name,
  782. BAT_MANUFACTURER_NAME_LEN);
  783. data->bat_manufacturer_name[BAT_MANUFACTURER_NAME_LEN] = 0;
  784. ec_read_sequence(BAT_MODEL_NAME_ADDR,
  785. data->bat_model_name,
  786. BAT_MODEL_NAME_LEN);
  787. data->bat_model_name[BAT_MODEL_NAME_LEN] = 0;
  788. scnprintf(data->bat_serial_number, BAT_SERIAL_NUMBER_LEN + 1, "%d",
  789. ec_read_u16(BAT_SERIAL_NUMBER_ADDR));
  790. }
  791. static void initialize_fan_control_data(struct compal_data *data)
  792. {
  793. data->pwm_enable = 2; /* Keep motherboard in control for now */
  794. data->curr_pwm = 255; /* Try not to cause a CPU_on_fire exception
  795. if we take over... */
  796. }
  797. static int setup_rfkill(void)
  798. {
  799. int ret;
  800. wifi_rfkill = rfkill_alloc("compal-wifi", &compal_device->dev,
  801. RFKILL_TYPE_WLAN, &compal_rfkill_ops,
  802. (void *) WIRELESS_WLAN);
  803. if (!wifi_rfkill)
  804. return -ENOMEM;
  805. ret = rfkill_register(wifi_rfkill);
  806. if (ret)
  807. goto err_wifi;
  808. bt_rfkill = rfkill_alloc("compal-bluetooth", &compal_device->dev,
  809. RFKILL_TYPE_BLUETOOTH, &compal_rfkill_ops,
  810. (void *) WIRELESS_BT);
  811. if (!bt_rfkill) {
  812. ret = -ENOMEM;
  813. goto err_allocate_bt;
  814. }
  815. ret = rfkill_register(bt_rfkill);
  816. if (ret)
  817. goto err_register_bt;
  818. return 0;
  819. err_register_bt:
  820. rfkill_destroy(bt_rfkill);
  821. err_allocate_bt:
  822. rfkill_unregister(wifi_rfkill);
  823. err_wifi:
  824. rfkill_destroy(wifi_rfkill);
  825. return ret;
  826. }
  827. static int __init compal_init(void)
  828. {
  829. int ret;
  830. if (acpi_disabled) {
  831. printk(KERN_ERR DRIVER_NAME": ACPI needs to be enabled for "
  832. "this driver to work!\n");
  833. return -ENODEV;
  834. }
  835. if (!force && !dmi_check_system(compal_dmi_table)) {
  836. printk(KERN_ERR DRIVER_NAME": Motherboard not recognized (You "
  837. "could try the module's force-parameter)");
  838. return -ENODEV;
  839. }
  840. if (!acpi_video_backlight_support()) {
  841. struct backlight_properties props;
  842. memset(&props, 0, sizeof(struct backlight_properties));
  843. props.max_brightness = BACKLIGHT_LEVEL_MAX;
  844. compalbl_device = backlight_device_register(DRIVER_NAME,
  845. NULL, NULL,
  846. &compalbl_ops,
  847. &props);
  848. if (IS_ERR(compalbl_device))
  849. return PTR_ERR(compalbl_device);
  850. }
  851. ret = platform_driver_register(&compal_driver);
  852. if (ret)
  853. goto err_backlight;
  854. compal_device = platform_device_alloc(DRIVER_NAME, -1);
  855. if (!compal_device) {
  856. ret = -ENOMEM;
  857. goto err_platform_driver;
  858. }
  859. ret = platform_device_add(compal_device); /* This calls compal_probe */
  860. if (ret)
  861. goto err_platform_device;
  862. ret = setup_rfkill();
  863. if (ret)
  864. goto err_rfkill;
  865. printk(KERN_INFO DRIVER_NAME": Driver "DRIVER_VERSION
  866. " successfully loaded\n");
  867. return 0;
  868. err_rfkill:
  869. platform_device_del(compal_device);
  870. err_platform_device:
  871. platform_device_put(compal_device);
  872. err_platform_driver:
  873. platform_driver_unregister(&compal_driver);
  874. err_backlight:
  875. backlight_device_unregister(compalbl_device);
  876. return ret;
  877. }
  878. static int __devinit compal_probe(struct platform_device *pdev)
  879. {
  880. int err;
  881. struct compal_data *data;
  882. if (!extra_features)
  883. return 0;
  884. /* Fan control */
  885. data = kzalloc(sizeof(struct compal_data), GFP_KERNEL);
  886. if (!data)
  887. return -ENOMEM;
  888. initialize_fan_control_data(data);
  889. err = sysfs_create_group(&pdev->dev.kobj, &compal_attribute_group);
  890. if (err)
  891. return err;
  892. data->hwmon_dev = hwmon_device_register(&pdev->dev);
  893. if (IS_ERR(data->hwmon_dev)) {
  894. err = PTR_ERR(data->hwmon_dev);
  895. sysfs_remove_group(&pdev->dev.kobj,
  896. &compal_attribute_group);
  897. kfree(data);
  898. return err;
  899. }
  900. /* Power supply */
  901. initialize_power_supply_data(data);
  902. power_supply_register(&compal_device->dev, &data->psy);
  903. platform_set_drvdata(pdev, data);
  904. return 0;
  905. }
  906. static void __exit compal_cleanup(void)
  907. {
  908. platform_device_unregister(compal_device);
  909. platform_driver_unregister(&compal_driver);
  910. backlight_device_unregister(compalbl_device);
  911. rfkill_unregister(wifi_rfkill);
  912. rfkill_unregister(bt_rfkill);
  913. rfkill_destroy(wifi_rfkill);
  914. rfkill_destroy(bt_rfkill);
  915. printk(KERN_INFO DRIVER_NAME": Driver unloaded\n");
  916. }
  917. static int __devexit compal_remove(struct platform_device *pdev)
  918. {
  919. struct compal_data *data;
  920. if (!extra_features)
  921. return 0;
  922. printk(KERN_INFO DRIVER_NAME": Unloading: resetting fan control "
  923. "to motherboard\n");
  924. pwm_disable_control();
  925. data = platform_get_drvdata(pdev);
  926. hwmon_device_unregister(data->hwmon_dev);
  927. power_supply_unregister(&data->psy);
  928. platform_set_drvdata(pdev, NULL);
  929. kfree(data);
  930. sysfs_remove_group(&pdev->dev.kobj, &compal_attribute_group);
  931. return 0;
  932. }
  933. module_init(compal_init);
  934. module_exit(compal_cleanup);
  935. MODULE_AUTHOR("Cezary Jackiewicz");
  936. MODULE_AUTHOR("Roald Frederickx (roald.frederickx@gmail.com)");
  937. MODULE_DESCRIPTION("Compal Laptop Support");
  938. MODULE_VERSION(DRIVER_VERSION);
  939. MODULE_LICENSE("GPL");
  940. MODULE_ALIAS("dmi:*:rnIFL90:rvrIFT00:*");
  941. MODULE_ALIAS("dmi:*:rnIFL90:rvrREFERENCE:*");
  942. MODULE_ALIAS("dmi:*:rnIFL91:rvrIFT00:*");
  943. MODULE_ALIAS("dmi:*:rnJFL92:rvrIFT00:*");
  944. MODULE_ALIAS("dmi:*:rnIFT00:rvrIFT00:*");
  945. MODULE_ALIAS("dmi:*:rnJHL90:rvrREFERENCE:*");
  946. MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron910:*");
  947. MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1010:*");
  948. MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1011:*");
  949. MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1012:*");
  950. MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1110:*");
  951. MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1210:*");