OSDN Git Service

Fix some Mac WiFi drivers conflict
[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 persistance */
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 static void hdaps_mousedev_poll(unsigned long unused)
473 {
474         int ret;
475
476         stale_readout = 1;
477
478         /* Cannot sleep.  Try nonblockingly.  If we fail, try again later. */
479         if (thinkpad_ec_try_lock())
480                 goto keep_active;
481
482         ret = __hdaps_update(1); /* fast update, we're in softirq context */
483         thinkpad_ec_unlock();
484         /* Any of "successful", "not yet ready" and "not prefetched"? */
485         if (ret != 0 && ret != -EBUSY && ret != -ENODATA) {
486                 printk(KERN_ERR
487                        "hdaps: poll failed, disabling updates\n");
488                 return;
489         }
490
491 keep_active:
492         /* Even if we failed now, pos_x,y may have been updated earlier: */
493         input_report_abs(hdaps_idev, ABS_X, pos_x - rest_x);
494         input_report_abs(hdaps_idev, ABS_Y, pos_y - rest_y);
495         input_sync(hdaps_idev);
496         input_report_abs(hdaps_idev_raw, ABS_X, pos_x);
497         input_report_abs(hdaps_idev_raw, ABS_Y, pos_y);
498         input_sync(hdaps_idev_raw);
499         mod_timer(&hdaps_timer, jiffies + HZ/sampling_rate);
500 }
501
502
503 /* Sysfs Files */
504
505 static ssize_t hdaps_position_show(struct device *dev,
506                                    struct device_attribute *attr, char *buf)
507 {
508         int ret = hdaps_update();
509         if (ret)
510                 return ret;
511         return sprintf(buf, "(%d,%d)\n", pos_x, pos_y);
512 }
513
514 static ssize_t hdaps_temp1_show(struct device *dev,
515                                 struct device_attribute *attr, char *buf)
516 {
517         int ret = hdaps_update();
518         if (ret)
519                 return ret;
520         return sprintf(buf, "%d\n", temperature);
521 }
522
523 static ssize_t hdaps_keyboard_activity_show(struct device *dev,
524                                             struct device_attribute *attr,
525                                             char *buf)
526 {
527         int ret = hdaps_update();
528         if (ret)
529                 return ret;
530         return sprintf(buf, "%u\n",
531            get_jiffies_64() < last_keyboard_jiffies + KMACT_REMEMBER_PERIOD);
532 }
533
534 static ssize_t hdaps_mouse_activity_show(struct device *dev,
535                                          struct device_attribute *attr,
536                                          char *buf)
537 {
538         int ret = hdaps_update();
539         if (ret)
540                 return ret;
541         return sprintf(buf, "%u\n",
542            get_jiffies_64() < last_mouse_jiffies + KMACT_REMEMBER_PERIOD);
543 }
544
545 static ssize_t hdaps_calibrate_show(struct device *dev,
546                                     struct device_attribute *attr, char *buf)
547 {
548         return sprintf(buf, "(%d,%d)\n", rest_x, rest_y);
549 }
550
551 static ssize_t hdaps_calibrate_store(struct device *dev,
552                                      struct device_attribute *attr,
553                                      const char *buf, size_t count)
554 {
555         hdaps_calibrate();
556         return count;
557 }
558
559 static ssize_t hdaps_invert_show(struct device *dev,
560                                  struct device_attribute *attr, char *buf)
561 {
562         return sprintf(buf, "%u\n", hdaps_invert);
563 }
564
565 static ssize_t hdaps_invert_store(struct device *dev,
566                                   struct device_attribute *attr,
567                                   const char *buf, size_t count)
568 {
569         int invert;
570
571         if (sscanf(buf, "%d", &invert) != 1 ||
572             invert < 0 || invert > HDAPS_ORIENT_MAX)
573                 return -EINVAL;
574
575         hdaps_invert = invert;
576         hdaps_calibrate();
577
578         return count;
579 }
580
581 static ssize_t hdaps_sampling_rate_show(
582         struct device *dev, struct device_attribute *attr, char *buf)
583 {
584         return sprintf(buf, "%d\n", sampling_rate);
585 }
586
587 static ssize_t hdaps_sampling_rate_store(
588         struct device *dev, struct device_attribute *attr,
589         const char *buf, size_t count)
590 {
591         int rate, ret;
592         if (sscanf(buf, "%d", &rate) != 1 || rate > HZ || rate <= 0) {
593                 printk(KERN_WARNING
594                        "must have 0<input_sampling_rate<=HZ=%d\n", HZ);
595                 return -EINVAL;
596         }
597         ret = hdaps_set_ec_config(rate*oversampling_ratio,
598                                   running_avg_filter_order);
599         if (ret)
600                 return ret;
601         sampling_rate = rate;
602         return count;
603 }
604
605 static ssize_t hdaps_oversampling_ratio_show(
606         struct device *dev, struct device_attribute *attr, char *buf)
607 {
608         int ec_rate, order;
609         int ret = hdaps_get_ec_config(&ec_rate, &order);
610         if (ret)
611                 return ret;
612         return sprintf(buf, "%u\n", ec_rate / sampling_rate);
613 }
614
615 static ssize_t hdaps_oversampling_ratio_store(
616         struct device *dev, struct device_attribute *attr,
617         const char *buf, size_t count)
618 {
619         int ratio, ret;
620         if (sscanf(buf, "%d", &ratio) != 1 || ratio < 1)
621                 return -EINVAL;
622         ret = hdaps_set_ec_config(sampling_rate*ratio,
623                                   running_avg_filter_order);
624         if (ret)
625                 return ret;
626         oversampling_ratio = ratio;
627         return count;
628 }
629
630 static ssize_t hdaps_running_avg_filter_order_show(
631         struct device *dev, struct device_attribute *attr, char *buf)
632 {
633         int rate, order;
634         int ret = hdaps_get_ec_config(&rate, &order);
635         if (ret)
636                 return ret;
637         return sprintf(buf, "%u\n", order);
638 }
639
640 static ssize_t hdaps_running_avg_filter_order_store(
641         struct device *dev, struct device_attribute *attr,
642         const char *buf, size_t count)
643 {
644         int order, ret;
645         if (sscanf(buf, "%d", &order) != 1)
646                 return -EINVAL;
647         ret = hdaps_set_ec_config(sampling_rate*oversampling_ratio, order);
648         if (ret)
649                 return ret;
650         running_avg_filter_order = order;
651         return count;
652 }
653
654 static int hdaps_mousedev_open(struct input_dev *dev)
655 {
656         if (!try_module_get(THIS_MODULE))
657                 return -ENODEV;
658
659         mutex_lock(&hdaps_users_mtx);
660         if (hdaps_users++ == 0) /* first input user */
661                 mod_timer(&hdaps_timer, jiffies + HZ/sampling_rate);
662         mutex_unlock(&hdaps_users_mtx);
663         return 0;
664 }
665
666 static void hdaps_mousedev_close(struct input_dev *dev)
667 {
668         mutex_lock(&hdaps_users_mtx);
669         if (--hdaps_users == 0) /* no input users left */
670                 del_timer_sync(&hdaps_timer);
671         mutex_unlock(&hdaps_users_mtx);
672
673         module_put(THIS_MODULE);
674 }
675
676 static DEVICE_ATTR(position, 0444, hdaps_position_show, NULL);
677 static DEVICE_ATTR(temp1, 0444, hdaps_temp1_show, NULL);
678   /* "temp1" instead of "temperature" is hwmon convention */
679 static DEVICE_ATTR(keyboard_activity, 0444,
680                    hdaps_keyboard_activity_show, NULL);
681 static DEVICE_ATTR(mouse_activity, 0444, hdaps_mouse_activity_show, NULL);
682 static DEVICE_ATTR(calibrate, 0644,
683                    hdaps_calibrate_show, hdaps_calibrate_store);
684 static DEVICE_ATTR(invert, 0644, hdaps_invert_show, hdaps_invert_store);
685 static DEVICE_ATTR(sampling_rate, 0644,
686                    hdaps_sampling_rate_show, hdaps_sampling_rate_store);
687 static DEVICE_ATTR(oversampling_ratio, 0644,
688                    hdaps_oversampling_ratio_show,
689                    hdaps_oversampling_ratio_store);
690 static DEVICE_ATTR(running_avg_filter_order, 0644,
691                    hdaps_running_avg_filter_order_show,
692                    hdaps_running_avg_filter_order_store);
693
694 static struct attribute *hdaps_attributes[] = {
695         &dev_attr_position.attr,
696         &dev_attr_temp1.attr,
697         &dev_attr_keyboard_activity.attr,
698         &dev_attr_mouse_activity.attr,
699         &dev_attr_calibrate.attr,
700         &dev_attr_invert.attr,
701         &dev_attr_sampling_rate.attr,
702         &dev_attr_oversampling_ratio.attr,
703         &dev_attr_running_avg_filter_order.attr,
704         NULL,
705 };
706
707 static struct attribute_group hdaps_attribute_group = {
708         .attrs = hdaps_attributes,
709 };
710
711
712 /* Module stuff */
713
714 /* hdaps_dmi_match_invert - found an inverted match. */
715 static int __init hdaps_dmi_match_invert(const struct dmi_system_id *id)
716 {
717         unsigned int orient = (kernel_ulong_t) id->driver_data;
718         hdaps_invert = orient;
719         printk(KERN_INFO "hdaps: %s detected, setting orientation %u\n",
720                id->ident, orient);
721         return 1; /* stop enumeration */
722 }
723
724 #define HDAPS_DMI_MATCH_INVERT(vendor, model, orient) { \
725         .ident = vendor " " model,                      \
726         .callback = hdaps_dmi_match_invert,             \
727         .driver_data = (void *)(orient),                \
728         .matches = {                                    \
729                 DMI_MATCH(DMI_BOARD_VENDOR, vendor),    \
730                 DMI_MATCH(DMI_PRODUCT_VERSION, model)   \
731         }                                               \
732 }
733
734 /* List of models with abnormal axis configuration.
735    Note that HDAPS_DMI_MATCH_NORMAL("ThinkPad T42") would match
736    "ThinkPad T42p", and enumeration stops after first match,
737    so the order of the entries matters. */
738 struct dmi_system_id __initdata hdaps_whitelist[] = {
739         HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad R50p", HDAPS_ORIENT_INVERT_XY),
740         HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad R60", HDAPS_ORIENT_INVERT_XY),
741         HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T41p", HDAPS_ORIENT_INVERT_XY),
742         HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T42p", HDAPS_ORIENT_INVERT_XY),
743         HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad X40", HDAPS_ORIENT_INVERT_Y),
744         HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad X41", HDAPS_ORIENT_INVERT_Y),
745         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R60", HDAPS_ORIENT_INVERT_XY),
746         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61", HDAPS_ORIENT_INVERT_XY),
747         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T60", HDAPS_ORIENT_INVERT_XY),
748         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61", HDAPS_ORIENT_INVERT_XY),
749         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X60 Tablet", HDAPS_ORIENT_INVERT_Y),
750         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X60s", HDAPS_ORIENT_INVERT_Y),
751         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X60", HDAPS_ORIENT_SWAP | HDAPS_ORIENT_INVERT_X),
752         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61", HDAPS_ORIENT_SWAP | HDAPS_ORIENT_INVERT_X),
753         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T400s", HDAPS_ORIENT_INVERT_X),
754         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T400", HDAPS_ORIENT_INVERT_XY),
755         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T410s", HDAPS_ORIENT_SWAP),
756         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T410", HDAPS_ORIENT_INVERT_XY),
757         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T500", HDAPS_ORIENT_INVERT_XY),
758         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad W51O", HDAPS_ORIENT_MAX),
759         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X200", HDAPS_ORIENT_SWAP | HDAPS_ORIENT_INVERT_X | HDAPS_ORIENT_INVERT_Y),
760         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X201 Tablet", HDAPS_ORIENT_SWAP | HDAPS_ORIENT_INVERT_XY),
761         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X201s", HDAPS_ORIENT_SWAP | HDAPS_ORIENT_INVERT_XY),
762         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X201", HDAPS_ORIENT_SWAP | HDAPS_ORIENT_INVERT_X),
763         HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X220", HDAPS_ORIENT_SWAP),
764         { .ident = NULL }
765 };
766
767 static int __init hdaps_init(void)
768 {
769         int ret;
770
771         /* Determine axis orientation orientation */
772         if (hdaps_invert == HDAPS_ORIENT_UNDEFINED) /* set by module param? */
773                 if (dmi_check_system(hdaps_whitelist) < 1) /* in whitelist? */
774                         hdaps_invert = 0; /* default */
775
776         /* Init timer before platform_driver_register, in case of suspend */
777         init_timer(&hdaps_timer);
778         hdaps_timer.function = hdaps_mousedev_poll;
779         ret = platform_driver_register(&hdaps_driver);
780         if (ret)
781                 goto out;
782
783         pdev = platform_device_register_simple("hdaps", -1, NULL, 0);
784         if (IS_ERR(pdev)) {
785                 ret = PTR_ERR(pdev);
786                 goto out_driver;
787         }
788
789         ret = sysfs_create_group(&pdev->dev.kobj, &hdaps_attribute_group);
790         if (ret)
791                 goto out_device;
792
793         hdaps_idev = input_allocate_device();
794         if (!hdaps_idev) {
795                 ret = -ENOMEM;
796                 goto out_group;
797         }
798
799         hdaps_idev_raw = input_allocate_device();
800         if (!hdaps_idev_raw) {
801                 ret = -ENOMEM;
802                 goto out_idev_first;
803         }
804
805         /* calibration for the input device (deferred to avoid delay) */
806         needs_calibration = 1;
807
808         /* initialize the joystick-like fuzzed input device */
809         hdaps_idev->name = "hdaps";
810         hdaps_idev->phys = "hdaps/input0";
811         hdaps_idev->id.bustype = BUS_HOST;
812         hdaps_idev->id.vendor  = HDAPS_INPUT_VENDOR;
813         hdaps_idev->id.product = HDAPS_INPUT_PRODUCT;
814         hdaps_idev->id.version = HDAPS_INPUT_JS_VERSION;
815 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
816         hdaps_idev->cdev.dev = &pdev->dev;
817 #endif
818         hdaps_idev->evbit[0] = BIT(EV_ABS);
819         hdaps_idev->open = hdaps_mousedev_open;
820         hdaps_idev->close = hdaps_mousedev_close;
821         input_set_abs_params(hdaps_idev, ABS_X,
822                         -256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT);
823         input_set_abs_params(hdaps_idev, ABS_Y,
824                         -256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT);
825
826         ret = input_register_device(hdaps_idev);
827         if (ret)
828                 goto out_idev;
829
830         /* initialize the raw data input device */
831         hdaps_idev_raw->name = "raw_hdaps_data";
832         hdaps_idev_raw->phys = "hdaps/input1";
833         hdaps_idev_raw->id.bustype = BUS_HOST;
834         hdaps_idev_raw->id.vendor  = HDAPS_INPUT_VENDOR;
835         hdaps_idev_raw->id.product = HDAPS_INPUT_PRODUCT;
836         hdaps_idev_raw->id.version = HDAPS_INPUT_RAW_VERSION;
837 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
838         hdaps_idev_raw->cdev.dev = &pdev->dev;
839 #endif
840         hdaps_idev_raw->evbit[0] = BIT(EV_ABS);
841         hdaps_idev_raw->open = hdaps_mousedev_open;
842         hdaps_idev_raw->close = hdaps_mousedev_close;
843         input_set_abs_params(hdaps_idev_raw, ABS_X, -32768, 32767, 0, 0);
844         input_set_abs_params(hdaps_idev_raw, ABS_Y, -32768, 32767, 0, 0);
845
846         ret = input_register_device(hdaps_idev_raw);
847         if (ret)
848                 goto out_idev_reg_first;
849
850         printk(KERN_INFO "hdaps: driver successfully loaded.\n");
851         return 0;
852
853 out_idev_reg_first:
854         input_unregister_device(hdaps_idev);
855 out_idev:
856         input_free_device(hdaps_idev_raw);
857 out_idev_first:
858         input_free_device(hdaps_idev);
859 out_group:
860         sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group);
861 out_device:
862         platform_device_unregister(pdev);
863 out_driver:
864         platform_driver_unregister(&hdaps_driver);
865         hdaps_device_shutdown();
866 out:
867         printk(KERN_WARNING "hdaps: driver init failed (ret=%d)!\n", ret);
868         return ret;
869 }
870
871 static void __exit hdaps_exit(void)
872 {
873         input_unregister_device(hdaps_idev_raw);
874         input_unregister_device(hdaps_idev);
875         hdaps_device_shutdown(); /* ignore errors, effect is negligible */
876         sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group);
877         platform_device_unregister(pdev);
878         platform_driver_unregister(&hdaps_driver);
879
880         printk(KERN_INFO "hdaps: driver unloaded.\n");
881 }
882
883 module_init(hdaps_init);
884 module_exit(hdaps_exit);
885
886 module_param_named(invert, hdaps_invert, uint, 0);
887 MODULE_PARM_DESC(invert, "axis orientation code");
888
889 MODULE_AUTHOR("Robert Love");
890 MODULE_DESCRIPTION("IBM Hard Drive Active Protection System (HDAPS) driver");
891 MODULE_LICENSE("GPL v2");