29 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
34 #include <linux/kernel.h>
36 #include <linux/module.h>
42 #define HDAPS_LOW_PORT 0x1600
43 #define HDAPS_NR_PORTS 0x30
45 #define HDAPS_PORT_STATE 0x1611
46 #define HDAPS_PORT_YPOS 0x1612
47 #define HDAPS_PORT_XPOS 0x1614
48 #define HDAPS_PORT_TEMP1 0x1616
49 #define HDAPS_PORT_YVAR 0x1617
50 #define HDAPS_PORT_XVAR 0x1619
51 #define HDAPS_PORT_TEMP2 0x161b
52 #define HDAPS_PORT_UNKNOWN 0x161c
53 #define HDAPS_PORT_KMACT 0x161d
55 #define STATE_FRESH 0x50
57 #define KEYBD_MASK 0x20
58 #define MOUSE_MASK 0x40
59 #define KEYBD_ISSET(n) (!! (n & KEYBD_MASK))
60 #define MOUSE_ISSET(n) (!! (n & MOUSE_MASK))
62 #define INIT_TIMEOUT_MSECS 4000
63 #define INIT_WAIT_MSECS 200
65 #define HDAPS_POLL_INTERVAL 50
66 #define HDAPS_INPUT_FUZZ 4
67 #define HDAPS_INPUT_FLAT 4
69 #define HDAPS_X_AXIS (1 << 0)
70 #define HDAPS_Y_AXIS (1 << 1)
71 #define HDAPS_BOTH_AXES (HDAPS_X_AXIS | HDAPS_Y_AXIS)
74 static struct input_polled_dev *hdaps_idev;
75 static unsigned int hdaps_invert;
76 static u8 km_activity;
87 return inb(port) & 0xff;
96 if (__get_latch(port) == val)
105 static int __wait_latch(
u16 port,
u8 val)
109 for (i = 0; i < 20; i++) {
110 if (!__check_latch(port, val))
122 static void __device_refresh(
void)
136 static int __device_refresh_sync(
void)
146 static inline void __device_complete(
void)
158 static int hdaps_readb_one(
unsigned int port,
u8 *val)
165 ret = __device_refresh_sync();
178 static int __hdaps_read_pair(
unsigned int port1,
unsigned int port2,
182 if (__device_refresh_sync())
203 static int hdaps_read_pair(
unsigned int port1,
unsigned int port2,
204 int *val1,
int *val2)
209 ret = __hdaps_read_pair(port1, port2, val1, val2);
219 static int hdaps_device_init(
void)
221 int total, ret = -
ENXIO;
227 if (__wait_latch(0x161f, 0x00))
238 if (__check_latch(0x1611, 0x03) &&
239 __check_latch(0x1611, 0x02) &&
240 __check_latch(0x1611, 0x01))
244 __get_latch(0x1611));
249 if (__wait_latch(0x161f, 0x00))
251 if (__wait_latch(0x1611, 0x00))
253 if (__wait_latch(0x1612, 0x60))
255 if (__wait_latch(0x1613, 0x00))
260 if (__wait_latch(0x161f, 0x00))
267 if (__wait_latch(0x161f, 0x00))
269 if (__device_refresh_sync())
271 if (__wait_latch(0x1611, 0x00))
280 if (!__wait_latch(0x1611, 0x02)) {
300 ret = hdaps_device_init();
304 pr_info(
"device successfully initialized\n");
308 #ifdef CONFIG_PM_SLEEP
309 static int hdaps_resume(
struct device *dev)
311 return hdaps_device_init();
318 .probe = hdaps_probe,
329 static void hdaps_calibrate(
void)
334 static void hdaps_mousedev_poll(
struct input_polled_dev *dev)
336 struct input_dev *input_dev = dev->input;
344 input_report_abs(input_dev,
ABS_X, x - rest_x);
345 input_report_abs(input_dev,
ABS_Y, y - rest_y);
346 input_sync(input_dev);
364 return sprintf(buf,
"(%d,%d)\n", x, y);
376 return sprintf(buf,
"(%d,%d)\n", x, y);
405 static ssize_t hdaps_keyboard_activity_show(
struct device *dev,
422 return sprintf(buf,
"(%d,%d)\n", rest_x, rest_y);
427 const char *buf,
size_t count)
439 return sprintf(buf,
"%u\n", hdaps_invert);
444 const char *buf,
size_t count)
448 if (
sscanf(buf,
"%d", &invert) != 1 ||
452 hdaps_invert = invert;
462 static DEVICE_ATTR(keyboard_activity, 0444, hdaps_keyboard_activity_show,
NULL);
463 static DEVICE_ATTR(mouse_activity, 0444, hdaps_mouse_activity_show,
NULL);
465 static DEVICE_ATTR(invert, 0644, hdaps_invert_show, hdaps_invert_store);
467 static struct attribute *hdaps_attributes[] = {
468 &dev_attr_position.attr,
469 &dev_attr_variance.attr,
470 &dev_attr_temp1.attr,
471 &dev_attr_temp2.attr,
472 &dev_attr_keyboard_activity.attr,
473 &dev_attr_mouse_activity.attr,
474 &dev_attr_calibrate.attr,
475 &dev_attr_invert.attr,
480 .attrs = hdaps_attributes,
496 hdaps_invert = (
unsigned long)id->driver_data;
497 pr_info(
"inverting axis (%u) readings\n", hdaps_invert);
498 return hdaps_dmi_match(
id);
501 #define HDAPS_DMI_MATCH_INVERT(vendor, model, axes) { \
502 .ident = vendor " " model, \
503 .callback = hdaps_dmi_match_invert, \
504 .driver_data = (void *)axes, \
506 DMI_MATCH(DMI_BOARD_VENDOR, vendor), \
507 DMI_MATCH(DMI_PRODUCT_VERSION, model) \
511 #define HDAPS_DMI_MATCH_NORMAL(vendor, model) \
512 HDAPS_DMI_MATCH_INVERT(vendor, model, 0)
545 static int __init hdaps_init(
void)
547 struct input_dev *
idev;
551 pr_warn(
"supported laptop not found!\n");
565 pdev = platform_device_register_simple(
"hdaps", -1,
NULL, 0);
581 hdaps_idev->poll = hdaps_mousedev_poll;
588 idev = hdaps_idev->input;
589 idev->name =
"hdaps";
590 idev->phys =
"isa1600/input0";
592 idev->dev.parent = &pdev->
dev;
594 input_set_abs_params(idev,
ABS_X,
596 input_set_abs_params(idev,
ABS_Y,
603 pr_info(
"driver successfully loaded\n");
617 pr_warn(
"driver init failed (ret=%d)!\n", ret);
621 static void __exit hdaps_exit(
void)
638 "2 invert y-axis, 3 invert both axes.");