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 19MODULE_AUTHOR("Victor Krapivin <vik@belcaf.minsk.by>"); 20MODULE_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 122static unsigned long ba0_addr; 123static unsigned int *ba0; 124 125#ifdef CS461X_FULL_MAP 126static unsigned long ba1_addr; 127static 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 137static void cs461x_poke(unsigned long reg, unsigned int val) 138{ 139 ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff] = val; 140} 141 142static unsigned int cs461x_peek(unsigned long reg) 143{ 144 return ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]; 145} 146 147#endif 148 149static void cs461x_pokeBA0(unsigned long reg, unsigned int val) 150{ 151 ba0[reg >> 2] = val; 152} 153 154static unsigned int cs461x_peekBA0(unsigned long reg) 155{ 156 return ba0[reg >> 2]; 157} 158 159static int cs461x_free(struct pci_dev *pdev) 160{ 161 struct gameport *port = pci_get_drvdata(pdev); 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 176static void cs461x_gameport_trigger(struct gameport *gameport) 177{ 178 cs461x_pokeBA0(BA0_JSPT, 0xFF); //outb(gameport->io, 0xFF); 179} 180 181static unsigned char cs461x_gameport_read(struct gameport *gameport) 182{ 183 return cs461x_peekBA0(BA0_JSPT); //inb(gameport->io); 184} 185 186static 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 206static 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 221static 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}; 227MODULE_DEVICE_TABLE(pci, cs461x_pci_tbl); 228 229static 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 pci_set_drvdata(pdev, 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 307static void __devexit cs461x_pci_remove(struct pci_dev *pdev) 308{ 309 cs461x_free(pdev); 310} 311 312static struct pci_driver cs461x_pci_driver = { 313 name: "PCI Gameport", 314 id_table: cs461x_pci_tbl, 315 probe: cs461x_pci_probe, 316 remove: __devexit_p(cs461x_pci_remove), 317}; 318 319int __init js_cs461x_init(void) 320{ 321 return pci_module_init(&cs461x_pci_driver); 322} 323 324void __exit js_cs461x_exit(void) 325{ 326 pci_unregister_driver(&cs461x_pci_driver); 327} 328 329module_init(js_cs461x_init); 330module_exit(js_cs461x_exit); 331 332