Path: blob/master/drivers/input/joystick/warrior.c
15111 views
/*1* Copyright (c) 1999-2001 Vojtech Pavlik2*/34/*5* Logitech WingMan Warrior joystick driver for Linux6*/78/*9* This program is free warftware; you can redistribute it and/or modify10* it under the terms of the GNU General Public License as published by11* the Free Software Foundation; either version 2 of the License, or12* (at your option) any later version.13*14* This program is distributed in the hope that it will be useful,15* but WITHOUT ANY WARRANTY; without even the implied warranty of16* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the17* GNU General Public License for more details.18*19* You should have received a copy of the GNU General Public License20* along with this program; if not, write to the Free Software21* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA22*23* Should you need to contact me, the author, you can do so either by24* e-mail - mail your message to <[email protected]>, or by paper mail:25* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic26*/2728#include <linux/kernel.h>29#include <linux/module.h>30#include <linux/slab.h>31#include <linux/input.h>32#include <linux/serio.h>33#include <linux/init.h>3435#define DRIVER_DESC "Logitech WingMan Warrior joystick driver"3637MODULE_AUTHOR("Vojtech Pavlik <[email protected]>");38MODULE_DESCRIPTION(DRIVER_DESC);39MODULE_LICENSE("GPL");4041/*42* Constants.43*/4445#define WARRIOR_MAX_LENGTH 1646static char warrior_lengths[] = { 0, 4, 12, 3, 4, 4, 0, 0 };4748/*49* Per-Warrior data.50*/5152struct warrior {53struct input_dev *dev;54int idx, len;55unsigned char data[WARRIOR_MAX_LENGTH];56char phys[32];57};5859/*60* warrior_process_packet() decodes packets the driver receives from the61* Warrior. It updates the data accordingly.62*/6364static void warrior_process_packet(struct warrior *warrior)65{66struct input_dev *dev = warrior->dev;67unsigned char *data = warrior->data;6869if (!warrior->idx) return;7071switch ((data[0] >> 4) & 7) {72case 1: /* Button data */73input_report_key(dev, BTN_TRIGGER, data[3] & 1);74input_report_key(dev, BTN_THUMB, (data[3] >> 1) & 1);75input_report_key(dev, BTN_TOP, (data[3] >> 2) & 1);76input_report_key(dev, BTN_TOP2, (data[3] >> 3) & 1);77break;78case 3: /* XY-axis info->data */79input_report_abs(dev, ABS_X, ((data[0] & 8) << 5) - (data[2] | ((data[0] & 4) << 5)));80input_report_abs(dev, ABS_Y, (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7));81break;82case 5: /* Throttle, spinner, hat info->data */83input_report_abs(dev, ABS_THROTTLE, (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7));84input_report_abs(dev, ABS_HAT0X, (data[3] & 2 ? 1 : 0) - (data[3] & 1 ? 1 : 0));85input_report_abs(dev, ABS_HAT0Y, (data[3] & 8 ? 1 : 0) - (data[3] & 4 ? 1 : 0));86input_report_rel(dev, REL_DIAL, (data[2] | ((data[0] & 4) << 5)) - ((data[0] & 8) << 5));87break;88}89input_sync(dev);90}9192/*93* warrior_interrupt() is called by the low level driver when characters94* are ready for us. We then buffer them for further processing, or call the95* packet processing routine.96*/9798static irqreturn_t warrior_interrupt(struct serio *serio,99unsigned char data, unsigned int flags)100{101struct warrior *warrior = serio_get_drvdata(serio);102103if (data & 0x80) {104if (warrior->idx) warrior_process_packet(warrior);105warrior->idx = 0;106warrior->len = warrior_lengths[(data >> 4) & 7];107}108109if (warrior->idx < warrior->len)110warrior->data[warrior->idx++] = data;111112if (warrior->idx == warrior->len) {113if (warrior->idx) warrior_process_packet(warrior);114warrior->idx = 0;115warrior->len = 0;116}117return IRQ_HANDLED;118}119120/*121* warrior_disconnect() is the opposite of warrior_connect()122*/123124static void warrior_disconnect(struct serio *serio)125{126struct warrior *warrior = serio_get_drvdata(serio);127128serio_close(serio);129serio_set_drvdata(serio, NULL);130input_unregister_device(warrior->dev);131kfree(warrior);132}133134/*135* warrior_connect() is the routine that is called when someone adds a136* new serio device. It looks for the Warrior, and if found, registers137* it as an input device.138*/139140static int warrior_connect(struct serio *serio, struct serio_driver *drv)141{142struct warrior *warrior;143struct input_dev *input_dev;144int err = -ENOMEM;145146warrior = kzalloc(sizeof(struct warrior), GFP_KERNEL);147input_dev = input_allocate_device();148if (!warrior || !input_dev)149goto fail1;150151warrior->dev = input_dev;152snprintf(warrior->phys, sizeof(warrior->phys), "%s/input0", serio->phys);153154input_dev->name = "Logitech WingMan Warrior";155input_dev->phys = warrior->phys;156input_dev->id.bustype = BUS_RS232;157input_dev->id.vendor = SERIO_WARRIOR;158input_dev->id.product = 0x0001;159input_dev->id.version = 0x0100;160input_dev->dev.parent = &serio->dev;161162input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) |163BIT_MASK(EV_ABS);164input_dev->keybit[BIT_WORD(BTN_TRIGGER)] = BIT_MASK(BTN_TRIGGER) |165BIT_MASK(BTN_THUMB) | BIT_MASK(BTN_TOP) | BIT_MASK(BTN_TOP2);166input_dev->relbit[0] = BIT_MASK(REL_DIAL);167input_set_abs_params(input_dev, ABS_X, -64, 64, 0, 8);168input_set_abs_params(input_dev, ABS_Y, -64, 64, 0, 8);169input_set_abs_params(input_dev, ABS_THROTTLE, -112, 112, 0, 0);170input_set_abs_params(input_dev, ABS_HAT0X, -1, 1, 0, 0);171input_set_abs_params(input_dev, ABS_HAT0Y, -1, 1, 0, 0);172173serio_set_drvdata(serio, warrior);174175err = serio_open(serio, drv);176if (err)177goto fail2;178179err = input_register_device(warrior->dev);180if (err)181goto fail3;182183return 0;184185fail3: serio_close(serio);186fail2: serio_set_drvdata(serio, NULL);187fail1: input_free_device(input_dev);188kfree(warrior);189return err;190}191192/*193* The serio driver structure.194*/195196static struct serio_device_id warrior_serio_ids[] = {197{198.type = SERIO_RS232,199.proto = SERIO_WARRIOR,200.id = SERIO_ANY,201.extra = SERIO_ANY,202},203{ 0 }204};205206MODULE_DEVICE_TABLE(serio, warrior_serio_ids);207208static struct serio_driver warrior_drv = {209.driver = {210.name = "warrior",211},212.description = DRIVER_DESC,213.id_table = warrior_serio_ids,214.interrupt = warrior_interrupt,215.connect = warrior_connect,216.disconnect = warrior_disconnect,217};218219/*220* The functions for inserting/removing us as a module.221*/222223static int __init warrior_init(void)224{225return serio_register_driver(&warrior_drv);226}227228static void __exit warrior_exit(void)229{230serio_unregister_driver(&warrior_drv);231}232233module_init(warrior_init);234module_exit(warrior_exit);235236237