cs461x.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:9k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

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