Commit | Line | Data |
---|---|---|
1a59d1b8 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
1da177e4 | 2 | /* |
1da177e4 LT |
3 | * Copyright (c) 1998-2001 Vojtech Pavlik |
4 | */ | |
5 | ||
6 | /* | |
7 | * Driver for Amiga joysticks for Linux/m68k | |
8 | */ | |
9 | ||
10 | /* | |
1da177e4 LT |
11 | */ |
12 | ||
13 | #include <linux/types.h> | |
14 | #include <linux/errno.h> | |
15 | #include <linux/kernel.h> | |
16 | #include <linux/module.h> | |
1da177e4 LT |
17 | #include <linux/init.h> |
18 | #include <linux/input.h> | |
19 | #include <linux/interrupt.h> | |
72ba9f0c | 20 | #include <linux/mutex.h> |
1da177e4 | 21 | |
1da177e4 LT |
22 | #include <asm/amigahw.h> |
23 | #include <asm/amigaints.h> | |
24 | ||
25 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | |
26 | MODULE_DESCRIPTION("Driver for Amiga joysticks"); | |
27 | MODULE_LICENSE("GPL"); | |
28 | ||
29 | static int amijoy[2] = { 0, 1 }; | |
30 | module_param_array_named(map, amijoy, uint, NULL, 0); | |
31 | MODULE_PARM_DESC(map, "Map of attached joysticks in form of <a>,<b> (default is 0,1)"); | |
32 | ||
8b1a198b | 33 | static int amijoy_used; |
72ba9f0c | 34 | static DEFINE_MUTEX(amijoy_mutex); |
17dd3f0f | 35 | static struct input_dev *amijoy_dev[2]; |
1da177e4 LT |
36 | static char *amijoy_phys[2] = { "amijoy/input0", "amijoy/input1" }; |
37 | ||
7d12e780 | 38 | static irqreturn_t amijoy_interrupt(int irq, void *dummy) |
1da177e4 LT |
39 | { |
40 | int i, data = 0, button = 0; | |
41 | ||
42 | for (i = 0; i < 2; i++) | |
43 | if (amijoy[i]) { | |
44 | ||
45 | switch (i) { | |
b4290a23 AV |
46 | case 0: data = ~amiga_custom.joy0dat; button = (~ciaa.pra >> 6) & 1; break; |
47 | case 1: data = ~amiga_custom.joy1dat; button = (~ciaa.pra >> 7) & 1; break; | |
1da177e4 LT |
48 | } |
49 | ||
17dd3f0f | 50 | input_report_key(amijoy_dev[i], BTN_TRIGGER, button); |
1da177e4 | 51 | |
17dd3f0f | 52 | input_report_abs(amijoy_dev[i], ABS_X, ((data >> 1) & 1) - ((data >> 9) & 1)); |
1da177e4 | 53 | data = ~(data ^ (data << 1)); |
17dd3f0f | 54 | input_report_abs(amijoy_dev[i], ABS_Y, ((data >> 1) & 1) - ((data >> 9) & 1)); |
1da177e4 | 55 | |
17dd3f0f | 56 | input_sync(amijoy_dev[i]); |
1da177e4 LT |
57 | } |
58 | return IRQ_HANDLED; | |
59 | } | |
60 | ||
61 | static int amijoy_open(struct input_dev *dev) | |
62 | { | |
8b1a198b | 63 | int err; |
1da177e4 | 64 | |
72ba9f0c | 65 | err = mutex_lock_interruptible(&amijoy_mutex); |
8b1a198b DT |
66 | if (err) |
67 | return err; | |
1da177e4 | 68 | |
8b1a198b | 69 | if (!amijoy_used && request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", amijoy_interrupt)) { |
1da177e4 | 70 | printk(KERN_ERR "amijoy.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB); |
8b1a198b DT |
71 | err = -EBUSY; |
72 | goto out; | |
1da177e4 LT |
73 | } |
74 | ||
8b1a198b DT |
75 | amijoy_used++; |
76 | out: | |
72ba9f0c | 77 | mutex_unlock(&amijoy_mutex); |
8b1a198b | 78 | return err; |
1da177e4 LT |
79 | } |
80 | ||
81 | static void amijoy_close(struct input_dev *dev) | |
82 | { | |
72ba9f0c | 83 | mutex_lock(&amijoy_mutex); |
8b1a198b | 84 | if (!--amijoy_used) |
1da177e4 | 85 | free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt); |
72ba9f0c | 86 | mutex_unlock(&amijoy_mutex); |
1da177e4 LT |
87 | } |
88 | ||
89 | static int __init amijoy_init(void) | |
90 | { | |
91 | int i, j; | |
17dd3f0f | 92 | int err; |
1da177e4 | 93 | |
3183968c GU |
94 | if (!MACH_IS_AMIGA) |
95 | return -ENODEV; | |
96 | ||
17dd3f0f DT |
97 | for (i = 0; i < 2; i++) { |
98 | if (!amijoy[i]) | |
99 | continue; | |
1da177e4 | 100 | |
17dd3f0f DT |
101 | amijoy_dev[i] = input_allocate_device(); |
102 | if (!amijoy_dev[i]) { | |
103 | err = -ENOMEM; | |
104 | goto fail; | |
105 | } | |
1da177e4 | 106 | |
17dd3f0f DT |
107 | if (!request_mem_region(CUSTOM_PHYSADDR + 10 + i * 2, 2, "amijoy [Denise]")) { |
108 | input_free_device(amijoy_dev[i]); | |
109 | err = -EBUSY; | |
110 | goto fail; | |
111 | } | |
1da177e4 | 112 | |
17dd3f0f DT |
113 | amijoy_dev[i]->name = "Amiga joystick"; |
114 | amijoy_dev[i]->phys = amijoy_phys[i]; | |
115 | amijoy_dev[i]->id.bustype = BUS_AMIGA; | |
116 | amijoy_dev[i]->id.vendor = 0x0001; | |
117 | amijoy_dev[i]->id.product = 0x0003; | |
118 | amijoy_dev[i]->id.version = 0x0100; | |
119 | ||
120 | amijoy_dev[i]->open = amijoy_open; | |
121 | amijoy_dev[i]->close = amijoy_close; | |
122 | ||
7b19ada2 JS |
123 | amijoy_dev[i]->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
124 | amijoy_dev[i]->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y); | |
125 | amijoy_dev[i]->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) | | |
126 | BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT); | |
17dd3f0f | 127 | for (j = 0; j < 2; j++) { |
b84ae4a1 | 128 | input_set_abs_params(amijoy_dev[i], ABS_X + j, |
987a6c02 | 129 | -1, 1, 0, 0); |
1da177e4 | 130 | } |
17dd3f0f | 131 | |
127278ce DT |
132 | err = input_register_device(amijoy_dev[i]); |
133 | if (err) { | |
134 | input_free_device(amijoy_dev[i]); | |
135 | goto fail; | |
136 | } | |
17dd3f0f | 137 | } |
1da177e4 | 138 | return 0; |
17dd3f0f DT |
139 | |
140 | fail: while (--i >= 0) | |
141 | if (amijoy[i]) { | |
142 | input_unregister_device(amijoy_dev[i]); | |
143 | release_mem_region(CUSTOM_PHYSADDR + 10 + i * 2, 2); | |
144 | } | |
145 | return err; | |
1da177e4 LT |
146 | } |
147 | ||
148 | static void __exit amijoy_exit(void) | |
149 | { | |
150 | int i; | |
151 | ||
152 | for (i = 0; i < 2; i++) | |
153 | if (amijoy[i]) { | |
17dd3f0f DT |
154 | input_unregister_device(amijoy_dev[i]); |
155 | release_mem_region(CUSTOM_PHYSADDR + 10 + i * 2, 2); | |
1da177e4 LT |
156 | } |
157 | } | |
158 | ||
159 | module_init(amijoy_init); | |
160 | module_exit(amijoy_exit); |