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