diff options
Diffstat (limited to 'drivers/input/joystick/turbografx.c')
-rw-r--r-- | drivers/input/joystick/turbografx.c | 215 |
1 files changed, 132 insertions, 83 deletions
diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c index 0c5b9c8297cd..7e9764937d06 100644 --- a/drivers/input/joystick/turbografx.c +++ b/drivers/input/joystick/turbografx.c | |||
@@ -42,19 +42,21 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | |||
42 | MODULE_DESCRIPTION("TurboGraFX parallel port interface driver"); | 42 | MODULE_DESCRIPTION("TurboGraFX parallel port interface driver"); |
43 | MODULE_LICENSE("GPL"); | 43 | MODULE_LICENSE("GPL"); |
44 | 44 | ||
45 | static int tgfx[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; | 45 | #define TGFX_MAX_PORTS 3 |
46 | static int tgfx_nargs __initdata = 0; | 46 | #define TGFX_MAX_DEVICES 7 |
47 | module_param_array_named(map, tgfx, int, &tgfx_nargs, 0); | ||
48 | MODULE_PARM_DESC(map, "Describes first set of devices (<parport#>,<js1>,<js2>,..<js7>"); | ||
49 | 47 | ||
50 | static int tgfx_2[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; | 48 | struct tgfx_config { |
51 | static int tgfx_nargs_2 __initdata = 0; | 49 | int args[TGFX_MAX_DEVICES + 1]; |
52 | module_param_array_named(map2, tgfx_2, int, &tgfx_nargs_2, 0); | 50 | int nargs; |
53 | MODULE_PARM_DESC(map2, "Describes second set of devices"); | 51 | }; |
52 | |||
53 | static struct tgfx_config tgfx[TGFX_MAX_PORTS] __initdata; | ||
54 | 54 | ||
55 | static int tgfx_3[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; | 55 | module_param_array_named(map, tgfx[0].args, int, &tgfx[0].nargs, 0); |
56 | static int tgfx_nargs_3 __initdata = 0; | 56 | MODULE_PARM_DESC(map, "Describes first set of devices (<parport#>,<js1>,<js2>,..<js7>"); |
57 | module_param_array_named(map3, tgfx_3, int, &tgfx_nargs_3, 0); | 57 | module_param_array_named(map2, tgfx[1].args, int, &tgfx[1].nargs, 0); |
58 | MODULE_PARM_DESC(map2, "Describes second set of devices"); | ||
59 | module_param_array_named(map3, tgfx[2].args, int, &tgfx[2].nargs, 0); | ||
58 | MODULE_PARM_DESC(map3, "Describes third set of devices"); | 60 | MODULE_PARM_DESC(map3, "Describes third set of devices"); |
59 | 61 | ||
60 | __obsolete_setup("tgfx="); | 62 | __obsolete_setup("tgfx="); |
@@ -75,17 +77,17 @@ __obsolete_setup("tgfx_3="); | |||
75 | #define TGFX_TOP2 0x08 | 77 | #define TGFX_TOP2 0x08 |
76 | 78 | ||
77 | static int tgfx_buttons[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2 }; | 79 | static int tgfx_buttons[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2 }; |
78 | static char *tgfx_name = "TurboGraFX Multisystem joystick"; | ||
79 | 80 | ||
80 | static struct tgfx { | 81 | static struct tgfx { |
81 | struct pardevice *pd; | 82 | struct pardevice *pd; |
82 | struct timer_list timer; | 83 | struct timer_list timer; |
83 | struct input_dev dev[7]; | 84 | struct input_dev *dev[TGFX_MAX_DEVICES]; |
84 | char phys[7][32]; | 85 | char name[TGFX_MAX_DEVICES][64]; |
86 | char phys[TGFX_MAX_DEVICES][32]; | ||
85 | int sticks; | 87 | int sticks; |
86 | int used; | 88 | int used; |
87 | struct semaphore sem; | 89 | struct semaphore sem; |
88 | } *tgfx_base[3]; | 90 | } *tgfx_base[TGFX_MAX_PORTS]; |
89 | 91 | ||
90 | /* | 92 | /* |
91 | * tgfx_timer() reads and analyzes TurboGraFX joystick data. | 93 | * tgfx_timer() reads and analyzes TurboGraFX joystick data. |
@@ -100,7 +102,7 @@ static void tgfx_timer(unsigned long private) | |||
100 | for (i = 0; i < 7; i++) | 102 | for (i = 0; i < 7; i++) |
101 | if (tgfx->sticks & (1 << i)) { | 103 | if (tgfx->sticks & (1 << i)) { |
102 | 104 | ||
103 | dev = tgfx->dev + i; | 105 | dev = tgfx->dev[i]; |
104 | 106 | ||
105 | parport_write_data(tgfx->pd->port, ~(1 << i)); | 107 | parport_write_data(tgfx->pd->port, ~(1 << i)); |
106 | data1 = parport_read_status(tgfx->pd->port) ^ 0x7f; | 108 | data1 = parport_read_status(tgfx->pd->port) ^ 0x7f; |
@@ -153,118 +155,165 @@ static void tgfx_close(struct input_dev *dev) | |||
153 | up(&tgfx->sem); | 155 | up(&tgfx->sem); |
154 | } | 156 | } |
155 | 157 | ||
158 | |||
159 | |||
156 | /* | 160 | /* |
157 | * tgfx_probe() probes for tg gamepads. | 161 | * tgfx_probe() probes for tg gamepads. |
158 | */ | 162 | */ |
159 | 163 | ||
160 | static struct tgfx __init *tgfx_probe(int *config, int nargs) | 164 | static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs) |
161 | { | 165 | { |
162 | struct tgfx *tgfx; | 166 | struct tgfx *tgfx; |
167 | struct input_dev *input_dev; | ||
163 | struct parport *pp; | 168 | struct parport *pp; |
169 | struct pardevice *pd; | ||
164 | int i, j; | 170 | int i, j; |
171 | int err; | ||
165 | 172 | ||
166 | if (config[0] < 0) | 173 | pp = parport_find_number(parport); |
167 | return NULL; | ||
168 | |||
169 | if (nargs < 2) { | ||
170 | printk(KERN_ERR "turbografx.c: at least one joystick must be specified\n"); | ||
171 | return NULL; | ||
172 | } | ||
173 | |||
174 | pp = parport_find_number(config[0]); | ||
175 | |||
176 | if (!pp) { | 174 | if (!pp) { |
177 | printk(KERN_ERR "turbografx.c: no such parport\n"); | 175 | printk(KERN_ERR "turbografx.c: no such parport\n"); |
178 | return NULL; | 176 | err = -EINVAL; |
177 | goto err_out; | ||
179 | } | 178 | } |
180 | 179 | ||
181 | if (!(tgfx = kzalloc(sizeof(struct tgfx), GFP_KERNEL))) { | 180 | pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); |
182 | parport_put_port(pp); | 181 | if (!pd) { |
183 | return NULL; | 182 | printk(KERN_ERR "turbografx.c: parport busy already - lp.o loaded?\n"); |
183 | err = -EBUSY; | ||
184 | goto err_put_pp; | ||
184 | } | 185 | } |
185 | 186 | ||
186 | init_MUTEX(&tgfx->sem); | 187 | tgfx = kzalloc(sizeof(struct tgfx), GFP_KERNEL); |
187 | 188 | if (!tgfx) { | |
188 | tgfx->pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); | 189 | printk(KERN_ERR "turbografx.c: Not enough memory\n"); |
189 | 190 | err = -ENOMEM; | |
190 | parport_put_port(pp); | 191 | goto err_unreg_pardev; |
191 | |||
192 | if (!tgfx->pd) { | ||
193 | printk(KERN_ERR "turbografx.c: parport busy already - lp.o loaded?\n"); | ||
194 | kfree(tgfx); | ||
195 | return NULL; | ||
196 | } | 192 | } |
197 | 193 | ||
194 | init_MUTEX(&tgfx->sem); | ||
195 | tgfx->pd = pd; | ||
198 | init_timer(&tgfx->timer); | 196 | init_timer(&tgfx->timer); |
199 | tgfx->timer.data = (long) tgfx; | 197 | tgfx->timer.data = (long) tgfx; |
200 | tgfx->timer.function = tgfx_timer; | 198 | tgfx->timer.function = tgfx_timer; |
201 | 199 | ||
202 | tgfx->sticks = 0; | 200 | for (i = 0; i < n_devs; i++) { |
201 | if (n_buttons[i] < 1) | ||
202 | continue; | ||
203 | 203 | ||
204 | for (i = 0; i < nargs - 1; i++) | 204 | if (n_buttons[i] > 6) { |
205 | if (config[i+1] > 0 && config[i+1] < 6) { | 205 | printk(KERN_ERR "turbografx.c: Invalid number of buttons %d\n", n_buttons[i]); |
206 | 206 | err = -EINVAL; | |
207 | tgfx->sticks |= (1 << i); | 207 | goto err_free_devs; |
208 | } | ||
208 | 209 | ||
209 | tgfx->dev[i].private = tgfx; | 210 | tgfx->dev[i] = input_dev = input_allocate_device(); |
210 | tgfx->dev[i].open = tgfx_open; | 211 | if (!input_dev) { |
211 | tgfx->dev[i].close = tgfx_close; | 212 | printk(KERN_ERR "turbografx.c: Not enough memory for input device\n"); |
213 | err = -ENOMEM; | ||
214 | goto err_free_devs; | ||
215 | } | ||
212 | 216 | ||
213 | sprintf(tgfx->phys[i], "%s/input0", tgfx->pd->port->name); | 217 | tgfx->sticks |= (1 << i); |
218 | snprintf(tgfx->name[i], sizeof(tgfx->name[i]), | ||
219 | "TurboGraFX %d-button Multisystem joystick", n_buttons[i]); | ||
220 | snprintf(tgfx->phys[i], sizeof(tgfx->phys[i]), | ||
221 | "%s/input%d", tgfx->pd->port->name, i); | ||
214 | 222 | ||
215 | tgfx->dev[i].name = tgfx_name; | 223 | input_dev->name = tgfx->name[i]; |
216 | tgfx->dev[i].phys = tgfx->phys[i]; | 224 | input_dev->phys = tgfx->phys[i]; |
217 | tgfx->dev[i].id.bustype = BUS_PARPORT; | 225 | input_dev->id.bustype = BUS_PARPORT; |
218 | tgfx->dev[i].id.vendor = 0x0003; | 226 | input_dev->id.vendor = 0x0003; |
219 | tgfx->dev[i].id.product = config[i+1]; | 227 | input_dev->id.product = n_buttons[i]; |
220 | tgfx->dev[i].id.version = 0x0100; | 228 | input_dev->id.version = 0x0100; |
221 | 229 | ||
222 | tgfx->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | 230 | input_dev->private = tgfx; |
223 | tgfx->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y); | 231 | input_dev->open = tgfx_open; |
232 | input_dev->close = tgfx_close; | ||
224 | 233 | ||
225 | for (j = 0; j < config[i+1]; j++) | 234 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); |
226 | set_bit(tgfx_buttons[j], tgfx->dev[i].keybit); | 235 | input_set_abs_params(input_dev, ABS_X, -1, 1, 0, 0); |
236 | input_set_abs_params(input_dev, ABS_Y, -1, 1, 0, 0); | ||
227 | 237 | ||
228 | tgfx->dev[i].absmin[ABS_X] = -1; tgfx->dev[i].absmax[ABS_X] = 1; | 238 | for (j = 0; j < n_buttons[i]; j++) |
229 | tgfx->dev[i].absmin[ABS_Y] = -1; tgfx->dev[i].absmax[ABS_Y] = 1; | 239 | set_bit(tgfx_buttons[j], input_dev->keybit); |
230 | 240 | ||
231 | input_register_device(tgfx->dev + i); | 241 | input_register_device(tgfx->dev[i]); |
232 | printk(KERN_INFO "input: %d-button Multisystem joystick on %s\n", | 242 | } |
233 | config[i+1], tgfx->pd->port->name); | ||
234 | } | ||
235 | 243 | ||
236 | if (!tgfx->sticks) { | 244 | if (!tgfx->sticks) { |
237 | parport_unregister_device(tgfx->pd); | 245 | printk(KERN_ERR "turbografx.c: No valid devices specified\n"); |
238 | kfree(tgfx); | 246 | err = -EINVAL; |
239 | return NULL; | 247 | goto err_free_tgfx; |
240 | } | 248 | } |
241 | 249 | ||
242 | return tgfx; | 250 | return tgfx; |
251 | |||
252 | err_free_devs: | ||
253 | while (--i >= 0) | ||
254 | input_unregister_device(tgfx->dev[i]); | ||
255 | err_free_tgfx: | ||
256 | kfree(tgfx); | ||
257 | err_unreg_pardev: | ||
258 | parport_unregister_device(pd); | ||
259 | err_put_pp: | ||
260 | parport_put_port(pp); | ||
261 | err_out: | ||
262 | return ERR_PTR(err); | ||
263 | } | ||
264 | |||
265 | static void __exit tgfx_remove(struct tgfx *tgfx) | ||
266 | { | ||
267 | int i; | ||
268 | |||
269 | for (i = 0; i < TGFX_MAX_DEVICES; i++) | ||
270 | if (tgfx->dev[i]) | ||
271 | input_unregister_device(tgfx->dev[i]); | ||
272 | parport_unregister_device(tgfx->pd); | ||
273 | kfree(tgfx); | ||
243 | } | 274 | } |
244 | 275 | ||
245 | static int __init tgfx_init(void) | 276 | static int __init tgfx_init(void) |
246 | { | 277 | { |
247 | tgfx_base[0] = tgfx_probe(tgfx, tgfx_nargs); | 278 | int i; |
248 | tgfx_base[1] = tgfx_probe(tgfx_2, tgfx_nargs_2); | 279 | int have_dev = 0; |
249 | tgfx_base[2] = tgfx_probe(tgfx_3, tgfx_nargs_3); | 280 | int err = 0; |
281 | |||
282 | for (i = 0; i < TGFX_MAX_PORTS; i++) { | ||
283 | if (tgfx[i].nargs == 0 || tgfx[i].args[0] < 0) | ||
284 | continue; | ||
285 | |||
286 | if (tgfx[i].nargs < 2) { | ||
287 | printk(KERN_ERR "turbografx.c: at least one joystick must be specified\n"); | ||
288 | err = -EINVAL; | ||
289 | break; | ||
290 | } | ||
291 | |||
292 | tgfx_base[i] = tgfx_probe(tgfx[i].args[0], tgfx[i].args + 1, tgfx[i].nargs - 1); | ||
293 | if (IS_ERR(tgfx_base[i])) { | ||
294 | err = PTR_ERR(tgfx_base[i]); | ||
295 | break; | ||
296 | } | ||
297 | |||
298 | have_dev = 1; | ||
299 | } | ||
250 | 300 | ||
251 | if (tgfx_base[0] || tgfx_base[1] || tgfx_base[2]) | 301 | if (err) { |
252 | return 0; | 302 | while (--i >= 0) |
303 | tgfx_remove(tgfx_base[i]); | ||
304 | return err; | ||
305 | } | ||
253 | 306 | ||
254 | return -ENODEV; | 307 | return have_dev ? 0 : -ENODEV; |
255 | } | 308 | } |
256 | 309 | ||
257 | static void __exit tgfx_exit(void) | 310 | static void __exit tgfx_exit(void) |
258 | { | 311 | { |
259 | int i, j; | 312 | int i; |
260 | 313 | ||
261 | for (i = 0; i < 3; i++) | 314 | for (i = 0; i < TGFX_MAX_PORTS; i++) |
262 | if (tgfx_base[i]) { | 315 | if (tgfx_base[i]) |
263 | for (j = 0; j < 7; j++) | 316 | tgfx_remove(tgfx_base[i]); |
264 | if (tgfx_base[i]->sticks & (1 << j)) | ||
265 | input_unregister_device(tgfx_base[i]->dev + j); | ||
266 | parport_unregister_device(tgfx_base[i]->pd); | ||
267 | } | ||
268 | } | 317 | } |
269 | 318 | ||
270 | module_init(tgfx_init); | 319 | module_init(tgfx_init); |