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