Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Copyright (c) 1999-2001 Vojtech Pavlik
0004  */
0005 
0006 /*
0007  * Logitech WingMan Warrior joystick driver for Linux
0008  */
0009 
0010 /*
0011  */
0012 
0013 #include <linux/kernel.h>
0014 #include <linux/module.h>
0015 #include <linux/slab.h>
0016 #include <linux/input.h>
0017 #include <linux/serio.h>
0018 
0019 #define DRIVER_DESC "Logitech WingMan Warrior joystick driver"
0020 
0021 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
0022 MODULE_DESCRIPTION(DRIVER_DESC);
0023 MODULE_LICENSE("GPL");
0024 
0025 /*
0026  * Constants.
0027  */
0028 
0029 #define WARRIOR_MAX_LENGTH  16
0030 static char warrior_lengths[] = { 0, 4, 12, 3, 4, 4, 0, 0 };
0031 
0032 /*
0033  * Per-Warrior data.
0034  */
0035 
0036 struct warrior {
0037     struct input_dev *dev;
0038     int idx, len;
0039     unsigned char data[WARRIOR_MAX_LENGTH];
0040     char phys[32];
0041 };
0042 
0043 /*
0044  * warrior_process_packet() decodes packets the driver receives from the
0045  * Warrior. It updates the data accordingly.
0046  */
0047 
0048 static void warrior_process_packet(struct warrior *warrior)
0049 {
0050     struct input_dev *dev = warrior->dev;
0051     unsigned char *data = warrior->data;
0052 
0053     if (!warrior->idx) return;
0054 
0055     switch ((data[0] >> 4) & 7) {
0056         case 1:                 /* Button data */
0057             input_report_key(dev, BTN_TRIGGER,  data[3]       & 1);
0058             input_report_key(dev, BTN_THUMB,   (data[3] >> 1) & 1);
0059             input_report_key(dev, BTN_TOP,     (data[3] >> 2) & 1);
0060             input_report_key(dev, BTN_TOP2,    (data[3] >> 3) & 1);
0061             break;
0062         case 3:                 /* XY-axis info->data */
0063             input_report_abs(dev, ABS_X, ((data[0] & 8) << 5) - (data[2] | ((data[0] & 4) << 5)));
0064             input_report_abs(dev, ABS_Y, (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7));
0065             break;
0066         case 5:                 /* Throttle, spinner, hat info->data */
0067             input_report_abs(dev, ABS_THROTTLE, (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7));
0068             input_report_abs(dev, ABS_HAT0X, (data[3] & 2 ? 1 : 0) - (data[3] & 1 ? 1 : 0));
0069             input_report_abs(dev, ABS_HAT0Y, (data[3] & 8 ? 1 : 0) - (data[3] & 4 ? 1 : 0));
0070             input_report_rel(dev, REL_DIAL,  (data[2] | ((data[0] & 4) << 5)) - ((data[0] & 8) << 5));
0071             break;
0072     }
0073     input_sync(dev);
0074 }
0075 
0076 /*
0077  * warrior_interrupt() is called by the low level driver when characters
0078  * are ready for us. We then buffer them for further processing, or call the
0079  * packet processing routine.
0080  */
0081 
0082 static irqreturn_t warrior_interrupt(struct serio *serio,
0083         unsigned char data, unsigned int flags)
0084 {
0085     struct warrior *warrior = serio_get_drvdata(serio);
0086 
0087     if (data & 0x80) {
0088         if (warrior->idx) warrior_process_packet(warrior);
0089         warrior->idx = 0;
0090         warrior->len = warrior_lengths[(data >> 4) & 7];
0091     }
0092 
0093     if (warrior->idx < warrior->len)
0094         warrior->data[warrior->idx++] = data;
0095 
0096     if (warrior->idx == warrior->len) {
0097         if (warrior->idx) warrior_process_packet(warrior);
0098         warrior->idx = 0;
0099         warrior->len = 0;
0100     }
0101     return IRQ_HANDLED;
0102 }
0103 
0104 /*
0105  * warrior_disconnect() is the opposite of warrior_connect()
0106  */
0107 
0108 static void warrior_disconnect(struct serio *serio)
0109 {
0110     struct warrior *warrior = serio_get_drvdata(serio);
0111 
0112     serio_close(serio);
0113     serio_set_drvdata(serio, NULL);
0114     input_unregister_device(warrior->dev);
0115     kfree(warrior);
0116 }
0117 
0118 /*
0119  * warrior_connect() is the routine that is called when someone adds a
0120  * new serio device. It looks for the Warrior, and if found, registers
0121  * it as an input device.
0122  */
0123 
0124 static int warrior_connect(struct serio *serio, struct serio_driver *drv)
0125 {
0126     struct warrior *warrior;
0127     struct input_dev *input_dev;
0128     int err = -ENOMEM;
0129 
0130     warrior = kzalloc(sizeof(struct warrior), GFP_KERNEL);
0131     input_dev = input_allocate_device();
0132     if (!warrior || !input_dev)
0133         goto fail1;
0134 
0135     warrior->dev = input_dev;
0136     snprintf(warrior->phys, sizeof(warrior->phys), "%s/input0", serio->phys);
0137 
0138     input_dev->name = "Logitech WingMan Warrior";
0139     input_dev->phys = warrior->phys;
0140     input_dev->id.bustype = BUS_RS232;
0141     input_dev->id.vendor = SERIO_WARRIOR;
0142     input_dev->id.product = 0x0001;
0143     input_dev->id.version = 0x0100;
0144     input_dev->dev.parent = &serio->dev;
0145 
0146     input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) |
0147         BIT_MASK(EV_ABS);
0148     input_dev->keybit[BIT_WORD(BTN_TRIGGER)] = BIT_MASK(BTN_TRIGGER) |
0149         BIT_MASK(BTN_THUMB) | BIT_MASK(BTN_TOP) | BIT_MASK(BTN_TOP2);
0150     input_dev->relbit[0] = BIT_MASK(REL_DIAL);
0151     input_set_abs_params(input_dev, ABS_X, -64, 64, 0, 8);
0152     input_set_abs_params(input_dev, ABS_Y, -64, 64, 0, 8);
0153     input_set_abs_params(input_dev, ABS_THROTTLE, -112, 112, 0, 0);
0154     input_set_abs_params(input_dev, ABS_HAT0X, -1, 1, 0, 0);
0155     input_set_abs_params(input_dev, ABS_HAT0Y, -1, 1, 0, 0);
0156 
0157     serio_set_drvdata(serio, warrior);
0158 
0159     err = serio_open(serio, drv);
0160     if (err)
0161         goto fail2;
0162 
0163     err = input_register_device(warrior->dev);
0164     if (err)
0165         goto fail3;
0166 
0167     return 0;
0168 
0169  fail3: serio_close(serio);
0170  fail2: serio_set_drvdata(serio, NULL);
0171  fail1: input_free_device(input_dev);
0172     kfree(warrior);
0173     return err;
0174 }
0175 
0176 /*
0177  * The serio driver structure.
0178  */
0179 
0180 static const struct serio_device_id warrior_serio_ids[] = {
0181     {
0182         .type   = SERIO_RS232,
0183         .proto  = SERIO_WARRIOR,
0184         .id = SERIO_ANY,
0185         .extra  = SERIO_ANY,
0186     },
0187     { 0 }
0188 };
0189 
0190 MODULE_DEVICE_TABLE(serio, warrior_serio_ids);
0191 
0192 static struct serio_driver warrior_drv = {
0193     .driver     = {
0194         .name   = "warrior",
0195     },
0196     .description    = DRIVER_DESC,
0197     .id_table   = warrior_serio_ids,
0198     .interrupt  = warrior_interrupt,
0199     .connect    = warrior_connect,
0200     .disconnect = warrior_disconnect,
0201 };
0202 
0203 module_serio_driver(warrior_drv);