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");
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 __iomem *ba0;
123 #ifdef CS461X_FULL_MAP
124 static unsigned long ba1_addr;
127 unsigned int __iomem *data0;
128 unsigned int __iomem *data1;
129 unsigned int __iomem *pmem;
130 unsigned int __iomem *reg;
132 unsigned int __iomem *idx[4];
135 static void cs461x_poke(unsigned long reg, unsigned int val)
137 writel(val, &ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]);
140 static unsigned int cs461x_peek(unsigned long reg)
142 return readl(&ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]);
147 static void cs461x_pokeBA0(unsigned long reg, unsigned int val)
149 writel(val, &ba0[reg >> 2]);
152 static unsigned int cs461x_peekBA0(unsigned long reg)
154 return readl(&ba0[reg >> 2]);
157 static int cs461x_free(struct pci_dev *pdev)
159 struct gameport *port = pci_get_drvdata(pdev);
162 gameport_unregister_port(port);
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);
174 static void cs461x_gameport_trigger(struct gameport *gameport)
176 cs461x_pokeBA0(BA0_JSPT, 0xFF); //outb(gameport->io, 0xFF);
179 static unsigned char cs461x_gameport_read(struct gameport *gameport)
181 return cs461x_peekBA0(BA0_JSPT); //inb(gameport->io);
184 static int cs461x_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
186 unsigned js1, js2, jst;
188 js1 = cs461x_peekBA0(BA0_JSC1);
189 js2 = cs461x_peekBA0(BA0_JSC2);
190 jst = cs461x_peekBA0(BA0_JSPT);
192 *buttons = (~jst >> 4) & 0x0F;
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;
199 for(jst=0;jst<4;++jst)
200 if(axes[jst]==0xFFFF) axes[jst] = -1;
204 static int cs461x_gameport_open(struct gameport *gameport, int mode)
207 case GAMEPORT_MODE_COOKED:
208 case GAMEPORT_MODE_RAW:
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 */
222 MODULE_DEVICE_TABLE(pci, cs461x_pci_tbl);
224 static int __devinit cs461x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
227 struct gameport* port;
229 rc = pci_enable_device(pdev);
231 printk(KERN_ERR "cs461x: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n",
232 pdev->bus->number, pdev->devfn, rc);
236 ba0_addr = pci_resource_start(pdev, 0);
237 #ifdef CS461X_FULL_MAP
238 ba1_addr = pci_resource_start(pdev, 1);
240 if (ba0_addr == 0 || ba0_addr == ~0
241 #ifdef CS461X_FULL_MAP
242 || ba1_addr == 0 || ba1_addr == ~0
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);
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);
260 if (ba0 == NULL || ba1.name.data0 == NULL ||
261 ba1.name.data1 == NULL || ba1.name.pmem == NULL ||
262 ba1.name.reg == NULL) {
273 if (!(port = gameport_allocate_port())) {
274 printk(KERN_ERR "cs461x: Memory allocation failed\n");
279 pci_set_drvdata(pdev, port);
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;
286 gameport_set_name(port, "CS416x");
287 gameport_set_phys(port, "pci%s/gameport0", pci_name(pdev));
288 port->dev.parent = &pdev->dev;
290 cs461x_pokeBA0(BA0_JSIO, 0xFF); // ?
291 cs461x_pokeBA0(BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW);
293 gameport_register_port(port);
298 static void __devexit cs461x_pci_remove(struct pci_dev *pdev)
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),
310 static int __init cs461x_init(void)
312 return pci_register_driver(&cs461x_pci_driver);
315 static void __exit cs461x_exit(void)
317 pci_unregister_driver(&cs461x_pci_driver);
320 module_init(cs461x_init);
321 module_exit(cs461x_exit);