Advertisement
Guest User

Untitled

a guest
Jan 18th, 2020
102
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 12.46 KB | None | 0 0
  1. #include <linux/delay.h>
  2. #include <linux/platform_device.h>
  3. #include <linux/input.h>
  4. #include <linux/kernel.h>
  5. #include <linux/module.h>
  6. #include <linux/timer.h>
  7. #include <linux/dmi.h>
  8. #include <asm/io.h>
  9. #include <linux/leds.h>
  10.  
  11. /* data port used by apple SMC */
  12. #define APPLESMC_DATA_PORT  0x300
  13. /* command/status port used by apple SMC */
  14. #define APPLESMC_CMD_PORT   0x304
  15.  
  16. #define APPLESMC_NR_PORTS   5 /* 0x300-0x304 */
  17.  
  18. #define APPLESMC_STATUS_MASK    0x0f
  19. #define APPLESMC_READ_CMD   0x10
  20. #define APPLESMC_WRITE_CMD  0x11
  21.  
  22. #define CLAMSHELL_KEY       "MSLD" //r-o length 1 (unused)
  23.  
  24. #define FANS_COUNT      "FNum" //r-o length 1
  25. #define FANS_MANUAL     "FS! " //r-w length 2
  26. #define FAN_ACTUAL_SPEED    "F0Ac" //r-o length 2
  27. #define FAN_MIN_SPEED       "F0Mn" //r-o length 2
  28. #define FAN_MAX_SPEED       "F0Mx" //r-o length 2
  29. #define FAN_SAFE_SPEED      "F0Sf" //r-o length 2
  30. #define FAN_TARGET_SPEED    "F0Tg" //r-w length 2
  31.  
  32. #define INIT_TIMEOUT_MSECS  5000    /* wait up to 5s for device init ... */
  33. #define INIT_WAIT_MSECS     50  /* ... in 50ms increments */
  34.  
  35. #define APPLESMC_POLL_PERIOD    (HZ/20) /* poll for input every 1/20s */
  36. #define APPLESMC_INPUT_FUZZ 4   /* input event threshold */
  37. #define APPLESMC_INPUT_FLAT 4
  38.  
  39. static int debug = 0;
  40. static struct platform_device *pdev;
  41.  
  42. static struct mutex mutex = __MUTEX_INITIALIZER(mutex);
  43. static DECLARE_MUTEX(applesmc_sem);
  44.  
  45. /*
  46.  * __wait_status - Wait up to 100ms for the status port to get a certain value
  47.  * (masked with 0x0f), returning zero if the value is obtained.  Callers must
  48.  * hold applesmc_sem.
  49.  */
  50. static int __wait_status(u8 val)
  51. {
  52.     unsigned int i;
  53.  
  54.     val = val & APPLESMC_STATUS_MASK;
  55.  
  56.     for (i = 0; i < 10000; i++) {
  57.         if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == val)
  58.             return 0;
  59.         udelay(10);
  60.     }
  61.  
  62.     printk(KERN_WARNING "applesmc: wait status failed: %x != %x\n",
  63.                         val, inb(APPLESMC_CMD_PORT));
  64.  
  65.     return -EIO;
  66. }
  67.  
  68. /*
  69.  * applesmc_read_key - reads len bytes from a given key, and put them in buffer.
  70.  * Returns zero on success or a negative error on failure. Callers must
  71.  * hold applesmc_sem.
  72.  */
  73. static int applesmc_read_key(const char* key, u8* buffer, u8 len)
  74. {
  75.     int ret = -EIO;
  76.     int i;
  77.  
  78.     outb(APPLESMC_READ_CMD, APPLESMC_CMD_PORT);
  79.     if (__wait_status(0x0c))
  80.         goto out;
  81.    
  82.     for (i = 0; i < 4; i++) {
  83.         outb(key[i], APPLESMC_DATA_PORT);
  84.         if (__wait_status(0x04))
  85.             goto out;
  86.     }
  87.     if (debug) printk(KERN_DEBUG "<%s", key);
  88.  
  89.     outb(len, APPLESMC_DATA_PORT);
  90.     if (debug) printk(KERN_DEBUG ">%x", len);
  91.  
  92.     for (i = 0; i < len; i++) {
  93.         if (__wait_status(0x05))
  94.             goto out;
  95.         buffer[i] = inb(APPLESMC_DATA_PORT);
  96.         if (debug) printk(KERN_DEBUG "<%x", buffer[i]);
  97.     }
  98.     if (debug) printk(KERN_DEBUG "\n");
  99.     ret = 0;
  100.  
  101. out:
  102.     return ret;
  103. }
  104.  
  105. /*
  106.  * applesmc_write_key - writes len bytes from buffer to a given key.
  107.  * Returns zero on success or a negative error on failure. Callers must
  108.  * hold applesmc_sem.
  109.  */
  110. static int applesmc_write_key(const char* key, u8* buffer, u8 len)
  111. {
  112.     int ret = -EIO;
  113.     int i;
  114.  
  115.     outb(APPLESMC_WRITE_CMD, APPLESMC_CMD_PORT);
  116.     if (__wait_status(0x0c))
  117.         goto out;
  118.    
  119.     for (i = 0; i < 4; i++) {
  120.         outb(key[i], APPLESMC_DATA_PORT);
  121.         if (__wait_status(0x04))
  122.             goto out;
  123.     }
  124.  
  125.     outb(len, APPLESMC_DATA_PORT);
  126.  
  127.     for (i = 0; i < len; i++) {
  128.         if (__wait_status(0x04))
  129.             goto out;
  130.         outb(buffer[i], APPLESMC_DATA_PORT);
  131.     }
  132.  
  133.     ret = 0;
  134. out:
  135.     return ret;
  136. }
  137.  
  138.  
  139. static int applesmc_device_init(void)
  140. {
  141.     int total, ret = -ENXIO;
  142.     u8 buffer[2];
  143.  
  144.     mutex_lock(&mutex);
  145.     //down(&applesmc_sem);
  146.  
  147.     for (total = INIT_TIMEOUT_MSECS; total > 0; total -= INIT_WAIT_MSECS) {
  148.         if (debug) printk(KERN_DEBUG "applesmc try %d\n", total);
  149.         buffer[0] = 0xe0;
  150.         buffer[1] = 0x00;
  151.         msleep(INIT_WAIT_MSECS);
  152.     }
  153.  
  154.     printk(KERN_WARNING "applesmc: failed to init the device\n");
  155.  
  156. out:
  157.     //up(&applesmc_sem);
  158.     mutex_unlock(&mutex);
  159.     return ret;
  160. }
  161.  
  162. /*
  163.  * applesmc_get_fan_count - get the number of fans. Callers must NOT hold
  164.  * applesmc_sem.
  165.  */
  166. static int applesmc_get_fan_count(void)
  167. {
  168.     int ret;
  169.     u8 buffer[1];
  170.  
  171.     //down(&applesmc_sem);
  172.     mutex_lock(&mutex);
  173.  
  174.     ret = applesmc_read_key(FANS_COUNT, buffer, 1);
  175.  
  176.     //up(&applesmc_sem);
  177.     mutex_unlock(&mutex);
  178.  
  179.     if (ret)
  180.         return ret;
  181.     else
  182.         return buffer[0];
  183. }
  184.  
  185. /* Device model stuff */
  186. static int applesmc_probe(struct platform_device *dev)
  187. {
  188.     int ret;
  189.  
  190.     ret = applesmc_device_init();
  191.     if (ret)
  192.         return ret;
  193.  
  194.     printk(KERN_INFO "applesmc: device successfully initialized.\n");
  195.     return 0;
  196. }
  197.  
  198. static int applesmc_resume(struct platform_device *dev)
  199. {
  200.     return applesmc_device_init();
  201. }
  202.  
  203. static struct platform_driver applesmc_driver = {
  204.     .probe = applesmc_probe,
  205.     .resume = applesmc_resume,
  206.     .driver = {
  207.         .name = "applesmc",
  208.         .owner = THIS_MODULE,
  209.     },
  210. };
  211.  
  212. static ssize_t applesmc_show_fan_speed(struct device *dev, char *sysfsbuf,
  213.                         const char* key, int offset)
  214. {
  215.     int ret;
  216.     unsigned int speed = 0;
  217.     char newkey[5];
  218.     u8 buffer[2];
  219.  
  220.     newkey[0] = key[0];
  221.     newkey[1] = '0' + offset;
  222.     newkey[2] = key[2];
  223.     newkey[3] = key[3];
  224.     newkey[4] = 0;
  225.  
  226.     //down(&applesmc_sem);
  227.     mutex_lock(&mutex);
  228.  
  229.     ret = applesmc_read_key(newkey, buffer, 2);
  230.     speed = ((buffer[0] << 8 | buffer[1]) >> 2);
  231.  
  232.     //up(&applesmc_sem);
  233.     mutex_unlock(&mutex);
  234.  
  235.     if (ret)
  236.         return ret;
  237.     else
  238.         return sprintf(sysfsbuf, "%u\n", speed);
  239. }
  240.  
  241. static ssize_t applesmc_store_fan_speed(struct device *dev,
  242.                     const char *sysfsbuf, size_t count,
  243.                     const char* key, int offset)
  244. {
  245.     int ret;
  246.     u32 speed;
  247.     char newkey[5];
  248.     u8 buffer[2];
  249.  
  250.     speed = simple_strtoul(sysfsbuf, NULL, 10);
  251.  
  252.     if (speed > 0x4000) /* Bigger than a 14-bit value */
  253.         return -EINVAL;
  254.  
  255.     newkey[0] = key[0];
  256.     newkey[1] = '0' + offset;
  257.     newkey[2] = key[2];
  258.     newkey[3] = key[3];
  259.     newkey[4] = 0;
  260.  
  261.     //down(&applesmc_sem);
  262.     mutex_lock(&mutex);
  263.  
  264.  
  265.     buffer[0] = (speed >> 6) & 0xff;
  266.     buffer[1] = (speed << 2) & 0xff;
  267.     ret = applesmc_write_key(newkey, buffer, 2);
  268.  
  269.     //up(&applesmc_sem);
  270.     mutex_unlock(&mutex);
  271.  
  272.     if (ret)
  273.         return ret;
  274.     else
  275.         return count;
  276. }
  277.  
  278. static ssize_t applesmc_show_fan_manual(struct device *dev, char *sysfsbuf,
  279.                                 int offset)
  280. {
  281.     int ret;
  282.     u16 manual = 0;
  283.     u8 buffer[2];
  284.  
  285.     //down(&applesmc_sem);
  286.     mutex_lock(&mutex);
  287.  
  288.     ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
  289.     manual = ((buffer[0] << 8 | buffer[1]) >> offset) & 0x01;
  290.  
  291.     //up(&applesmc_sem);
  292.     mutex_unlock(&mutex);
  293.  
  294.     if (ret)
  295.         return ret;
  296.     else
  297.         return sprintf(sysfsbuf, "%d\n", manual);
  298. }
  299.  
  300. static ssize_t applesmc_store_fan_manual(struct device *dev,
  301.                 const char *sysfsbuf, size_t count, int offset)
  302. {
  303.     int ret;
  304.     u8 buffer[2];
  305.     u32 input;
  306.     u16 val;
  307.  
  308.     input = simple_strtoul(sysfsbuf, NULL, 10);
  309.  
  310.     //down(&applesmc_sem);
  311.     mutex_lock(&mutex);
  312.  
  313.     ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
  314.     val = (buffer[0] << 8 | buffer[1]);
  315.     if (ret)
  316.         goto out;
  317.  
  318.     if (input)
  319.         val = val | (0x01 << offset);
  320.     else
  321.         val = val & ~(0x01 << offset);
  322.  
  323.     buffer[0] = (val >> 8) & 0xFF;
  324.     buffer[1] = val & 0xFF;
  325.  
  326.     ret = applesmc_write_key(FANS_MANUAL, buffer, 2);
  327.  
  328. out:
  329.     //up(&applesmc_sem);
  330.     mutex_unlock(&mutex);
  331.  
  332.     if (ret)
  333.         return ret;
  334.     else
  335.         return count;
  336. }
  337.  
  338. /*
  339.  * Macro defining helper functions and DEVICE_ATTR for a fan sysfs entries.
  340.  *  - show actual speed
  341.  *  - show/store minimum speed
  342.  *  - show maximum speed
  343.  *  - show safe speed
  344.  *  - show/store target speed
  345.  *  - show/store manual mode
  346.  */
  347. #define sysfs_fan_speeds_offset(offset) \
  348. static ssize_t show_fan_actual_speed_##offset (struct device *dev, \
  349.                 struct device_attribute *attr, char *buf) \
  350. { \
  351.     return applesmc_show_fan_speed(dev, buf, FAN_ACTUAL_SPEED, offset); \
  352. } \
  353. static DEVICE_ATTR(fan##offset##_actual_speed, S_IRUGO, \
  354.                     show_fan_actual_speed_##offset, NULL); \
  355. \
  356. static ssize_t show_fan_minimum_speed_##offset (struct device *dev, \
  357.                 struct device_attribute *attr, char *buf) \
  358. { \
  359.     return applesmc_show_fan_speed(dev, buf, FAN_MIN_SPEED, offset); \
  360. } \
  361. static ssize_t store_fan_minimum_speed_##offset (struct device *dev, \
  362.         struct device_attribute *attr, const char *buf, size_t count) \
  363. { \
  364.     return applesmc_store_fan_speed(dev, buf, count, FAN_MIN_SPEED, offset); \
  365. } \
  366. static DEVICE_ATTR(fan##offset##_minimum_speed, S_IRUGO | S_IWUSR, \
  367.     show_fan_minimum_speed_##offset, store_fan_minimum_speed_##offset); \
  368. \
  369. static ssize_t show_fan_maximum_speed_##offset (struct device *dev, \
  370.                 struct device_attribute *attr, char *buf) \
  371. { \
  372.     return applesmc_show_fan_speed(dev, buf, FAN_MAX_SPEED, offset); \
  373. } \
  374. static DEVICE_ATTR(fan##offset##_maximum_speed, S_IRUGO, \
  375.                 show_fan_maximum_speed_##offset, NULL); \
  376. \
  377. static ssize_t show_fan_safe_speed_##offset (struct device *dev, \
  378.                 struct device_attribute *attr, char *buf) \
  379. { \
  380.     return applesmc_show_fan_speed(dev, buf, FAN_SAFE_SPEED, offset); \
  381. } \
  382. static DEVICE_ATTR(fan##offset##_safe_speed, S_IRUGO, \
  383.                     show_fan_safe_speed_##offset, NULL); \
  384. \
  385. static ssize_t show_fan_target_speed_##offset (struct device *dev, \
  386.                 struct device_attribute *attr, char *buf) \
  387. { \
  388.     return applesmc_show_fan_speed(dev, buf, FAN_TARGET_SPEED, offset); \
  389. } \
  390. static ssize_t store_fan_target_speed_##offset (struct device *dev, \
  391.         struct device_attribute *attr, const char *buf, size_t count) \
  392. { \
  393.     return applesmc_store_fan_speed(dev, buf, count, FAN_TARGET_SPEED, offset); \
  394. } \
  395. static DEVICE_ATTR(fan##offset##_target_speed, S_IRUGO | S_IWUSR, \
  396.     show_fan_target_speed_##offset, store_fan_target_speed_##offset); \
  397. static ssize_t show_fan_manual_##offset (struct device *dev, \
  398.                 struct device_attribute *attr, char *buf) \
  399. { \
  400.     return applesmc_show_fan_manual(dev, buf, offset); \
  401. } \
  402. static ssize_t store_fan_manual_##offset (struct device *dev, \
  403.         struct device_attribute *attr, const char *buf, size_t count) \
  404. { \
  405.     return applesmc_store_fan_manual(dev, buf, count, offset); \
  406. } \
  407. static DEVICE_ATTR(fan##offset##_manual, S_IRUGO | S_IWUSR, \
  408.            show_fan_manual_##offset, store_fan_manual_##offset);
  409.  
  410. /*
  411.  * Create the needed functions for each fan using the macro defined above
  412.  * (2 fans are supported)
  413.  */
  414. sysfs_fan_speeds_offset(0);
  415. sysfs_fan_speeds_offset(1);
  416.  
  417. /* Macro creating the sysfs entries for a fan */
  418. #define device_create_file_fan(ret, client, offset) \
  419. do { \
  420. ret = sysfs_create_file(client, &dev_attr_fan##offset##_actual_speed.attr); \
  421. if (ret) break; \
  422. ret = sysfs_create_file(client, &dev_attr_fan##offset##_minimum_speed.attr); \
  423. if (ret) break; \
  424. ret = sysfs_create_file(client, &dev_attr_fan##offset##_maximum_speed.attr); \
  425. if (ret) break; \
  426. ret = sysfs_create_file(client, &dev_attr_fan##offset##_safe_speed.attr); \
  427. if (ret) break; \
  428. ret = sysfs_create_file(client, &dev_attr_fan##offset##_target_speed.attr); \
  429. if (ret) break; \
  430. ret = sysfs_create_file(client, &dev_attr_fan##offset##_manual.attr); \
  431. } while (0)
  432.  
  433.  
  434. static int __init applesmc_init(void)
  435. {
  436.     int ret;
  437.     int count;
  438.  
  439.     if (!request_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS,
  440.                                 "applesmc")) {
  441.         ret = -ENXIO;
  442.         goto out;
  443.     }
  444.  
  445.     ret = platform_driver_register(&applesmc_driver);
  446.     if (ret)
  447.         goto out_region;
  448.  
  449.     pdev = platform_device_register_simple("applesmc", -1, NULL, 0);
  450.     if (IS_ERR(pdev)) {
  451.         ret = PTR_ERR(pdev);
  452.         goto out_driver;
  453.     }
  454.  
  455.     /* create fan files */
  456.     count = applesmc_get_fan_count();
  457.     if (count < 0) {
  458.         printk(KERN_ERR "applesmc: Cannot get the number of fans.\n");
  459.     }
  460.     else {
  461.         printk(KERN_INFO "applesmc: %d fans found.\n", count);
  462.  
  463.         switch (count) {
  464.         default:
  465.             printk(KERN_WARNING "applesmc: More than 2 fans found,"
  466.                     " but at most 2 fans are supported"
  467.                         " by the driver.\n");
  468.         case 2:
  469.             device_create_file_fan(ret, &pdev->dev.kobj, 1);
  470.             if (ret)
  471.                 goto out_device;
  472.         case 1:
  473.             device_create_file_fan(ret, &pdev->dev.kobj, 0);
  474.             if (ret)
  475.                 goto out_device;
  476.         case 0:
  477.             ;
  478.         }
  479.     }
  480.  
  481.     printk(KERN_INFO "applesmc: driver successfully loaded.\n");
  482.     return 0;
  483.  
  484. out_device:
  485.     platform_device_unregister(pdev);
  486. out_driver:
  487.     platform_driver_unregister(&applesmc_driver);
  488. out_region:
  489.     release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
  490. out:
  491.     printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret);
  492.     return ret;
  493. }
  494.  
  495. static void __exit applesmc_exit(void)
  496. {
  497.     platform_device_unregister(pdev);
  498.     platform_driver_unregister(&applesmc_driver);
  499.     release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
  500.  
  501.     printk(KERN_INFO "applesmc: driver unloaded.\n");
  502. }
  503.  
  504. module_init(applesmc_init);
  505. module_exit(applesmc_exit);
  506.  
  507. MODULE_AUTHOR("Videot4pe");
  508. MODULE_DESCRIPTION("Fan control");
  509. MODULE_LICENSE("GPL v2");
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement