1 /* 2 * Copyright (c) 1999-2001 Vojtech Pavlik 3 */ 4 5 /* 6 * Creative Labs Blaster GamePad Cobra 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 25 #include <linux/kernel.h> 26 #include <linux/module.h> 27 #include <linux/slab.h> 28 #include <linux/gameport.h> 29 #include <linux/input.h> 30 #include <linux/jiffies.h> 31 32 #define DRIVER_DESC "Creative Labs Blaster GamePad Cobra driver" 33 34 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); 35 MODULE_DESCRIPTION(DRIVER_DESC); 36 MODULE_LICENSE("GPL"); 37 38 #define COBRA_MAX_STROBE 45 /* 45 us max wait for first strobe */ 39 #define COBRA_LENGTH 36 40 41 static int cobra_btn[] = { BTN_START, BTN_SELECT, BTN_TL, BTN_TR, BTN_X, BTN_Y, BTN_Z, BTN_A, BTN_B, BTN_C, BTN_TL2, BTN_TR2, 0 }; 42 43 struct cobra { 44 struct gameport *gameport; 45 struct input_dev *dev[2]; 46 int reads; 47 int bads; 48 unsigned char exists; 49 char phys[2][32]; 50 }; 51 52 static unsigned char cobra_read_packet(struct gameport *gameport, unsigned int *data) 53 { 54 unsigned long flags; 55 unsigned char u, v, w; 56 __u64 buf[2]; 57 int r[2], t[2]; 58 int i, j, ret; 59 60 int strobe = gameport_time(gameport, COBRA_MAX_STROBE); 61 62 for (i = 0; i < 2; i++) { 63 r[i] = buf[i] = 0; 64 t[i] = COBRA_MAX_STROBE; 65 } 66 67 local_irq_save(flags); 68 69 u = gameport_read(gameport); 70 71 do { 72 t[0]--; t[1]--; 73 v = gameport_read(gameport); 74 for (i = 0, w = u ^ v; i < 2 && w; i++, w >>= 2) 75 if (w & 0x30) { 76 if ((w & 0x30) < 0x30 && r[i] < COBRA_LENGTH && t[i] > 0) { 77 buf[i] |= (__u64)((w >> 5) & 1) << r[i]++; 78 t[i] = strobe; 79 u = v; 80 } else t[i] = 0; 81 } 82 } while (t[0] > 0 || t[1] > 0); 83 84 local_irq_restore(flags); 85 86 ret = 0; 87 88 for (i = 0; i < 2; i++) { 89 90 if (r[i] != COBRA_LENGTH) continue; 91 92 for (j = 0; j < COBRA_LENGTH && (buf[i] & 0x04104107f) ^ 0x041041040; j++) 93 buf[i] = (buf[i] >> 1) | ((__u64)(buf[i] & 1) << (COBRA_LENGTH - 1)); 94 95 if (j < COBRA_LENGTH) ret |= (1 << i); 96 97 data[i] = ((buf[i] >> 7) & 0x000001f) | ((buf[i] >> 8) & 0x00003e0) 98 | ((buf[i] >> 9) & 0x0007c00) | ((buf[i] >> 10) & 0x00f8000) 99 | ((buf[i] >> 11) & 0x1f00000); 100 101 } 102 103 return ret; 104 } 105 106 static void cobra_poll(struct gameport *gameport) 107 { 108 struct cobra *cobra = gameport_get_drvdata(gameport); 109 struct input_dev *dev; 110 unsigned int data[2]; 111 int i, j, r; 112 113 cobra->reads++; 114 115 if ((r = cobra_read_packet(gameport, data)) != cobra->exists) { 116 cobra->bads++; 117 return; 118 } 119 120 for (i = 0; i < 2; i++) 121 if (cobra->exists & r & (1 << i)) { 122 123 dev = cobra->dev[i]; 124 125 input_report_abs(dev, ABS_X, ((data[i] >> 4) & 1) - ((data[i] >> 3) & 1)); 126 input_report_abs(dev, ABS_Y, ((data[i] >> 2) & 1) - ((data[i] >> 1) & 1)); 127 128 for (j = 0; cobra_btn[j]; j++) 129 input_report_key(dev, cobra_btn[j], data[i] & (0x20 << j)); 130 131 input_sync(dev); 132 133 } 134 } 135 136 static int cobra_open(struct input_dev *dev) 137 { 138 struct cobra *cobra = input_get_drvdata(dev); 139 140 gameport_start_polling(cobra->gameport); 141 return 0; 142 } 143 144 static void cobra_close(struct input_dev *dev) 145 { 146 struct cobra *cobra = input_get_drvdata(dev); 147 148 gameport_stop_polling(cobra->gameport); 149 } 150 151 static int cobra_connect(struct gameport *gameport, struct gameport_driver *drv) 152 { 153 struct cobra *cobra; 154 struct input_dev *input_dev; 155 unsigned int data[2]; 156 int i, j; 157 int err; 158 159 cobra = kzalloc(sizeof(struct cobra), GFP_KERNEL); 160 if (!cobra) 161 return -ENOMEM; 162 163 cobra->gameport = gameport; 164 165 gameport_set_drvdata(gameport, cobra); 166 167 err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); 168 if (err) 169 goto fail1; 170 171 cobra->exists = cobra_read_packet(gameport, data); 172 173 for (i = 0; i < 2; i++) 174 if ((cobra->exists >> i) & data[i] & 1) { 175 printk(KERN_WARNING "cobra.c: Device %d on %s has the Ext bit set. ID is: %d" 176 " Contact vojtech@ucw.cz\n", i, gameport->phys, (data[i] >> 2) & 7); 177 cobra->exists &= ~(1 << i); 178 } 179 180 if (!cobra->exists) { 181 err = -ENODEV; 182 goto fail2; 183 } 184 185 gameport_set_poll_handler(gameport, cobra_poll); 186 gameport_set_poll_interval(gameport, 20); 187 188 for (i = 0; i < 2; i++) { 189 if (~(cobra->exists >> i) & 1) 190 continue; 191 192 cobra->dev[i] = input_dev = input_allocate_device(); 193 if (!input_dev) { 194 err = -ENOMEM; 195 goto fail3; 196 } 197 198 snprintf(cobra->phys[i], sizeof(cobra->phys[i]), 199 "%s/input%d", gameport->phys, i); 200 201 input_dev->name = "Creative Labs Blaster GamePad Cobra"; 202 input_dev->phys = cobra->phys[i]; 203 input_dev->id.bustype = BUS_GAMEPORT; 204 input_dev->id.vendor = GAMEPORT_ID_VENDOR_CREATIVE; 205 input_dev->id.product = 0x0008; 206 input_dev->id.version = 0x0100; 207 input_dev->dev.parent = &gameport->dev; 208 209 input_set_drvdata(input_dev, cobra); 210 211 input_dev->open = cobra_open; 212 input_dev->close = cobra_close; 213 214 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); 215 input_set_abs_params(input_dev, ABS_X, -1, 1, 0, 0); 216 input_set_abs_params(input_dev, ABS_Y, -1, 1, 0, 0); 217 for (j = 0; cobra_btn[j]; j++) 218 set_bit(cobra_btn[j], input_dev->keybit); 219 220 err = input_register_device(cobra->dev[i]); 221 if (err) 222 goto fail4; 223 } 224 225 return 0; 226 227 fail4: input_free_device(cobra->dev[i]); 228 fail3: while (--i >= 0) 229 if (cobra->dev[i]) 230 input_unregister_device(cobra->dev[i]); 231 fail2: gameport_close(gameport); 232 fail1: gameport_set_drvdata(gameport, NULL); 233 kfree(cobra); 234 return err; 235 } 236 237 static void cobra_disconnect(struct gameport *gameport) 238 { 239 struct cobra *cobra = gameport_get_drvdata(gameport); 240 int i; 241 242 for (i = 0; i < 2; i++) 243 if ((cobra->exists >> i) & 1) 244 input_unregister_device(cobra->dev[i]); 245 gameport_close(gameport); 246 gameport_set_drvdata(gameport, NULL); 247 kfree(cobra); 248 } 249 250 static struct gameport_driver cobra_drv = { 251 .driver = { 252 .name = "cobra", 253 }, 254 .description = DRIVER_DESC, 255 .connect = cobra_connect, 256 .disconnect = cobra_disconnect, 257 }; 258 259 module_gameport_driver(cobra_drv); 260