Advertisement
Guest User

Untitled

a guest
Jul 1st, 2015
230
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.28 KB | None | 0 0
  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. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement