/drivers/input/gameport/cs461x.c

https://bitbucket.org/evzijst/gittest · C · 322 lines · 235 code · 59 blank · 28 comment · 29 complexity · aa639f5adb08b1f26ec97ed5bcbaa6df MD5 · raw file

  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. Tested on Linux 686 2.4.0-test9, ALSA 0.5.8a and CS4610
  6. */
  7. #include <asm/io.h>
  8. #include <linux/module.h>
  9. #include <linux/ioport.h>
  10. #include <linux/config.h>
  11. #include <linux/init.h>
  12. #include <linux/gameport.h>
  13. #include <linux/slab.h>
  14. #include <linux/pci.h>
  15. MODULE_AUTHOR("Victor Krapivin");
  16. MODULE_LICENSE("GPL");
  17. /*
  18. These options are experimental
  19. #define CS461X_FULL_MAP
  20. */
  21. #ifndef PCI_VENDOR_ID_CIRRUS
  22. #define PCI_VENDOR_ID_CIRRUS 0x1013
  23. #endif
  24. #ifndef PCI_DEVICE_ID_CIRRUS_4610
  25. #define PCI_DEVICE_ID_CIRRUS_4610 0x6001
  26. #endif
  27. #ifndef PCI_DEVICE_ID_CIRRUS_4612
  28. #define PCI_DEVICE_ID_CIRRUS_4612 0x6003
  29. #endif
  30. #ifndef PCI_DEVICE_ID_CIRRUS_4615
  31. #define PCI_DEVICE_ID_CIRRUS_4615 0x6004
  32. #endif
  33. /* Registers */
  34. #define BA0_JSPT 0x00000480
  35. #define BA0_JSCTL 0x00000484
  36. #define BA0_JSC1 0x00000488
  37. #define BA0_JSC2 0x0000048C
  38. #define BA0_JSIO 0x000004A0
  39. /* Bits for JSPT */
  40. #define JSPT_CAX 0x00000001
  41. #define JSPT_CAY 0x00000002
  42. #define JSPT_CBX 0x00000004
  43. #define JSPT_CBY 0x00000008
  44. #define JSPT_BA1 0x00000010
  45. #define JSPT_BA2 0x00000020
  46. #define JSPT_BB1 0x00000040
  47. #define JSPT_BB2 0x00000080
  48. /* Bits for JSCTL */
  49. #define JSCTL_SP_MASK 0x00000003
  50. #define JSCTL_SP_SLOW 0x00000000
  51. #define JSCTL_SP_MEDIUM_SLOW 0x00000001
  52. #define JSCTL_SP_MEDIUM_FAST 0x00000002
  53. #define JSCTL_SP_FAST 0x00000003
  54. #define JSCTL_ARE 0x00000004
  55. /* Data register pairs masks */
  56. #define JSC1_Y1V_MASK 0x0000FFFF
  57. #define JSC1_X1V_MASK 0xFFFF0000
  58. #define JSC1_Y1V_SHIFT 0
  59. #define JSC1_X1V_SHIFT 16
  60. #define JSC2_Y2V_MASK 0x0000FFFF
  61. #define JSC2_X2V_MASK 0xFFFF0000
  62. #define JSC2_Y2V_SHIFT 0
  63. #define JSC2_X2V_SHIFT 16
  64. /* JS GPIO */
  65. #define JSIO_DAX 0x00000001
  66. #define JSIO_DAY 0x00000002
  67. #define JSIO_DBX 0x00000004
  68. #define JSIO_DBY 0x00000008
  69. #define JSIO_AXOE 0x00000010
  70. #define JSIO_AYOE 0x00000020
  71. #define JSIO_BXOE 0x00000040
  72. #define JSIO_BYOE 0x00000080
  73. /*
  74. The card initialization code is obfuscated; the module cs461x
  75. need to be loaded after ALSA modules initialized and something
  76. played on the CS 4610 chip (see sources for details of CS4610
  77. initialization code from ALSA)
  78. */
  79. /* Card specific definitions */
  80. #define CS461X_BA0_SIZE 0x2000
  81. #define CS461X_BA1_DATA0_SIZE 0x3000
  82. #define CS461X_BA1_DATA1_SIZE 0x3800
  83. #define CS461X_BA1_PRG_SIZE 0x7000
  84. #define CS461X_BA1_REG_SIZE 0x0100
  85. #define BA1_SP_DMEM0 0x00000000
  86. #define BA1_SP_DMEM1 0x00010000
  87. #define BA1_SP_PMEM 0x00020000
  88. #define BA1_SP_REG 0x00030000
  89. #define BA1_DWORD_SIZE (13 * 1024 + 512)
  90. #define BA1_MEMORY_COUNT 3
  91. /*
  92. Only one CS461x card is still suppoted; the code requires
  93. redesign to avoid this limitatuion.
  94. */
  95. static unsigned long ba0_addr;
  96. static unsigned int __iomem *ba0;
  97. #ifdef CS461X_FULL_MAP
  98. static unsigned long ba1_addr;
  99. static union ba1_t {
  100. struct {
  101. unsigned int __iomem *data0;
  102. unsigned int __iomem *data1;
  103. unsigned int __iomem *pmem;
  104. unsigned int __iomem *reg;
  105. } name;
  106. unsigned int __iomem *idx[4];
  107. } ba1;
  108. static void cs461x_poke(unsigned long reg, unsigned int val)
  109. {
  110. writel(val, &ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]);
  111. }
  112. static unsigned int cs461x_peek(unsigned long reg)
  113. {
  114. return readl(&ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]);
  115. }
  116. #endif
  117. static void cs461x_pokeBA0(unsigned long reg, unsigned int val)
  118. {
  119. writel(val, &ba0[reg >> 2]);
  120. }
  121. static unsigned int cs461x_peekBA0(unsigned long reg)
  122. {
  123. return readl(&ba0[reg >> 2]);
  124. }
  125. static int cs461x_free(struct pci_dev *pdev)
  126. {
  127. struct gameport *port = pci_get_drvdata(pdev);
  128. if (port)
  129. gameport_unregister_port(port);
  130. if (ba0) iounmap(ba0);
  131. #ifdef CS461X_FULL_MAP
  132. if (ba1.name.data0) iounmap(ba1.name.data0);
  133. if (ba1.name.data1) iounmap(ba1.name.data1);
  134. if (ba1.name.pmem) iounmap(ba1.name.pmem);
  135. if (ba1.name.reg) iounmap(ba1.name.reg);
  136. #endif
  137. return 0;
  138. }
  139. static void cs461x_gameport_trigger(struct gameport *gameport)
  140. {
  141. cs461x_pokeBA0(BA0_JSPT, 0xFF); //outb(gameport->io, 0xFF);
  142. }
  143. static unsigned char cs461x_gameport_read(struct gameport *gameport)
  144. {
  145. return cs461x_peekBA0(BA0_JSPT); //inb(gameport->io);
  146. }
  147. static int cs461x_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
  148. {
  149. unsigned js1, js2, jst;
  150. js1 = cs461x_peekBA0(BA0_JSC1);
  151. js2 = cs461x_peekBA0(BA0_JSC2);
  152. jst = cs461x_peekBA0(BA0_JSPT);
  153. *buttons = (~jst >> 4) & 0x0F;
  154. axes[0] = ((js1 & JSC1_Y1V_MASK) >> JSC1_Y1V_SHIFT) & 0xFFFF;
  155. axes[1] = ((js1 & JSC1_X1V_MASK) >> JSC1_X1V_SHIFT) & 0xFFFF;
  156. axes[2] = ((js2 & JSC2_Y2V_MASK) >> JSC2_Y2V_SHIFT) & 0xFFFF;
  157. axes[3] = ((js2 & JSC2_X2V_MASK) >> JSC2_X2V_SHIFT) & 0xFFFF;
  158. for(jst=0;jst<4;++jst)
  159. if(axes[jst]==0xFFFF) axes[jst] = -1;
  160. return 0;
  161. }
  162. static int cs461x_gameport_open(struct gameport *gameport, int mode)
  163. {
  164. switch (mode) {
  165. case GAMEPORT_MODE_COOKED:
  166. case GAMEPORT_MODE_RAW:
  167. return 0;
  168. default:
  169. return -1;
  170. }
  171. return 0;
  172. }
  173. static struct pci_device_id cs461x_pci_tbl[] = {
  174. { PCI_VENDOR_ID_CIRRUS, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4610 */
  175. { PCI_VENDOR_ID_CIRRUS, 0x6003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4612 */
  176. { PCI_VENDOR_ID_CIRRUS, 0x6005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4615 */
  177. { 0, }
  178. };
  179. MODULE_DEVICE_TABLE(pci, cs461x_pci_tbl);
  180. static int __devinit cs461x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  181. {
  182. int rc;
  183. struct gameport* port;
  184. rc = pci_enable_device(pdev);
  185. if (rc) {
  186. printk(KERN_ERR "cs461x: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n",
  187. pdev->bus->number, pdev->devfn, rc);
  188. return rc;
  189. }
  190. ba0_addr = pci_resource_start(pdev, 0);
  191. #ifdef CS461X_FULL_MAP
  192. ba1_addr = pci_resource_start(pdev, 1);
  193. #endif
  194. if (ba0_addr == 0 || ba0_addr == ~0
  195. #ifdef CS461X_FULL_MAP
  196. || ba1_addr == 0 || ba1_addr == ~0
  197. #endif
  198. ) {
  199. printk(KERN_ERR "cs461x: wrong address - ba0 = 0x%lx\n", ba0_addr);
  200. #ifdef CS461X_FULL_MAP
  201. printk(KERN_ERR "cs461x: wrong address - ba1 = 0x%lx\n", ba1_addr);
  202. #endif
  203. cs461x_free(pdev);
  204. return -ENOMEM;
  205. }
  206. ba0 = ioremap(ba0_addr, CS461X_BA0_SIZE);
  207. #ifdef CS461X_FULL_MAP
  208. ba1.name.data0 = ioremap(ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE);
  209. ba1.name.data1 = ioremap(ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE);
  210. ba1.name.pmem = ioremap(ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE);
  211. ba1.name.reg = ioremap(ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE);
  212. if (ba0 == NULL || ba1.name.data0 == NULL ||
  213. ba1.name.data1 == NULL || ba1.name.pmem == NULL ||
  214. ba1.name.reg == NULL) {
  215. cs461x_free(pdev);
  216. return -ENOMEM;
  217. }
  218. #else
  219. if (ba0 == NULL) {
  220. cs461x_free(pdev);
  221. return -ENOMEM;
  222. }
  223. #endif
  224. if (!(port = gameport_allocate_port())) {
  225. printk(KERN_ERR "cs461x: Memory allocation failed\n");
  226. cs461x_free(pdev);
  227. return -ENOMEM;
  228. }
  229. pci_set_drvdata(pdev, port);
  230. port->open = cs461x_gameport_open;
  231. port->trigger = cs461x_gameport_trigger;
  232. port->read = cs461x_gameport_read;
  233. port->cooked_read = cs461x_gameport_cooked_read;
  234. gameport_set_name(port, "CS416x");
  235. gameport_set_phys(port, "pci%s/gameport0", pci_name(pdev));
  236. port->dev.parent = &pdev->dev;
  237. cs461x_pokeBA0(BA0_JSIO, 0xFF); // ?
  238. cs461x_pokeBA0(BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW);
  239. gameport_register_port(port);
  240. return 0;
  241. }
  242. static void __devexit cs461x_pci_remove(struct pci_dev *pdev)
  243. {
  244. cs461x_free(pdev);
  245. }
  246. static struct pci_driver cs461x_pci_driver = {
  247. .name = "CS461x_gameport",
  248. .id_table = cs461x_pci_tbl,
  249. .probe = cs461x_pci_probe,
  250. .remove = __devexit_p(cs461x_pci_remove),
  251. };
  252. static int __init cs461x_init(void)
  253. {
  254. return pci_register_driver(&cs461x_pci_driver);
  255. }
  256. static void __exit cs461x_exit(void)
  257. {
  258. pci_unregister_driver(&cs461x_pci_driver);
  259. }
  260. module_init(cs461x_init);
  261. module_exit(cs461x_exit);