Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Copyright (c) 2001 Vojtech Pavlik
0004  */
0005 
0006 /*
0007  * Guillemot Digital Interface Protocol driver for Linux
0008  */
0009 
0010 /*
0011  */
0012 
0013 #include <linux/kernel.h>
0014 #include <linux/slab.h>
0015 #include <linux/module.h>
0016 #include <linux/delay.h>
0017 #include <linux/gameport.h>
0018 #include <linux/input.h>
0019 #include <linux/jiffies.h>
0020 
0021 #define DRIVER_DESC "Guillemot Digital joystick driver"
0022 
0023 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
0024 MODULE_DESCRIPTION(DRIVER_DESC);
0025 MODULE_LICENSE("GPL");
0026 
0027 #define GUILLEMOT_MAX_START 600 /* 600 us */
0028 #define GUILLEMOT_MAX_STROBE    60  /* 60 us */
0029 #define GUILLEMOT_MAX_LENGTH    17  /* 17 bytes */
0030 
0031 static short guillemot_abs_pad[] =
0032     { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, -1 };
0033 
0034 static short guillemot_btn_pad[] =
0035     { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_MODE, BTN_SELECT, -1 };
0036 
0037 static struct {
0038         int x;
0039         int y;
0040 } guillemot_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
0041 
0042 struct guillemot_type {
0043     unsigned char id;
0044     short *abs;
0045     short *btn;
0046     int hat;
0047     char *name;
0048 };
0049 
0050 struct guillemot {
0051     struct gameport *gameport;
0052     struct input_dev *dev;
0053     int bads;
0054     int reads;
0055     struct guillemot_type *type;
0056     unsigned char length;
0057     char phys[32];
0058 };
0059 
0060 static struct guillemot_type guillemot_type[] = {
0061     { 0x00, guillemot_abs_pad, guillemot_btn_pad, 1, "Guillemot Pad" },
0062     { 0 }};
0063 
0064 /*
0065  * guillemot_read_packet() reads Guillemot joystick data.
0066  */
0067 
0068 static int guillemot_read_packet(struct gameport *gameport, u8 *data)
0069 {
0070     unsigned long flags;
0071     unsigned char u, v;
0072     unsigned int t, s;
0073     int i;
0074 
0075     for (i = 0; i < GUILLEMOT_MAX_LENGTH; i++)
0076         data[i] = 0;
0077 
0078     i = 0;
0079     t = gameport_time(gameport, GUILLEMOT_MAX_START);
0080     s = gameport_time(gameport, GUILLEMOT_MAX_STROBE);
0081 
0082     local_irq_save(flags);
0083     gameport_trigger(gameport);
0084     v = gameport_read(gameport);
0085 
0086     while (t > 0 && i < GUILLEMOT_MAX_LENGTH * 8) {
0087         t--;
0088         u = v; v = gameport_read(gameport);
0089         if (v & ~u & 0x10) {
0090             data[i >> 3] |= ((v >> 5) & 1) << (i & 7);
0091             i++;
0092             t = s;
0093         }
0094     }
0095 
0096     local_irq_restore(flags);
0097 
0098     return i;
0099 }
0100 
0101 /*
0102  * guillemot_poll() reads and analyzes Guillemot joystick data.
0103  */
0104 
0105 static void guillemot_poll(struct gameport *gameport)
0106 {
0107     struct guillemot *guillemot = gameport_get_drvdata(gameport);
0108     struct input_dev *dev = guillemot->dev;
0109     u8 data[GUILLEMOT_MAX_LENGTH];
0110     int i;
0111 
0112     guillemot->reads++;
0113 
0114     if (guillemot_read_packet(guillemot->gameport, data) != GUILLEMOT_MAX_LENGTH * 8 ||
0115         data[0] != 0x55 || data[16] != 0xaa) {
0116         guillemot->bads++;
0117     } else {
0118 
0119         for (i = 0; i < 6 && guillemot->type->abs[i] >= 0; i++)
0120             input_report_abs(dev, guillemot->type->abs[i], data[i + 5]);
0121 
0122         if (guillemot->type->hat) {
0123             input_report_abs(dev, ABS_HAT0X, guillemot_hat_to_axis[data[4] >> 4].x);
0124             input_report_abs(dev, ABS_HAT0Y, guillemot_hat_to_axis[data[4] >> 4].y);
0125         }
0126 
0127         for (i = 0; i < 16 && guillemot->type->btn[i] >= 0; i++)
0128             input_report_key(dev, guillemot->type->btn[i], (data[2 + (i >> 3)] >> (i & 7)) & 1);
0129     }
0130 
0131     input_sync(dev);
0132 }
0133 
0134 /*
0135  * guillemot_open() is a callback from the input open routine.
0136  */
0137 
0138 static int guillemot_open(struct input_dev *dev)
0139 {
0140     struct guillemot *guillemot = input_get_drvdata(dev);
0141 
0142     gameport_start_polling(guillemot->gameport);
0143     return 0;
0144 }
0145 
0146 /*
0147  * guillemot_close() is a callback from the input close routine.
0148  */
0149 
0150 static void guillemot_close(struct input_dev *dev)
0151 {
0152     struct guillemot *guillemot = input_get_drvdata(dev);
0153 
0154     gameport_stop_polling(guillemot->gameport);
0155 }
0156 
0157 /*
0158  * guillemot_connect() probes for Guillemot joysticks.
0159  */
0160 
0161 static int guillemot_connect(struct gameport *gameport, struct gameport_driver *drv)
0162 {
0163     struct guillemot *guillemot;
0164     struct input_dev *input_dev;
0165     u8 data[GUILLEMOT_MAX_LENGTH];
0166     int i, t;
0167     int err;
0168 
0169     guillemot = kzalloc(sizeof(struct guillemot), GFP_KERNEL);
0170     input_dev = input_allocate_device();
0171     if (!guillemot || !input_dev) {
0172         err = -ENOMEM;
0173         goto fail1;
0174     }
0175 
0176     guillemot->gameport = gameport;
0177     guillemot->dev = input_dev;
0178 
0179     gameport_set_drvdata(gameport, guillemot);
0180 
0181     err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
0182     if (err)
0183         goto fail1;
0184 
0185     i = guillemot_read_packet(gameport, data);
0186 
0187     if (i != GUILLEMOT_MAX_LENGTH * 8 || data[0] != 0x55 || data[16] != 0xaa) {
0188         err = -ENODEV;
0189         goto fail2;
0190     }
0191 
0192     for (i = 0; guillemot_type[i].name; i++)
0193         if (guillemot_type[i].id == data[11])
0194             break;
0195 
0196     if (!guillemot_type[i].name) {
0197         printk(KERN_WARNING "guillemot.c: Unknown joystick on %s. [ %02x%02x:%04x, ver %d.%02d ]\n",
0198             gameport->phys, data[12], data[13], data[11], data[14], data[15]);
0199         err = -ENODEV;
0200         goto fail2;
0201     }
0202 
0203     gameport_set_poll_handler(gameport, guillemot_poll);
0204     gameport_set_poll_interval(gameport, 20);
0205 
0206     snprintf(guillemot->phys, sizeof(guillemot->phys), "%s/input0", gameport->phys);
0207     guillemot->type = guillemot_type + i;
0208 
0209     input_dev->name = guillemot_type[i].name;
0210     input_dev->phys = guillemot->phys;
0211     input_dev->id.bustype = BUS_GAMEPORT;
0212     input_dev->id.vendor = GAMEPORT_ID_VENDOR_GUILLEMOT;
0213     input_dev->id.product = guillemot_type[i].id;
0214     input_dev->id.version = (int)data[14] << 8 | data[15];
0215     input_dev->dev.parent = &gameport->dev;
0216 
0217     input_set_drvdata(input_dev, guillemot);
0218 
0219     input_dev->open = guillemot_open;
0220     input_dev->close = guillemot_close;
0221 
0222     input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
0223 
0224     for (i = 0; (t = guillemot->type->abs[i]) >= 0; i++)
0225         input_set_abs_params(input_dev, t, 0, 255, 0, 0);
0226 
0227     if (guillemot->type->hat) {
0228         input_set_abs_params(input_dev, ABS_HAT0X, -1, 1, 0, 0);
0229         input_set_abs_params(input_dev, ABS_HAT0Y, -1, 1, 0, 0);
0230     }
0231 
0232     for (i = 0; (t = guillemot->type->btn[i]) >= 0; i++)
0233         set_bit(t, input_dev->keybit);
0234 
0235     err = input_register_device(guillemot->dev);
0236     if (err)
0237         goto fail2;
0238 
0239     return 0;
0240 
0241 fail2:  gameport_close(gameport);
0242 fail1:  gameport_set_drvdata(gameport, NULL);
0243     input_free_device(input_dev);
0244     kfree(guillemot);
0245     return err;
0246 }
0247 
0248 static void guillemot_disconnect(struct gameport *gameport)
0249 {
0250     struct guillemot *guillemot = gameport_get_drvdata(gameport);
0251 
0252     printk(KERN_INFO "guillemot.c: Failed %d reads out of %d on %s\n", guillemot->reads, guillemot->bads, guillemot->phys);
0253     input_unregister_device(guillemot->dev);
0254     gameport_close(gameport);
0255     kfree(guillemot);
0256 }
0257 
0258 static struct gameport_driver guillemot_drv = {
0259     .driver     = {
0260         .name   = "guillemot",
0261     },
0262     .description    = DRIVER_DESC,
0263     .connect    = guillemot_connect,
0264     .disconnect = guillemot_disconnect,
0265 };
0266 
0267 module_gameport_driver(guillemot_drv);