^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Apple Motion Sensor driver (joystick emulation)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2005 Stelian Pop (stelian@popies.net)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.ch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "ams.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) static bool joystick;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) module_param(joystick, bool, S_IRUGO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) MODULE_PARM_DESC(joystick, "Enable the input class device on module load");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) static bool invert;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) module_param(invert, bool, S_IWUSR | S_IRUGO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) MODULE_PARM_DESC(invert, "Invert input data on X and Y axis");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) static DEFINE_MUTEX(ams_input_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) static void ams_idev_poll(struct input_dev *idev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) s8 x, y, z;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) mutex_lock(&ams_info.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) ams_sensors(&x, &y, &z);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) x -= ams_info.xcalib;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) y -= ams_info.ycalib;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) z -= ams_info.zcalib;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) input_report_abs(idev, ABS_X, invert ? -x : x);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) input_report_abs(idev, ABS_Y, invert ? -y : y);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) input_report_abs(idev, ABS_Z, z);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) input_sync(idev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) mutex_unlock(&ams_info.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) /* Call with ams_info.lock held! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) static int ams_input_enable(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) struct input_dev *input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) s8 x, y, z;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) ams_sensors(&x, &y, &z);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) ams_info.xcalib = x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) ams_info.ycalib = y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) ams_info.zcalib = z;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) input = input_allocate_device();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) if (!input)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) input->name = "Apple Motion Sensor";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) input->id.bustype = ams_info.bustype;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) input->id.vendor = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) input->dev.parent = &ams_info.of_dev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) input_set_abs_params(input, ABS_X, -50, 50, 3, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) input_set_abs_params(input, ABS_Y, -50, 50, 3, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) input_set_abs_params(input, ABS_Z, -50, 50, 3, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) input_set_capability(input, EV_KEY, BTN_TOUCH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) error = input_setup_polling(input, ams_idev_poll);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) goto err_free_input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) input_set_poll_interval(input, 25);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) error = input_register_device(input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) goto err_free_input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) ams_info.idev = input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) joystick = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) err_free_input:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) input_free_device(input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static void ams_input_disable(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) if (ams_info.idev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) input_unregister_device(ams_info.idev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) ams_info.idev = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) joystick = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) static ssize_t ams_input_show_joystick(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) return sprintf(buf, "%d\n", joystick);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) static ssize_t ams_input_store_joystick(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) struct device_attribute *attr, const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) unsigned long enable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) int error = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) ret = kstrtoul(buf, 0, &enable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) if (enable > 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) mutex_lock(&ams_input_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if (enable != joystick) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) if (enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) error = ams_input_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) ams_input_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) mutex_unlock(&ams_input_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) return error ? error : count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) static DEVICE_ATTR(joystick, S_IRUGO | S_IWUSR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) ams_input_show_joystick, ams_input_store_joystick);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) int ams_input_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) if (joystick)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) ams_input_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) return device_create_file(&ams_info.of_dev->dev, &dev_attr_joystick);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) void ams_input_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) device_remove_file(&ams_info.of_dev->dev, &dev_attr_joystick);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) mutex_lock(&ams_input_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) ams_input_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) mutex_unlock(&ams_input_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }