File: /usr/src/linux/drivers/char/joystick/cs461x.c
1 /*
2 The all defines and part of code (such as cs461x_*) are
3 contributed from ALSA 0.5.8 sources.
4 See http://www.alsa-project.org/ for sources
5
6 Tested on Linux 686 2.4.0-test9, ALSA 0.5.8a and CS4610
7 */
8
9 #include <asm/io.h>
10
11 #include <linux/module.h>
12 #include <linux/ioport.h>
13 #include <linux/config.h>
14 #include <linux/init.h>
15 #include <linux/gameport.h>
16 #include <linux/slab.h>
17 #include <linux/pci.h>
18
19 MODULE_AUTHOR("Victor Krapivin <vik@belcaf.minsk.by>");
20 MODULE_LICENSE("GPL");
21
22 /*
23 These options are experimental
24
25 #define CS461X_FULL_MAP
26 */
27
28 #define COOKED_MODE
29
30
31 #ifndef PCI_VENDOR_ID_CIRRUS
32 #define PCI_VENDOR_ID_CIRRUS 0x1013
33 #endif
34 #ifndef PCI_DEVICE_ID_CIRRUS_4610
35 #define PCI_DEVICE_ID_CIRRUS_4610 0x6001
36 #endif
37 #ifndef PCI_DEVICE_ID_CIRRUS_4612
38 #define PCI_DEVICE_ID_CIRRUS_4612 0x6003
39 #endif
40 #ifndef PCI_DEVICE_ID_CIRRUS_4615
41 #define PCI_DEVICE_ID_CIRRUS_4615 0x6004
42 #endif
43
44 /* Registers */
45
46 #define BA0_JSPT 0x00000480
47 #define BA0_JSCTL 0x00000484
48 #define BA0_JSC1 0x00000488
49 #define BA0_JSC2 0x0000048C
50 #define BA0_JSIO 0x000004A0
51
52 /* Bits for JSPT */
53
54 #define JSPT_CAX 0x00000001
55 #define JSPT_CAY 0x00000002
56 #define JSPT_CBX 0x00000004
57 #define JSPT_CBY 0x00000008
58 #define JSPT_BA1 0x00000010
59 #define JSPT_BA2 0x00000020
60 #define JSPT_BB1 0x00000040
61 #define JSPT_BB2 0x00000080
62
63 /* Bits for JSCTL */
64
65 #define JSCTL_SP_MASK 0x00000003
66 #define JSCTL_SP_SLOW 0x00000000
67 #define JSCTL_SP_MEDIUM_SLOW 0x00000001
68 #define JSCTL_SP_MEDIUM_FAST 0x00000002
69 #define JSCTL_SP_FAST 0x00000003
70 #define JSCTL_ARE 0x00000004
71
72 /* Data register pairs masks */
73
74 #define JSC1_Y1V_MASK 0x0000FFFF
75 #define JSC1_X1V_MASK 0xFFFF0000
76 #define JSC1_Y1V_SHIFT 0
77 #define JSC1_X1V_SHIFT 16
78 #define JSC2_Y2V_MASK 0x0000FFFF
79 #define JSC2_X2V_MASK 0xFFFF0000
80 #define JSC2_Y2V_SHIFT 0
81 #define JSC2_X2V_SHIFT 16
82
83 /* JS GPIO */
84
85 #define JSIO_DAX 0x00000001
86 #define JSIO_DAY 0x00000002
87 #define JSIO_DBX 0x00000004
88 #define JSIO_DBY 0x00000008
89 #define JSIO_AXOE 0x00000010
90 #define JSIO_AYOE 0x00000020
91 #define JSIO_BXOE 0x00000040
92 #define JSIO_BYOE 0x00000080
93
94 /*
95 The card initialization code is obfuscated; the module cs461x
96 need to be loaded after ALSA modules initialized and something
97 played on the CS 4610 chip (see sources for details of CS4610
98 initialization code from ALSA)
99 */
100
101 /* Card specific definitions */
102
103 #define CS461X_BA0_SIZE 0x2000
104 #define CS461X_BA1_DATA0_SIZE 0x3000
105 #define CS461X_BA1_DATA1_SIZE 0x3800
106 #define CS461X_BA1_PRG_SIZE 0x7000
107 #define CS461X_BA1_REG_SIZE 0x0100
108
109 #define BA1_SP_DMEM0 0x00000000
110 #define BA1_SP_DMEM1 0x00010000
111 #define BA1_SP_PMEM 0x00020000
112 #define BA1_SP_REG 0x00030000
113
114 #define BA1_DWORD_SIZE (13 * 1024 + 512)
115 #define BA1_MEMORY_COUNT 3
116
117 /*
118 Only one CS461x card is still suppoted; the code requires
119 redesign to avoid this limitatuion.
120 */
121
122 static unsigned long ba0_addr;
123 static unsigned int *ba0;
124
125 #ifdef CS461X_FULL_MAP
126 static unsigned long ba1_addr;
127 static union ba1_t {
128 struct {
129 unsigned int *data0;
130 unsigned int *data1;
131 unsigned int *pmem;
132 unsigned int *reg;
133 } name;
134 unsigned int *idx[4];
135 } ba1;
136
137 static void cs461x_poke(unsigned long reg, unsigned int val)
138 {
139 ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff] = val;
140 }
141
142 static unsigned int cs461x_peek(unsigned long reg)
143 {
144 return ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff];
145 }
146
147 #endif
148
149 static void cs461x_pokeBA0(unsigned long reg, unsigned int val)
150 {
151 ba0[reg >> 2] = val;
152 }
153
154 static unsigned int cs461x_peekBA0(unsigned long reg)
155 {
156 return ba0[reg >> 2];
157 }
158
159 static int cs461x_free(struct pci_dev *pdev)
160 {
161 struct gameport *port = (struct gameport *)pdev->driver_data;
162 if(port){
163 gameport_unregister_port(port);
164 kfree(port);
165 }
166 if (ba0) iounmap(ba0);
167 #ifdef CS461X_FULL_MAP
168 if (ba1.name.data0) iounmap(ba1.name.data0);
169 if (ba1.name.data1) iounmap(ba1.name.data1);
170 if (ba1.name.pmem) iounmap(ba1.name.pmem);
171 if (ba1.name.reg) iounmap(ba1.name.reg);
172 #endif
173 return 0;
174 }
175
176 static void cs461x_gameport_trigger(struct gameport *gameport)
177 {
178 cs461x_pokeBA0(BA0_JSPT, 0xFF); //outb(gameport->io, 0xFF);
179 }
180
181 static unsigned char cs461x_gameport_read(struct gameport *gameport)
182 {
183 return cs461x_peekBA0(BA0_JSPT); //inb(gameport->io);
184 }
185
186 static int cs461x_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
187 {
188 unsigned js1, js2, jst;
189
190 js1 = cs461x_peekBA0(BA0_JSC1);
191 js2 = cs461x_peekBA0(BA0_JSC2);
192 jst = cs461x_peekBA0(BA0_JSPT);
193
194 *buttons = (~jst >> 4) & 0x0F;
195
196 axes[0] = ((js1 & JSC1_Y1V_MASK) >> JSC1_Y1V_SHIFT) & 0xFFFF;
197 axes[1] = ((js1 & JSC1_X1V_MASK) >> JSC1_X1V_SHIFT) & 0xFFFF;
198 axes[2] = ((js2 & JSC2_Y2V_MASK) >> JSC2_Y2V_SHIFT) & 0xFFFF;
199 axes[3] = ((js2 & JSC2_X2V_MASK) >> JSC2_X2V_SHIFT) & 0xFFFF;
200
201 for(jst=0;jst<4;++jst)
202 if(axes[jst]==0xFFFF) axes[jst] = -1;
203 return 0;
204 }
205
206 static int cs461x_gameport_open(struct gameport *gameport, int mode)
207 {
208 switch (mode) {
209 #ifdef COOKED_MODE
210 case GAMEPORT_MODE_COOKED:
211 return 0;
212 #endif
213 case GAMEPORT_MODE_RAW:
214 return 0;
215 default:
216 return -1;
217 }
218 return 0;
219 }
220
221 static struct pci_device_id cs461x_pci_tbl[] __devinitdata = {
222 { PCI_VENDOR_ID_CIRRUS, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4610 */
223 { PCI_VENDOR_ID_CIRRUS, 0x6003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4612 */
224 { PCI_VENDOR_ID_CIRRUS, 0x6005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4615 */
225 { 0, }
226 };
227 MODULE_DEVICE_TABLE(pci, cs461x_pci_tbl);
228
229 static int __devinit cs461x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
230 {
231 int rc;
232 struct gameport* port;
233
234 rc = pci_enable_device(pdev);
235 if (rc) {
236 printk(KERN_ERR "cs461x: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n",
237 pdev->bus->number, pdev->devfn, rc);
238 return rc;
239 }
240
241 ba0_addr = pci_resource_start(pdev, 0);
242 #ifdef CS461X_FULL_MAP
243 ba1_addr = pci_resource_start(pdev, 1);
244 #endif
245 if (ba0_addr == 0 || ba0_addr == ~0
246 #ifdef CS461X_FULL_MAP
247 || ba1_addr == 0 || ba1_addr == ~0
248 #endif
249 ) {
250 printk(KERN_ERR "cs461x: wrong address - ba0 = 0x%lx\n", ba0_addr);
251 #ifdef CS461X_FULL_MAP
252 printk(KERN_ERR "cs461x: wrong address - ba1 = 0x%lx\n", ba1_addr);
253 #endif
254 cs461x_free(pdev);
255 return -ENOMEM;
256 }
257
258 ba0 = ioremap(ba0_addr, CS461X_BA0_SIZE);
259 #ifdef CS461X_FULL_MAP
260 ba1.name.data0 = ioremap(ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE);
261 ba1.name.data1 = ioremap(ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE);
262 ba1.name.pmem = ioremap(ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE);
263 ba1.name.reg = ioremap(ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE);
264
265 if (ba0 == NULL || ba1.name.data0 == NULL ||
266 ba1.name.data1 == NULL || ba1.name.pmem == NULL ||
267 ba1.name.reg == NULL) {
268 cs461x_free(pdev);
269 return -ENOMEM;
270 }
271 #else
272 if (ba0 == NULL){
273 cs461x_free(pdev);
274 return -ENOMEM;
275 }
276 #endif
277 printk(KERN_INFO "CS461x PCI: %lx[%d]\n",
278 ba0_addr, CS461X_BA0_SIZE);
279
280 if (!(port = kmalloc(sizeof(struct gameport), GFP_KERNEL))) {
281 printk(KERN_ERR "Memory allocation failed.\n");
282 cs461x_free(pdev);
283 return -ENOMEM;
284 }
285 memset(port, 0, sizeof(struct gameport));
286
287 pdev->driver_data = port;
288
289 port->open = cs461x_gameport_open;
290 port->read = cs461x_gameport_read;
291 port->trigger = cs461x_gameport_trigger;
292 #ifdef COOKED_MODE
293 port->cooked_read = cs461x_gameport_cooked_read;
294 #endif
295
296 cs461x_pokeBA0(BA0_JSIO, 0xFF); // ?
297 cs461x_pokeBA0(BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW);
298
299 gameport_register_port(port);
300
301 printk(KERN_INFO "gameport%d: CS461x Gameport speed %d kHz\n",
302 port->number, port->speed);
303
304 return 0;
305 }
306
307 static void __devexit cs461x_pci_remove(struct pci_dev *pdev)
308 {
309 cs461x_free(pdev);
310 }
311
312 static struct pci_driver cs461x_pci_driver = {
313 name: "PCI Gameport",
314 id_table: cs461x_pci_tbl,
315 probe: cs461x_pci_probe,
316 remove: cs461x_pci_remove,
317 };
318
319 int __init js_cs461x_init(void)
320 {
321 return pci_module_init(&cs461x_pci_driver);
322 }
323
324 void __exit js_cs461x_exit(void)
325 {
326 pci_unregister_driver(&cs461x_pci_driver);
327 }
328
329 module_init(js_cs461x_init);
330 module_exit(js_cs461x_exit);
331
332