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
6 Tested on Linux 686 2.4.0-test9, ALSA 0.5.8a and CS4610
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>
19 MODULE_AUTHOR("Victor Krapivin <vik@belcaf.minsk.by>");
20 MODULE_LICENSE("GPL");
23 These options are experimental
25 #define CS461X_FULL_MAP
29 #ifndef PCI_VENDOR_ID_CIRRUS
30 #define PCI_VENDOR_ID_CIRRUS 0x1013
32 #ifndef PCI_DEVICE_ID_CIRRUS_4610
33 #define PCI_DEVICE_ID_CIRRUS_4610 0x6001
35 #ifndef PCI_DEVICE_ID_CIRRUS_4612
36 #define PCI_DEVICE_ID_CIRRUS_4612 0x6003
38 #ifndef PCI_DEVICE_ID_CIRRUS_4615
39 #define PCI_DEVICE_ID_CIRRUS_4615 0x6004
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
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
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
70 /* Data register pairs masks */
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
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
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)
99 /* Card specific definitions */
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
107 #define BA1_SP_DMEM0 0x00000000
108 #define BA1_SP_DMEM1 0x00010000
109 #define BA1_SP_PMEM 0x00020000
110 #define BA1_SP_REG 0x00030000
112 #define BA1_DWORD_SIZE (13 * 1024 + 512)
113 #define BA1_MEMORY_COUNT 3
116 Only one CS461x card is still suppoted; the code requires
117 redesign to avoid this limitatuion.
120 static unsigned long ba0_addr
;
121 static unsigned int *ba0
;
123 static char phys
[32];
124 static char name
[] = "CS416x Gameport";
126 #ifdef CS461X_FULL_MAP
127 static unsigned long ba1_addr
;
135 unsigned int *idx
[4];
138 static void cs461x_poke(unsigned long reg
, unsigned int val
)
140 ba1
.idx
[(reg
>> 16) & 3][(reg
>> 2) & 0x3fff] = val
;
143 static unsigned int cs461x_peek(unsigned long reg
)
145 return ba1
.idx
[(reg
>> 16) & 3][(reg
>> 2) & 0x3fff];
150 static void cs461x_pokeBA0(unsigned long reg
, unsigned int val
)
155 static unsigned int cs461x_peekBA0(unsigned long reg
)
157 return ba0
[reg
>> 2];
160 static int cs461x_free(struct pci_dev
*pdev
)
162 struct gameport
*port
= pci_get_drvdata(pdev
);
164 gameport_unregister_port(port
);
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
);
177 static void cs461x_gameport_trigger(struct gameport
*gameport
)
179 cs461x_pokeBA0(BA0_JSPT
, 0xFF); //outb(gameport->io, 0xFF);
182 static unsigned char cs461x_gameport_read(struct gameport
*gameport
)
184 return cs461x_peekBA0(BA0_JSPT
); //inb(gameport->io);
187 static int cs461x_gameport_cooked_read(struct gameport
*gameport
, int *axes
, int *buttons
)
189 unsigned js1
, js2
, jst
;
191 js1
= cs461x_peekBA0(BA0_JSC1
);
192 js2
= cs461x_peekBA0(BA0_JSC2
);
193 jst
= cs461x_peekBA0(BA0_JSPT
);
195 *buttons
= (~jst
>> 4) & 0x0F;
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;
202 for(jst
=0;jst
<4;++jst
)
203 if(axes
[jst
]==0xFFFF) axes
[jst
] = -1;
207 static int cs461x_gameport_open(struct gameport
*gameport
, int mode
)
210 case GAMEPORT_MODE_COOKED
:
211 case GAMEPORT_MODE_RAW
:
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 */
225 MODULE_DEVICE_TABLE(pci
, cs461x_pci_tbl
);
227 static int __devinit
cs461x_pci_probe(struct pci_dev
*pdev
, const struct pci_device_id
*ent
)
230 struct gameport
* port
;
232 rc
= pci_enable_device(pdev
);
234 printk(KERN_ERR
"cs461x: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n",
235 pdev
->bus
->number
, pdev
->devfn
, rc
);
239 ba0_addr
= pci_resource_start(pdev
, 0);
240 #ifdef CS461X_FULL_MAP
241 ba1_addr
= pci_resource_start(pdev
, 1);
243 if (ba0_addr
== 0 || ba0_addr
== ~0
244 #ifdef CS461X_FULL_MAP
245 || ba1_addr
== 0 || ba1_addr
== ~0
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
);
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
);
263 if (ba0
== NULL
|| ba1
.name
.data0
== NULL
||
264 ba1
.name
.data1
== NULL
|| ba1
.name
.pmem
== NULL
||
265 ba1
.name
.reg
== NULL
) {
276 if (!(port
= kmalloc(sizeof(struct gameport
), GFP_KERNEL
))) {
277 printk(KERN_ERR
"Memory allocation failed.\n");
281 memset(port
, 0, sizeof(struct gameport
));
283 pci_set_drvdata(pdev
, port
);
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
;
290 sprintf(phys
, "pci%s/gameport0", pci_name(pdev
));
294 port
->id
.bustype
= BUS_PCI
;
295 port
->id
.vendor
= pdev
->vendor
;
296 port
->id
.product
= pdev
->device
;
298 cs461x_pokeBA0(BA0_JSIO
, 0xFF); // ?
299 cs461x_pokeBA0(BA0_JSCTL
, JSCTL_SP_MEDIUM_SLOW
);
301 gameport_register_port(port
);
303 printk(KERN_INFO
"gameport: %s on pci%s speed %d kHz\n",
304 name
, pci_name(pdev
), port
->speed
);
309 static void __devexit
cs461x_pci_remove(struct pci_dev
*pdev
)
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
),
321 int __init
cs461x_init(void)
323 return pci_module_init(&cs461x_pci_driver
);
326 void __exit
cs461x_exit(void)
328 pci_unregister_driver(&cs461x_pci_driver
);
331 module_init(cs461x_init
);
332 module_exit(cs461x_exit
);