daily pastebin goal
68%
SHARE
TWEET

Untitled

a guest Jul 1st, 2015 207 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.  *  eee.c - Asus eeePC extras
  3.  *
  4.  *  Copyright (C) 2007 Andrew Tipton
  5.  *
  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.  *
  11.  *  Ths program is distributed in the hope that it will be useful,
  12.  *  but WITOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTAILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; if not, write to the Free Software
  18.  *  Foundation, Inc., 59 Template Place, Suite 330, Boston, MA  02111-1307 USA
  19.  *  
  20.  *  ---------
  21.  *
  22.  *  WARNING:  This is an extremely *experimental* module!  This code has been
  23.  *  developed through trial-and-error, which means I don't really understand
  24.  *  100% what's going on here...  That means there's a chance that there could
  25.  *  be unintended side-effects which might cause data loss or even physical
  26.  *  damage!
  27.  *
  28.  *  Again, this code comes WITHOUT ANY WARRANTY whatsoever.
  29.  */
  30.  
  31. #include <linux/module.h>
  32. #include <linux/kernel.h>
  33. #include <linux/proc_fs.h>
  34. #include <asm/uaccess.h>
  35. #include <asm/io.h>             // For inb() and outb()
  36. #include <linux/i2c.h>
  37. #include <linux/mutex.h>
  38.  
  39.  
  40. /* Module info */
  41. MODULE_LICENSE("GPL");
  42. MODULE_AUTHOR("Andrew Tipton");
  43. MODULE_DESCRIPTION("Support for eeePC-specific functionality.");
  44. #define EEE_VERSION "0.2"
  45.  
  46.  
  47. /* PLL access functions.
  48.  *
  49.  * Note that this isn't really the "proper" way to use the I2C API... :)
  50.  * I2C_SMBUS_BLOCK_MAX is 32, the maximum size of a block read/write.
  51.  */
  52. static void eee_pll_init(void);
  53. static void eee_pll_read(void);
  54. static void eee_pll_write(void);
  55. static void eee_pll_cleanup(void);
  56.  
  57.  
  58. static struct i2c_client eee_pll_smbus_client = {
  59.     .adapter = NULL,
  60.     .addr = 0x69,
  61.     .flags = 0,
  62. };
  63. static char eee_pll_data[I2C_SMBUS_BLOCK_MAX];
  64. static int eee_pll_datalen = 0;
  65.  
  66. static void eee_pll_init(void) {
  67.     eee_pll_smbus_client.adapter = i2c_get_adapter(0);
  68.  
  69.     // Fill the eee_pll_data buffer.
  70.     eee_pll_read();
  71. }
  72.  
  73. // Takes approx 150ms to execute.
  74. static void eee_pll_read(void) {
  75.     memset(eee_pll_data, 0, I2C_SMBUS_BLOCK_MAX);
  76.     eee_pll_datalen = i2c_smbus_read_block_data(&eee_pll_smbus_client, 0, eee_pll_data);
  77. }
  78.  
  79. // Takes approx 150ms to execute ???
  80. static void eee_pll_write(void) {
  81.     i2c_smbus_write_block_data(&eee_pll_smbus_client, 0, eee_pll_datalen, eee_pll_data);
  82. }
  83.  
  84. static void eee_pll_cleanup(void) {
  85.     i2c_put_adapter(eee_pll_smbus_client.adapter);
  86. }
  87.  
  88. /* Embedded controller access functions.
  89.  *
  90.  * The ENE KB3310 embedded controller has a feature known as "Index IO"
  91.  * which allows the entire 64KB address space of the controller to be
  92.  * accessed via a set of ISA I/O ports at 0x380-0x384.  This allows us
  93.  * direct access to all of the controller's ROM, RAM, SFRs, and peripheral
  94.  * registers;  this access bypasses the EC firmware entirely.
  95.  *
  96.  * This is much faster than using ec_transaction(), and it also allows us to
  97.  * do things which are not possible through the EC's official interface.
  98.  *
  99.  * An Indexed IO write to an EC register takes approx. 90us, while an EC
  100.  * transaction takes approx. 2500ms.
  101.  */
  102. #define EC_IDX_ADDRH 0x381
  103. #define EC_IDX_ADDRL 0x382
  104. #define EC_IDX_DATA 0x383
  105. #define HIGH_BYTE(x) ((x & 0xff00) >> 8)
  106. #define LOW_BYTE(x) (x & 0x00ff)
  107. static DEFINE_MUTEX(eee_ec_mutex);
  108.  
  109. static unsigned char eee_ec_read(unsigned short addr) {
  110.     unsigned char data;
  111.  
  112.     mutex_lock(&eee_ec_mutex);
  113.     outb(HIGH_BYTE(addr), EC_IDX_ADDRH);
  114.     outb(LOW_BYTE(addr), EC_IDX_ADDRL);
  115.     data = inb(EC_IDX_DATA);
  116.     mutex_unlock(&eee_ec_mutex);
  117.  
  118.     return data;
  119. }
  120.  
  121. static void eee_ec_write(unsigned short addr, unsigned char data) {
  122.     mutex_lock(&eee_ec_mutex);
  123.     outb(HIGH_BYTE(addr), EC_IDX_ADDRH);
  124.     outb(LOW_BYTE(addr), EC_IDX_ADDRL);
  125.     outb(data, EC_IDX_DATA);
  126.     mutex_unlock(&eee_ec_mutex);
  127. }
  128.  
  129. static void eee_ec_gpio_set(int pin, int value) {
  130.     unsigned short port;
  131.     unsigned char mask;
  132.  
  133.     port = 0xFC20 + ((pin >> 3) & 0x1f);
  134.     mask = 1 << (pin & 0x07);
  135.     if (value) {
  136.         eee_ec_write(port, eee_ec_read(port) | mask);
  137.     } else {
  138.         eee_ec_write(port, eee_ec_read(port) & ~mask);
  139.     }
  140. }
  141.  
  142. static int eee_ec_gpio_get(int pin) {
  143.     unsigned short port;
  144.     unsigned char mask;
  145.     unsigned char status;
  146.  
  147.     port = 0xfc20 + ((pin >> 3) & 0x1f);
  148.     mask = 1 << (pin & 0x07);
  149.     status = eee_ec_read(port) & mask;
  150.  
  151.     return (status) ? 1 : 0;
  152. }
  153.  
  154. /*** Fan and temperature functions ***/
  155. #define EC_ST00 0xF451          // Temperature of CPU (C)
  156. #define EC_SC02 0xF463          // Fan PWM duty cycle (%)
  157. #define EC_SC05 0xF466          // High byte of fan speed (RPM)
  158. #define EC_SC06 0xF467          // Low byte of fan speed (RPM)
  159. #define EC_SFB3 0xF4D3          // Flag byte containing SF25 (FANctrl)
  160.  
  161. static unsigned int eee_get_temperature(void) {
  162.     return eee_ec_read(EC_ST00);
  163. }
  164.  
  165. static unsigned int eee_fan_get_rpm(void) {
  166.     return (eee_ec_read(EC_SC05) << 8) | eee_ec_read(EC_SC06);
  167. }
  168.  
  169. // 1 if fan is in manual mode, 0 if controlled by the EC
  170. static int eee_fan_get_manual(void) {
  171.     return (eee_ec_read(EC_SFB3) & 0x02) ? 1 : 0;
  172. }
  173.  
  174. static void eee_fan_set_manual(int manual) {
  175.     if (manual) {
  176.         // SF25=1: Prevent the EC from controlling the fan.
  177.         eee_ec_write(EC_SFB3, eee_ec_read(EC_SFB3) | 0x02);
  178.     } else {
  179.         // SF25=0: Allow the EC to control the fan.
  180.         eee_ec_write(EC_SFB3, eee_ec_read(EC_SFB3) & ~0x02);
  181.     }
  182. }
  183.  
  184. static void eee_fan_set_speed(unsigned int speed) {
  185.     eee_ec_write(EC_SC02, (speed > 100) ? 100 : speed);
  186. }
  187.  
  188. static unsigned int eee_fan_get_speed(void) {
  189.     return eee_ec_read(EC_SC02);
  190. }
  191.  
  192.  
  193. /*** Voltage functions ***/
  194. #define EC_VOLTAGE_PIN 0x66
  195. enum eee_voltage { Low=0, High=1 };
  196. static enum eee_voltage eee_get_voltage(void) {
  197.     return eee_ec_gpio_get(EC_VOLTAGE_PIN);
  198. }
  199. static void eee_set_voltage(enum eee_voltage voltage) {
  200.     eee_ec_gpio_set(EC_VOLTAGE_PIN, voltage);
  201. }
  202.  
  203. /*** FSB functions ***/
  204. static void eee_get_freq(int *n, int *m) {
  205.     *m = eee_pll_data[11] & 0x3F;
  206.     *n = eee_pll_data[12];
  207. }
  208.  
  209. static void eee_set_freq(int n, int m) {
  210.     int current_n = 0, current_m = 0;
  211.     eee_get_freq(&current_n, &current_m);
  212.     if (current_n != n || current_m != m) {
  213.         eee_pll_data[11] = m & 0x3F;
  214.         eee_pll_data[12] = n & 0xFF;
  215.         eee_pll_write();
  216.     }
  217. }
  218.  
  219. /*** /proc file functions ***/
  220.  
  221. static struct proc_dir_entry *eee_proc_rootdir;
  222. #define EEE_PROC_READFUNC(NAME) \
  223.     void eee_proc_readfunc_##NAME (char *buf, int buflen, int *bufpos)
  224. #define EEE_PROC_WRITEFUNC(NAME) \
  225.     void eee_proc_writefunc_##NAME (const char *buf, int buflen, int *bufpos)
  226. #define EEE_PROC_PRINTF(FMT, ARGS...) \
  227.     *bufpos += snprintf(buf + *bufpos, buflen - *bufpos, FMT, ##ARGS)
  228. #define EEE_PROC_SCANF(COUNT, FMT, ARGS...) \
  229.     do { \
  230.         int len = 0; \
  231.         int cnt = sscanf(buf + *bufpos, FMT "%n", ##ARGS, &len); \
  232.         if (cnt < COUNT) { \
  233.             printk(KERN_DEBUG "eee:  scanf(\"%s\") wanted %d args, but got %d.\n", FMT, COUNT, cnt); \
  234.             return; \
  235.         } \
  236.         *bufpos += len; \
  237.     } while (0)
  238. #define EEE_PROC_MEMCPY(SRC, SRCLEN) \
  239.     do { \
  240.         int len = SRCLEN; \
  241.         if (len > (buflen - *bufpos)) \
  242.             len = buflen - *bufpos; \
  243.         memcpy(buf + *bufpos, SRC, (SRCLEN > (buflen - *bufpos)) ? (buflen - *bufpos) : SRCLEN); \
  244.         *bufpos += len; \
  245.     } while (0)
  246. #define EEE_PROC_FILES_BEGIN \
  247.     static struct eee_proc_file eee_proc_files[] = {
  248. #define EEE_PROC_RW(NAME, MODE) \
  249.     { #NAME, MODE, &eee_proc_readfunc_##NAME, &eee_proc_writefunc_##NAME }
  250. #define EEE_PROC_RO(NAME, MODE) \
  251.     { #NAME, MODE, &eee_proc_readfunc_##NAME, NULL }
  252. #define EEE_PROC_FILES_END \
  253.     { NULL, 0, NULL, NULL } };
  254.  
  255. struct eee_proc_file {
  256.     char *name;
  257.     int mode;
  258.     void (*readfunc)(char *buf, int buflen, int *bufpos);
  259.     void (*writefunc)(const char *buf, int buflen, int *bufpos);
  260. };
  261.  
  262.  
  263. EEE_PROC_READFUNC(fsb) {
  264.     int n = 0;
  265.     int m = 0;
  266.     int voltage = 0;
  267.     eee_get_freq(&n, &m);
  268.     voltage = (int)eee_get_voltage();
  269.     EEE_PROC_PRINTF("%d %d %d\n", n, m, voltage);
  270. }
  271.  
  272. EEE_PROC_WRITEFUNC(fsb) {
  273.     int n = 70;     // sensible defaults
  274.     int m = 24;
  275.     int voltage = 0;
  276.     EEE_PROC_SCANF(3, "%i %i %i", &n, &m, &voltage);
  277.     eee_set_freq(n, m);
  278.     eee_set_voltage(voltage);
  279. }
  280.  
  281. EEE_PROC_READFUNC(pll) {
  282.     eee_pll_read();
  283.     EEE_PROC_MEMCPY(eee_pll_data, eee_pll_datalen);
  284. }
  285.  
  286. EEE_PROC_READFUNC(fan_speed) {
  287.     int speed = eee_fan_get_speed();
  288.     EEE_PROC_PRINTF("%d\n", speed);
  289. }
  290.  
  291. EEE_PROC_WRITEFUNC(fan_speed) {
  292.     unsigned int speed = 0;
  293.     EEE_PROC_SCANF(1, "%u", &speed);
  294.     eee_fan_set_speed(speed);
  295. }
  296.  
  297. EEE_PROC_READFUNC(fan_rpm) {
  298.     int rpm = eee_fan_get_rpm();
  299.     EEE_PROC_PRINTF("%d\n", rpm);
  300. }
  301.  
  302. EEE_PROC_READFUNC(fan_manual) {
  303.     EEE_PROC_PRINTF("%d\n", eee_fan_get_manual());
  304. }
  305.  
  306. EEE_PROC_WRITEFUNC(fan_manual) {
  307.     int manual = 0;
  308.     EEE_PROC_SCANF(1, "%i", &manual);
  309.     eee_fan_set_manual(manual);
  310. }
  311.  
  312. #if 0
  313. EEE_PROC_READFUNC(fan_mode) {
  314.     enum eee_fan_mode mode = eee_fan_get_mode();
  315.     switch (mode) {
  316.         case Manual:    EEE_PROC_PRINTF("manual\n");
  317.                         break;
  318.         case Automatic: EEE_PROC_PRINTF("auto\n");
  319.                         break;
  320.         case Embedded:  EEE_PROC_PRINTF("embedded\n");
  321.                         break;
  322.     }
  323. }
  324.  
  325. EEE_PROC_WRITEFUNC(fan_mode) {
  326.     enum eee_fan_mode mode = Automatic;
  327.     char inputstr[16];
  328.     EEE_PROC_SCANF(1, "%15s", inputstr);
  329.     if (strcmp(inputstr, "manual") == 0) {
  330.         mode = Manual;
  331.     } else if (strcmp(inputstr, "auto") == 0) {
  332.         mode = Automatic;
  333.     } else if (strcmp(inputstr, "embedded") == 0) {
  334.         mode = Embedded;
  335.     }
  336.     eee_fan_set_mode(mode);
  337. }
  338. #endif
  339.  
  340. EEE_PROC_READFUNC(temperature) {
  341.     unsigned int t = eee_get_temperature();
  342.     EEE_PROC_PRINTF("%d\n", t);
  343. }
  344.  
  345. EEE_PROC_FILES_BEGIN
  346.     EEE_PROC_RW(fsb,            0644),
  347.     EEE_PROC_RO(pll,            0400),
  348.     EEE_PROC_RW(fan_speed,      0644),
  349.     EEE_PROC_RO(fan_rpm,        0444),
  350.     EEE_PROC_RW(fan_manual,     0644),
  351.     EEE_PROC_RO(temperature,    0444),
  352. EEE_PROC_FILES_END
  353.    
  354.  
  355. int eee_proc_readfunc(char *buffer, char **buffer_location, off_t offset,
  356.                       int buffer_length, int *eof, void *data)
  357. {
  358.     struct eee_proc_file *procfile = (struct eee_proc_file *)data;
  359.     int bufpos = 0;
  360.  
  361.     if (!procfile || !procfile->readfunc) {
  362.         return -EIO;
  363.     }
  364.  
  365.     *eof = 1;
  366.     if (offset > 0) {
  367.         return 0;
  368.     }
  369.  
  370.     (*procfile->readfunc)(buffer, buffer_length, &bufpos);
  371.     return bufpos;
  372. }
  373.  
  374. int eee_proc_writefunc(struct file *file, const char *buffer,
  375.                        unsigned long count, void *data)
  376. {
  377.     char userdata[129];
  378.     int bufpos = 0;
  379.     struct eee_proc_file *procfile = (struct eee_proc_file *)data;
  380.  
  381.     if (!procfile || !procfile->writefunc) {
  382.         return -EIO;
  383.     }
  384.  
  385.     if (copy_from_user(userdata, buffer, (count > 128) ? 128 : count)) {
  386.         printk(KERN_DEBUG "eee: copy_from_user() failed\n");
  387.         return -EIO;
  388.     }
  389.     userdata[128] = 0;      // So that sscanf() doesn't overflow...
  390.  
  391.     (*procfile->writefunc)(userdata, count, &bufpos);
  392.     return count;
  393. }
  394.  
  395. int eee_proc_init(void) {
  396.     int i;
  397.  
  398.     /* Create the /proc/eee directory. */
  399.     eee_proc_rootdir = proc_mkdir("eee", NULL);
  400.     if (!eee_proc_rootdir) {
  401.         printk(KERN_ERR "eee: Unable to create /proc/eee\n");
  402.         return false;
  403.     }
  404.     eee_proc_rootdir->owner = THIS_MODULE;
  405.  
  406.     /* Create the individual proc files. */
  407.     for (i=0; eee_proc_files[i].name; i++) {
  408.         struct proc_dir_entry *proc_file;
  409.         struct eee_proc_file *f = &eee_proc_files[i];
  410.  
  411.         proc_file = create_proc_entry(f->name, f->mode, eee_proc_rootdir);
  412.         if (!proc_file) {
  413.             printk(KERN_ERR "eee: Unable to create /proc/eee/%s", f->name);
  414.             goto proc_init_cleanup;
  415.         }
  416.         proc_file->read_proc = &eee_proc_readfunc;
  417.         if (f->writefunc) {
  418.             proc_file->write_proc = &eee_proc_writefunc;
  419.         }
  420.         proc_file->data = f;
  421.         proc_file->owner = THIS_MODULE;
  422.         proc_file->mode = S_IFREG | f->mode;
  423.         proc_file->uid = 0;
  424.         proc_file->gid = 0;
  425.     }
  426.     return true;
  427.  
  428.     /* We had an error, so cleanup all of the proc files... */
  429. proc_init_cleanup:
  430.     for (; i >= 0; i--) {
  431.         remove_proc_entry(eee_proc_files[i].name, eee_proc_rootdir);
  432.     }
  433.     remove_proc_entry("eee", NULL);
  434.     return false;
  435. }
  436.  
  437. void eee_proc_cleanup(void) {
  438.     int i;
  439.     for (i = 0; eee_proc_files[i].name; i++) {
  440.         remove_proc_entry(eee_proc_files[i].name, eee_proc_rootdir);
  441.     }
  442.     remove_proc_entry("eee", NULL);
  443. }
  444.  
  445.  
  446.  
  447. /*** Module initialization ***/
  448.  
  449. int init_module(void) {
  450.     eee_pll_init();
  451.     eee_proc_init();
  452.     printk(KERN_NOTICE "Asus eeePC extras, version %s\n", EEE_VERSION);
  453.     return 0;
  454. }
  455.  
  456. void cleanup_module(void) {
  457.     eee_pll_cleanup();
  458.     eee_proc_cleanup();
  459. }
RAW Paste Data
Top