i8k.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:19k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * i8k.c -- Linux driver for accessing the SMM BIOS on Dell laptops.
  3.  *     See http://www.debian.org/~dz/i8k/ for more information
  4.  *     and for latest version of this driver.
  5.  *
  6.  * Copyright (C) 2001  Massimo Dal Zotto <dz@debian.org>
  7.  *
  8.  * This program is free software; you can redistribute it and/or modify it
  9.  * under the terms of the GNU General Public License as published by the
  10.  * Free Software Foundation; either version 2, or (at your option) any
  11.  * later version.
  12.  *
  13.  * This program is distributed in the hope that it will be useful, but
  14.  * WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.  * General Public License for more details.
  17.  */
  18. #include <linux/module.h>
  19. #include <linux/version.h>
  20. #include <linux/types.h>
  21. #include <linux/init.h>
  22. #include <linux/proc_fs.h>
  23. #include <linux/apm_bios.h>
  24. #include <linux/kbd_kern.h>
  25. #include <linux/kbd_ll.h>
  26. #include <linux/timer.h>
  27. #include <asm/uaccess.h>
  28. #include <asm/io.h>
  29. #include <linux/i8k.h>
  30. #define I8K_VERSION "1.13 14/05/2002"
  31. #define I8K_SMM_FN_STATUS 0x0025
  32. #define I8K_SMM_POWER_STATUS 0x0069
  33. #define I8K_SMM_SET_FAN 0x01a3
  34. #define I8K_SMM_GET_FAN 0x00a3
  35. #define I8K_SMM_GET_SPEED 0x02a3
  36. #define I8K_SMM_GET_TEMP 0x10a3
  37. #define I8K_SMM_GET_DELL_SIG 0xffa3
  38. #define I8K_SMM_BIOS_VERSION 0x00a6
  39. #define I8K_FAN_MULT 30
  40. #define I8K_MAX_TEMP 127
  41. #define I8K_FN_NONE 0x00
  42. #define I8K_FN_UP 0x01
  43. #define I8K_FN_DOWN 0x02
  44. #define I8K_FN_MUTE 0x04
  45. #define I8K_FN_MASK 0x07
  46. #define I8K_FN_SHIFT 8
  47. #define I8K_POWER_AC 0x05
  48. #define I8K_POWER_BATTERY 0x01
  49. #define I8K_TEMPERATURE_BUG 1
  50. #define DELL_SIGNATURE "Dell Computer"
  51. /* Interval between polling of keys, in jiffies. */
  52. #define I8K_POLL_INTERVAL (HZ/20)
  53. #define I8K_REPEAT_DELAY 250 /* 250 ms */
  54. #define I8K_REPEAT_RATE 10
  55. /*
  56.  * (To be escaped) Scancodes for the keys.  These were chosen to match other
  57.  * "Internet" keyboards.
  58.  */
  59. #define I8K_KEYS_UP_SCANCODE 0x30
  60. #define I8K_KEYS_DOWN_SCANCODE 0x2e
  61. #define I8K_KEYS_MUTE_SCANCODE 0x20
  62. static char *supported_models[] = {
  63.     "Inspiron",
  64.     "Latitude",
  65.     NULL
  66. };
  67. static char system_vendor[48] = "?";
  68. static char product_name [48] = "?";
  69. static char bios_version [4]  = "?";
  70. static char serial_number[16] = "?";
  71. int force = 0;
  72. int restricted = 0;
  73. int handle_buttons = 0;
  74. int repeat_delay = I8K_REPEAT_DELAY;
  75. int repeat_rate = I8K_REPEAT_RATE;
  76. int power_status = 0;
  77. static struct timer_list  i8k_keys_timer;
  78. MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)");
  79. MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops");
  80. MODULE_LICENSE("GPL");
  81. MODULE_PARM(force, "i");
  82. MODULE_PARM(restricted, "i");
  83. MODULE_PARM(handle_buttons, "i");
  84. MODULE_PARM(repeat_delay, "i");
  85. MODULE_PARM(repeat_rate, "i");
  86. MODULE_PARM(power_status, "i");
  87. MODULE_PARM_DESC(force, "Force loading without checking for supported models");
  88. MODULE_PARM_DESC(restricted, "Allow fan control if SYS_ADMIN capability set");
  89. MODULE_PARM_DESC(handle_buttons, "Generate keyboard events for i8k buttons");
  90. MODULE_PARM_DESC(repeat_delay, "I8k buttons repeat delay (ms)");
  91. MODULE_PARM_DESC(repeat_rate, "I8k buttons repeat rate");
  92. MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k");
  93. static ssize_t i8k_read(struct file *, char *, size_t, loff_t *);
  94. static int i8k_ioctl(struct inode *, struct file *, unsigned int,
  95.      unsigned long);
  96. static void i8k_keys_set_timer(void);
  97. static struct file_operations i8k_fops = {
  98.     read: i8k_read,
  99.     ioctl: i8k_ioctl,
  100. };
  101. typedef struct {
  102.     unsigned int eax;
  103.     unsigned int ebx __attribute__ ((packed));
  104.     unsigned int ecx __attribute__ ((packed));
  105.     unsigned int edx __attribute__ ((packed));
  106.     unsigned int esi __attribute__ ((packed));
  107.     unsigned int edi __attribute__ ((packed));
  108. } SMMRegisters;
  109. typedef struct {
  110.     u8 type;
  111.     u8 length;
  112.     u16 handle;
  113. } DMIHeader;
  114. /*
  115.  * Call the System Management Mode BIOS. Code provided by Jonathan Buzzard.
  116.  */
  117. static int i8k_smm(SMMRegisters *regs)
  118. {
  119.     int rc;
  120.     int eax = regs->eax;
  121.     asm("pushl %%eaxnt" 
  122. "movl 0(%%eax),%%edxnt" 
  123. "push %%edxnt" 
  124. "movl 4(%%eax),%%ebxnt" 
  125. "movl 8(%%eax),%%ecxnt" 
  126. "movl 12(%%eax),%%edxnt" 
  127. "movl 16(%%eax),%%esint" 
  128. "movl 20(%%eax),%%edint" 
  129. "popl %%eaxnt" 
  130. "out %%al,$0xb2nt" 
  131. "out %%al,$0x84nt" 
  132. "xchgl %%eax,(%%esp)nt"
  133. "movl %%ebx,4(%%eax)nt" 
  134. "movl %%ecx,8(%%eax)nt" 
  135. "movl %%edx,12(%%eax)nt" 
  136. "movl %%esi,16(%%eax)nt" 
  137. "movl %%edi,20(%%eax)nt" 
  138. "popl %%edxnt" 
  139. "movl %%edx,0(%%eax)nt" 
  140. "lahfnt" 
  141. "shrl $8,%%eaxnt" 
  142. "andl $1,%%eaxn" 
  143. : "=a" (rc)
  144. : "a" (regs)
  145. : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
  146.     if ((rc != 0) || ((regs->eax & 0xffff) == 0xffff) || (regs->eax == eax)) {
  147. return -EINVAL;
  148.     }
  149.     return 0;
  150. }
  151. /*
  152.  * Read the bios version. Return the version as an integer corresponding
  153.  * to the ascii value, for example "A17" is returned as 0x00413137.
  154.  */
  155. static int i8k_get_bios_version(void)
  156. {
  157.     SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
  158.     int rc;
  159.     regs.eax = I8K_SMM_BIOS_VERSION;
  160.     if ((rc=i8k_smm(&regs)) < 0) {
  161. return rc;
  162.     }
  163.     return regs.eax;
  164. }
  165. /*
  166.  * Read the machine id.
  167.  */
  168. static int i8k_get_serial_number(unsigned char *buff)
  169. {
  170.     strncpy(buff, serial_number, 16);
  171.     return 0;
  172. }
  173. /*
  174.  * Read the Fn key status.
  175.  */
  176. static int i8k_get_fn_status(void)
  177. {
  178.     SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
  179.     int rc;
  180.     regs.eax = I8K_SMM_FN_STATUS;
  181.     if ((rc=i8k_smm(&regs)) < 0) {
  182. return rc;
  183.     }
  184.     switch ((regs.eax >> I8K_FN_SHIFT) & I8K_FN_MASK) {
  185.     case I8K_FN_UP:
  186. return I8K_VOL_UP;
  187.     case I8K_FN_DOWN:
  188. return I8K_VOL_DOWN;
  189.     case I8K_FN_MUTE:
  190. return I8K_VOL_MUTE;
  191.     default:
  192. return 0;
  193.     }
  194. }
  195. /*
  196.  * Read the power status.
  197.  */
  198. static int i8k_get_power_status(void)
  199. {
  200.     SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
  201.     int rc;
  202.     regs.eax = I8K_SMM_POWER_STATUS;
  203.     if ((rc=i8k_smm(&regs)) < 0) {
  204. return rc;
  205.     }
  206.     switch (regs.eax & 0xff) {
  207.     case I8K_POWER_AC:
  208. return I8K_AC;
  209.     default:
  210. return I8K_BATTERY;
  211.     }
  212. }
  213. /*
  214.  * Read the fan status.
  215.  */
  216. static int i8k_get_fan_status(int fan)
  217. {
  218.     SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
  219.     int rc;
  220.     regs.eax = I8K_SMM_GET_FAN;
  221.     regs.ebx = fan & 0xff;
  222.     if ((rc=i8k_smm(&regs)) < 0) {
  223. return rc;
  224.     }
  225.     return (regs.eax & 0xff);
  226. }
  227. /*
  228.  * Read the fan speed in RPM.
  229.  */
  230. static int i8k_get_fan_speed(int fan)
  231. {
  232.     SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
  233.     int rc;
  234.     regs.eax = I8K_SMM_GET_SPEED;
  235.     regs.ebx = fan & 0xff;
  236.     if ((rc=i8k_smm(&regs)) < 0) {
  237. return rc;
  238.     }
  239.     return (regs.eax & 0xffff) * I8K_FAN_MULT;
  240. }
  241. /*
  242.  * Set the fan speed (off, low, high). Returns the new fan status.
  243.  */
  244. static int i8k_set_fan(int fan, int speed)
  245. {
  246.     SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
  247.     int rc;
  248.     speed = (speed < 0) ? 0 : ((speed > I8K_FAN_MAX) ? I8K_FAN_MAX : speed);
  249.     regs.eax = I8K_SMM_SET_FAN;
  250.     regs.ebx = (fan & 0xff) | (speed << 8);
  251.     if ((rc=i8k_smm(&regs)) < 0) {
  252. return rc;
  253.     }
  254.     return (i8k_get_fan_status(fan));
  255. }
  256. /*
  257.  * Read the cpu temperature.
  258.  */
  259. static int i8k_get_cpu_temp(void)
  260. {
  261.     SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
  262.     int rc;
  263.     int temp;
  264. #ifdef I8K_TEMPERATURE_BUG
  265.     static int prev = 0;
  266. #endif
  267.     regs.eax = I8K_SMM_GET_TEMP;
  268.     if ((rc=i8k_smm(&regs)) < 0) {
  269. return rc;
  270.     }
  271.     temp = regs.eax & 0xff;
  272. #ifdef I8K_TEMPERATURE_BUG
  273.     /*
  274.      * Sometimes the temperature sensor returns 0x99, which is out of range.
  275.      * In this case we return (once) the previous cached value. For example:
  276.      # 1003655137 00000058 00005a4b
  277.      # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees
  278.      # 1003655139 00000054 00005c52
  279.      */
  280.     if (temp > I8K_MAX_TEMP) {
  281. temp = prev;
  282. prev = I8K_MAX_TEMP;
  283.     } else {
  284. prev = temp;
  285.     }
  286. #endif
  287.     return temp;
  288. }
  289. static int i8k_get_dell_signature(void)
  290. {
  291.     SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
  292.     int rc;
  293.     regs.eax = I8K_SMM_GET_DELL_SIG;
  294.     if ((rc=i8k_smm(&regs)) < 0) {
  295. return rc;
  296.     }
  297.     if ((regs.eax == 1145651527) && (regs.edx == 1145392204)) {
  298. return 0;
  299.     } else {
  300. return -1;
  301.     }
  302. }
  303. static int i8k_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
  304.      unsigned long arg)
  305. {
  306.     int val;
  307.     int speed;
  308.     unsigned char buff[16];
  309.     if (!arg) {
  310. return -EINVAL;
  311.     }
  312.     switch (cmd) {
  313.     case I8K_BIOS_VERSION:
  314. val = i8k_get_bios_version();
  315. break;
  316.     case I8K_MACHINE_ID:
  317. memset(buff, 0, 16);
  318. val = i8k_get_serial_number(buff);
  319. break;
  320.     case I8K_FN_STATUS:
  321. val = i8k_get_fn_status();
  322. break;
  323.     case I8K_POWER_STATUS:
  324. val = i8k_get_power_status();
  325. break;
  326.     case I8K_GET_TEMP:
  327. val = i8k_get_cpu_temp();
  328. break;
  329.     case I8K_GET_SPEED:
  330. if (copy_from_user(&val, (int *)arg, sizeof(int))) {
  331.     return -EFAULT;
  332. }
  333. val = i8k_get_fan_speed(val);
  334. break;
  335.     case I8K_GET_FAN:
  336. if (copy_from_user(&val, (int *)arg, sizeof(int))) {
  337.     return -EFAULT;
  338. }
  339. val = i8k_get_fan_status(val);
  340. break;
  341.     case I8K_SET_FAN:
  342. if (restricted && !capable(CAP_SYS_ADMIN)) {
  343.     return -EPERM;
  344. }
  345. if (copy_from_user(&val, (int *)arg, sizeof(int))) {
  346.     return -EFAULT;
  347. }
  348. if (copy_from_user(&speed, (int *)arg+1, sizeof(int))) {
  349.     return -EFAULT;
  350. }
  351. val = i8k_set_fan(val, speed);
  352. break;
  353.     default:
  354. return -EINVAL;
  355.     }
  356.     if (val < 0) {
  357. return val;
  358.     }
  359.     switch (cmd) {
  360.     case I8K_BIOS_VERSION:
  361. if (copy_to_user((int *)arg, &val, 4)) {
  362.     return -EFAULT;
  363. }
  364. break;
  365.     case I8K_MACHINE_ID:
  366. if (copy_to_user((int *)arg, buff, 16)) {
  367.     return -EFAULT;
  368. }
  369. break;
  370.     default:
  371. if (copy_to_user((int *)arg, &val, sizeof(int))) {
  372.     return -EFAULT;
  373. }
  374. break;
  375.     }
  376.     return 0;
  377. }
  378. /*
  379.  * Print the information for /proc/i8k.
  380.  */
  381. static int i8k_get_info(char *buffer, char **start, off_t fpos, int length)
  382. {
  383.     int n, fn_key, cpu_temp, ac_power;
  384.     int left_fan, right_fan, left_speed, right_speed;
  385.     cpu_temp     = i8k_get_cpu_temp(); /* 11100 祍 */
  386.     left_fan     = i8k_get_fan_status(I8K_FAN_LEFT); /*   580 祍 */
  387.     right_fan    = i8k_get_fan_status(I8K_FAN_RIGHT); /*   580 祍 */
  388.     left_speed   = i8k_get_fan_speed(I8K_FAN_LEFT); /*   580 祍 */
  389.     right_speed  = i8k_get_fan_speed(I8K_FAN_RIGHT); /*   580 祍 */
  390.     fn_key       = i8k_get_fn_status(); /*   750 祍 */
  391.     if (power_status) {
  392. ac_power = i8k_get_power_status(); /* 14700 祍 */
  393.     } else {
  394. ac_power = -1;
  395.     }
  396.     /*
  397.      * Info:
  398.      *
  399.      * 1)  Format version (this will change if format changes)
  400.      * 2)  BIOS version
  401.      * 3)  BIOS machine ID
  402.      * 4)  Cpu temperature
  403.      * 5)  Left fan status
  404.      * 6)  Right fan status
  405.      * 7)  Left fan speed
  406.      * 8)  Right fan speed
  407.      * 9)  AC power
  408.      * 10) Fn Key status
  409.      */
  410.     n = sprintf(buffer, "%s %s %s %d %d %d %d %d %d %dn",
  411. I8K_PROC_FMT,
  412. bios_version,
  413. serial_number,
  414. cpu_temp,
  415. left_fan,
  416. right_fan,
  417. left_speed,
  418. right_speed,
  419. ac_power,
  420. fn_key);
  421.     return n;
  422. }
  423. static ssize_t i8k_read(struct file *f, char *buffer, size_t len, loff_t *fpos)
  424. {
  425.     int n;
  426.     char info[128];
  427.     n = i8k_get_info(info, NULL, 0, 128);
  428.     if (n <= 0) {
  429. return n;
  430.     }
  431.     if (*fpos >= n) {
  432. return 0;
  433.     }
  434.     if ((*fpos + len) >= n) {
  435. len = n - *fpos;
  436.     }
  437.     if (copy_to_user(buffer, info, len) != 0) {
  438. return -EFAULT;
  439.     }
  440.     *fpos += len;
  441.     return len;
  442. }
  443. /*
  444.  * i8k_keys stuff. Thanks to David Bustos <bustos@caltech.edu>
  445.  */
  446. static unsigned char i8k_keys_make_scancode(int x) {
  447.     switch (x) {
  448.     case I8K_FN_UP: return I8K_KEYS_UP_SCANCODE;
  449.     case I8K_FN_DOWN: return I8K_KEYS_DOWN_SCANCODE;
  450.     case I8K_FN_MUTE: return I8K_KEYS_MUTE_SCANCODE;
  451.     }
  452.     return 0;
  453. }
  454. static void i8k_keys_poll(unsigned long data) {
  455.     static int last = 0;
  456.     static int repeat = 0;
  457.     int  curr;
  458.     curr = i8k_get_fn_status();
  459.     if (curr >= 0) {
  460. if (curr != last) {
  461.     repeat = jiffies + (HZ * repeat_delay / 1000);
  462.     if (last != 0) {
  463. handle_scancode(0xe0, 0);
  464. handle_scancode(i8k_keys_make_scancode(last), 0);
  465.     }
  466.     if (curr != 0) {
  467. handle_scancode(0xe0, 1);
  468. handle_scancode(i8k_keys_make_scancode(curr), 1);
  469.     }
  470. } else {
  471.     /* Generate keyboard repeat events with current scancode -- dz */
  472.     if ((curr) && (repeat_rate > 0) && (jiffies >= repeat)) {
  473. repeat = jiffies + (HZ / repeat_rate);
  474. handle_scancode(0xe0, 1);
  475. handle_scancode(i8k_keys_make_scancode(curr), 1);
  476.     }
  477. }
  478. last = curr;
  479.     }
  480.     /* Reset the timer. */
  481.     i8k_keys_set_timer();
  482. }
  483. static void i8k_keys_set_timer() {
  484.     i8k_keys_timer.expires = jiffies + I8K_POLL_INTERVAL;
  485.     add_timer(&i8k_keys_timer);
  486. }
  487. static char* __init string_trim(char *s, int size)
  488. {
  489.     int len;
  490.     char *p;
  491.     if ((len = strlen(s)) > size) {
  492. len = size;
  493.     }
  494.     for (p=s+len-1; len && (*p==' '); len--,p--) {
  495. *p = '';
  496.     }
  497.     return s;
  498. }
  499. /* DMI code, stolen from arch/i386/kernel/dmi_scan.c */
  500. /*
  501.  * |<-- dmi->length -->|
  502.  * |                   |
  503.  * |dmi header    s=N  | string1,, ..., stringN,, ..., 
  504.  *                |                       |
  505.  *                +-----------------------+
  506.  */
  507. static char* __init dmi_string(DMIHeader *dmi, u8 s)
  508. {
  509.     u8 *p;
  510.     if (!s) {
  511. return "";
  512.     }
  513.     s--;
  514.     p = (u8 *)dmi + dmi->length;
  515.     while (s > 0) {
  516. p += strlen(p);
  517. p++;
  518. s--;
  519.     }
  520.     return p;
  521. }
  522. static void __init dmi_decode(DMIHeader *dmi)
  523. {
  524.     u8 *data = (u8 *) dmi;
  525.     char *p;
  526. #ifdef I8K_DEBUG
  527.     int i;
  528.     printk("%08x ", (int)data);
  529.     for (i=0; i<data[1] && i<64; i++) {
  530. printk("%02x ", data[i]);
  531.     }
  532.     printk("n");
  533. #endif
  534.     switch (dmi->type) {
  535.     case  0: /* BIOS Information */
  536. p = dmi_string(dmi,data[5]);
  537. if (*p) {
  538.     strncpy(bios_version, p, sizeof(bios_version));
  539.     string_trim(bios_version, sizeof(bios_version));
  540. }
  541. break;
  542.     case 1: /* System Information */
  543. p = dmi_string(dmi,data[4]);
  544. if (*p) {
  545.     strncpy(system_vendor, p, sizeof(system_vendor));
  546.     string_trim(system_vendor, sizeof(system_vendor));
  547. }
  548. p = dmi_string(dmi,data[5]);
  549. if (*p) {
  550.     strncpy(product_name, p, sizeof(product_name));
  551.     string_trim(product_name, sizeof(product_name));
  552. }
  553. p = dmi_string(dmi,data[7]);
  554. if (*p) {
  555.     strncpy(serial_number, p, sizeof(serial_number));
  556.     string_trim(serial_number, sizeof(serial_number));
  557. }
  558. break;
  559.     }
  560. }
  561. static int __init dmi_table(u32 base, int len, int num, void (*fn)(DMIHeader*))
  562. {
  563.     u8 *buf;
  564.     u8 *data;
  565.     DMIHeader *dmi;
  566.     int i = 1;
  567.     buf = ioremap(base, len);
  568.     if (buf == NULL) {
  569. return -1;
  570.     }
  571.     data = buf;
  572.     /*
  573.      * Stop when we see al the items the table claimed to have
  574.      * or we run off the end of the table (also happens)
  575.      */
  576.     while ((i<num) && ((data-buf) < len)) {
  577. dmi = (DMIHeader *)data;
  578. /*
  579.  * Avoid misparsing crud if the length of the last
  580.  * record is crap
  581.  */
  582. if ((data-buf+dmi->length) >= len) {
  583.     break;
  584. }
  585. fn(dmi);
  586. data += dmi->length;
  587. /*
  588.  * Don't go off the end of the data if there is
  589.  * stuff looking like string fill past the end
  590.  */
  591. while (((data-buf) < len) && (*data || data[1])) {
  592.     data++;
  593. }
  594. data += 2;
  595. i++;
  596.     }
  597.     iounmap(buf);
  598.     return 0;
  599. }
  600. static int __init dmi_iterate(void (*decode)(DMIHeader *))
  601. {
  602.     unsigned char buf[20];
  603.     long fp = 0x000e0000L;
  604.     fp -= 16;
  605.     while (fp < 0x000fffffL) {
  606. fp += 16;
  607. isa_memcpy_fromio(buf, fp, 20);
  608. if (memcmp(buf, "_DMI_", 5)==0) {
  609.     u16 num  = buf[13]<<8  | buf[12];
  610.     u16 len  = buf [7]<<8  | buf [6];
  611.     u32 base = buf[11]<<24 | buf[10]<<16 | buf[9]<<8 | buf[8];
  612. #ifdef I8K_DEBUG
  613.     printk(KERN_INFO "DMI %d.%d present.n",
  614.    buf[14]>>4, buf[14]&0x0F);
  615.     printk(KERN_INFO "%d structures occupying %d bytes.n",
  616.    buf[13]<<8 | buf[12],
  617.    buf [7]<<8 | buf[6]);
  618.     printk(KERN_INFO "DMI table at 0x%08X.n",
  619.    buf[11]<<24 | buf[10]<<16 | buf[9]<<8 | buf[8]);
  620. #endif
  621.     if (dmi_table(base, len, num, decode)==0) {
  622. return 0;
  623.     }
  624. }
  625.     }
  626.     return -1;
  627. }
  628. /* end of DMI code */
  629. /*
  630.  * Get DMI information.
  631.  */
  632. static int __init i8k_dmi_probe(void)
  633. {
  634.     char **p;
  635.     if (dmi_iterate(dmi_decode) != 0) {
  636. printk(KERN_INFO "i8k: unable to get DMI informationn");
  637. return -ENODEV;
  638.     }
  639.     if (strncmp(system_vendor,DELL_SIGNATURE,strlen(DELL_SIGNATURE)) != 0) {
  640. printk(KERN_INFO "i8k: not running on a Dell systemn");
  641. return -ENODEV;
  642.     }
  643.     for (p=supported_models; ; p++) {
  644. if (!*p) {
  645.     printk(KERN_INFO "i8k: unsupported model: %sn", product_name);
  646.     return -ENODEV;
  647. }
  648. if (strncmp(product_name,*p,strlen(*p)) == 0) {
  649.     break;
  650. }
  651.     }
  652.     return 0;
  653. }
  654. /*
  655.  * Probe for the presence of a supported laptop.
  656.  */
  657. static int __init i8k_probe(void)
  658. {
  659.     char buff[4];
  660.     int version;
  661.     int smm_found = 0;
  662.     /*
  663.      * Get DMI information
  664.      */
  665.     if (i8k_dmi_probe() != 0) {
  666. printk(KERN_INFO "i8k: vendor=%s, model=%s, version=%sn",
  667.        system_vendor, product_name, bios_version);
  668.     }
  669.     /*
  670.      * Get SMM Dell signature
  671.      */
  672.     if (i8k_get_dell_signature() != 0) {
  673. printk(KERN_INFO "i8k: unable to get SMM Dell signaturen");
  674.     } else {
  675. smm_found = 1;
  676.     }
  677.     /*
  678.      * Get SMM BIOS version.
  679.      */
  680.     version = i8k_get_bios_version();
  681.     if (version <= 0) {
  682. printk(KERN_INFO "i8k: unable to get SMM BIOS versionn");
  683.     } else {
  684. smm_found = 1;
  685. buff[0] = (version >> 16) & 0xff;
  686. buff[1] = (version >>  8) & 0xff;
  687. buff[2] = (version)       & 0xff;
  688. buff[3] = '';
  689. /*
  690.  * If DMI BIOS version is unknown use SMM BIOS version.
  691.  */
  692. if (bios_version[0] == '?') {
  693.     strcpy(bios_version, buff);
  694. }
  695. /*
  696.  * Check if the two versions match.
  697.  */
  698. if (strncmp(buff,bios_version,sizeof(bios_version)) != 0) {
  699.     printk(KERN_INFO "i8k: BIOS version mismatch: %s != %sn",
  700.    buff, bios_version);
  701. }
  702.     }
  703.     if (!smm_found && !force) {
  704. return -ENODEV;
  705.     }
  706.     return 0;
  707. }
  708. #ifdef MODULE
  709. static
  710. #endif
  711. int __init i8k_init(void)
  712. {
  713.     struct proc_dir_entry *proc_i8k;
  714.     /* Are we running on an supported laptop? */
  715.     if (i8k_probe() != 0) {
  716. return -ENODEV;
  717.     }
  718.     /* Register the proc entry */
  719.     proc_i8k = create_proc_info_entry("i8k", 0, NULL, i8k_get_info);
  720.     if (!proc_i8k) {
  721. return -ENOENT;
  722.     }
  723.     proc_i8k->proc_fops = &i8k_fops;
  724.     SET_MODULE_OWNER(proc_i8k);
  725.     printk(KERN_INFO
  726.    "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)n",
  727.    I8K_VERSION);
  728.     /* Register the i8k_keys timer. */
  729.     if (handle_buttons) {
  730. printk(KERN_INFO
  731.        "i8k: enabling buttons events, delay=%d, rate=%dn",
  732.        repeat_delay, repeat_rate);
  733. init_timer(&i8k_keys_timer);
  734. i8k_keys_timer.function = i8k_keys_poll;
  735. i8k_keys_set_timer();
  736.     }
  737.     return 0;
  738. }
  739. #ifdef MODULE
  740. int init_module(void)
  741. {
  742.     return i8k_init();
  743. }
  744. void cleanup_module(void)
  745. {
  746.     /* Remove the proc entry */
  747.     remove_proc_entry("i8k", NULL);
  748.     /* Unregister the i8k_keys timer. */
  749.     while (handle_buttons && !del_timer(&i8k_keys_timer)) {
  750. schedule_timeout(I8K_POLL_INTERVAL);
  751.     }
  752.     printk(KERN_INFO "i8k: module unloadedn");
  753. }
  754. #endif
  755. /* end of file */