Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.12 322 lines 9.2 kB view raw
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"); 20MODULE_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 120static unsigned long ba0_addr; 121static unsigned int __iomem *ba0; 122 123#ifdef CS461X_FULL_MAP 124static unsigned long ba1_addr; 125static 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 135static void cs461x_poke(unsigned long reg, unsigned int val) 136{ 137 writel(val, &ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]); 138} 139 140static unsigned int cs461x_peek(unsigned long reg) 141{ 142 return readl(&ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]); 143} 144 145#endif 146 147static void cs461x_pokeBA0(unsigned long reg, unsigned int val) 148{ 149 writel(val, &ba0[reg >> 2]); 150} 151 152static unsigned int cs461x_peekBA0(unsigned long reg) 153{ 154 return readl(&ba0[reg >> 2]); 155} 156 157static 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 174static void cs461x_gameport_trigger(struct gameport *gameport) 175{ 176 cs461x_pokeBA0(BA0_JSPT, 0xFF); //outb(gameport->io, 0xFF); 177} 178 179static unsigned char cs461x_gameport_read(struct gameport *gameport) 180{ 181 return cs461x_peekBA0(BA0_JSPT); //inb(gameport->io); 182} 183 184static 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 204static 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 216static 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}; 222MODULE_DEVICE_TABLE(pci, cs461x_pci_tbl); 223 224static 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 298static void __devexit cs461x_pci_remove(struct pci_dev *pdev) 299{ 300 cs461x_free(pdev); 301} 302 303static 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 310static int __init cs461x_init(void) 311{ 312 return pci_register_driver(&cs461x_pci_driver); 313} 314 315static void __exit cs461x_exit(void) 316{ 317 pci_unregister_driver(&cs461x_pci_driver); 318} 319 320module_init(cs461x_init); 321module_exit(cs461x_exit); 322