Linux-2.6.12-rc2
[linux-flexiantxendom0-natty.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");
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 __iomem *ba0;
122
123 #ifdef CS461X_FULL_MAP
124 static unsigned long ba1_addr;
125 static union ba1_t {
126         struct {
127                 unsigned int __iomem *data0;
128                 unsigned int __iomem *data1;
129                 unsigned int __iomem *pmem;
130                 unsigned int __iomem *reg;
131         } name;
132         unsigned int __iomem *idx[4];
133 } ba1;
134
135 static void cs461x_poke(unsigned long reg, unsigned int val)
136 {
137         writel(val, &ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]);
138 }
139
140 static unsigned int cs461x_peek(unsigned long reg)
141 {
142         return readl(&ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]);
143 }
144
145 #endif
146
147 static void cs461x_pokeBA0(unsigned long reg, unsigned int val)
148 {
149         writel(val, &ba0[reg >> 2]);
150 }
151
152 static unsigned int cs461x_peekBA0(unsigned long reg)
153 {
154         return readl(&ba0[reg >> 2]);
155 }
156
157 static int cs461x_free(struct pci_dev *pdev)
158 {
159         struct gameport *port = pci_get_drvdata(pdev);
160
161         if (port)
162             gameport_unregister_port(port);
163
164         if (ba0) iounmap(ba0);
165 #ifdef CS461X_FULL_MAP
166         if (ba1.name.data0) iounmap(ba1.name.data0);
167         if (ba1.name.data1) iounmap(ba1.name.data1);
168         if (ba1.name.pmem)  iounmap(ba1.name.pmem);
169         if (ba1.name.reg)   iounmap(ba1.name.reg);
170 #endif
171         return 0;
172 }
173
174 static void cs461x_gameport_trigger(struct gameport *gameport)
175 {
176         cs461x_pokeBA0(BA0_JSPT, 0xFF);  //outb(gameport->io, 0xFF);
177 }
178
179 static unsigned char cs461x_gameport_read(struct gameport *gameport)
180 {
181         return cs461x_peekBA0(BA0_JSPT); //inb(gameport->io);
182 }
183
184 static int cs461x_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
185 {
186         unsigned js1, js2, jst;
187
188         js1 = cs461x_peekBA0(BA0_JSC1);
189         js2 = cs461x_peekBA0(BA0_JSC2);
190         jst = cs461x_peekBA0(BA0_JSPT);
191
192         *buttons = (~jst >> 4) & 0x0F;
193
194         axes[0] = ((js1 & JSC1_Y1V_MASK) >> JSC1_Y1V_SHIFT) & 0xFFFF;
195         axes[1] = ((js1 & JSC1_X1V_MASK) >> JSC1_X1V_SHIFT) & 0xFFFF;
196         axes[2] = ((js2 & JSC2_Y2V_MASK) >> JSC2_Y2V_SHIFT) & 0xFFFF;
197         axes[3] = ((js2 & JSC2_X2V_MASK) >> JSC2_X2V_SHIFT) & 0xFFFF;
198
199         for(jst=0;jst<4;++jst)
200                 if(axes[jst]==0xFFFF) axes[jst] = -1;
201         return 0;
202 }
203
204 static int cs461x_gameport_open(struct gameport *gameport, int mode)
205 {
206         switch (mode) {
207                 case GAMEPORT_MODE_COOKED:
208                 case GAMEPORT_MODE_RAW:
209                         return 0;
210                 default:
211                         return -1;
212         }
213         return 0;
214 }
215
216 static struct pci_device_id cs461x_pci_tbl[] = {
217         { PCI_VENDOR_ID_CIRRUS, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4610 */
218         { PCI_VENDOR_ID_CIRRUS, 0x6003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4612 */
219         { PCI_VENDOR_ID_CIRRUS, 0x6005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4615 */
220         { 0, }
221 };
222 MODULE_DEVICE_TABLE(pci, cs461x_pci_tbl);
223
224 static int __devinit cs461x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
225 {
226         int rc;
227         struct gameport* port;
228
229         rc = pci_enable_device(pdev);
230         if (rc) {
231                 printk(KERN_ERR "cs461x: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n",
232                         pdev->bus->number, pdev->devfn, rc);
233                 return rc;
234         }
235
236         ba0_addr = pci_resource_start(pdev, 0);
237 #ifdef CS461X_FULL_MAP
238         ba1_addr = pci_resource_start(pdev, 1);
239 #endif
240         if (ba0_addr == 0 || ba0_addr == ~0
241 #ifdef CS461X_FULL_MAP
242             || ba1_addr == 0 || ba1_addr == ~0
243 #endif
244             ) {
245                 printk(KERN_ERR "cs461x: wrong address - ba0 = 0x%lx\n", ba0_addr);
246 #ifdef CS461X_FULL_MAP
247                 printk(KERN_ERR "cs461x: wrong address - ba1 = 0x%lx\n", ba1_addr);
248 #endif
249                 cs461x_free(pdev);
250                 return -ENOMEM;
251         }
252
253         ba0 = ioremap(ba0_addr, CS461X_BA0_SIZE);
254 #ifdef CS461X_FULL_MAP
255         ba1.name.data0 = ioremap(ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE);
256         ba1.name.data1 = ioremap(ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE);
257         ba1.name.pmem  = ioremap(ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE);
258         ba1.name.reg   = ioremap(ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE);
259
260         if (ba0 == NULL || ba1.name.data0 == NULL ||
261             ba1.name.data1 == NULL || ba1.name.pmem == NULL ||
262             ba1.name.reg == NULL) {
263                 cs461x_free(pdev);
264                 return -ENOMEM;
265         }
266 #else
267         if (ba0 == NULL) {
268                 cs461x_free(pdev);
269                 return -ENOMEM;
270         }
271 #endif
272
273         if (!(port = gameport_allocate_port())) {
274                 printk(KERN_ERR "cs461x: Memory allocation failed\n");
275                 cs461x_free(pdev);
276                 return -ENOMEM;
277         }
278
279         pci_set_drvdata(pdev, port);
280
281         port->open = cs461x_gameport_open;
282         port->trigger = cs461x_gameport_trigger;
283         port->read = cs461x_gameport_read;
284         port->cooked_read = cs461x_gameport_cooked_read;
285
286         gameport_set_name(port, "CS416x");
287         gameport_set_phys(port, "pci%s/gameport0", pci_name(pdev));
288         port->dev.parent = &pdev->dev;
289
290         cs461x_pokeBA0(BA0_JSIO, 0xFF); // ?
291         cs461x_pokeBA0(BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW);
292
293         gameport_register_port(port);
294
295         return 0;
296 }
297
298 static void __devexit cs461x_pci_remove(struct pci_dev *pdev)
299 {
300         cs461x_free(pdev);
301 }
302
303 static struct pci_driver cs461x_pci_driver = {
304         .name =         "CS461x_gameport",
305         .id_table =     cs461x_pci_tbl,
306         .probe =        cs461x_pci_probe,
307         .remove =       __devexit_p(cs461x_pci_remove),
308 };
309
310 static int __init cs461x_init(void)
311 {
312         return pci_register_driver(&cs461x_pci_driver);
313 }
314
315 static void __exit cs461x_exit(void)
316 {
317         pci_unregister_driver(&cs461x_pci_driver);
318 }
319
320 module_init(cs461x_init);
321 module_exit(cs461x_exit);
322