1 /* 2 * Copyright (c) 2001 Vojtech Pavlik 3 */ 4 5 /* 6 * Guillemot Digital Interface Protocol driver for Linux 7 */ 8 9 /* 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23 * 24 * Should you need to contact me, the author, you can do so either by 25 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: 26 * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic 27 */ 28 29 #include <linux/kernel.h> 30 #include <linux/slab.h> 31 #include <linux/module.h> 32 #include <linux/delay.h> 33 #include <linux/init.h> 34 #include <linux/gameport.h> 35 #include <linux/input.h> 36 #include <linux/jiffies.h> 37 38 #define DRIVER_DESC "Guillemot Digital joystick driver" 39 40 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); 41 MODULE_DESCRIPTION(DRIVER_DESC); 42 MODULE_LICENSE("GPL"); 43 44 #define GUILLEMOT_MAX_START 600 /* 600 us */ 45 #define GUILLEMOT_MAX_STROBE 60 /* 60 us */ 46 #define GUILLEMOT_MAX_LENGTH 17 /* 17 bytes */ 47 48 static short guillemot_abs_pad[] = 49 { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, -1 }; 50 51 static short guillemot_btn_pad[] = 52 { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_MODE, BTN_SELECT, -1 }; 53 54 static struct { 55 int x; 56 int y; 57 } guillemot_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; 58 59 struct guillemot_type { 60 unsigned char id; 61 short *abs; 62 short *btn; 63 int hat; 64 char *name; 65 }; 66 67 struct guillemot { 68 struct gameport *gameport; 69 struct input_dev *dev; 70 int bads; 71 int reads; 72 struct guillemot_type *type; 73 unsigned char length; 74 char phys[32]; 75 }; 76 77 static struct guillemot_type guillemot_type[] = { 78 { 0x00, guillemot_abs_pad, guillemot_btn_pad, 1, "Guillemot Pad" }, 79 { 0 }}; 80 81 /* 82 * guillemot_read_packet() reads Guillemot joystick data. 83 */ 84 85 static int guillemot_read_packet(struct gameport *gameport, u8 *data) 86 { 87 unsigned long flags; 88 unsigned char u, v; 89 unsigned int t, s; 90 int i; 91 92 for (i = 0; i < GUILLEMOT_MAX_LENGTH; i++) 93 data[i] = 0; 94 95 i = 0; 96 t = gameport_time(gameport, GUILLEMOT_MAX_START); 97 s = gameport_time(gameport, GUILLEMOT_MAX_STROBE); 98 99 local_irq_save(flags); 100 gameport_trigger(gameport); 101 v = gameport_read(gameport); 102 103 while (t > 0 && i < GUILLEMOT_MAX_LENGTH * 8) { 104 t--; 105 u = v; v = gameport_read(gameport); 106 if (v & ~u & 0x10) { 107 data[i >> 3] |= ((v >> 5) & 1) << (i & 7); 108 i++; 109 t = s; 110 } 111 } 112 113 local_irq_restore(flags); 114 115 return i; 116 } 117 118 /* 119 * guillemot_poll() reads and analyzes Guillemot joystick data. 120 */ 121 122 static void guillemot_poll(struct gameport *gameport) 123 { 124 struct guillemot *guillemot = gameport_get_drvdata(gameport); 125 struct input_dev *dev = guillemot->dev; 126 u8 data[GUILLEMOT_MAX_LENGTH]; 127 int i; 128 129 guillemot->reads++; 130 131 if (guillemot_read_packet(guillemot->gameport, data) != GUILLEMOT_MAX_LENGTH * 8 || 132 data[0] != 0x55 || data[16] != 0xaa) { 133 guillemot->bads++; 134 } else { 135 136 for (i = 0; i < 6 && guillemot->type->abs[i] >= 0; i++) 137 input_report_abs(dev, guillemot->type->abs[i], data[i + 5]); 138 139 if (guillemot->type->hat) { 140 input_report_abs(dev, ABS_HAT0X, guillemot_hat_to_axis[data[4] >> 4].x); 141 input_report_abs(dev, ABS_HAT0Y, guillemot_hat_to_axis[data[4] >> 4].y); 142 } 143 144 for (i = 0; i < 16 && guillemot->type->btn[i] >= 0; i++) 145 input_report_key(dev, guillemot->type->btn[i], (data[2 + (i >> 3)] >> (i & 7)) & 1); 146 } 147 148 input_sync(dev); 149 } 150 151 /* 152 * guillemot_open() is a callback from the input open routine. 153 */ 154 155 static int guillemot_open(struct input_dev *dev) 156 { 157 struct guillemot *guillemot = input_get_drvdata(dev); 158 159 gameport_start_polling(guillemot->gameport); 160 return 0; 161 } 162 163 /* 164 * guillemot_close() is a callback from the input close routine. 165 */ 166 167 static void guillemot_close(struct input_dev *dev) 168 { 169 struct guillemot *guillemot = input_get_drvdata(dev); 170 171 gameport_stop_polling(guillemot->gameport); 172 } 173 174 /* 175 * guillemot_connect() probes for Guillemot joysticks. 176 */ 177 178 static int guillemot_connect(struct gameport *gameport, struct gameport_driver *drv) 179 { 180 struct guillemot *guillemot; 181 struct input_dev *input_dev; 182 u8 data[GUILLEMOT_MAX_LENGTH]; 183 int i, t; 184 int err; 185 186 guillemot = kzalloc(sizeof(struct guillemot), GFP_KERNEL); 187 input_dev = input_allocate_device(); 188 if (!guillemot || !input_dev) { 189 err = -ENOMEM; 190 goto fail1; 191 } 192 193 guillemot->gameport = gameport; 194 guillemot->dev = input_dev; 195 196 gameport_set_drvdata(gameport, guillemot); 197 198 err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); 199 if (err) 200 goto fail1; 201 202 i = guillemot_read_packet(gameport, data); 203 204 if (i != GUILLEMOT_MAX_LENGTH * 8 || data[0] != 0x55 || data[16] != 0xaa) { 205 err = -ENODEV; 206 goto fail2; 207 } 208 209 for (i = 0; guillemot_type[i].name; i++) 210 if (guillemot_type[i].id == data[11]) 211 break; 212 213 if (!guillemot_type[i].name) { 214 printk(KERN_WARNING "guillemot.c: Unknown joystick on %s. [ %02x%02x:%04x, ver %d.%02d ]\n", 215 gameport->phys, data[12], data[13], data[11], data[14], data[15]); 216 err = -ENODEV; 217 goto fail2; 218 } 219 220 gameport_set_poll_handler(gameport, guillemot_poll); 221 gameport_set_poll_interval(gameport, 20); 222 223 snprintf(guillemot->phys, sizeof(guillemot->phys), "%s/input0", gameport->phys); 224 guillemot->type = guillemot_type + i; 225 226 input_dev->name = guillemot_type[i].name; 227 input_dev->phys = guillemot->phys; 228 input_dev->id.bustype = BUS_GAMEPORT; 229 input_dev->id.vendor = GAMEPORT_ID_VENDOR_GUILLEMOT; 230 input_dev->id.product = guillemot_type[i].id; 231 input_dev->id.version = (int)data[14] << 8 | data[15]; 232 input_dev->dev.parent = &gameport->dev; 233 234 input_set_drvdata(input_dev, guillemot); 235 236 input_dev->open = guillemot_open; 237 input_dev->close = guillemot_close; 238 239 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); 240 241 for (i = 0; (t = guillemot->type->abs[i]) >= 0; i++) 242 input_set_abs_params(input_dev, t, 0, 255, 0, 0); 243 244 if (guillemot->type->hat) { 245 input_set_abs_params(input_dev, ABS_HAT0X, -1, 1, 0, 0); 246 input_set_abs_params(input_dev, ABS_HAT0Y, -1, 1, 0, 0); 247 } 248 249 for (i = 0; (t = guillemot->type->btn[i]) >= 0; i++) 250 set_bit(t, input_dev->keybit); 251 252 err = input_register_device(guillemot->dev); 253 if (err) 254 goto fail2; 255 256 return 0; 257 258 fail2: gameport_close(gameport); 259 fail1: gameport_set_drvdata(gameport, NULL); 260 input_free_device(input_dev); 261 kfree(guillemot); 262 return err; 263 } 264 265 static void guillemot_disconnect(struct gameport *gameport) 266 { 267 struct guillemot *guillemot = gameport_get_drvdata(gameport); 268 269 printk(KERN_INFO "guillemot.c: Failed %d reads out of %d on %s\n", guillemot->reads, guillemot->bads, guillemot->phys); 270 input_unregister_device(guillemot->dev); 271 gameport_close(gameport); 272 kfree(guillemot); 273 } 274 275 static struct gameport_driver guillemot_drv = { 276 .driver = { 277 .name = "guillemot", 278 }, 279 .description = DRIVER_DESC, 280 .connect = guillemot_connect, 281 .disconnect = guillemot_disconnect, 282 }; 283 284 module_gameport_driver(guillemot_drv); 285