diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2019-07-10 23:24:10 -0700 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2019-07-10 23:24:10 -0700 |
commit | 597473720f4dc69749542bfcfed4a927a43d935e (patch) | |
tree | 711bf773910fb93d1dd9120c633adc807685e0d8 /drivers/input | |
parent | f0dd687815f9546860fc3ac4379d55da045942c9 (diff) | |
parent | 593fdd4fb44ef2cbf4ec53ec2c6eb60eb079bb4c (diff) | |
download | linux-597473720f4dc69749542bfcfed4a927a43d935e.tar.bz2 |
Merge branch 'next' into for-linus
Prepare input updates for 5.3 merge window.
Diffstat (limited to 'drivers/input')
34 files changed, 1138 insertions, 789 deletions
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 4c1e427dfabb..319c641edb93 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -812,6 +812,7 @@ static bool joydev_dev_is_blacklisted(struct input_dev *dev) static bool joydev_dev_is_absolute_mouse(struct input_dev *dev) { DECLARE_BITMAP(jd_scratch, KEY_CNT); + bool ev_match = false; BUILD_BUG_ON(ABS_CNT > KEY_CNT || EV_CNT > KEY_CNT); @@ -830,17 +831,36 @@ static bool joydev_dev_is_absolute_mouse(struct input_dev *dev) * considered to be an absolute mouse if the following is * true: * - * 1) Event types are exactly EV_ABS, EV_KEY and EV_SYN. + * 1) Event types are exactly + * EV_ABS, EV_KEY and EV_SYN + * or + * EV_ABS, EV_KEY, EV_SYN and EV_MSC + * or + * EV_ABS, EV_KEY, EV_SYN, EV_MSC and EV_REL. * 2) Absolute events are exactly ABS_X and ABS_Y. * 3) Keys are exactly BTN_LEFT, BTN_RIGHT and BTN_MIDDLE. * 4) Device is not on "Amiga" bus. */ bitmap_zero(jd_scratch, EV_CNT); + /* VMware VMMouse, HP ILO2 */ __set_bit(EV_ABS, jd_scratch); __set_bit(EV_KEY, jd_scratch); __set_bit(EV_SYN, jd_scratch); - if (!bitmap_equal(jd_scratch, dev->evbit, EV_CNT)) + if (bitmap_equal(jd_scratch, dev->evbit, EV_CNT)) + ev_match = true; + + /* HP ILO2, AMI BMC firmware */ + __set_bit(EV_MSC, jd_scratch); + if (bitmap_equal(jd_scratch, dev->evbit, EV_CNT)) + ev_match = true; + + /* VMware Virtual USB Mouse, QEMU USB Tablet, ATEN BMC firmware */ + __set_bit(EV_REL, jd_scratch); + if (bitmap_equal(jd_scratch, dev->evbit, EV_CNT)) + ev_match = true; + + if (!ev_match) return false; bitmap_zero(jd_scratch, ABS_CNT); diff --git a/drivers/input/joystick/iforce/Kconfig b/drivers/input/joystick/iforce/Kconfig index ab4dbcbcbf50..55f6ae1da6b0 100644 --- a/drivers/input/joystick/iforce/Kconfig +++ b/drivers/input/joystick/iforce/Kconfig @@ -13,15 +13,15 @@ config JOYSTICK_IFORCE module will be called iforce. config JOYSTICK_IFORCE_USB - bool "I-Force USB joysticks and wheels" - depends on JOYSTICK_IFORCE && (JOYSTICK_IFORCE=m || USB=y) && USB + tristate "I-Force USB joysticks and wheels" + depends on JOYSTICK_IFORCE && USB help Say Y here if you have an I-Force joystick or steering wheel connected to your USB port. config JOYSTICK_IFORCE_232 - bool "I-Force Serial joysticks and wheels" - depends on JOYSTICK_IFORCE && (JOYSTICK_IFORCE=m || SERIO=y) && SERIO + tristate "I-Force Serial joysticks and wheels" + depends on JOYSTICK_IFORCE && SERIO help Say Y here if you have an I-Force joystick or steering wheel connected to your serial (COM) port. diff --git a/drivers/input/joystick/iforce/Makefile b/drivers/input/joystick/iforce/Makefile index bc5bda22f15e..414075019a4f 100644 --- a/drivers/input/joystick/iforce/Makefile +++ b/drivers/input/joystick/iforce/Makefile @@ -4,8 +4,7 @@ # By Johann Deneux <johann.deneux@gmail.com> # -obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o - +obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o iforce-y := iforce-ff.o iforce-main.o iforce-packets.o -iforce-$(CONFIG_JOYSTICK_IFORCE_232) += iforce-serio.o -iforce-$(CONFIG_JOYSTICK_IFORCE_USB) += iforce-usb.o +obj-$(CONFIG_JOYSTICK_IFORCE_232) += iforce-serio.o +obj-$(CONFIG_JOYSTICK_IFORCE_USB) += iforce-usb.o diff --git a/drivers/input/joystick/iforce/iforce-ff.c b/drivers/input/joystick/iforce/iforce-ff.c index 3536d5f5ad18..56973dd97fd6 100644 --- a/drivers/input/joystick/iforce/iforce-ff.c +++ b/drivers/input/joystick/iforce/iforce-ff.c @@ -384,12 +384,12 @@ int iforce_upload_periodic(struct iforce *iforce, struct ff_effect *effect, stru } switch (effect->u.periodic.waveform) { - case FF_SQUARE: wave_code = 0x20; break; - case FF_TRIANGLE: wave_code = 0x21; break; - case FF_SINE: wave_code = 0x22; break; - case FF_SAW_UP: wave_code = 0x23; break; - case FF_SAW_DOWN: wave_code = 0x24; break; - default: wave_code = 0x20; break; + case FF_SQUARE: wave_code = 0x20; break; + case FF_TRIANGLE: wave_code = 0x21; break; + case FF_SINE: wave_code = 0x22; break; + case FF_SAW_UP: wave_code = 0x23; break; + case FF_SAW_DOWN: wave_code = 0x24; break; + default: wave_code = 0x20; break; } if (!old || need_core(old, effect)) { @@ -488,9 +488,9 @@ int iforce_upload_condition(struct iforce *iforce, struct ff_effect *effect, str int core_err = 0; switch (effect->type) { - case FF_SPRING: type = 0x40; break; - case FF_DAMPER: type = 0x41; break; - default: return -1; + case FF_SPRING: type = 0x40; break; + case FF_DAMPER: type = 0x41; break; + default: return -1; } if (!old || need_condition_modifier(iforce, old, effect)) { diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c index 58d5cfe46526..40eb65bfd57e 100644 --- a/drivers/input/joystick/iforce/iforce-main.c +++ b/drivers/input/joystick/iforce/iforce-main.c @@ -21,10 +21,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <asm/unaligned.h> #include "iforce.h" MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <johann.deneux@gmail.com>"); -MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver"); +MODULE_DESCRIPTION("Core I-Force joysticks and wheels driver"); MODULE_LICENSE("GPL"); static signed short btn_joystick[] = @@ -67,6 +68,7 @@ static struct iforce_device iforce_device[] = { { 0x05ef, 0x8888, "AVB Top Shot Force Feedback Racing Wheel", btn_wheel, abs_wheel, ff_iforce }, //? { 0x061c, 0xc0a4, "ACT LABS Force RS", btn_wheel, abs_wheel, ff_iforce }, //? { 0x061c, 0xc084, "ACT LABS Force RS", btn_wheel, abs_wheel, ff_iforce }, + { 0x06a3, 0xff04, "Saitek R440 Force Wheel", btn_wheel, abs_wheel, ff_iforce }, //? { 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce }, //? { 0x06f8, 0x0001, "Guillemot Jet Leader Force Feedback", btn_joystick, abs_joystick_rudder, ff_iforce }, { 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel", btn_wheel, abs_wheel, ff_iforce }, //? @@ -132,22 +134,21 @@ static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect, * Upload the effect */ switch (effect->type) { + case FF_PERIODIC: + ret = iforce_upload_periodic(iforce, effect, old); + break; - case FF_PERIODIC: - ret = iforce_upload_periodic(iforce, effect, old); - break; - - case FF_CONSTANT: - ret = iforce_upload_constant(iforce, effect, old); - break; + case FF_CONSTANT: + ret = iforce_upload_constant(iforce, effect, old); + break; - case FF_SPRING: - case FF_DAMPER: - ret = iforce_upload_condition(iforce, effect, old); - break; + case FF_SPRING: + case FF_DAMPER: + ret = iforce_upload_condition(iforce, effect, old); + break; - default: - return -EINVAL; + default: + return -EINVAL; } if (ret == 0) { @@ -185,15 +186,7 @@ static int iforce_open(struct input_dev *dev) { struct iforce *iforce = input_get_drvdata(dev); - switch (iforce->bus) { -#ifdef CONFIG_JOYSTICK_IFORCE_USB - case IFORCE_USB: - iforce->irq->dev = iforce->usbdev; - if (usb_submit_urb(iforce->irq, GFP_KERNEL)) - return -EIO; - break; -#endif - } + iforce->xport_ops->start_io(iforce); if (test_bit(EV_FF, dev->evbit)) { /* Enable force feedback */ @@ -226,27 +219,17 @@ static void iforce_close(struct input_dev *dev) !test_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)); } - switch (iforce->bus) { -#ifdef CONFIG_JOYSTICK_IFORCE_USB - case IFORCE_USB: - usb_kill_urb(iforce->irq); - usb_kill_urb(iforce->out); - usb_kill_urb(iforce->ctrl); - break; -#endif -#ifdef CONFIG_JOYSTICK_IFORCE_232 - case IFORCE_232: - //TODO: Wait for the last packets to be sent - break; -#endif - } + iforce->xport_ops->stop_io(iforce); } -int iforce_init_device(struct iforce *iforce) +int iforce_init_device(struct device *parent, u16 bustype, + struct iforce *iforce) { struct input_dev *input_dev; struct ff_device *ff; - unsigned char c[] = "CEOV"; + u8 c[] = "CEOV"; + u8 buf[IFORCE_MAX_LENGTH]; + size_t len; int i, error; int ff_effects = 0; @@ -264,20 +247,8 @@ int iforce_init_device(struct iforce *iforce) * Input device fields. */ - switch (iforce->bus) { -#ifdef CONFIG_JOYSTICK_IFORCE_USB - case IFORCE_USB: - input_dev->id.bustype = BUS_USB; - input_dev->dev.parent = &iforce->usbdev->dev; - break; -#endif -#ifdef CONFIG_JOYSTICK_IFORCE_232 - case IFORCE_232: - input_dev->id.bustype = BUS_RS232; - input_dev->dev.parent = &iforce->serio->dev; - break; -#endif - } + input_dev->id.bustype = bustype; + input_dev->dev.parent = parent; input_set_drvdata(input_dev, iforce); @@ -302,7 +273,7 @@ int iforce_init_device(struct iforce *iforce) */ for (i = 0; i < 20; i++) - if (!iforce_get_id_packet(iforce, "O")) + if (!iforce_get_id_packet(iforce, 'O', buf, &len)) break; if (i == 20) { /* 5 seconds */ @@ -316,23 +287,23 @@ int iforce_init_device(struct iforce *iforce) * Get device info. */ - if (!iforce_get_id_packet(iforce, "M")) - input_dev->id.vendor = (iforce->edata[2] << 8) | iforce->edata[1]; + if (!iforce_get_id_packet(iforce, 'M', buf, &len) || len < 3) + input_dev->id.vendor = get_unaligned_le16(buf + 1); else dev_warn(&iforce->dev->dev, "Device does not respond to id packet M\n"); - if (!iforce_get_id_packet(iforce, "P")) - input_dev->id.product = (iforce->edata[2] << 8) | iforce->edata[1]; + if (!iforce_get_id_packet(iforce, 'P', buf, &len) || len < 3) + input_dev->id.product = get_unaligned_le16(buf + 1); else dev_warn(&iforce->dev->dev, "Device does not respond to id packet P\n"); - if (!iforce_get_id_packet(iforce, "B")) - iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1]; + if (!iforce_get_id_packet(iforce, 'B', buf, &len) || len < 3) + iforce->device_memory.end = get_unaligned_le16(buf + 1); else dev_warn(&iforce->dev->dev, "Device does not respond to id packet B\n"); - if (!iforce_get_id_packet(iforce, "N")) - ff_effects = iforce->edata[1]; + if (!iforce_get_id_packet(iforce, 'N', buf, &len) || len < 2) + ff_effects = buf[1]; else dev_warn(&iforce->dev->dev, "Device does not respond to id packet N\n"); @@ -348,8 +319,9 @@ int iforce_init_device(struct iforce *iforce) */ for (i = 0; c[i]; i++) - if (!iforce_get_id_packet(iforce, c + i)) - iforce_dump_packet(iforce, "info", iforce->ecmd, iforce->edata); + if (!iforce_get_id_packet(iforce, c[i], buf, &len)) + iforce_dump_packet(iforce, "info", + (FF_CMD_QUERY & 0xff00) | len, buf); /* * Disable spring, enable force feedback. @@ -383,34 +355,29 @@ int iforce_init_device(struct iforce *iforce) signed short t = iforce->type->abs[i]; switch (t) { + case ABS_X: + case ABS_Y: + case ABS_WHEEL: + input_set_abs_params(input_dev, t, -1920, 1920, 16, 128); + set_bit(t, input_dev->ffbit); + break; - case ABS_X: - case ABS_Y: - case ABS_WHEEL: - - input_set_abs_params(input_dev, t, -1920, 1920, 16, 128); - set_bit(t, input_dev->ffbit); - break; - - case ABS_THROTTLE: - case ABS_GAS: - case ABS_BRAKE: - - input_set_abs_params(input_dev, t, 0, 255, 0, 0); - break; - - case ABS_RUDDER: - - input_set_abs_params(input_dev, t, -128, 127, 0, 0); - break; + case ABS_THROTTLE: + case ABS_GAS: + case ABS_BRAKE: + input_set_abs_params(input_dev, t, 0, 255, 0, 0); + break; - case ABS_HAT0X: - case ABS_HAT0Y: - case ABS_HAT1X: - case ABS_HAT1Y: + case ABS_RUDDER: + input_set_abs_params(input_dev, t, -128, 127, 0, 0); + break; - input_set_abs_params(input_dev, t, -1, 1, 0, 0); - break; + case ABS_HAT0X: + case ABS_HAT0Y: + case ABS_HAT1X: + case ABS_HAT1Y: + input_set_abs_params(input_dev, t, -1, 1, 0, 0); + break; } } @@ -443,35 +410,4 @@ int iforce_init_device(struct iforce *iforce) fail: input_free_device(input_dev); return error; } - -static int __init iforce_init(void) -{ - int err = 0; - -#ifdef CONFIG_JOYSTICK_IFORCE_USB - err = usb_register(&iforce_usb_driver); - if (err) - return err; -#endif -#ifdef CONFIG_JOYSTICK_IFORCE_232 - err = serio_register_driver(&iforce_serio_drv); -#ifdef CONFIG_JOYSTICK_IFORCE_USB - if (err) - usb_deregister(&iforce_usb_driver); -#endif -#endif - return err; -} - -static void __exit iforce_exit(void) -{ -#ifdef CONFIG_JOYSTICK_IFORCE_USB - usb_deregister(&iforce_usb_driver); -#endif -#ifdef CONFIG_JOYSTICK_IFORCE_232 - serio_unregister_driver(&iforce_serio_drv); -#endif -} - -module_init(iforce_init); -module_exit(iforce_exit); +EXPORT_SYMBOL(iforce_init_device); diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c index c10169f4554e..76c4475740ab 100644 --- a/drivers/input/joystick/iforce/iforce-packets.c +++ b/drivers/input/joystick/iforce/iforce-packets.c @@ -21,6 +21,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <asm/unaligned.h> #include "iforce.h" static struct { @@ -91,27 +92,12 @@ int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data) /* * If necessary, start the transmission */ - switch (iforce->bus) { + if (empty) + iforce->xport_ops->xmit(iforce); -#ifdef CONFIG_JOYSTICK_IFORCE_232 - case IFORCE_232: - if (empty) - iforce_serial_xmit(iforce); - break; -#endif -#ifdef CONFIG_JOYSTICK_IFORCE_USB - case IFORCE_USB: - - if (iforce->usbdev && empty && - !test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) { - - iforce_usb_xmit(iforce); - } - break; -#endif - } return 0; } +EXPORT_SYMBOL(iforce_send_packet); /* Start or stop an effect */ int iforce_control_playback(struct iforce* iforce, u16 id, unsigned int value) @@ -145,157 +131,96 @@ static int mark_core_as_ready(struct iforce *iforce, unsigned short addr) return -1; } -void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data) +static void iforce_report_hats_buttons(struct iforce *iforce, u8 *data) { struct input_dev *dev = iforce->dev; int i; - static int being_used = 0; - if (being_used) - dev_warn(&iforce->dev->dev, - "re-entrant call to iforce_process %d\n", being_used); - being_used++; - -#ifdef CONFIG_JOYSTICK_IFORCE_232 - if (HI(iforce->expect_packet) == HI(cmd)) { - iforce->expect_packet = 0; - iforce->ecmd = cmd; - memcpy(iforce->edata, data, IFORCE_MAX_LENGTH); - } -#endif - wake_up(&iforce->wait); + input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x); + input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y); - if (!iforce->type) { - being_used--; - return; - } - - switch (HI(cmd)) { - - case 0x01: /* joystick position data */ - case 0x03: /* wheel position data */ - if (HI(cmd) == 1) { - input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0])); - input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2])); - input_report_abs(dev, ABS_THROTTLE, 255 - data[4]); - if (LO(cmd) >= 8 && test_bit(ABS_RUDDER ,dev->absbit)) - input_report_abs(dev, ABS_RUDDER, (__s8)data[7]); - } else { - input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0])); - input_report_abs(dev, ABS_GAS, 255 - data[2]); - input_report_abs(dev, ABS_BRAKE, 255 - data[3]); - } + for (i = 0; iforce->type->btn[i] >= 0; i++) + input_report_key(dev, iforce->type->btn[i], + data[(i >> 3) + 5] & (1 << (i & 7))); - input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x); - input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y); - - for (i = 0; iforce->type->btn[i] >= 0; i++) - input_report_key(dev, iforce->type->btn[i], data[(i >> 3) + 5] & (1 << (i & 7))); - - /* If there are untouched bits left, interpret them as the second hat */ - if (i <= 8) { - int btns = data[6]; - if (test_bit(ABS_HAT1X, dev->absbit)) { - if (btns & 8) input_report_abs(dev, ABS_HAT1X, -1); - else if (btns & 2) input_report_abs(dev, ABS_HAT1X, 1); - else input_report_abs(dev, ABS_HAT1X, 0); - } - if (test_bit(ABS_HAT1Y, dev->absbit)) { - if (btns & 1) input_report_abs(dev, ABS_HAT1Y, -1); - else if (btns & 4) input_report_abs(dev, ABS_HAT1Y, 1); - else input_report_abs(dev, ABS_HAT1Y, 0); - } - } + /* If there are untouched bits left, interpret them as the second hat */ + if (i <= 8) { + u8 btns = data[6]; - input_sync(dev); - - break; - - case 0x02: /* status report */ - input_report_key(dev, BTN_DEAD, data[0] & 0x02); - input_sync(dev); + if (test_bit(ABS_HAT1X, dev->absbit)) { + if (btns & BIT(3)) + input_report_abs(dev, ABS_HAT1X, -1); + else if (btns & BIT(1)) + input_report_abs(dev, ABS_HAT1X, 1); + else + input_report_abs(dev, ABS_HAT1X, 0); + } - /* Check if an effect was just started or stopped */ - i = data[1] & 0x7f; - if (data[1] & 0x80) { - if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { - /* Report play event */ - input_report_ff_status(dev, i, FF_STATUS_PLAYING); - } - } else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { - /* Report stop event */ - input_report_ff_status(dev, i, FF_STATUS_STOPPED); - } - if (LO(cmd) > 3) { - int j; - for (j = 3; j < LO(cmd); j += 2) - mark_core_as_ready(iforce, data[j] | (data[j+1]<<8)); - } - break; + if (test_bit(ABS_HAT1Y, dev->absbit)) { + if (btns & BIT(0)) + input_report_abs(dev, ABS_HAT1Y, -1); + else if (btns & BIT(2)) + input_report_abs(dev, ABS_HAT1Y, 1); + else + input_report_abs(dev, ABS_HAT1Y, 0); + } } - being_used--; } -int iforce_get_id_packet(struct iforce *iforce, char *packet) +void iforce_process_packet(struct iforce *iforce, + u8 packet_id, u8 *data, size_t len) { - switch (iforce->bus) { + struct input_dev *dev = iforce->dev; + int i, j; - case IFORCE_USB: { -#ifdef CONFIG_JOYSTICK_IFORCE_USB - int status; + switch (packet_id) { - iforce->cr.bRequest = packet[0]; - iforce->ctrl->dev = iforce->usbdev; + case 0x01: /* joystick position data */ + input_report_abs(dev, ABS_X, + (__s16) get_unaligned_le16(data)); + input_report_abs(dev, ABS_Y, + (__s16) get_unaligned_le16(data + 2)); + input_report_abs(dev, ABS_THROTTLE, 255 - data[4]); - status = usb_submit_urb(iforce->ctrl, GFP_KERNEL); - if (status) { - dev_err(&iforce->intf->dev, - "usb_submit_urb failed %d\n", status); - return -1; - } + if (len >= 8 && test_bit(ABS_RUDDER ,dev->absbit)) + input_report_abs(dev, ABS_RUDDER, (__s8)data[7]); - wait_event_interruptible_timeout(iforce->wait, - iforce->ctrl->status != -EINPROGRESS, HZ); + iforce_report_hats_buttons(iforce, data); - if (iforce->ctrl->status) { - dev_dbg(&iforce->intf->dev, - "iforce->ctrl->status = %d\n", - iforce->ctrl->status); - usb_unlink_urb(iforce->ctrl); - return -1; - } -#else - printk(KERN_DEBUG "iforce_get_id_packet: iforce->bus = USB!\n"); -#endif - } + input_sync(dev); break; - case IFORCE_232: + case 0x03: /* wheel position data */ + input_report_abs(dev, ABS_WHEEL, + (__s16) get_unaligned_le16(data)); + input_report_abs(dev, ABS_GAS, 255 - data[2]); + input_report_abs(dev, ABS_BRAKE, 255 - data[3]); -#ifdef CONFIG_JOYSTICK_IFORCE_232 - iforce->expect_packet = FF_CMD_QUERY; - iforce_send_packet(iforce, FF_CMD_QUERY, packet); + iforce_report_hats_buttons(iforce, data); - wait_event_interruptible_timeout(iforce->wait, - !iforce->expect_packet, HZ); + input_sync(dev); + break; + + case 0x02: /* status report */ + input_report_key(dev, BTN_DEAD, data[0] & 0x02); + input_sync(dev); - if (iforce->expect_packet) { - iforce->expect_packet = 0; - return -1; + /* Check if an effect was just started or stopped */ + i = data[1] & 0x7f; + if (data[1] & 0x80) { + if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { + /* Report play event */ + input_report_ff_status(dev, i, FF_STATUS_PLAYING); + } + } else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { + /* Report stop event */ + input_report_ff_status(dev, i, FF_STATUS_STOPPED); } -#else - dev_err(&iforce->dev->dev, - "iforce_get_id_packet: iforce->bus = SERIO!\n"); -#endif - break; - default: - dev_err(&iforce->dev->dev, - "iforce_get_id_packet: iforce->bus = %d\n", - iforce->bus); + for (j = 3; j < len; j += 2) + mark_core_as_ready(iforce, get_unaligned_le16(data + j)); + break; } - - return -(iforce->edata[0] != packet[0]); } - +EXPORT_SYMBOL(iforce_process_packet); diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c index f4ba4a751fe0..e7692a38591e 100644 --- a/drivers/input/joystick/iforce/iforce-serio.c +++ b/drivers/input/joystick/iforce/iforce-serio.c @@ -21,10 +21,26 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <linux/serio.h> #include "iforce.h" -void iforce_serial_xmit(struct iforce *iforce) +struct iforce_serio { + struct iforce iforce; + + struct serio *serio; + int idx, pkt, len, id; + u8 csum; + u8 expect_packet; + u8 cmd_response[IFORCE_MAX_LENGTH]; + u8 cmd_response_len; + u8 data_in[IFORCE_MAX_LENGTH]; +}; + +static void iforce_serio_xmit(struct iforce *iforce) { + struct iforce_serio *iforce_serio = container_of(iforce, + struct iforce_serio, + iforce); unsigned char cs; int i; unsigned long flags; @@ -45,19 +61,20 @@ again: cs = 0x2b; - serio_write(iforce->serio, 0x2b); + serio_write(iforce_serio->serio, 0x2b); - serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]); + serio_write(iforce_serio->serio, iforce->xmit.buf[iforce->xmit.tail]); cs ^= iforce->xmit.buf[iforce->xmit.tail]; XMIT_INC(iforce->xmit.tail, 1); for (i=iforce->xmit.buf[iforce->xmit.tail]; i >= 0; --i) { - serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]); + serio_write(iforce_serio->serio, + iforce->xmit.buf[iforce->xmit.tail]); cs ^= iforce->xmit.buf[iforce->xmit.tail]; XMIT_INC(iforce->xmit.tail, 1); } - serio_write(iforce->serio, cs); + serio_write(iforce_serio->serio, cs); if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags)) goto again; @@ -67,54 +84,118 @@ again: spin_unlock_irqrestore(&iforce->xmit_lock, flags); } +static int iforce_serio_get_id(struct iforce *iforce, u8 id, + u8 *response_data, size_t *response_len) +{ + struct iforce_serio *iforce_serio = container_of(iforce, + struct iforce_serio, + iforce); + + iforce_serio->expect_packet = HI(FF_CMD_QUERY); + iforce_serio->cmd_response_len = 0; + + iforce_send_packet(iforce, FF_CMD_QUERY, &id); + + wait_event_interruptible_timeout(iforce->wait, + !iforce_serio->expect_packet, HZ); + + if (iforce_serio->expect_packet) { + iforce_serio->expect_packet = 0; + return -ETIMEDOUT; + } + + if (iforce_serio->cmd_response[0] != id) + return -EIO; + + memcpy(response_data, iforce_serio->cmd_response, + iforce_serio->cmd_response_len); + *response_len = iforce_serio->cmd_response_len; + + return 0; +} + +static int iforce_serio_start_io(struct iforce *iforce) +{ + /* No special handling required */ + return 0; +} + +static void iforce_serio_stop_io(struct iforce *iforce) +{ + //TODO: Wait for the last packets to be sent +} + +static const struct iforce_xport_ops iforce_serio_xport_ops = { + .xmit = iforce_serio_xmit, + .get_id = iforce_serio_get_id, + .start_io = iforce_serio_start_io, + .stop_io = iforce_serio_stop_io, +}; + static void iforce_serio_write_wakeup(struct serio *serio) { struct iforce *iforce = serio_get_drvdata(serio); - iforce_serial_xmit(iforce); + iforce_serio_xmit(iforce); } static irqreturn_t iforce_serio_irq(struct serio *serio, - unsigned char data, unsigned int flags) + unsigned char data, unsigned int flags) { - struct iforce *iforce = serio_get_drvdata(serio); + struct iforce_serio *iforce_serio = serio_get_drvdata(serio); + struct iforce *iforce = &iforce_serio->iforce; - if (!iforce->pkt) { + if (!iforce_serio->pkt) { if (data == 0x2b) - iforce->pkt = 1; + iforce_serio->pkt = 1; goto out; } - if (!iforce->id) { + if (!iforce_serio->id) { if (data > 3 && data != 0xff) - iforce->pkt = 0; + iforce_serio->pkt = 0; else - iforce->id = data; + iforce_serio->id = data; goto out; } - if (!iforce->len) { + if (!iforce_serio->len) { if (data > IFORCE_MAX_LENGTH) { - iforce->pkt = 0; - iforce->id = 0; + iforce_serio->pkt = 0; + iforce_serio->id = 0; } else { - iforce->len = data; + iforce_serio->len = data; } goto out; } - if (iforce->idx < iforce->len) { - iforce->csum += iforce->data[iforce->idx++] = data; + if (iforce_serio->idx < iforce_serio->len) { + iforce_serio->data_in[iforce_serio->idx++] = data; + iforce_serio->csum += data; goto out; } - if (iforce->idx == iforce->len) { - iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data); - iforce->pkt = 0; - iforce->id = 0; - iforce->len = 0; - iforce->idx = 0; - iforce->csum = 0; + if (iforce_serio->idx == iforce_serio->len) { + /* Handle command completion */ + if (iforce_serio->expect_packet == iforce_serio->id) { + iforce_serio->expect_packet = 0; + memcpy(iforce_serio->cmd_response, + iforce_serio->data_in, IFORCE_MAX_LENGTH); + iforce_serio->cmd_response_len = iforce_serio->len; + + /* Signal that command is done */ + wake_up(&iforce->wait); + } else if (likely(iforce->type)) { + iforce_process_packet(iforce, iforce_serio->id, + iforce_serio->data_in, + iforce_serio->len); + } + + iforce_serio->pkt = 0; + iforce_serio->id = 0; + iforce_serio->len = 0; + iforce_serio->idx = 0; + iforce_serio->csum = 0; } out: return IRQ_HANDLED; @@ -122,23 +203,23 @@ out: static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv) { - struct iforce *iforce; + struct iforce_serio *iforce_serio; int err; - iforce = kzalloc(sizeof(struct iforce), GFP_KERNEL); - if (!iforce) + iforce_serio = kzalloc(sizeof(*iforce_serio), GFP_KERNEL); + if (!iforce_serio) return -ENOMEM; - iforce->bus = IFORCE_232; - iforce->serio = serio; + iforce_serio->iforce.xport_ops = &iforce_serio_xport_ops; - serio_set_drvdata(serio, iforce); + iforce_serio->serio = serio; + serio_set_drvdata(serio, iforce_serio); err = serio_open(serio, drv); if (err) goto fail1; - err = iforce_init_device(iforce); + err = iforce_init_device(&serio->dev, BUS_RS232, &iforce_serio->iforce); if (err) goto fail2; @@ -146,18 +227,18 @@ static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv) fail2: serio_close(serio); fail1: serio_set_drvdata(serio, NULL); - kfree(iforce); + kfree(iforce_serio); return err; } static void iforce_serio_disconnect(struct serio *serio) { - struct iforce *iforce = serio_get_drvdata(serio); + struct iforce_serio *iforce_serio = serio_get_drvdata(serio); - input_unregister_device(iforce->dev); + input_unregister_device(iforce_serio->iforce.dev); serio_close(serio); serio_set_drvdata(serio, NULL); - kfree(iforce); + kfree(iforce_serio); } static const struct serio_device_id iforce_serio_ids[] = { @@ -183,3 +264,9 @@ struct serio_driver iforce_serio_drv = { .connect = iforce_serio_connect, .disconnect = iforce_serio_disconnect, }; + +module_serio_driver(iforce_serio_drv); + +MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <johann.deneux@gmail.com>"); +MODULE_DESCRIPTION("RS232 I-Force joysticks and wheels driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c index 78073259c9a1..75a2b0ea37b4 100644 --- a/drivers/input/joystick/iforce/iforce-usb.c +++ b/drivers/input/joystick/iforce/iforce-usb.c @@ -21,10 +21,24 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <linux/usb.h> #include "iforce.h" -void iforce_usb_xmit(struct iforce *iforce) +struct iforce_usb { + struct iforce iforce; + + struct usb_device *usbdev; + struct usb_interface *intf; + struct urb *irq, *out; + + u8 data_in[IFORCE_MAX_LENGTH] ____cacheline_aligned; + u8 data_out[IFORCE_MAX_LENGTH] ____cacheline_aligned; +}; + +static void __iforce_usb_xmit(struct iforce *iforce) { + struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb, + iforce); int n, c; unsigned long flags; @@ -36,31 +50,32 @@ void iforce_usb_xmit(struct iforce *iforce) return; } - ((char *)iforce->out->transfer_buffer)[0] = iforce->xmit.buf[iforce->xmit.tail]; + ((char *)iforce_usb->out->transfer_buffer)[0] = iforce->xmit.buf[iforce->xmit.tail]; XMIT_INC(iforce->xmit.tail, 1); n = iforce->xmit.buf[iforce->xmit.tail]; XMIT_INC(iforce->xmit.tail, 1); - iforce->out->transfer_buffer_length = n + 1; - iforce->out->dev = iforce->usbdev; + iforce_usb->out->transfer_buffer_length = n + 1; + iforce_usb->out->dev = iforce_usb->usbdev; /* Copy rest of data then */ c = CIRC_CNT_TO_END(iforce->xmit.head, iforce->xmit.tail, XMIT_SIZE); if (n < c) c=n; - memcpy(iforce->out->transfer_buffer + 1, + memcpy(iforce_usb->out->transfer_buffer + 1, &iforce->xmit.buf[iforce->xmit.tail], c); if (n != c) { - memcpy(iforce->out->transfer_buffer + 1 + c, + memcpy(iforce_usb->out->transfer_buffer + 1 + c, &iforce->xmit.buf[0], n-c); } XMIT_INC(iforce->xmit.tail, n); - if ( (n=usb_submit_urb(iforce->out, GFP_ATOMIC)) ) { + if ( (n=usb_submit_urb(iforce_usb->out, GFP_ATOMIC)) ) { clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); - dev_warn(&iforce->intf->dev, "usb_submit_urb failed %d\n", n); + dev_warn(&iforce_usb->intf->dev, + "usb_submit_urb failed %d\n", n); } /* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended. @@ -69,10 +84,77 @@ void iforce_usb_xmit(struct iforce *iforce) spin_unlock_irqrestore(&iforce->xmit_lock, flags); } +static void iforce_usb_xmit(struct iforce *iforce) +{ + if (!test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) + __iforce_usb_xmit(iforce); +} + +static int iforce_usb_get_id(struct iforce *iforce, u8 id, + u8 *response_data, size_t *response_len) +{ + struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb, + iforce); + u8 *buf; + int status; + + buf = kmalloc(IFORCE_MAX_LENGTH, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + status = usb_control_msg(iforce_usb->usbdev, + usb_rcvctrlpipe(iforce_usb->usbdev, 0), + id, + USB_TYPE_VENDOR | USB_DIR_IN | + USB_RECIP_INTERFACE, + 0, 0, buf, IFORCE_MAX_LENGTH, HZ); + if (status < 0) { + dev_err(&iforce_usb->intf->dev, + "usb_submit_urb failed: %d\n", status); + } else if (buf[0] != id) { + status = -EIO; + } else { + memcpy(response_data, buf, status); + *response_len = status; + status = 0; + } + + kfree(buf); + return status; +} + +static int iforce_usb_start_io(struct iforce *iforce) +{ + struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb, + iforce); + + if (usb_submit_urb(iforce_usb->irq, GFP_KERNEL)) + return -EIO; + + return 0; +} + +static void iforce_usb_stop_io(struct iforce *iforce) +{ + struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb, + iforce); + + usb_kill_urb(iforce_usb->irq); + usb_kill_urb(iforce_usb->out); +} + +static const struct iforce_xport_ops iforce_usb_xport_ops = { + .xmit = iforce_usb_xmit, + .get_id = iforce_usb_get_id, + .start_io = iforce_usb_start_io, + .stop_io = iforce_usb_stop_io, +}; + static void iforce_usb_irq(struct urb *urb) { - struct iforce *iforce = urb->context; - struct device *dev = &iforce->intf->dev; + struct iforce_usb *iforce_usb = urb->context; + struct iforce *iforce = &iforce_usb->iforce; + struct device *dev = &iforce_usb->intf->dev; int status; switch (urb->status) { @@ -92,11 +174,11 @@ static void iforce_usb_irq(struct urb *urb) goto exit; } - iforce_process_packet(iforce, - (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1); + iforce_process_packet(iforce, iforce_usb->data_in[0], + iforce_usb->data_in + 1, urb->actual_length - 1); exit: - status = usb_submit_urb (urb, GFP_ATOMIC); + status = usb_submit_urb(urb, GFP_ATOMIC); if (status) dev_err(dev, "%s - usb_submit_urb failed with result %d\n", __func__, status); @@ -104,35 +186,28 @@ exit: static void iforce_usb_out(struct urb *urb) { - struct iforce *iforce = urb->context; + struct iforce_usb *iforce_usb = urb->context; + struct iforce *iforce = &iforce_usb->iforce; if (urb->status) { clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); - dev_dbg(&iforce->intf->dev, "urb->status %d, exiting\n", + dev_dbg(&iforce_usb->intf->dev, "urb->status %d, exiting\n", urb->status); return; } - iforce_usb_xmit(iforce); + __iforce_usb_xmit(iforce); wake_up(&iforce->wait); } -static void iforce_usb_ctrl(struct urb *urb) -{ - struct iforce *iforce = urb->context; - if (urb->status) return; - iforce->ecmd = 0xff00 | urb->actual_length; - wake_up(&iforce->wait); -} - static int iforce_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev(intf); struct usb_host_interface *interface; struct usb_endpoint_descriptor *epirq, *epout; - struct iforce *iforce; + struct iforce_usb *iforce_usb; int err = -ENOMEM; interface = intf->cur_altsetting; @@ -143,48 +218,45 @@ static int iforce_usb_probe(struct usb_interface *intf, epirq = &interface->endpoint[0].desc; epout = &interface->endpoint[1].desc; - if (!(iforce = kzalloc(sizeof(struct iforce) + 32, GFP_KERNEL))) - goto fail; - - if (!(iforce->irq = usb_alloc_urb(0, GFP_KERNEL))) + iforce_usb = kzalloc(sizeof(*iforce_usb), GFP_KERNEL); + if (!iforce_usb) goto fail; - if (!(iforce->out = usb_alloc_urb(0, GFP_KERNEL))) + iforce_usb->irq = usb_alloc_urb(0, GFP_KERNEL); + if (!iforce_usb->irq) goto fail; - if (!(iforce->ctrl = usb_alloc_urb(0, GFP_KERNEL))) + iforce_usb->out = usb_alloc_urb(0, GFP_KERNEL); + if (!iforce_usb->out) goto fail; - iforce->bus = IFORCE_USB; - iforce->usbdev = dev; - iforce->intf = intf; - - iforce->cr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE; - iforce->cr.wIndex = 0; - iforce->cr.wLength = cpu_to_le16(16); + iforce_usb->iforce.xport_ops = &iforce_usb_xport_ops; - usb_fill_int_urb(iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress), - iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval); + iforce_usb->usbdev = dev; + iforce_usb->intf = intf; - usb_fill_int_urb(iforce->out, dev, usb_sndintpipe(dev, epout->bEndpointAddress), - iforce + 1, 32, iforce_usb_out, iforce, epout->bInterval); + usb_fill_int_urb(iforce_usb->irq, dev, + usb_rcvintpipe(dev, epirq->bEndpointAddress), + iforce_usb->data_in, sizeof(iforce_usb->data_in), + iforce_usb_irq, iforce_usb, epirq->bInterval); - usb_fill_control_urb(iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0), - (void*) &iforce->cr, iforce->edata, 16, iforce_usb_ctrl, iforce); + usb_fill_int_urb(iforce_usb->out, dev, + usb_sndintpipe(dev, epout->bEndpointAddress), + iforce_usb->data_out, sizeof(iforce_usb->data_out), + iforce_usb_out, iforce_usb, epout->bInterval); - err = iforce_init_device(iforce); + err = iforce_init_device(&intf->dev, BUS_USB, &iforce_usb->iforce); if (err) goto fail; - usb_set_intfdata(intf, iforce); + usb_set_intfdata(intf, iforce_usb); return 0; fail: - if (iforce) { - usb_free_urb(iforce->irq); - usb_free_urb(iforce->out); - usb_free_urb(iforce->ctrl); - kfree(iforce); + if (iforce_usb) { + usb_free_urb(iforce_usb->irq); + usb_free_urb(iforce_usb->out); + kfree(iforce_usb); } return err; @@ -192,17 +264,16 @@ fail: static void iforce_usb_disconnect(struct usb_interface *intf) { - struct iforce *iforce = usb_get_intfdata(intf); + struct iforce_usb *iforce_usb = usb_get_intfdata(intf); usb_set_intfdata(intf, NULL); - input_unregister_device(iforce->dev); + input_unregister_device(iforce_usb->iforce.dev); - usb_free_urb(iforce->irq); - usb_free_urb(iforce->out); - usb_free_urb(iforce->ctrl); + usb_free_urb(iforce_usb->irq); + usb_free_urb(iforce_usb->out); - kfree(iforce); + kfree(iforce_usb); } static const struct usb_device_id iforce_usb_ids[] = { @@ -214,6 +285,7 @@ static const struct usb_device_id iforce_usb_ids[] = { { USB_DEVICE(0x05ef, 0x8888) }, /* AVB Top Shot FFB Racing Wheel */ { USB_DEVICE(0x061c, 0xc0a4) }, /* ACT LABS Force RS */ { USB_DEVICE(0x061c, 0xc084) }, /* ACT LABS Force RS */ + { USB_DEVICE(0x06a3, 0xff04) }, /* Saitek R440 Force Wheel */ { USB_DEVICE(0x06f8, 0x0001) }, /* Guillemot Race Leader Force Feedback */ { USB_DEVICE(0x06f8, 0x0003) }, /* Guillemot Jet Leader Force Feedback */ { USB_DEVICE(0x06f8, 0x0004) }, /* Guillemot Force Feedback Racing Wheel */ @@ -229,3 +301,9 @@ struct usb_driver iforce_usb_driver = { .disconnect = iforce_usb_disconnect, .id_table = iforce_usb_ids, }; + +module_usb_driver(iforce_usb_driver); + +MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <johann.deneux@gmail.com>"); +MODULE_DESCRIPTION("USB I-Force joysticks and wheels driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h index 0e9d01f8bcb6..3e91cc381488 100644 --- a/drivers/input/joystick/iforce/iforce.h +++ b/drivers/input/joystick/iforce/iforce.h @@ -26,8 +26,6 @@ #include <linux/input.h> #include <linux/module.h> #include <linux/spinlock.h> -#include <linux/usb.h> -#include <linux/serio.h> #include <linux/circ_buf.h> #include <linux/mutex.h> @@ -40,10 +38,6 @@ #define IFORCE_MAX_LENGTH 16 -/* iforce::bus */ -#define IFORCE_232 1 -#define IFORCE_USB 2 - #define IFORCE_EFFECTS_MAX 32 /* Each force feedback effect is made of one core effect, which can be @@ -93,27 +87,21 @@ struct iforce_device { signed short *ff; }; +struct iforce; + +struct iforce_xport_ops { + void (*xmit)(struct iforce *iforce); + int (*get_id)(struct iforce *iforce, u8 id, + u8 *response_data, size_t *response_len); + int (*start_io)(struct iforce *iforce); + void (*stop_io)(struct iforce *iforce); +}; + struct iforce { struct input_dev *dev; /* Input device interface */ struct iforce_device *type; - int bus; - - unsigned char data[IFORCE_MAX_LENGTH]; - unsigned char edata[IFORCE_MAX_LENGTH]; - u16 ecmd; - u16 expect_packet; - -#ifdef CONFIG_JOYSTICK_IFORCE_232 - struct serio *serio; /* RS232 transfer */ - int idx, pkt, len, id; - unsigned char csum; -#endif -#ifdef CONFIG_JOYSTICK_IFORCE_USB - struct usb_device *usbdev; /* USB transfer */ - struct usb_interface *intf; - struct urb *irq, *out, *ctrl; - struct usb_ctrlrequest cr; -#endif + const struct iforce_xport_ops *xport_ops; + spinlock_t xmit_lock; /* Buffer used for asynchronous sending of bytes to the device */ struct circ_buf xmit; @@ -139,23 +127,24 @@ struct iforce { /* Encode a time value */ #define TIME_SCALE(a) (a) +static inline int iforce_get_id_packet(struct iforce *iforce, u8 id, + u8 *response_data, size_t *response_len) +{ + return iforce->xport_ops->get_id(iforce, id, + response_data, response_len); +} /* Public functions */ -/* iforce-serio.c */ -void iforce_serial_xmit(struct iforce *iforce); - -/* iforce-usb.c */ -void iforce_usb_xmit(struct iforce *iforce); - /* iforce-main.c */ -int iforce_init_device(struct iforce *iforce); +int iforce_init_device(struct device *parent, u16 bustype, + struct iforce *iforce); /* iforce-packets.c */ int iforce_control_playback(struct iforce*, u16 id, unsigned int); -void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data); +void iforce_process_packet(struct iforce *iforce, + u8 packet_id, u8 *data, size_t len); int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data); void iforce_dump_packet(struct iforce *iforce, char *msg, u16 cmd, unsigned char *data); -int iforce_get_id_packet(struct iforce *iforce, char *packet); /* iforce-ff.c */ int iforce_upload_periodic(struct iforce *, struct ff_effect *, struct ff_effect *); diff --git a/drivers/input/keyboard/davinci_keyscan.c b/drivers/input/keyboard/davinci_keyscan.c index b20a5d044caa..b4db72f833ca 100644 --- a/drivers/input/keyboard/davinci_keyscan.c +++ b/drivers/input/keyboard/davinci_keyscan.c @@ -32,10 +32,6 @@ #include <linux/errno.h> #include <linux/slab.h> -#include <asm/irq.h> - -#include <mach/hardware.h> -#include <mach/irqs.h> #include <linux/platform_data/keyscan-davinci.h> /* Key scan registers */ diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 6cd199e8a370..c186c2552b04 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -774,7 +774,6 @@ static int gpio_keys_probe(struct platform_device *pdev) struct fwnode_handle *child = NULL; struct gpio_keys_drvdata *ddata; struct input_dev *input; - size_t size; int i, error; int wakeup = 0; @@ -784,9 +783,8 @@ static int gpio_keys_probe(struct platform_device *pdev) return PTR_ERR(pdata); } - size = sizeof(struct gpio_keys_drvdata) + - pdata->nbuttons * sizeof(struct gpio_button_data); - ddata = devm_kzalloc(dev, size, GFP_KERNEL); + ddata = devm_kzalloc(dev, struct_size(ddata, data, pdata->nbuttons), + GFP_KERNEL); if (!ddata) { dev_err(dev, "failed to allocate state\n"); return -ENOMEM; diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index edc7262103b9..033655ab5ed0 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -168,6 +168,8 @@ gpio_keys_polled_get_devtree_pdata(struct device *dev) pdata->rep = device_property_present(dev, "autorepeat"); device_property_read_u32(dev, "poll-interval", &pdata->poll_interval); + device_property_read_string(dev, "label", &pdata->name); + device_for_each_child_node(dev, child) { if (fwnode_property_read_u32(child, "linux,code", &button->code)) { @@ -235,7 +237,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) struct gpio_keys_polled_dev *bdev; struct input_polled_dev *poll_dev; struct input_dev *input; - size_t size; int error; int i; @@ -250,9 +251,8 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) return -EINVAL; } - size = sizeof(struct gpio_keys_polled_dev) + - pdata->nbuttons * sizeof(struct gpio_keys_button_data); - bdev = devm_kzalloc(dev, size, GFP_KERNEL); + bdev = devm_kzalloc(dev, struct_size(bdev, data, pdata->nbuttons), + GFP_KERNEL); if (!bdev) { dev_err(dev, "no memory for private data\n"); return -ENOMEM; @@ -272,7 +272,7 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) input = poll_dev->input; - input->name = pdev->name; + input->name = pdata->name ?: pdev->name; input->phys = DRV_NAME"/input0"; input->id.bustype = BUS_HOST; diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c index ae9c51cc85f9..97500a2de2d5 100644 --- a/drivers/input/keyboard/imx_keypad.c +++ b/drivers/input/keyboard/imx_keypad.c @@ -422,7 +422,6 @@ static int imx_keypad_probe(struct platform_device *pdev) dev_get_platdata(&pdev->dev); struct imx_keypad *keypad; struct input_dev *input_dev; - struct resource *res; int irq, error, i, row, col; if (!keymap_data && !pdev->dev.of_node) { @@ -455,8 +454,7 @@ static int imx_keypad_probe(struct platform_device *pdev) timer_setup(&keypad->check_matrix_timer, imx_keypad_check_for_events, 0); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - keypad->mmio_base = devm_ioremap_resource(&pdev->dev, res); + keypad->mmio_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(keypad->mmio_base)) return PTR_ERR(keypad->mmio_base); diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c index 6da607d3b811..3bbd7e652533 100644 --- a/drivers/input/keyboard/tca8418_keypad.c +++ b/drivers/input/keyboard/tca8418_keypad.c @@ -266,7 +266,7 @@ static int tca8418_keypad_probe(struct i2c_client *client, struct tca8418_keypad *keypad_data; struct input_dev *input; u32 rows = 0, cols = 0; - int error, row_shift, max_keys; + int error, row_shift; u8 reg; /* Check i2c driver capabilities */ @@ -291,7 +291,6 @@ static int tca8418_keypad_probe(struct i2c_client *client, } row_shift = get_count_order(cols); - max_keys = rows << row_shift; /* Allocate memory for keypad_data and input device */ keypad_data = devm_kzalloc(dev, sizeof(*keypad_data), GFP_KERNEL); diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 16f41eece6d2..54d36f98b426 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -190,6 +190,15 @@ config INPUT_M68K_BEEP tristate "M68k Beeper support" depends on M68K +config INPUT_MAX77650_ONKEY + tristate "Maxim MAX77650 ONKEY support" + depends on MFD_MAX77650 + help + Support the ONKEY of the MAX77650 PMIC as an input device. + + To compile this driver as a module, choose M here: the module + will be called max77650-onkey. + config INPUT_MAX77693_HAPTIC tristate "MAXIM MAX77693/MAX77843 haptic controller support" depends on (MFD_MAX77693 || MFD_MAX77843) && PWM @@ -873,4 +882,15 @@ config INPUT_SC27XX_VIBRA To compile this driver as a module, choose M here. The module will be called sc27xx_vibra. +config INPUT_STPMIC1_ONKEY + tristate "STPMIC1 PMIC Onkey support" + depends on MFD_STPMIC1 + help + Say Y to enable support of onkey embedded into STPMIC1 PMIC. onkey + can be used to wakeup from low power modes and force a shut-down on + long press. + + To compile this driver as a module, choose M here: the + module will be called stpmic1_onkey. + endif diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index d871991c2eee..8fd187f314bd 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o +obj-$(CONFIG_INPUT_MAX77650_ONKEY) += max77650-onkey.o obj-$(CONFIG_INPUT_MAX77693_HAPTIC) += max77693-haptic.o obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o obj-$(CONFIG_INPUT_MAX8997_HAPTIC) += max8997_haptic.o @@ -73,6 +74,7 @@ obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o obj-$(CONFIG_INPUT_SIRFSOC_ONKEY) += sirfsoc-onkey.o obj-$(CONFIG_INPUT_SOC_BUTTON_ARRAY) += soc_button_array.o obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o +obj-$(CONFIG_INPUT_STPMIC1_ONKEY) += stpmic1_onkey.o obj-$(CONFIG_INPUT_TPS65218_PWRBUTTON) += tps65218-pwrbutton.o obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o @@ -83,3 +85,4 @@ obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o obj-$(CONFIG_INPUT_YEALINK) += yealink.o obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR) += ideapad_slidebar.o + diff --git a/drivers/input/misc/da9063_onkey.c b/drivers/input/misc/da9063_onkey.c index 3e9c353d82ef..c06e067bd627 100644 --- a/drivers/input/misc/da9063_onkey.c +++ b/drivers/input/misc/da9063_onkey.c @@ -1,16 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * OnKey device driver for DA9063, DA9062 and DA9061 PMICs * Copyright (C) 2015 Dialog Semiconductor Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/module.h> @@ -22,7 +13,6 @@ #include <linux/regmap.h> #include <linux/of.h> #include <linux/mfd/da9063/core.h> -#include <linux/mfd/da9063/pdata.h> #include <linux/mfd/da9063/registers.h> #include <linux/mfd/da9062/core.h> #include <linux/mfd/da9062/registers.h> @@ -201,8 +191,6 @@ static void da9063_cancel_poll(void *data) static int da9063_onkey_probe(struct platform_device *pdev) { - struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent); - struct da9063_pdata *pdata = dev_get_platdata(da9063->dev); struct da9063_onkey *onkey; const struct of_device_id *match; int irq; @@ -229,12 +217,8 @@ static int da9063_onkey_probe(struct platform_device *pdev) return -ENXIO; } - if (pdata) - onkey->key_power = pdata->key_power; - else - onkey->key_power = - !of_property_read_bool(pdev->dev.of_node, - "dlg,disable-key-power"); + onkey->key_power = !of_property_read_bool(pdev->dev.of_node, + "dlg,disable-key-power"); onkey->input = devm_input_allocate_device(&pdev->dev); if (!onkey->input) { diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c index 47eb8ca729fe..abca895a6156 100644 --- a/drivers/input/misc/hp_sdc_rtc.c +++ b/drivers/input/misc/hp_sdc_rtc.c @@ -441,12 +441,10 @@ static int hp_sdc_rtc_proc_show(struct seq_file *m, void *v) seq_puts(m, "BBRTC\t\t: READ FAILED!\n"); } else { seq_printf(m, - "rtc_time\t: %02d:%02d:%02d\n" - "rtc_date\t: %04d-%02d-%02d\n" + "rtc_time\t: %ptRt\n" + "rtc_date\t: %ptRd\n" "rtc_epoch\t: %04lu\n", - tm.tm_hour, tm.tm_min, tm.tm_sec, - tm.tm_year + 1900, tm.tm_mon + 1, - tm.tm_mday, epoch); + &tm, &tm, epoch); } if (hp_sdc_rtc_read_rt(&tv)) { diff --git a/drivers/input/misc/max77650-onkey.c b/drivers/input/misc/max77650-onkey.c new file mode 100644 index 000000000000..4d875f2ac13d --- /dev/null +++ b/drivers/input/misc/max77650-onkey.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2018 BayLibre SAS +// Author: Bartosz Golaszewski <bgolaszewski@baylibre.com> +// +// ONKEY driver for MAXIM 77650/77651 charger/power-supply. + +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/mfd/max77650.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +#define MAX77650_ONKEY_MODE_MASK BIT(3) +#define MAX77650_ONKEY_MODE_PUSH 0x00 +#define MAX77650_ONKEY_MODE_SLIDE BIT(3) + +struct max77650_onkey { + struct input_dev *input; + unsigned int code; +}; + +static irqreturn_t max77650_onkey_falling(int irq, void *data) +{ + struct max77650_onkey *onkey = data; + + input_report_key(onkey->input, onkey->code, 0); + input_sync(onkey->input); + + return IRQ_HANDLED; +} + +static irqreturn_t max77650_onkey_rising(int irq, void *data) +{ + struct max77650_onkey *onkey = data; + + input_report_key(onkey->input, onkey->code, 1); + input_sync(onkey->input); + + return IRQ_HANDLED; +} + +static int max77650_onkey_probe(struct platform_device *pdev) +{ + int irq_r, irq_f, error, mode; + struct max77650_onkey *onkey; + struct device *dev, *parent; + struct regmap *map; + unsigned int type; + + dev = &pdev->dev; + parent = dev->parent; + + map = dev_get_regmap(parent, NULL); + if (!map) + return -ENODEV; + + onkey = devm_kzalloc(dev, sizeof(*onkey), GFP_KERNEL); + if (!onkey) + return -ENOMEM; + + error = device_property_read_u32(dev, "linux,code", &onkey->code); + if (error) + onkey->code = KEY_POWER; + + if (device_property_read_bool(dev, "maxim,onkey-slide")) { + mode = MAX77650_ONKEY_MODE_SLIDE; + type = EV_SW; + } else { + mode = MAX77650_ONKEY_MODE_PUSH; + type = EV_KEY; + } + + error = regmap_update_bits(map, MAX77650_REG_CNFG_GLBL, + MAX77650_ONKEY_MODE_MASK, mode); + if (error) + return error; + + irq_f = platform_get_irq_byname(pdev, "nEN_F"); + if (irq_f < 0) + return irq_f; + + irq_r = platform_get_irq_byname(pdev, "nEN_R"); + if (irq_r < 0) + return irq_r; + + onkey->input = devm_input_allocate_device(dev); + if (!onkey->input) + return -ENOMEM; + + onkey->input->name = "max77650_onkey"; + onkey->input->phys = "max77650_onkey/input0"; + onkey->input->id.bustype = BUS_I2C; + input_set_capability(onkey->input, type, onkey->code); + + error = devm_request_any_context_irq(dev, irq_f, max77650_onkey_falling, + IRQF_ONESHOT, "onkey-down", onkey); + if (error < 0) + return error; + + error = devm_request_any_context_irq(dev, irq_r, max77650_onkey_rising, + IRQF_ONESHOT, "onkey-up", onkey); + if (error < 0) + return error; + + return input_register_device(onkey->input); +} + +static struct platform_driver max77650_onkey_driver = { + .driver = { + .name = "max77650-onkey", + }, + .probe = max77650_onkey_probe, +}; +module_platform_driver(max77650_onkey_driver); + +MODULE_DESCRIPTION("MAXIM 77650/77651 ONKEY driver"); +MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:max77650-onkey"); diff --git a/drivers/input/misc/stpmic1_onkey.c b/drivers/input/misc/stpmic1_onkey.c new file mode 100644 index 000000000000..7b49c9997df7 --- /dev/null +++ b/drivers/input/misc/stpmic1_onkey.c @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) STMicroelectronics 2018 +// Author: Pascal Paillet <p.paillet@st.com> for STMicroelectronics. + +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/mfd/stpmic1.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/property.h> +#include <linux/regmap.h> + +/** + * struct stpmic1_onkey - OnKey data + * @input_dev: pointer to input device + * @irq_falling: irq that we are hooked on to + * @irq_rising: irq that we are hooked on to + */ +struct stpmic1_onkey { + struct input_dev *input_dev; + int irq_falling; + int irq_rising; +}; + +static irqreturn_t onkey_falling_irq(int irq, void *ponkey) +{ + struct stpmic1_onkey *onkey = ponkey; + struct input_dev *input_dev = onkey->input_dev; + + input_report_key(input_dev, KEY_POWER, 1); + pm_wakeup_event(input_dev->dev.parent, 0); + input_sync(input_dev); + + return IRQ_HANDLED; +} + +static irqreturn_t onkey_rising_irq(int irq, void *ponkey) +{ + struct stpmic1_onkey *onkey = ponkey; + struct input_dev *input_dev = onkey->input_dev; + + input_report_key(input_dev, KEY_POWER, 0); + pm_wakeup_event(input_dev->dev.parent, 0); + input_sync(input_dev); + + return IRQ_HANDLED; +} + +static int stpmic1_onkey_probe(struct platform_device *pdev) +{ + struct stpmic1 *pmic = dev_get_drvdata(pdev->dev.parent); + struct device *dev = &pdev->dev; + struct input_dev *input_dev; + struct stpmic1_onkey *onkey; + unsigned int val, reg = 0; + int error; + + onkey = devm_kzalloc(dev, sizeof(*onkey), GFP_KERNEL); + if (!onkey) + return -ENOMEM; + + onkey->irq_falling = platform_get_irq_byname(pdev, "onkey-falling"); + if (onkey->irq_falling < 0) { + dev_err(dev, "failed: request IRQ onkey-falling %d\n", + onkey->irq_falling); + return onkey->irq_falling; + } + + onkey->irq_rising = platform_get_irq_byname(pdev, "onkey-rising"); + if (onkey->irq_rising < 0) { + dev_err(dev, "failed: request IRQ onkey-rising %d\n", + onkey->irq_rising); + return onkey->irq_rising; + } + + if (!device_property_read_u32(dev, "power-off-time-sec", &val)) { + if (val > 0 && val <= 16) { + dev_dbg(dev, "power-off-time=%d seconds\n", val); + reg |= PONKEY_PWR_OFF; + reg |= ((16 - val) & PONKEY_TURNOFF_TIMER_MASK); + } else { + dev_err(dev, "power-off-time-sec out of range\n"); + return -EINVAL; + } + } + + if (device_property_present(dev, "st,onkey-clear-cc-flag")) + reg |= PONKEY_CC_FLAG_CLEAR; + + error = regmap_update_bits(pmic->regmap, PKEY_TURNOFF_CR, + PONKEY_TURNOFF_MASK, reg); + if (error) { + dev_err(dev, "PKEY_TURNOFF_CR write failed: %d\n", error); + return error; + } + + if (device_property_present(dev, "st,onkey-pu-inactive")) { + error = regmap_update_bits(pmic->regmap, PADS_PULL_CR, + PONKEY_PU_INACTIVE, + PONKEY_PU_INACTIVE); + if (error) { + dev_err(dev, "ONKEY Pads configuration failed: %d\n", + error); + return error; + } + } + + input_dev = devm_input_allocate_device(dev); + if (!input_dev) { + dev_err(dev, "Can't allocate Pwr Onkey Input Device\n"); + return -ENOMEM; + } + + input_dev->name = "pmic_onkey"; + input_dev->phys = "pmic_onkey/input0"; + + input_set_capability(input_dev, EV_KEY, KEY_POWER); + + onkey->input_dev = input_dev; + + /* interrupt is nested in a thread */ + error = devm_request_threaded_irq(dev, onkey->irq_falling, NULL, + onkey_falling_irq, IRQF_ONESHOT, + dev_name(dev), onkey); + if (error) { + dev_err(dev, "Can't get IRQ Onkey Falling: %d\n", error); + return error; + } + + error = devm_request_threaded_irq(dev, onkey->irq_rising, NULL, + onkey_rising_irq, IRQF_ONESHOT, + dev_name(dev), onkey); + if (error) { + dev_err(dev, "Can't get IRQ Onkey Rising: %d\n", error); + return error; + } + + error = input_register_device(input_dev); + if (error) { + dev_err(dev, "Can't register power button: %d\n", error); + return error; + } + + platform_set_drvdata(pdev, onkey); + device_init_wakeup(dev, true); + + return 0; +} + +static int __maybe_unused stpmic1_onkey_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct stpmic1_onkey *onkey = platform_get_drvdata(pdev); + + if (device_may_wakeup(dev)) { + enable_irq_wake(onkey->irq_falling); + enable_irq_wake(onkey->irq_rising); + } + return 0; +} + +static int __maybe_unused stpmic1_onkey_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct stpmic1_onkey *onkey = platform_get_drvdata(pdev); + + if (device_may_wakeup(dev)) { + disable_irq_wake(onkey->irq_falling); + disable_irq_wake(onkey->irq_rising); + } + return 0; +} + +static SIMPLE_DEV_PM_OPS(stpmic1_onkey_pm, + stpmic1_onkey_suspend, + stpmic1_onkey_resume); + +static const struct of_device_id of_stpmic1_onkey_match[] = { + { .compatible = "st,stpmic1-onkey" }, + { }, +}; + +MODULE_DEVICE_TABLE(of, of_stpmic1_onkey_match); + +static struct platform_driver stpmic1_onkey_driver = { + .probe = stpmic1_onkey_probe, + .driver = { + .name = "stpmic1_onkey", + .of_match_table = of_match_ptr(of_stpmic1_onkey_match), + .pm = &stpmic1_onkey_pm, + }, +}; +module_platform_driver(stpmic1_onkey_driver); + +MODULE_DESCRIPTION("Onkey driver for STPMIC1"); +MODULE_AUTHOR("Pascal Paillet <p.paillet@st.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 2c0561e20b7f..e2c824abd19c 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -37,6 +37,7 @@ #include <linux/completion.h> #include <linux/of.h> #include <linux/property.h> +#include <linux/input/elan-i2c-ids.h> #include <linux/regulator/consumer.h> #include <asm/unaligned.h> @@ -99,6 +100,7 @@ struct elan_tp_data { u8 max_baseline; bool baseline_ready; u8 clickpad; + bool middle_button; }; static int elan_get_fwinfo(u16 ic_type, u16 *validpage_count, @@ -366,27 +368,62 @@ static unsigned int elan_convert_resolution(u8 val) static int elan_query_device_parameters(struct elan_tp_data *data) { + struct i2c_client *client = data->client; unsigned int x_traces, y_traces; + u32 x_mm, y_mm; u8 hw_x_res, hw_y_res; int error; - error = data->ops->get_max(data->client, &data->max_x, &data->max_y); - if (error) - return error; - - error = data->ops->get_num_traces(data->client, &x_traces, &y_traces); - if (error) - return error; + if (device_property_read_u32(&client->dev, + "touchscreen-size-x", &data->max_x) || + device_property_read_u32(&client->dev, + "touchscreen-size-y", &data->max_y)) { + error = data->ops->get_max(data->client, + &data->max_x, + &data->max_y); + if (error) + return error; + } else { + /* size is the maximum + 1 */ + --data->max_x; + --data->max_y; + } + if (device_property_read_u32(&client->dev, + "elan,x_traces", + &x_traces) || + device_property_read_u32(&client->dev, + "elan,y_traces", + &y_traces)) { + error = data->ops->get_num_traces(data->client, + &x_traces, &y_traces); + if (error) + return error; + } data->width_x = data->max_x / x_traces; data->width_y = data->max_y / y_traces; - error = data->ops->get_resolution(data->client, &hw_x_res, &hw_y_res); - if (error) - return error; + if (device_property_read_u32(&client->dev, + "touchscreen-x-mm", &x_mm) || + device_property_read_u32(&client->dev, + "touchscreen-y-mm", &y_mm)) { + error = data->ops->get_resolution(data->client, + &hw_x_res, &hw_y_res); + if (error) + return error; + + data->x_res = elan_convert_resolution(hw_x_res); + data->y_res = elan_convert_resolution(hw_y_res); + } else { + data->x_res = (data->max_x + 1) / x_mm; + data->y_res = (data->max_y + 1) / y_mm; + } + + if (device_property_read_bool(&client->dev, "elan,clickpad")) + data->clickpad = 1; - data->x_res = elan_convert_resolution(hw_x_res); - data->y_res = elan_convert_resolution(hw_y_res); + if (device_property_read_bool(&client->dev, "elan,middle-button")) + data->middle_button = true; return 0; } @@ -926,8 +963,9 @@ static void elan_report_absolute(struct elan_tp_data *data, u8 *packet) finger_data += ETP_FINGER_DATA_LEN; } - input_report_key(input, BTN_LEFT, tp_info & 0x01); - input_report_key(input, BTN_RIGHT, tp_info & 0x02); + input_report_key(input, BTN_LEFT, tp_info & BIT(0)); + input_report_key(input, BTN_MIDDLE, tp_info & BIT(2)); + input_report_key(input, BTN_RIGHT, tp_info & BIT(1)); input_report_abs(input, ABS_DISTANCE, hover_event != 0); input_mt_report_pointer_emulation(input, true); input_sync(input); @@ -1061,10 +1099,13 @@ static int elan_setup_input_device(struct elan_tp_data *data) __set_bit(EV_ABS, input->evbit); __set_bit(INPUT_PROP_POINTER, input->propbit); - if (data->clickpad) + if (data->clickpad) { __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); - else + } else { __set_bit(BTN_RIGHT, input->keybit); + if (data->middle_button) + __set_bit(BTN_MIDDLE, input->keybit); + } __set_bit(BTN_LEFT, input->keybit); /* Set up ST parameters */ @@ -1335,55 +1376,6 @@ static const struct i2c_device_id elan_id[] = { MODULE_DEVICE_TABLE(i2c, elan_id); #ifdef CONFIG_ACPI -static const struct acpi_device_id elan_acpi_id[] = { - { "ELAN0000", 0 }, - { "ELAN0100", 0 }, - { "ELAN0600", 0 }, - { "ELAN0601", 0 }, - { "ELAN0602", 0 }, - { "ELAN0603", 0 }, - { "ELAN0604", 0 }, - { "ELAN0605", 0 }, - { "ELAN0606", 0 }, - { "ELAN0607", 0 }, - { "ELAN0608", 0 }, - { "ELAN0609", 0 }, - { "ELAN060B", 0 }, - { "ELAN060C", 0 }, - { "ELAN060F", 0 }, - { "ELAN0610", 0 }, - { "ELAN0611", 0 }, - { "ELAN0612", 0 }, - { "ELAN0615", 0 }, - { "ELAN0616", 0 }, - { "ELAN0617", 0 }, - { "ELAN0618", 0 }, - { "ELAN0619", 0 }, - { "ELAN061A", 0 }, - { "ELAN061B", 0 }, - { "ELAN061C", 0 }, - { "ELAN061D", 0 }, - { "ELAN061E", 0 }, - { "ELAN061F", 0 }, - { "ELAN0620", 0 }, - { "ELAN0621", 0 }, - { "ELAN0622", 0 }, - { "ELAN0623", 0 }, - { "ELAN0624", 0 }, - { "ELAN0625", 0 }, - { "ELAN0626", 0 }, - { "ELAN0627", 0 }, - { "ELAN0628", 0 }, - { "ELAN0629", 0 }, - { "ELAN062A", 0 }, - { "ELAN062B", 0 }, - { "ELAN062C", 0 }, - { "ELAN062D", 0 }, - { "ELAN0631", 0 }, - { "ELAN0632", 0 }, - { "ELAN1000", 0 }, - { } -}; MODULE_DEVICE_TABLE(acpi, elan_acpi_id); #endif diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 530142b5a115..ea1ee0f44a65 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -230,6 +230,52 @@ static void elantech_packet_dump(struct psmouse *psmouse) } /* + * Advertise INPUT_PROP_BUTTONPAD for clickpads. The testing of bit 12 in + * fw_version for this is based on the following fw_version & caps table: + * + * Laptop-model: fw_version: caps: buttons: + * Acer S3 0x461f00 10, 13, 0e clickpad + * Acer S7-392 0x581f01 50, 17, 0d clickpad + * Acer V5-131 0x461f02 01, 16, 0c clickpad + * Acer V5-551 0x461f00 ? clickpad + * Asus K53SV 0x450f01 78, 15, 0c 2 hw buttons + * Asus G46VW 0x460f02 00, 18, 0c 2 hw buttons + * Asus G750JX 0x360f00 00, 16, 0c 2 hw buttons + * Asus TP500LN 0x381f17 10, 14, 0e clickpad + * Asus X750JN 0x381f17 10, 14, 0e clickpad + * Asus UX31 0x361f00 20, 15, 0e clickpad + * Asus UX32VD 0x361f02 00, 15, 0e clickpad + * Avatar AVIU-145A2 0x361f00 ? clickpad + * Fujitsu CELSIUS H760 0x570f02 40, 14, 0c 3 hw buttons (**) + * Fujitsu CELSIUS H780 0x5d0f02 41, 16, 0d 3 hw buttons (**) + * Fujitsu LIFEBOOK E544 0x470f00 d0, 12, 09 2 hw buttons + * Fujitsu LIFEBOOK E546 0x470f00 50, 12, 09 2 hw buttons + * Fujitsu LIFEBOOK E547 0x470f00 50, 12, 09 2 hw buttons + * Fujitsu LIFEBOOK E554 0x570f01 40, 14, 0c 2 hw buttons + * Fujitsu LIFEBOOK E557 0x570f01 40, 14, 0c 2 hw buttons + * Fujitsu T725 0x470f01 05, 12, 09 2 hw buttons + * Fujitsu H730 0x570f00 c0, 14, 0c 3 hw buttons (**) + * Gigabyte U2442 0x450f01 58, 17, 0c 2 hw buttons + * Lenovo L430 0x350f02 b9, 15, 0c 2 hw buttons (*) + * Lenovo L530 0x350f02 b9, 15, 0c 2 hw buttons (*) + * Samsung NF210 0x150b00 78, 14, 0a 2 hw buttons + * Samsung NP770Z5E 0x575f01 10, 15, 0f clickpad + * Samsung NP700Z5B 0x361f06 21, 15, 0f clickpad + * Samsung NP900X3E-A02 0x575f03 ? clickpad + * Samsung NP-QX410 0x851b00 19, 14, 0c clickpad + * Samsung RC512 0x450f00 08, 15, 0c 2 hw buttons + * Samsung RF710 0x450f00 ? 2 hw buttons + * System76 Pangolin 0x250f01 ? 2 hw buttons + * (*) + 3 trackpoint buttons + * (**) + 0 trackpoint buttons + * Note: Lenovo L430 and Lenovo L530 have the same fw_version/caps + */ +static inline int elantech_is_buttonpad(struct elantech_device_info *info) +{ + return info->fw_version & 0x001000; +} + +/* * Interpret complete data packets and report absolute mode input events for * hardware version 1. (4 byte packets) */ @@ -526,7 +572,7 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse, input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); /* For clickpads map both buttons to BTN_LEFT */ - if (etd->info.fw_version & 0x001000) + if (elantech_is_buttonpad(&etd->info)) input_report_key(dev, BTN_LEFT, packet[0] & 0x03); else psmouse_report_standard_buttons(dev, packet[0]); @@ -544,7 +590,7 @@ static void elantech_input_sync_v4(struct psmouse *psmouse) unsigned char *packet = psmouse->packet; /* For clickpads map both buttons to BTN_LEFT */ - if (etd->info.fw_version & 0x001000) + if (elantech_is_buttonpad(&etd->info)) input_report_key(dev, BTN_LEFT, packet[0] & 0x03); else psmouse_report_standard_buttons(dev, packet[0]); @@ -994,88 +1040,6 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse) return rc; } -static int elantech_set_range(struct psmouse *psmouse, - unsigned int *x_min, unsigned int *y_min, - unsigned int *x_max, unsigned int *y_max, - unsigned int *width) -{ - struct elantech_data *etd = psmouse->private; - struct elantech_device_info *info = &etd->info; - unsigned char param[3]; - unsigned char traces; - - switch (info->hw_version) { - case 1: - *x_min = ETP_XMIN_V1; - *y_min = ETP_YMIN_V1; - *x_max = ETP_XMAX_V1; - *y_max = ETP_YMAX_V1; - break; - - case 2: - if (info->fw_version == 0x020800 || - info->fw_version == 0x020b00 || - info->fw_version == 0x020030) { - *x_min = ETP_XMIN_V2; - *y_min = ETP_YMIN_V2; - *x_max = ETP_XMAX_V2; - *y_max = ETP_YMAX_V2; - } else { - int i; - int fixed_dpi; - - i = (info->fw_version > 0x020800 && - info->fw_version < 0x020900) ? 1 : 2; - - if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) - return -1; - - fixed_dpi = param[1] & 0x10; - - if (((info->fw_version >> 16) == 0x14) && fixed_dpi) { - if (info->send_cmd(psmouse, ETP_SAMPLE_QUERY, param)) - return -1; - - *x_max = (info->capabilities[1] - i) * param[1] / 2; - *y_max = (info->capabilities[2] - i) * param[2] / 2; - } else if (info->fw_version == 0x040216) { - *x_max = 819; - *y_max = 405; - } else if (info->fw_version == 0x040219 || info->fw_version == 0x040215) { - *x_max = 900; - *y_max = 500; - } else { - *x_max = (info->capabilities[1] - i) * 64; - *y_max = (info->capabilities[2] - i) * 64; - } - } - break; - - case 3: - if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) - return -1; - - *x_max = (0x0f & param[0]) << 8 | param[1]; - *y_max = (0xf0 & param[0]) << 4 | param[2]; - break; - - case 4: - if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) - return -1; - - *x_max = (0x0f & param[0]) << 8 | param[1]; - *y_max = (0xf0 & param[0]) << 4 | param[2]; - traces = info->capabilities[1]; - if ((traces < 2) || (traces > *x_max)) - return -1; - - *width = *x_max / (traces - 1); - break; - } - - return 0; -} - /* * (value from firmware) * 10 + 790 = dpi * we also have to convert dpi to dots/mm (*10/254 to avoid floating point) @@ -1102,53 +1066,12 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse, return 0; } -/* - * Advertise INPUT_PROP_BUTTONPAD for clickpads. The testing of bit 12 in - * fw_version for this is based on the following fw_version & caps table: - * - * Laptop-model: fw_version: caps: buttons: - * Acer S3 0x461f00 10, 13, 0e clickpad - * Acer S7-392 0x581f01 50, 17, 0d clickpad - * Acer V5-131 0x461f02 01, 16, 0c clickpad - * Acer V5-551 0x461f00 ? clickpad - * Asus K53SV 0x450f01 78, 15, 0c 2 hw buttons - * Asus G46VW 0x460f02 00, 18, 0c 2 hw buttons - * Asus G750JX 0x360f00 00, 16, 0c 2 hw buttons - * Asus TP500LN 0x381f17 10, 14, 0e clickpad - * Asus X750JN 0x381f17 10, 14, 0e clickpad - * Asus UX31 0x361f00 20, 15, 0e clickpad - * Asus UX32VD 0x361f02 00, 15, 0e clickpad - * Avatar AVIU-145A2 0x361f00 ? clickpad - * Fujitsu CELSIUS H760 0x570f02 40, 14, 0c 3 hw buttons (**) - * Fujitsu CELSIUS H780 0x5d0f02 41, 16, 0d 3 hw buttons (**) - * Fujitsu LIFEBOOK E544 0x470f00 d0, 12, 09 2 hw buttons - * Fujitsu LIFEBOOK E546 0x470f00 50, 12, 09 2 hw buttons - * Fujitsu LIFEBOOK E547 0x470f00 50, 12, 09 2 hw buttons - * Fujitsu LIFEBOOK E554 0x570f01 40, 14, 0c 2 hw buttons - * Fujitsu LIFEBOOK E557 0x570f01 40, 14, 0c 2 hw buttons - * Fujitsu T725 0x470f01 05, 12, 09 2 hw buttons - * Fujitsu H730 0x570f00 c0, 14, 0c 3 hw buttons (**) - * Gigabyte U2442 0x450f01 58, 17, 0c 2 hw buttons - * Lenovo L430 0x350f02 b9, 15, 0c 2 hw buttons (*) - * Lenovo L530 0x350f02 b9, 15, 0c 2 hw buttons (*) - * Samsung NF210 0x150b00 78, 14, 0a 2 hw buttons - * Samsung NP770Z5E 0x575f01 10, 15, 0f clickpad - * Samsung NP700Z5B 0x361f06 21, 15, 0f clickpad - * Samsung NP900X3E-A02 0x575f03 ? clickpad - * Samsung NP-QX410 0x851b00 19, 14, 0c clickpad - * Samsung RC512 0x450f00 08, 15, 0c 2 hw buttons - * Samsung RF710 0x450f00 ? 2 hw buttons - * System76 Pangolin 0x250f01 ? 2 hw buttons - * (*) + 3 trackpoint buttons - * (**) + 0 trackpoint buttons - * Note: Lenovo L430 and Lenovo L530 have the same fw_version/caps - */ static void elantech_set_buttonpad_prop(struct psmouse *psmouse) { struct input_dev *dev = psmouse->dev; struct elantech_data *etd = psmouse->private; - if (etd->info.fw_version & 0x001000) { + if (elantech_is_buttonpad(&etd->info)) { __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); __clear_bit(BTN_RIGHT, dev->keybit); } @@ -1184,16 +1107,6 @@ static const struct dmi_system_id elantech_dmi_has_middle_button[] = { { } }; -static const char * const middle_button_pnp_ids[] = { - "LEN2131", /* ThinkPad P52 w/ NFC */ - "LEN2132", /* ThinkPad P52 */ - "LEN2133", /* ThinkPad P72 w/ NFC */ - "LEN2134", /* ThinkPad P72 */ - "LEN0407", - "LEN0408", - NULL -}; - /* * Set the appropriate event bits for the input subsystem */ @@ -1202,10 +1115,9 @@ static int elantech_set_input_params(struct psmouse *psmouse) struct input_dev *dev = psmouse->dev; struct elantech_data *etd = psmouse->private; struct elantech_device_info *info = &etd->info; - unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0, width = 0; - - if (elantech_set_range(psmouse, &x_min, &y_min, &x_max, &y_max, &width)) - return -1; + unsigned int x_min = info->x_min, y_min = info->y_min, + x_max = info->x_max, y_max = info->y_max, + width = info->width; __set_bit(INPUT_PROP_POINTER, dev->propbit); __set_bit(EV_KEY, dev->evbit); @@ -1213,8 +1125,7 @@ static int elantech_set_input_params(struct psmouse *psmouse) __clear_bit(EV_REL, dev->evbit); __set_bit(BTN_LEFT, dev->keybit); - if (dmi_check_system(elantech_dmi_has_middle_button) || - psmouse_matches_pnp_id(psmouse, middle_button_pnp_ids)) + if (info->has_middle_button) __set_bit(BTN_MIDDLE, dev->keybit); __set_bit(BTN_RIGHT, dev->keybit); @@ -1689,6 +1600,7 @@ static int elantech_query_info(struct psmouse *psmouse, struct elantech_device_info *info) { unsigned char param[3]; + unsigned char traces; memset(info, 0, sizeof(*info)); @@ -1757,6 +1669,90 @@ static int elantech_query_info(struct psmouse *psmouse, } } + /* query range information */ + switch (info->hw_version) { + case 1: + info->x_min = ETP_XMIN_V1; + info->y_min = ETP_YMIN_V1; + info->x_max = ETP_XMAX_V1; + info->y_max = ETP_YMAX_V1; + break; + + case 2: + if (info->fw_version == 0x020800 || + info->fw_version == 0x020b00 || + info->fw_version == 0x020030) { + info->x_min = ETP_XMIN_V2; + info->y_min = ETP_YMIN_V2; + info->x_max = ETP_XMAX_V2; + info->y_max = ETP_YMAX_V2; + } else { + int i; + int fixed_dpi; + + i = (info->fw_version > 0x020800 && + info->fw_version < 0x020900) ? 1 : 2; + + if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) + return -EINVAL; + + fixed_dpi = param[1] & 0x10; + + if (((info->fw_version >> 16) == 0x14) && fixed_dpi) { + if (info->send_cmd(psmouse, ETP_SAMPLE_QUERY, param)) + return -EINVAL; + + info->x_max = (info->capabilities[1] - i) * param[1] / 2; + info->y_max = (info->capabilities[2] - i) * param[2] / 2; + } else if (info->fw_version == 0x040216) { + info->x_max = 819; + info->y_max = 405; + } else if (info->fw_version == 0x040219 || info->fw_version == 0x040215) { + info->x_max = 900; + info->y_max = 500; + } else { + info->x_max = (info->capabilities[1] - i) * 64; + info->y_max = (info->capabilities[2] - i) * 64; + } + } + break; + + case 3: + if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) + return -EINVAL; + + info->x_max = (0x0f & param[0]) << 8 | param[1]; + info->y_max = (0xf0 & param[0]) << 4 | param[2]; + break; + + case 4: + if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) + return -EINVAL; + + info->x_max = (0x0f & param[0]) << 8 | param[1]; + info->y_max = (0xf0 & param[0]) << 4 | param[2]; + traces = info->capabilities[1]; + if ((traces < 2) || (traces > info->x_max)) + return -EINVAL; + + info->width = info->x_max / (traces - 1); + + /* column number of traces */ + info->x_traces = traces; + + /* row number of traces */ + traces = info->capabilities[2]; + if ((traces >= 2) && (traces <= info->y_max)) + info->y_traces = traces; + + break; + } + + /* check for the middle button: DMI matching or new v4 firmwares */ + info->has_middle_button = dmi_check_system(elantech_dmi_has_middle_button) || + (ETP_NEW_IC_SMBUS_HOST_NOTIFY(info->fw_version) && + !elantech_is_buttonpad(info)); + return 0; } @@ -1783,10 +1779,6 @@ static const char * const i2c_blacklist_pnp_ids[] = { * These are known to not be working properly as bits are missing * in elan_i2c. */ - "LEN2131", /* ThinkPad P52 w/ NFC */ - "LEN2132", /* ThinkPad P52 */ - "LEN2133", /* ThinkPad P72 w/ NFC */ - "LEN2134", /* ThinkPad P72 */ NULL }; @@ -1794,17 +1786,45 @@ static int elantech_create_smbus(struct psmouse *psmouse, struct elantech_device_info *info, bool leave_breadcrumbs) { - const struct property_entry i2c_properties[] = { - PROPERTY_ENTRY_BOOL("elan,trackpoint"), - { }, - }; + struct property_entry i2c_props[11] = {}; struct i2c_board_info smbus_board = { I2C_BOARD_INFO("elan_i2c", 0x15), .flags = I2C_CLIENT_HOST_NOTIFY, }; + unsigned int idx = 0; + + smbus_board.properties = i2c_props; + + i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-size-x", + info->x_max + 1); + i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-size-y", + info->y_max + 1); + i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-min-x", + info->x_min); + i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-min-y", + info->y_min); + if (info->x_res) + i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-x-mm", + (info->x_max + 1) / info->x_res); + if (info->y_res) + i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-y-mm", + (info->y_max + 1) / info->y_res); if (info->has_trackpoint) - smbus_board.properties = i2c_properties; + i2c_props[idx++] = PROPERTY_ENTRY_BOOL("elan,trackpoint"); + + if (info->has_middle_button) + i2c_props[idx++] = PROPERTY_ENTRY_BOOL("elan,middle-button"); + + if (info->x_traces) + i2c_props[idx++] = PROPERTY_ENTRY_U32("elan,x_traces", + info->x_traces); + if (info->y_traces) + i2c_props[idx++] = PROPERTY_ENTRY_U32("elan,y_traces", + info->y_traces); + + if (elantech_is_buttonpad(info)) + i2c_props[idx++] = PROPERTY_ENTRY_BOOL("elan,clickpad"); return psmouse_smbus_init(psmouse, &smbus_board, NULL, 0, false, leave_breadcrumbs); diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h index 119727085a60..a7eaa62af6a0 100644 --- a/drivers/input/mouse/elantech.h +++ b/drivers/input/mouse/elantech.h @@ -144,8 +144,15 @@ struct elantech_device_info { unsigned char debug; unsigned char hw_version; unsigned int fw_version; + unsigned int x_min; + unsigned int y_min; + unsigned int x_max; + unsigned int y_max; unsigned int x_res; unsigned int y_res; + unsigned int x_traces; + unsigned int y_traces; + unsigned int width; unsigned int bus; bool paritycheck; bool jumpy_cursor; @@ -153,6 +160,7 @@ struct elantech_device_info { bool crc_enabled; bool set_hw_resolution; bool has_trackpoint; + bool has_middle_button; int (*send_cmd)(struct psmouse *psmouse, unsigned char c, unsigned char *param); }; diff --git a/drivers/input/rmi4/rmi_f12.c b/drivers/input/rmi4/rmi_f12.c index 5c7f48915779..3b7d7b940cab 100644 --- a/drivers/input/rmi4/rmi_f12.c +++ b/drivers/input/rmi4/rmi_f12.c @@ -73,7 +73,6 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12) int pitch_y = 0; int rx_receivers = 0; int tx_receivers = 0; - int sensor_flags = 0; item = rmi_get_register_desc_item(&f12->control_reg_desc, 8); if (!item) { @@ -129,10 +128,9 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12) offset += 2; } - if (rmi_register_desc_has_subpacket(item, 4)) { - sensor_flags = buf[offset]; + /* Skip over sensor flags */ + if (rmi_register_desc_has_subpacket(item, 4)) offset += 1; - } sensor->x_mm = (pitch_x * rx_receivers) >> 12; sensor->y_mm = (pitch_y * tx_receivers) >> 12; diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c index 49d8d53e50b7..96f9b5397367 100644 --- a/drivers/input/serio/gscps2.c +++ b/drivers/input/serio/gscps2.c @@ -381,9 +381,9 @@ static int __init gscps2_probe(struct parisc_device *dev) goto fail; #endif - printk(KERN_INFO "serio: %s port at 0x%p irq %d @ %s\n", + pr_info("serio: %s port at 0x%08lx irq %d @ %s\n", ps2port->port->name, - ps2port->addr, + hpa, ps2port->padev->irq, ps2port->port->phys); diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c index 0b8a25c58d02..654252361653 100644 --- a/drivers/input/serio/hp_sdc.c +++ b/drivers/input/serio/hp_sdc.c @@ -884,8 +884,8 @@ static int __init hp_sdc_init(void) "HP SDC NMI", &hp_sdc)) goto err2; - printk(KERN_INFO PREFIX "HP SDC at 0x%p, IRQ %d (NMI IRQ %d)\n", - (void *)hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi); + pr_info(PREFIX "HP SDC at 0x%08lx, IRQ %d (NMI IRQ %d)\n", + hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi); hp_sdc_status_in8(); hp_sdc_data_in8(); diff --git a/drivers/input/serio/olpc_apsp.c b/drivers/input/serio/olpc_apsp.c index bae08226e3d9..a7cfab3db9ee 100644 --- a/drivers/input/serio/olpc_apsp.c +++ b/drivers/input/serio/olpc_apsp.c @@ -23,7 +23,6 @@ #include <linux/of.h> #include <linux/slab.h> #include <linux/delay.h> -#include <linux/clk.h> /* * The OLPC XO-1.75 and XO-4 laptops do not have a hardware PS/2 controller. @@ -75,7 +74,6 @@ struct olpc_apsp { struct serio *kbio; struct serio *padio; void __iomem *base; - struct clk *clk; int open_count; int irq; }; @@ -148,17 +146,11 @@ static int olpc_apsp_open(struct serio *port) struct olpc_apsp *priv = port->port_data; unsigned int tmp; unsigned long l; - int error; if (priv->open_count++ == 0) { - error = clk_prepare_enable(priv->clk); - if (error) - return error; - l = readl(priv->base + COMMAND_FIFO_STATUS); if (!(l & CMD_STS_MASK)) { dev_err(priv->dev, "SP cannot accept commands.\n"); - clk_disable_unprepare(priv->clk); return -EIO; } @@ -179,8 +171,6 @@ static void olpc_apsp_close(struct serio *port) /* Disable interrupt 0 */ tmp = readl(priv->base + PJ_INTERRUPT_MASK); writel(tmp | INT_0, priv->base + PJ_INTERRUPT_MASK); - - clk_disable_unprepare(priv->clk); } } @@ -208,10 +198,6 @@ static int olpc_apsp_probe(struct platform_device *pdev) if (priv->irq < 0) return priv->irq; - priv->clk = devm_clk_get(&pdev->dev, "sp"); - if (IS_ERR(priv->clk)) - return PTR_ERR(priv->clk); - /* KEYBOARD */ kb_serio = kzalloc(sizeof(struct serio), GFP_KERNEL); if (!kb_serio) diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 8b536778f1d8..6f4f9da0515c 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -261,16 +261,6 @@ enum v4l_dbg_inputs { MXT_V4L_INPUT_MAX, }; -static const struct v4l2_file_operations mxt_video_fops = { - .owner = THIS_MODULE, - .open = v4l2_fh_open, - .release = vb2_fop_release, - .unlocked_ioctl = video_ioctl2, - .read = vb2_fop_read, - .mmap = vb2_fop_mmap, - .poll = vb2_fop_poll, -}; - enum mxt_suspend_mode { MXT_SUSPEND_DEEP_SLEEP = 0, MXT_SUSPEND_T9_CTRL = 1, @@ -2224,6 +2214,16 @@ recheck: } #ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT_T37 +static const struct v4l2_file_operations mxt_video_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .unlocked_ioctl = video_ioctl2, + .read = vb2_fop_read, + .mmap = vb2_fop_mmap, + .poll = vb2_fop_poll, +}; + static u16 mxt_get_debug_value(struct mxt_data *data, unsigned int x, unsigned int y) { diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index c639ebce914c..3cc4341bbdff 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -27,6 +27,7 @@ #include <linux/gpio/consumer.h> #include <linux/input/mt.h> #include <linux/input/touchscreen.h> +#include <asm/unaligned.h> #define WORK_REGISTER_THRESHOLD 0x00 #define WORK_REGISTER_REPORT_RATE 0x08 @@ -228,7 +229,6 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) for (i = 0; i < tsdata->max_support_points; i++) { u8 *buf = &rdbuf[i * tplen + offset]; - bool down; type = buf[0] >> 6; /* ignore Reserved events */ @@ -239,23 +239,19 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) if (tsdata->version == EDT_M06 && type == TOUCH_EVENT_DOWN) continue; - x = ((buf[0] << 8) | buf[1]) & 0x0fff; - y = ((buf[2] << 8) | buf[3]) & 0x0fff; + x = get_unaligned_be16(buf) & 0x0fff; + y = get_unaligned_be16(buf + 2) & 0x0fff; /* The FT5x26 send the y coordinate first */ if (tsdata->version == EV_FT) swap(x, y); id = (buf[2] >> 4) & 0x0f; - down = type != TOUCH_EVENT_UP; input_mt_slot(tsdata->input, id); - input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER, down); - - if (!down) - continue; - - touchscreen_report_pos(tsdata->input, &tsdata->prop, x, y, - true); + if (input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER, + type != TOUCH_EVENT_UP)) + touchscreen_report_pos(tsdata->input, &tsdata->prop, + x, y, true); } input_mt_report_pointer_emulation(tsdata->input, true); diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index 7fe41965c5d1..b508d2693c0e 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -41,6 +41,7 @@ struct eeti_ts { struct input_dev *input; struct gpio_desc *attn_gpio; struct touchscreen_properties props; + struct mutex mutex; bool running; }; @@ -75,42 +76,80 @@ static void eeti_ts_report_event(struct eeti_ts *eeti, u8 *buf) input_sync(eeti->input); } +static int eeti_ts_read(struct eeti_ts *eeti) +{ + int len, error; + char buf[6]; + + len = i2c_master_recv(eeti->client, buf, sizeof(buf)); + if (len != sizeof(buf)) { + error = len < 0 ? len : -EIO; + dev_err(&eeti->client->dev, + "failed to read touchscreen data: %d\n", + error); + return error; + } + + /* Motion packet */ + if (buf[0] & 0x80) + eeti_ts_report_event(eeti, buf); + + return 0; +} + static irqreturn_t eeti_ts_isr(int irq, void *dev_id) { struct eeti_ts *eeti = dev_id; - int len; int error; - char buf[6]; + + mutex_lock(&eeti->mutex); do { - len = i2c_master_recv(eeti->client, buf, sizeof(buf)); - if (len != sizeof(buf)) { - error = len < 0 ? len : -EIO; - dev_err(&eeti->client->dev, - "failed to read touchscreen data: %d\n", - error); + /* + * If we have attention GPIO, trust it. Otherwise we'll read + * once and exit. We assume that in this case we are using + * level triggered interrupt and it will get raised again + * if/when there is more data. + */ + if (eeti->attn_gpio && + !gpiod_get_value_cansleep(eeti->attn_gpio)) { break; } - if (buf[0] & 0x80) { - /* Motion packet */ - eeti_ts_report_event(eeti, buf); - } - } while (eeti->running && - eeti->attn_gpio && gpiod_get_value_cansleep(eeti->attn_gpio)); + error = eeti_ts_read(eeti); + if (error) + break; + + } while (eeti->running && eeti->attn_gpio); + mutex_unlock(&eeti->mutex); return IRQ_HANDLED; } static void eeti_ts_start(struct eeti_ts *eeti) { + mutex_lock(&eeti->mutex); + eeti->running = true; - wmb(); enable_irq(eeti->client->irq); + + /* + * Kick the controller in case we are using edge interrupt and + * we missed our edge while interrupt was disabled. We expect + * the attention GPIO to be wired in this case. + */ + if (eeti->attn_gpio && gpiod_get_value_cansleep(eeti->attn_gpio)) + eeti_ts_read(eeti); + + mutex_unlock(&eeti->mutex); } static void eeti_ts_stop(struct eeti_ts *eeti) { + /* + * Not locking here, just setting a flag and expect that the + * interrupt thread will notice the flag eventually. + */ eeti->running = false; wmb(); disable_irq(eeti->client->irq); @@ -153,6 +192,8 @@ static int eeti_ts_probe(struct i2c_client *client, return -ENOMEM; } + mutex_init(&eeti->mutex); + input = devm_input_allocate_device(dev); if (!input) { dev_err(dev, "Failed to allocate input device.\n"); diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c index c10fc594f94d..e04eecd65bbb 100644 --- a/drivers/input/touchscreen/imx6ul_tsc.c +++ b/drivers/input/touchscreen/imx6ul_tsc.c @@ -364,8 +364,6 @@ static int imx6ul_tsc_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct imx6ul_tsc *tsc; struct input_dev *input_dev; - struct resource *tsc_mem; - struct resource *adc_mem; int err; int tsc_irq; int adc_irq; @@ -403,16 +401,14 @@ static int imx6ul_tsc_probe(struct platform_device *pdev) return err; } - tsc_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - tsc->tsc_regs = devm_ioremap_resource(&pdev->dev, tsc_mem); + tsc->tsc_regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(tsc->tsc_regs)) { err = PTR_ERR(tsc->tsc_regs); dev_err(&pdev->dev, "failed to remap tsc memory: %d\n", err); return err; } - adc_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); - tsc->adc_regs = devm_ioremap_resource(&pdev->dev, adc_mem); + tsc->adc_regs = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(tsc->adc_regs)) { err = PTR_ERR(tsc->adc_regs); dev_err(&pdev->dev, "failed to remap adc memory: %d\n", err); diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c index 4f6fe8cc8efa..5875bb1099a8 100644 --- a/drivers/input/touchscreen/iqs5xx.c +++ b/drivers/input/touchscreen/iqs5xx.c @@ -1056,8 +1056,6 @@ static int iqs5xx_probe(struct i2c_client *client, if (!iqs5xx) return -ENOMEM; - dev_set_drvdata(&client->dev, iqs5xx); - i2c_set_clientdata(client, iqs5xx); iqs5xx->client = client; diff --git a/drivers/input/touchscreen/raspberrypi-ts.c b/drivers/input/touchscreen/raspberrypi-ts.c index f456c1125bd6..69881265d121 100644 --- a/drivers/input/touchscreen/raspberrypi-ts.c +++ b/drivers/input/touchscreen/raspberrypi-ts.c @@ -147,8 +147,8 @@ static int rpi_ts_probe(struct platform_device *pdev) return -ENOMEM; ts->pdev = pdev; - ts->fw_regs_va = dma_zalloc_coherent(dev, PAGE_SIZE, &ts->fw_regs_phys, - GFP_KERNEL); + ts->fw_regs_va = dma_alloc_coherent(dev, PAGE_SIZE, &ts->fw_regs_phys, + GFP_KERNEL); if (!ts->fw_regs_va) { dev_err(dev, "failed to dma_alloc_coherent\n"); return -ENOMEM; diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c index 2a78e27b4495..cf9c9aa39f6e 100644 --- a/drivers/input/touchscreen/stmpe-ts.c +++ b/drivers/input/touchscreen/stmpe-ts.c @@ -30,8 +30,6 @@ * with touchscreen controller */ #define STMPE_REG_INT_STA 0x0B -#define STMPE_REG_ADC_CTRL1 0x20 -#define STMPE_REG_ADC_CTRL2 0x21 #define STMPE_REG_TSC_CTRL 0x40 #define STMPE_REG_TSC_CFG 0x41 #define STMPE_REG_FIFO_TH 0x4A @@ -49,17 +47,6 @@ #define STMPE_IRQ_TOUCH_DET 0 -#define SAMPLE_TIME(x) ((x & 0xf) << 4) -#define MOD_12B(x) ((x & 0x1) << 3) -#define REF_SEL(x) ((x & 0x1) << 1) -#define ADC_FREQ(x) (x & 0x3) -#define AVE_CTRL(x) ((x & 0x3) << 6) -#define DET_DELAY(x) ((x & 0x7) << 3) -#define SETTLING(x) (x & 0x7) -#define FRACTION_Z(x) (x & 0x7) -#define I_DRIVE(x) (x & 0x1) -#define OP_MODE(x) ((x & 0x7) << 1) - #define STMPE_TS_NAME "stmpe-ts" #define XY_MASK 0xfff @@ -69,15 +56,6 @@ * @idev: registered input device * @work: a work item used to scan the device * @dev: a pointer back to the MFD cell struct device* - * @sample_time: ADC converstion time in number of clock. - * (0 -> 36 clocks, 1 -> 44 clocks, 2 -> 56 clocks, 3 -> 64 clocks, - * 4 -> 80 clocks, 5 -> 96 clocks, 6 -> 144 clocks), - * recommended is 4. - * @mod_12b: ADC Bit mode (0 -> 10bit ADC, 1 -> 12bit ADC) - * @ref_sel: ADC reference source - * (0 -> internal reference, 1 -> external reference) - * @adc_freq: ADC Clock speed - * (0 -> 1.625 MHz, 1 -> 3.25 MHz, 2 || 3 -> 6.5 MHz) * @ave_ctrl: Sample average control * (0 -> 1 sample, 1 -> 2 samples, 2 -> 4 samples, 3 -> 8 samples) * @touch_det_delay: Touch detect interrupt delay @@ -99,10 +77,6 @@ struct stmpe_touch { struct input_dev *idev; struct delayed_work work; struct device *dev; - u8 sample_time; - u8 mod_12b; - u8 ref_sel; - u8 adc_freq; u8 ave_ctrl; u8 touch_det_delay; u8 settling; @@ -203,7 +177,7 @@ static irqreturn_t stmpe_ts_handler(int irq, void *data) static int stmpe_init_hw(struct stmpe_touch *ts) { int ret; - u8 adc_ctrl1, adc_ctrl1_mask, tsc_cfg, tsc_cfg_mask; + u8 tsc_cfg, tsc_cfg_mask; struct stmpe *stmpe = ts->stmpe; struct device *dev = ts->dev; @@ -213,27 +187,17 @@ static int stmpe_init_hw(struct stmpe_touch *ts) return ret; } - adc_ctrl1 = SAMPLE_TIME(ts->sample_time) | MOD_12B(ts->mod_12b) | - REF_SEL(ts->ref_sel); - adc_ctrl1_mask = SAMPLE_TIME(0xff) | MOD_12B(0xff) | REF_SEL(0xff); - - ret = stmpe_set_bits(stmpe, STMPE_REG_ADC_CTRL1, - adc_ctrl1_mask, adc_ctrl1); - if (ret) { - dev_err(dev, "Could not setup ADC\n"); - return ret; - } - - ret = stmpe_set_bits(stmpe, STMPE_REG_ADC_CTRL2, - ADC_FREQ(0xff), ADC_FREQ(ts->adc_freq)); + ret = stmpe811_adc_common_init(stmpe); if (ret) { - dev_err(dev, "Could not setup ADC\n"); + stmpe_disable(stmpe, STMPE_BLOCK_TOUCHSCREEN | STMPE_BLOCK_ADC); return ret; } - tsc_cfg = AVE_CTRL(ts->ave_ctrl) | DET_DELAY(ts->touch_det_delay) | - SETTLING(ts->settling); - tsc_cfg_mask = AVE_CTRL(0xff) | DET_DELAY(0xff) | SETTLING(0xff); + tsc_cfg = STMPE_AVE_CTRL(ts->ave_ctrl) | + STMPE_DET_DELAY(ts->touch_det_delay) | + STMPE_SETTLING(ts->settling); + tsc_cfg_mask = STMPE_AVE_CTRL(0xff) | STMPE_DET_DELAY(0xff) | + STMPE_SETTLING(0xff); ret = stmpe_set_bits(stmpe, STMPE_REG_TSC_CFG, tsc_cfg_mask, tsc_cfg); if (ret) { @@ -242,14 +206,14 @@ static int stmpe_init_hw(struct stmpe_touch *ts) } ret = stmpe_set_bits(stmpe, STMPE_REG_TSC_FRACTION_Z, - FRACTION_Z(0xff), FRACTION_Z(ts->fraction_z)); + STMPE_FRACTION_Z(0xff), STMPE_FRACTION_Z(ts->fraction_z)); if (ret) { dev_err(dev, "Could not config touch\n"); return ret; } ret = stmpe_set_bits(stmpe, STMPE_REG_TSC_I_DRIVE, - I_DRIVE(0xff), I_DRIVE(ts->i_drive)); + STMPE_I_DRIVE(0xff), STMPE_I_DRIVE(ts->i_drive)); if (ret) { dev_err(dev, "Could not config touch\n"); return ret; @@ -263,7 +227,7 @@ static int stmpe_init_hw(struct stmpe_touch *ts) } ret = stmpe_set_bits(stmpe, STMPE_REG_TSC_CTRL, - OP_MODE(0xff), OP_MODE(OP_MOD_XYZ)); + STMPE_OP_MODE(0xff), STMPE_OP_MODE(OP_MOD_XYZ)); if (ret) { dev_err(dev, "Could not set mode\n"); return ret; @@ -303,13 +267,13 @@ static void stmpe_ts_get_platform_info(struct platform_device *pdev, if (np) { if (!of_property_read_u32(np, "st,sample-time", &val)) - ts->sample_time = val; + ts->stmpe->sample_time = val; if (!of_property_read_u32(np, "st,mod-12b", &val)) - ts->mod_12b = val; + ts->stmpe->mod_12b = val; if (!of_property_read_u32(np, "st,ref-sel", &val)) - ts->ref_sel = val; + ts->stmpe->ref_sel = val; if (!of_property_read_u32(np, "st,adc-freq", &val)) - ts->adc_freq = val; + ts->stmpe->adc_freq = val; if (!of_property_read_u32(np, "st,ave-ctrl", &val)) ts->ave_ctrl = val; if (!of_property_read_u32(np, "st,touch-det-delay", &val)) |