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