OSDN Git Service

Update tp_smapi to 0.43
[android-x86/device-generic-common.git] / tp_smapi / hdaps.c
1 /*
2  * drivers/platform/x86/hdaps.c - driver for IBM's Hard Drive Active Protection System
3  *
4  * Copyright (C) 2005 Robert Love <rml@novell.com>
5  * Copyright (C) 2005 Jesper Juhl <jesper.juhl@gmail.com>
6  *
7  * The HardDisk Active Protection System (hdaps) is present in IBM ThinkPads
8  * starting with the R40, T41, and X40.  It provides a basic two-axis
9  * accelerometer and other data, such as the device's temperature.
10  *
11  * This driver is based on the document by Mark A. Smith available at
12  * http://www.almaden.ibm.com/cs/people/marksmith/tpaps.html and a lot of trial
13  * and error.
14  *
15  * This program is free software; you can redistribute it and/or modify it
16  * under the terms of the GNU General Public License v2 as published by the
17  * Free Software Foundation.
18  *
19  * This program is distributed in the hope that it will be useful, but WITHOUT
20  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
22  * more details.
23  *
24  * You should have received a copy of the GNU General Public License along with
25  * this program; if not, write to the Free Software Foundation, Inc.,
26  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
27  */
28
29 #include <linux/delay.h>
30 #include <linux/platform_device.h>
31 #include <linux/input.h>
32 #include <linux/kernel.h>
33 #include <linux/module.h>
34 #include <linux/timer.h>
35 #include <linux/dmi.h>
36 #include <linux/jiffies.h>
37 #include "thinkpad_ec.h"
38 #include <linux/pci_ids.h>
39 #include <linux/version.h>
40
41 /* Embedded controller accelerometer read command and its result: */
42 static const struct thinkpad_ec_row ec_accel_args =
43         { .mask = 0x0001, .val = {0x11} };
44 #define EC_ACCEL_IDX_READOUTS   0x1     /* readouts included in this read */
45                                         /* First readout, if READOUTS>=1: */
46 #define EC_ACCEL_IDX_YPOS1      0x2     /*   y-axis position word */
47 #define EC_ACCEL_IDX_XPOS1      0x4     /*   x-axis position word */
48 #define EC_ACCEL_IDX_TEMP1      0x6     /*   device temperature in Celsius */
49                                         /* Second readout, if READOUTS>=2: */
50 #define EC_ACCEL_IDX_XPOS2      0x7     /*   y-axis position word */
51 #define EC_ACCEL_IDX_YPOS2      0x9     /*   x-axis position word */
52 #define EC_ACCEL_IDX_TEMP2      0xb     /*   device temperature in Celsius */
53 #define EC_ACCEL_IDX_QUEUED     0xc     /* Number of queued readouts left */
54 #define EC_ACCEL_IDX_KMACT      0xd     /* keyboard or mouse activity */
55 #define EC_ACCEL_IDX_RETVAL     0xf     /* command return value, good=0x00 */
56
57 #define KEYBD_MASK              0x20    /* set if keyboard activity */
58 #define MOUSE_MASK              0x40    /* set if mouse activity */
59
60 #define READ_TIMEOUT_MSECS      100     /* wait this long for device read */
61 #define RETRY_MSECS             3       /* retry delay */
62
63 #define HDAPS_INPUT_FUZZ        4       /* input event threshold */
64 #define HDAPS_INPUT_FLAT        4
65 #define KMACT_REMEMBER_PERIOD   (HZ/10) /* keyboard/mouse persistence */
66
67 /* Input IDs */
68 #define HDAPS_INPUT_VENDOR      PCI_VENDOR_ID_IBM
69 #define HDAPS_INPUT_PRODUCT     0x5054 /* "TP", shared with thinkpad_acpi */
70 #define HDAPS_INPUT_JS_VERSION  0x6801 /* Joystick emulation input device */
71 #define HDAPS_INPUT_RAW_VERSION 0x4801 /* Raw accelerometer input device */
72
73 /* Axis orientation. */
74 /* The unnatural bit-representation of inversions is for backward
75  * compatibility with the"invert=1" module parameter.             */
76 #define HDAPS_ORIENT_INVERT_XY  0x01   /* Invert both X and Y axes.       */
77 #define HDAPS_ORIENT_INVERT_X   0x02   /* Invert the X axis (uninvert if
78                                         * already inverted by INVERT_XY). */
79 #define HDAPS_ORIENT_SWAP       0x04   /* Swap the axes. The swap occurs
80                                         * before inverting X or Y.        */
81 #define HDAPS_ORIENT_MAX        0x07
82 #define HDAPS_ORIENT_UNDEFINED  0xFF   /* Placeholder during initialization */
83 #define HDAPS_ORIENT_INVERT_Y   (HDAPS_ORIENT_INVERT_XY | HDAPS_ORIENT_INVERT_X)
84
85 static struct timer_list hdaps_timer;
86 static struct platform_device *pdev;
87 static struct input_dev *hdaps_idev;     /* joystick-like device with fuzz */
88 static struct input_dev *hdaps_idev_raw; /* raw hdaps sensor readouts */
89 static unsigned int hdaps_invert = HDAPS_ORIENT_UNDEFINED;
90 static int needs_calibration;
91
92 /* Configuration: */
93 static int sampling_rate = 50;       /* Sampling rate  */
94 static int oversampling_ratio = 5;   /* Ratio between our sampling rate and
95                                       * EC accelerometer sampling rate      */
96 static int running_avg_filter_order = 2; /* EC running average filter order */
97
98 /* Latest state readout: */
99 static int pos_x, pos_y;      /* position */
100 static int temperature;       /* temperature */
101 static int stale_readout = 1; /* last read invalid */
102 static int rest_x, rest_y;    /* calibrated rest position */
103
104 /* Last time we saw keyboard and mouse activity: */
105 static u64 last_keyboard_jiffies = INITIAL_JIFFIES;
106 static u64 last_mouse_jiffies = INITIAL_JIFFIES;
107 static u64 last_update_jiffies = INITIAL_JIFFIES;
108
109 /* input device use count */
110 static int hdaps_users;
111 static DEFINE_MUTEX(hdaps_users_mtx);
112
113 /* Some models require an axis transformation to the standard representation */
114 static void transform_axes(int *x, int *y)
115 {
116         if (hdaps_invert & HDAPS_ORIENT_SWAP) {
117                 int z;
118                 z = *x;
119                 *x = *y;
120                 *y = z;
121         }
122         if (hdaps_invert & HDAPS_ORIENT_INVERT_XY) {
123                 *x = -*x;
124                 *y = -*y;
125         }
126         if (hdaps_invert & HDAPS_ORIENT_INVERT_X)
127                 *x = -*x;
128 }
129
130 /**
131  * __hdaps_update - query current state, with locks already acquired
132  * @fast: if nonzero, do one quick attempt without retries.
133  *
134  * Query current accelerometer state and update global state variables.
135  * Also prefetches the next query. Caller must hold controller lock.
136  */
137 static int __hdaps_update(int fast)
138 {
139         /* Read data: */
140         struct thinkpad_ec_row data;
141         int ret;
142
143         data.mask = (1 << EC_ACCEL_IDX_READOUTS) | (1 << EC_ACCEL_IDX_KMACT) |
144                     (3 << EC_ACCEL_IDX_YPOS1)    | (3 << EC_ACCEL_IDX_XPOS1) |
145                     (1 << EC_ACCEL_IDX_TEMP1)    | (1 << EC_ACCEL_IDX_RETVAL);
146         if (fast)
147                 ret = thinkpad_ec_try_read_row(&ec_accel_args, &data);
148         else
149                 ret = thinkpad_ec_read_row(&ec_accel_args, &data);
150         thinkpad_ec_prefetch_row(&ec_accel_args); /* Prefetch even if error */
151         if (ret)
152                 return ret;
153
154         /* Check status: */
155         if (data.val[EC_ACCEL_IDX_RETVAL] != 0x00) {
156                 printk(KERN_WARNING "hdaps: read RETVAL=0x%02x\n",
157                        data.val[EC_ACCEL_IDX_RETVAL]);
158                 return -EIO;
159         }
160
161         if (data.val[EC_ACCEL_IDX_READOUTS] < 1)
162                 return -EBUSY; /* no pending readout, try again later */
163
164         /* Parse position data: */
165         pos_x = *(s16 *)(data.val+EC_ACCEL_IDX_XPOS1);
166         pos_y = *(s16 *)(data.val+EC_ACCEL_IDX_YPOS1);
167         transform_axes(&pos_x, &pos_y);
168
169         /* Keyboard and mouse activity status is cleared as soon as it's read,
170          * so applications will eat each other's events. Thus we remember any
171          * event for KMACT_REMEMBER_PERIOD jiffies.
172          */
173         if (data.val[EC_ACCEL_IDX_KMACT] & KEYBD_MASK)
174                 last_keyboard_jiffies = get_jiffies_64();
175         if (data.val[EC_ACCEL_IDX_KMACT] & MOUSE_MASK)
176                 last_mouse_jiffies = get_jiffies_64();
177
178         temperature = data.val[EC_ACCEL_IDX_TEMP1];
179
180         last_update_jiffies = get_jiffies_64();
181         stale_readout = 0;
182         if (needs_calibration) {
183                 rest_x = pos_x;
184                 rest_y = pos_y;
185                 needs_calibration = 0;
186         }
187
188         return 0;
189 }
190
191 /**
192  * hdaps_update - acquire locks and query current state
193  *
194  * Query current accelerometer state and update global state variables.
195  * Also prefetches the next query.
196  * Retries until timeout if the accelerometer is not in ready status (common).
197  * Does its own locking.
198  */
199 static int hdaps_update(void)
200 {
201         u64 age = get_jiffies_64() - last_update_jiffies;
202         int total, ret;
203
204         if (!stale_readout && age < (9*HZ)/(10*sampling_rate))
205                 return 0; /* already updated recently */
206         for (total = 0; total < READ_TIMEOUT_MSECS; total += RETRY_MSECS) {
207                 ret = thinkpad_ec_lock();
208                 if (ret)
209                         return ret;
210                 ret = __hdaps_update(0);
211                 thinkpad_ec_unlock();
212
213                 if (!ret)
214                         return 0;
215                 if (ret != -EBUSY)
216                         break;
217                 msleep(RETRY_MSECS);
218         }
219         return ret;
220 }
221
222 /**
223  * hdaps_set_power - enable or disable power to the accelerometer.
224  * Returns zero on success and negative error code on failure.  Can sleep.
225  */
226 static int hdaps_set_power(int on)
227 {
228         struct thinkpad_ec_row args =
229                 { .mask = 0x0003, .val = {0x14, on?0x01:0x00} };
230         struct thinkpad_ec_row data = { .mask = 0x8000 };
231         int ret = thinkpad_ec_read_row(&args, &data);
232         if (ret)
233                 return ret;
234         if (data.val[0xF] != 0x00)
235                 return -EIO;
236         return 0;
237 }
238
239 /**
240  * hdaps_set_ec_config - set accelerometer parameters.
241  * @ec_rate: embedded controller sampling rate
242  * @order: embedded controller running average filter order
243  * (Normally we have @ec_rate = sampling_rate * oversampling_ratio.)
244  * Returns zero on success and negative error code on failure.  Can sleep.
245  */
246 static int hdaps_set_ec_config(int ec_rate, int order)
247 {
248         struct thinkpad_ec_row args = { .mask = 0x000F,
249                 .val = {0x10, (u8)ec_rate, (u8)(ec_rate>>8), order} };
250         struct thinkpad_ec_row data = { .mask = 0x8000 };
251         int ret = thinkpad_ec_read_row(&args, &data);
252         printk(KERN_DEBUG "hdaps: setting ec_rate=%d, filter_order=%d\n",
253                ec_rate, order);
254         if (ret)
255                 return ret;
256         if (data.val[0xF] == 0x03) {
257                 printk(KERN_WARNING "hdaps: config param out of range\n");
258                 return -EINVAL;
259         }
260         if (data.val[0xF] == 0x06) {
261                 printk(KERN_WARNING "hdaps: config change already pending\n");
262                 return -EBUSY;
263         }
264         if (data.val[0xF] != 0x00) {
265                 printk(KERN_WARNING "hdaps: config change error, ret=%d\n",
266                       data.val[0xF]);
267                 return -EIO;
268         }
269         return 0;
270 }
271
272 /**
273  * hdaps_get_ec_config - get accelerometer parameters.
274  * @ec_rate: embedded controller sampling rate
275  * @order: embedded controller running average filter order
276  * Returns zero on success and negative error code on failure.  Can sleep.
277  */
278 static int hdaps_get_ec_config(int *ec_rate, int *order)
279 {
280         const struct thinkpad_ec_row args =
281                 { .mask = 0x0003, .val = {0x17, 0x82} };
282         struct thinkpad_ec_row data = { .mask = 0x801F };
283         int ret = thinkpad_ec_read_row(&args, &data);
284         if (ret)
285                 return ret;
286         if (data.val[0xF] != 0x00)
287                 return -EIO;
288         if (!(data.val[0x1] & 0x01))
289                 return -ENXIO; /* accelerometer polling not enabled */
290         if (data.val[0x1] & 0x02)
291                 return -EBUSY; /* config change in progress, retry later */
292         *ec_rate = data.val[0x2] | ((int)(data.val[0x3]) << 8);
293         *order = data.val[0x4];
294         return 0;
295 }
296
297 /**
298  * hdaps_get_ec_mode - get EC accelerometer mode
299  * Returns zero on success and negative error code on failure.  Can sleep.
300  */
301 static int hdaps_get_ec_mode(u8 *mode)
302 {
303         const struct thinkpad_ec_row args =
304                 { .mask = 0x0001, .val = {0x13} };
305         struct thinkpad_ec_row data = { .mask = 0x8002 };
306         int ret = thinkpad_ec_read_row(&args, &data);
307         if (ret)
308                 return ret;
309         if (data.val[0xF] != 0x00) {
310                 printk(KERN_WARNING
311                        "accelerometer not implemented (0x%02x)\n",
312                        data.val[0xF]);
313                 return -EIO;
314         }
315         *mode = data.val[0x1];
316         return 0;
317 }
318
319 /**
320  * hdaps_check_ec - checks something about the EC.
321  * Follows the clean-room spec for HDAPS; we don't know what it means.
322  * Returns zero on success and negative error code on failure.  Can sleep.
323  */
324 static int hdaps_check_ec(void)
325 {
326         const struct thinkpad_ec_row args =
327                 { .mask = 0x0003, .val = {0x17, 0x81} };
328         struct thinkpad_ec_row data = { .mask = 0x800E };
329         int ret = thinkpad_ec_read_row(&args, &data);
330         if (ret)
331                 return  ret;
332         if (!((data.val[0x1] == 0x00 && data.val[0x2] == 0x60) || /* cleanroom spec */
333               (data.val[0x1] == 0x01 && data.val[0x2] == 0x00)) || /* seen on T61 */
334             data.val[0x3] != 0x00 || data.val[0xF] != 0x00) {
335                 printk(KERN_WARNING
336                        "hdaps_check_ec: bad response (0x%x,0x%x,0x%x,0x%x)\n",
337                        data.val[0x1], data.val[0x2],
338                        data.val[0x3], data.val[0xF]);
339                 return -EIO;
340         }
341         return 0;
342 }
343
344 /**
345  * hdaps_device_init - initialize the accelerometer.
346  *
347  * Call several embedded controller functions to test and initialize the
348  * accelerometer.
349  * Returns zero on success and negative error code on failure. Can sleep.
350  */
351 #define FAILED_INIT(msg) printk(KERN_ERR "hdaps init failed at: %s\n", msg)
352 static int hdaps_device_init(void)
353 {
354         int ret;
355         u8 mode;
356
357         ret = thinkpad_ec_lock();
358         if (ret)
359                 return ret;
360
361         if (hdaps_get_ec_mode(&mode))
362                 { FAILED_INIT("hdaps_get_ec_mode failed"); goto bad; }
363
364         printk(KERN_DEBUG "hdaps: initial mode latch is 0x%02x\n", mode);
365         if (mode == 0x00)
366                 { FAILED_INIT("accelerometer not available"); goto bad; }
367
368         if (hdaps_check_ec())
369                 { FAILED_INIT("hdaps_check_ec failed"); goto bad; }
370
371         if (hdaps_set_power(1))
372                 { FAILED_INIT("hdaps_set_power failed"); goto bad; }
373
374         if (hdaps_set_ec_config(sampling_rate*oversampling_ratio,
375                                 running_avg_filter_order))
376                 { FAILED_INIT("hdaps_set_ec_config failed"); goto bad; }
377
378         thinkpad_ec_invalidate();
379         udelay(200);
380
381         /* Just prefetch instead of reading, to avoid ~1sec delay on load */
382         ret = thinkpad_ec_prefetch_row(&ec_accel_args);
383         if (ret)
384                 { FAILED_INIT("initial prefetch failed"); goto bad; }
385         goto good;
386 bad:
387         thinkpad_ec_invalidate();
388         ret = -ENXIO;
389 good:
390         stale_readout = 1;
391         thinkpad_ec_unlock();
392         return ret;
393 }
394
395 /**
396  * hdaps_device_shutdown - power off the accelerometer
397  * Returns nonzero on failure. Can sleep.
398  */
399 static int hdaps_device_shutdown(void)
400 {
401         int ret;
402         ret = hdaps_set_power(0);
403         if (ret) {
404                 printk(KERN_WARNING "hdaps: cannot power off\n");
405                 return ret;
406         }
407         ret = hdaps_set_ec_config(0, 1);
408         if (ret)
409                 printk(KERN_WARNING "hdaps: cannot stop EC sampling\n");
410         return ret;
411 }
412
413 /* Device model stuff */
414
415 static int hdaps_probe(struct platform_device *dev)
416 {
417         int ret;
418
419         ret = hdaps_device_init();
420         if (ret)
421                 return ret;
422
423         printk(KERN_INFO "hdaps: device successfully initialized.\n");
424         return 0;
425 }
426
427 static int hdaps_suspend(struct platform_device *dev, pm_message_t state)
428 {
429         /* Don't do hdaps polls until resume re-initializes the sensor. */
430         del_timer_sync(&hdaps_timer);
431         hdaps_device_shutdown(); /* ignore errors, effect is negligible */
432         return 0;
433 }
434
435 static int hdaps_resume(struct platform_device *dev)
436 {
437         int ret = hdaps_device_init();
438         if (ret)
439                 return ret;
440
441         mutex_lock(&hdaps_users_mtx);
442         if (hdaps_users)
443                 mod_timer(&hdaps_timer, jiffies + HZ/sampling_rate);
444         mutex_unlock(&hdaps_users_mtx);
445         return 0;
446 }
447
448 static struct platform_driver hdaps_driver = {
449         .probe = hdaps_probe,
450         .suspend = hdaps_suspend,
451         .resume = hdaps_resume,
452         .driver = {
453                 .name = "hdaps",
454                 .owner = THIS_MODULE,
455         },
456 };
457
458 /**
459  * hdaps_calibrate - set our "resting" values.
460  * Does its own locking.
461  */
462 static void hdaps_calibrate(void)
463 {
464         needs_calibration = 1;
465         hdaps_update();
466         /* If that fails, the mousedev poll will take care of things later. */
467 }
468
469 /* Timer handler for updating the input device. Runs in softirq context,
470  * so avoid lenghty or blocking operations.
471  */
472 #if LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0)
473 static void hdaps_mousedev_poll(unsigned long unused)
474 #else
475 static void hdaps_mousedev_poll(struct timer_list *unused)
476 #endif
477 {
478         int ret;
479
480         stale_readout = 1;
481
482         /* Cannot sleep.  Try nonblockingly.  If we fail, try again later. */
483         if (thinkpad_ec_try_lock())
484                 goto keep_active;
485
486         ret = __hdaps_update(1); /* fast update, we're in softirq context */
487         thinkpad_ec_unlock();
488         /* Any of "successful", "not yet ready" and "not prefetched"? */
489         if (ret != 0 && ret != -EBUSY && ret != -ENODATA) {
490                 printk(KERN_ERR
491                        "hdaps: poll failed, disabling updates\n");
492                 return;
493         }
494
495 keep_active:
496         /* Even if we failed now, pos_x,y may have been updated earlier: */
497         input_report_abs(hdaps_idev, ABS_X, pos_x - rest_x);
498         input_report_abs(hdaps_idev, ABS_Y, pos_y - rest_y);
499         input_sync(hdaps_idev);
500         input_report_abs(hdaps_idev_raw, ABS_X, pos_x);
501         input_report_abs(hdaps_idev_raw, ABS_Y, pos_y);
502         input_sync(hdaps_idev_raw);
503         mod_timer(&hdaps_timer, jiffies + HZ/sampling_rate);
504 }
505
506
507 /* Sysfs Files */
508
509 static ssize_t hdaps_position_show(struct device *dev,
510                                    struct device_attribute *attr, char *buf)
511 {
512         int ret = hdaps_update();
513         if (ret)
514                 return ret;
515         return sprintf(buf, "(%d,%d)\n", pos_x, pos_y);
516 }
517
518 static ssize_t hdaps_temp1_show(struct device *dev,
519                                 struct device_attribute *attr, char *buf)
520 {
521         int ret = hdaps_update();
522         if (ret)
523                 return ret;
524         return sprintf(buf, "%d\n", temperature);
525 }
526
527 static ssize_t hdaps_keyboard_activity_show(struct device *dev,
528                                             struct device_attribute *attr,
529                                             char *buf)
530 {
531         int ret = hdaps_update();
532         if (ret)
533                 return ret;
534         return sprintf(buf, "%u\n",
535            get_jiffies_64() < last_keyboard_jiffies + KMACT_REMEMBER_PERIOD);
536 }
537
538 static ssize_t hdaps_mouse_activity_show(struct device *dev,
539                                          struct device_attribute *attr,
540                                          char *buf)
541 {
542         int ret = hdaps_update();
543         if (ret)
544                 return ret;
545         return sprintf(buf, "%u\n",
546            get_jiffies_64() < last_mouse_jiffies + KMACT_REMEMBER_PERIOD);
547 }
548
549 static ssize_t hdaps_calibrate_show(struct device *dev,
550                                     struct device_attribute *attr, char *buf)
551 {
552         return sprintf(buf, "(%d,%d)\n", rest_x, rest_y);
553 }
554
555 static ssize_t hdaps_calibrate_store(struct device *dev,
556                                      struct device_attribute *attr,
557                                      const char *buf, size_t count)
558 {
559         hdaps_calibrate();
560         return count;
561 }
562
563 static ssize_t hdaps_invert_show(struct device *dev,
564                                  struct device_attribute *attr, char *buf)
565 {
566         return sprintf(buf, "%u\n", hdaps_invert);
567 }
568
569 static ssize_t hdaps_invert_store(struct device *dev,
570                                   struct device_attribute *attr,
571                                   const char *buf, size_t count)
572 {
573         int invert;
574
575         if (sscanf(buf, "%d", &invert) != 1 ||
576             invert < 0 || invert > HDAPS_ORIENT_MAX)
577                 return -EINVAL;
578
579         hdaps_invert = invert;
580         hdaps_calibrate();
581
582         return count;
583 }
584
585 static ssize_t hdaps_sampling_rate_show(
586         struct device *dev, struct device_attribute *attr, char *buf)
587 {
588         return sprintf(buf, "%d\n", sampling_rate);
589 }
590
591 static ssize_t hdaps_sampling_rate_store(
592         struct device *dev, struct device_attribute *attr,
593         const char *buf, size_t count)
594 {
595         int rate, ret;
596         if (sscanf(buf, "%d", &rate) != 1 || rate > HZ || rate <= 0) {
597                 printk(KERN_WARNING
598                        "must have 0<input_sampling_rate<=HZ=%d\n", HZ);
599                 return -EINVAL;
600         }
601         ret = hdaps_set_ec_config(rate*oversampling_ratio,
602                                   running_avg_filter_order);
603         if (ret)
604                 return ret;
605         sampling_rate = rate;
606         return count;
607 }
608
609 static ssize_t hdaps_oversampling_ratio_show(
610         struct device *dev, struct device_attribute *attr, char *buf)
611 {
612         int ec_rate, order;
613         int ret = hdaps_get_ec_config(&ec_rate, &order);
614         if (ret)
615                 return ret;
616         return sprintf(buf, "%u\n", ec_rate / sampling_rate);
617 }
618
619 static ssize_t hdaps_oversampling_ratio_store(
620         struct device *dev, struct device_attribute *attr,
621         const char *buf, size_t count)
622 {
623         int ratio, ret;
624         if (sscanf(buf, "%d", &ratio) != 1 || ratio < 1)
625                 return -EINVAL;
626         ret = hdaps_set_ec_config(sampling_rate*ratio,
627                                   running_avg_filter_order);
628         if (ret)
629                 return ret;
630         oversampling_ratio = ratio;
631         return count;
632 }
633
634 static ssize_t hdaps_running_avg_filter_order_show(
635         struct device *dev, struct device_attribute *attr, char *buf)
636 {
637         int rate, order;
638         int ret = hdaps_get_ec_config(&rate, &order);
639         if (ret)
640                 return ret;
641         return sprintf(buf, "%u\n", order);
642 }
643
644 static ssize_t hdaps_running_avg_filter_order_store(
645         struct device *dev, struct device_attribute *attr,
646         const char *buf, size_t count)
647 {
648         int order, ret;
649         if (sscanf(buf, "%d", &order) != 1)
650                 return -EINVAL;
651         ret = hdaps_set_ec_config(sampling_rate*oversampling_ratio, order);
652         if (ret)
653                 return ret;
654         running_avg_filter_order = order;
655         return count;
656 }
657
658 static int hdaps_mousedev_open(struct input_dev *dev)
659 {
660         if (!try_module_get(THIS_MODULE))
661                 return -ENODEV;
662
663         mutex_lock(&hdaps_users_mtx);
664         if (hdaps_users++ == 0) /* first input user */
665                 mod_timer(&hdaps_timer, jiffies + HZ/sampling_rate);
666         mutex_unlock(&hdaps_users_mtx);
667         return 0;
668 }
669
670 static void hdaps_mousedev_close(struct input_dev *dev)
671 {
672         mutex_lock(&hdaps_users_mtx);
673         if (--hdaps_users == 0) /* no input users left */
674                 del_timer_sync(&hdaps_timer);
675         mutex_unlock(&hdaps_users_mtx);
676
677         module_put(THIS_MODULE);
678 }
679
680 static DEVICE_ATTR(position, 0444, hdaps_position_show, NULL);
681 static DEVICE_ATTR(temp1, 0444, hdaps_temp1_show, NULL);
682   /* "temp1" instead of "temperature" is hwmon convention */
683 static DEVICE_ATTR(keyboard_activity, 0444,
684                    hdaps_keyboard_activity_show, NULL);
685 static DEVICE_ATTR(mouse_activity, 0444, hdaps_mouse_activity_show, NULL);
686 static DEVICE_ATTR(calibrate, 0644,
687                    hdaps_calibrate_show, hdaps_calibrate_store);
688 static DEVICE_ATTR(invert, 0644, hdaps_invert_show, hdaps_invert_store);
689 static DEVICE_ATTR(sampling_rate, 0644,
690                    hdaps_sampling_rate_show, hdaps_sampling_rate_store);
691 static DEVICE_ATTR(oversampling_ratio, 0644,
692                    hdaps_oversampling_ratio_show,
693                    hdaps_oversampling_ratio_store);
694 static DEVICE_ATTR(running_avg_filter_order, 0644,
695                    hdaps_running_avg_filter_order_show,
696                    hdaps_running_avg_filter_order_store);
697
698 static struct attribute *hdaps_attributes[] = {
699         &dev_attr_position.attr,
700         &dev_attr_temp1.attr,
701         &dev_attr_keyboard_activity.attr,
702         &dev_attr_mouse_activity.attr,
703         &dev_attr_calibrate.attr,
704         &dev_attr_invert.attr,
705         &dev_attr_sampling_rate.attr,
706         &dev_attr_oversampling_ratio.attr,
707         &dev_attr_running_avg_filter_order.attr,
708         NULL,
709 };
710
711 static struct attribute_group hdaps_attribute_group = {
712         .attrs = hdaps_attributes,
713 };
714
715
716 /* Module stuff */
717
718 /* hdaps_dmi_match_invert - found an inverted match. */
719 static int __init hdaps_dmi_match_invert(const struct dmi_system_id *id)
720 {
721         unsigned int orient = (kernel_ulong_t) id->driver_data;
722         hdaps_invert = orient;
723         printk(KERN_INFO "hdaps: %s detected, setting orientation %u\n",
724                id->ident, orient);
725         return 1; /* stop enumeration */
726 }
727
728 #define HDAPS_DMI_MATCH_INVERT(vendor, model, orient) { \
729         .ident = vendor " " model,                      \
730         .callback = hdaps_dmi_match_invert,             \
731         .driver_data = (void *)(orient),                \
732         .matches = {                                    \
733                 DMI_MATCH(DMI_BOARD_VENDOR, vendor),    \
734                 DMI_MATCH(DMI_PRODUCT_VERSION, model)   \
735         }                                               \
736 }
737
738 /* List of models with abnormal axis configuration.
739    Note that HDAPS_DMI_MATCH_NORMAL("ThinkPad T42") would match
740    "ThinkPad T42p", and enumeration stops after first match,
741    so the order of the entries matters. */
742 struct dmi_system_id __initconst hdaps_whitelist[] = {
743         HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad R50p", HDAPS_ORIENT_INVERT_XY),
744         HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad R60", HDAPS_ORIENT_INVERT_XY),
745         HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T41p", HDAPS_ORIENT_INVERT_XY),
746         HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T42p", HDAPS_ORIENT_INVERT_XY),
747         HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad X40", HDAPS_ORIENT_INVERT_Y),
748         HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad X41", HDAPS_ORIENT_INVERT_Y),
749         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R60", HDAPS_ORIENT_INVERT_XY),
750         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61", HDAPS_ORIENT_INVERT_XY),
751         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R400", HDAPS_ORIENT_INVERT_XY),
752         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R500", HDAPS_ORIENT_INVERT_XY),
753         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T60", HDAPS_ORIENT_INVERT_XY),
754         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61", HDAPS_ORIENT_INVERT_XY),
755         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X60 Tablet", HDAPS_ORIENT_INVERT_Y),
756         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X60s", HDAPS_ORIENT_INVERT_Y),
757         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X60", HDAPS_ORIENT_SWAP | HDAPS_ORIENT_INVERT_X),
758         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61", HDAPS_ORIENT_SWAP | HDAPS_ORIENT_INVERT_X),
759         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T400s", HDAPS_ORIENT_INVERT_X),
760         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T400", HDAPS_ORIENT_INVERT_XY),
761         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T410s", HDAPS_ORIENT_SWAP),
762         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T410", HDAPS_ORIENT_INVERT_XY),
763         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T500", HDAPS_ORIENT_INVERT_XY),
764         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T510", HDAPS_ORIENT_SWAP | HDAPS_ORIENT_INVERT_X | HDAPS_ORIENT_INVERT_Y),
765         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad W510", HDAPS_ORIENT_MAX),
766         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad W520", HDAPS_ORIENT_MAX),
767         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X200s", HDAPS_ORIENT_SWAP | HDAPS_ORIENT_INVERT_XY),
768         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X200", HDAPS_ORIENT_SWAP | HDAPS_ORIENT_INVERT_X | HDAPS_ORIENT_INVERT_Y),
769         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X201 Tablet", HDAPS_ORIENT_SWAP | HDAPS_ORIENT_INVERT_XY),
770         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X201s", HDAPS_ORIENT_SWAP | HDAPS_ORIENT_INVERT_XY),
771         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X201", HDAPS_ORIENT_SWAP | HDAPS_ORIENT_INVERT_X),
772         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X220", HDAPS_ORIENT_SWAP),
773         { .ident = NULL }
774 };
775
776 static int __init hdaps_init(void)
777 {
778         int ret;
779
780         /* Determine axis orientation orientation */
781         if (hdaps_invert == HDAPS_ORIENT_UNDEFINED) /* set by module param? */
782                 if (dmi_check_system(hdaps_whitelist) < 1) /* in whitelist? */
783                         hdaps_invert = 0; /* default */
784
785         /* Init timer before platform_driver_register, in case of suspend */
786 #if LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0)
787         init_timer(&hdaps_timer);
788         hdaps_timer.function = hdaps_mousedev_poll;
789 #else
790         timer_setup(&hdaps_timer, hdaps_mousedev_poll, 0);
791 #endif
792         ret = platform_driver_register(&hdaps_driver);
793         if (ret)
794                 goto out;
795
796         pdev = platform_device_register_simple("hdaps", -1, NULL, 0);
797         if (IS_ERR(pdev)) {
798                 ret = PTR_ERR(pdev);
799                 goto out_driver;
800         }
801
802         ret = sysfs_create_group(&pdev->dev.kobj, &hdaps_attribute_group);
803         if (ret)
804                 goto out_device;
805
806         hdaps_idev = input_allocate_device();
807         if (!hdaps_idev) {
808                 ret = -ENOMEM;
809                 goto out_group;
810         }
811
812         hdaps_idev_raw = input_allocate_device();
813         if (!hdaps_idev_raw) {
814                 ret = -ENOMEM;
815                 goto out_idev_first;
816         }
817
818         /* calibration for the input device (deferred to avoid delay) */
819         needs_calibration = 1;
820
821         /* initialize the joystick-like fuzzed input device */
822         hdaps_idev->name = "ThinkPad HDAPS joystick emulation";
823         hdaps_idev->phys = "hdaps/input0";
824         hdaps_idev->id.bustype = BUS_HOST;
825         hdaps_idev->id.vendor  = HDAPS_INPUT_VENDOR;
826         hdaps_idev->id.product = HDAPS_INPUT_PRODUCT;
827         hdaps_idev->id.version = HDAPS_INPUT_JS_VERSION;
828 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
829         hdaps_idev->cdev.dev = &pdev->dev;
830 #endif
831         hdaps_idev->evbit[0] = BIT(EV_ABS);
832         hdaps_idev->open = hdaps_mousedev_open;
833         hdaps_idev->close = hdaps_mousedev_close;
834         input_set_abs_params(hdaps_idev, ABS_X,
835                         -256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT);
836         input_set_abs_params(hdaps_idev, ABS_Y,
837                         -256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT);
838
839         ret = input_register_device(hdaps_idev);
840         if (ret)
841                 goto out_idev;
842
843         /* initialize the raw data input device */
844         hdaps_idev_raw->name = "ThinkPad HDAPS accelerometer data";
845         hdaps_idev_raw->phys = "hdaps/input1";
846         hdaps_idev_raw->id.bustype = BUS_HOST;
847         hdaps_idev_raw->id.vendor  = HDAPS_INPUT_VENDOR;
848         hdaps_idev_raw->id.product = HDAPS_INPUT_PRODUCT;
849         hdaps_idev_raw->id.version = HDAPS_INPUT_RAW_VERSION;
850 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
851         hdaps_idev_raw->cdev.dev = &pdev->dev;
852 #endif
853         hdaps_idev_raw->evbit[0] = BIT(EV_ABS);
854         hdaps_idev_raw->open = hdaps_mousedev_open;
855         hdaps_idev_raw->close = hdaps_mousedev_close;
856         input_set_abs_params(hdaps_idev_raw, ABS_X, -32768, 32767, 0, 0);
857         input_set_abs_params(hdaps_idev_raw, ABS_Y, -32768, 32767, 0, 0);
858
859         ret = input_register_device(hdaps_idev_raw);
860         if (ret)
861                 goto out_idev_reg_first;
862
863         printk(KERN_INFO "hdaps: driver successfully loaded.\n");
864         return 0;
865
866 out_idev_reg_first:
867         input_unregister_device(hdaps_idev);
868 out_idev:
869         input_free_device(hdaps_idev_raw);
870 out_idev_first:
871         input_free_device(hdaps_idev);
872 out_group:
873         sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group);
874 out_device:
875         platform_device_unregister(pdev);
876 out_driver:
877         platform_driver_unregister(&hdaps_driver);
878         hdaps_device_shutdown();
879 out:
880         printk(KERN_WARNING "hdaps: driver init failed (ret=%d)!\n", ret);
881         return ret;
882 }
883
884 static void __exit hdaps_exit(void)
885 {
886         input_unregister_device(hdaps_idev_raw);
887         input_unregister_device(hdaps_idev);
888         hdaps_device_shutdown(); /* ignore errors, effect is negligible */
889         sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group);
890         platform_device_unregister(pdev);
891         platform_driver_unregister(&hdaps_driver);
892
893         printk(KERN_INFO "hdaps: driver unloaded.\n");
894 }
895
896 module_init(hdaps_init);
897 module_exit(hdaps_exit);
898
899 module_param_named(invert, hdaps_invert, uint, 0);
900 MODULE_PARM_DESC(invert, "axis orientation code");
901
902 MODULE_AUTHOR("Robert Love");
903 MODULE_DESCRIPTION("IBM Hard Drive Active Protection System (HDAPS) driver");
904 MODULE_LICENSE("GPL v2");