opl3sa.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. /*
  2. * sound/opl3sa.c
  3. *
  4. * Low level driver for Yamaha YMF701B aka OPL3-SA chip
  5. *
  6. *
  7. *
  8. * Copyright (C) by Hannu Savolainen 1993-1997
  9. *
  10. * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  11. * Version 2 (June 1991). See the "COPYING" file distributed with this software
  12. * for more info.
  13. *
  14. * Changes:
  15. * Alan Cox Modularisation
  16. * Christoph Hellwig Adapted to module_init/module_exit
  17. * Arnaldo C. de Melo got rid of attach_uart401
  18. *
  19. * FIXME:
  20. * Check for install of mpu etc is wrong, should check result of the mss stuff
  21. */
  22. #include <linux/init.h>
  23. #include <linux/module.h>
  24. #include <linux/spinlock.h>
  25. #undef SB_OK
  26. #include "sound_config.h"
  27. #include "ad1848.h"
  28. #include "mpu401.h"
  29. #ifdef SB_OK
  30. #include "sb.h"
  31. static int sb_initialized;
  32. #endif
  33. static DEFINE_SPINLOCK(lock);
  34. static unsigned char opl3sa_read(int addr)
  35. {
  36. unsigned long flags;
  37. unsigned char tmp;
  38. spin_lock_irqsave(&lock,flags);
  39. outb((0x1d), 0xf86); /* password */
  40. outb(((unsigned char) addr), 0xf86); /* address */
  41. tmp = inb(0xf87); /* data */
  42. spin_unlock_irqrestore(&lock,flags);
  43. return tmp;
  44. }
  45. static void opl3sa_write(int addr, int data)
  46. {
  47. unsigned long flags;
  48. spin_lock_irqsave(&lock,flags);
  49. outb((0x1d), 0xf86); /* password */
  50. outb(((unsigned char) addr), 0xf86); /* address */
  51. outb(((unsigned char) data), 0xf87); /* data */
  52. spin_unlock_irqrestore(&lock,flags);
  53. }
  54. static int __init opl3sa_detect(void)
  55. {
  56. int tmp;
  57. if (((tmp = opl3sa_read(0x01)) & 0xc4) != 0x04)
  58. {
  59. DDB(printk("OPL3-SA detect error 1 (%x)\n", opl3sa_read(0x01)));
  60. /* return 0; */
  61. }
  62. /*
  63. * Check that the password feature has any effect
  64. */
  65. if (inb(0xf87) == tmp)
  66. {
  67. DDB(printk("OPL3-SA detect failed 2 (%x/%x)\n", tmp, inb(0xf87)));
  68. return 0;
  69. }
  70. tmp = (opl3sa_read(0x04) & 0xe0) >> 5;
  71. if (tmp != 0 && tmp != 1)
  72. {
  73. DDB(printk("OPL3-SA detect failed 3 (%d)\n", tmp));
  74. return 0;
  75. }
  76. DDB(printk("OPL3-SA mode %x detected\n", tmp));
  77. opl3sa_write(0x01, 0x00); /* Disable MSS */
  78. opl3sa_write(0x02, 0x00); /* Disable SB */
  79. opl3sa_write(0x03, 0x00); /* Disable MPU */
  80. return 1;
  81. }
  82. /*
  83. * Probe and attach routines for the Windows Sound System mode of
  84. * OPL3-SA
  85. */
  86. static int __init probe_opl3sa_wss(struct address_info *hw_config, struct resource *ports)
  87. {
  88. unsigned char tmp = 0x24; /* WSS enable */
  89. /*
  90. * Check if the IO port returns valid signature. The original MS Sound
  91. * system returns 0x04 while some cards (OPL3-SA for example)
  92. * return 0x00.
  93. */
  94. if (!opl3sa_detect())
  95. {
  96. printk(KERN_ERR "OSS: OPL3-SA chip not found\n");
  97. return 0;
  98. }
  99. switch (hw_config->io_base)
  100. {
  101. case 0x530:
  102. tmp |= 0x00;
  103. break;
  104. case 0xe80:
  105. tmp |= 0x08;
  106. break;
  107. case 0xf40:
  108. tmp |= 0x10;
  109. break;
  110. case 0x604:
  111. tmp |= 0x18;
  112. break;
  113. default:
  114. printk(KERN_ERR "OSS: Unsupported OPL3-SA/WSS base %x\n", hw_config->io_base);
  115. return 0;
  116. }
  117. opl3sa_write(0x01, tmp); /* WSS setup register */
  118. return probe_ms_sound(hw_config, ports);
  119. }
  120. static void __init attach_opl3sa_wss(struct address_info *hw_config, struct resource *ports)
  121. {
  122. int nm = num_mixers;
  123. /* FIXME */
  124. attach_ms_sound(hw_config, ports, THIS_MODULE);
  125. if (num_mixers > nm) /* A mixer was installed */
  126. {
  127. AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_CD);
  128. AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH);
  129. AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE);
  130. }
  131. }
  132. static int __init probe_opl3sa_mpu(struct address_info *hw_config)
  133. {
  134. unsigned char conf;
  135. static signed char irq_bits[] = {
  136. -1, -1, -1, -1, -1, 1, -1, 2, -1, 3, 4
  137. };
  138. if (hw_config->irq > 10)
  139. {
  140. printk(KERN_ERR "OPL3-SA: Bad MPU IRQ %d\n", hw_config->irq);
  141. return 0;
  142. }
  143. if (irq_bits[hw_config->irq] == -1)
  144. {
  145. printk(KERN_ERR "OPL3-SA: Bad MPU IRQ %d\n", hw_config->irq);
  146. return 0;
  147. }
  148. switch (hw_config->io_base)
  149. {
  150. case 0x330:
  151. conf = 0x00;
  152. break;
  153. case 0x332:
  154. conf = 0x20;
  155. break;
  156. case 0x334:
  157. conf = 0x40;
  158. break;
  159. case 0x300:
  160. conf = 0x60;
  161. break;
  162. default:
  163. return 0; /* Invalid port */
  164. }
  165. conf |= 0x83; /* MPU & OPL3 (synth) & game port enable */
  166. conf |= irq_bits[hw_config->irq] << 2;
  167. opl3sa_write(0x03, conf);
  168. hw_config->name = "OPL3-SA (MPU401)";
  169. return probe_uart401(hw_config, THIS_MODULE);
  170. }
  171. static void __exit unload_opl3sa_wss(struct address_info *hw_config)
  172. {
  173. int dma2 = hw_config->dma2;
  174. if (dma2 == -1)
  175. dma2 = hw_config->dma;
  176. release_region(0xf86, 2);
  177. release_region(hw_config->io_base, 4);
  178. ad1848_unload(hw_config->io_base + 4,
  179. hw_config->irq,
  180. hw_config->dma,
  181. dma2,
  182. 0);
  183. sound_unload_audiodev(hw_config->slots[0]);
  184. }
  185. static inline void __exit unload_opl3sa_mpu(struct address_info *hw_config)
  186. {
  187. unload_uart401(hw_config);
  188. }
  189. #ifdef SB_OK
  190. static inline void __exit unload_opl3sa_sb(struct address_info *hw_config)
  191. {
  192. sb_dsp_unload(hw_config);
  193. }
  194. #endif
  195. static int found_mpu;
  196. static struct address_info cfg;
  197. static struct address_info cfg_mpu;
  198. static int __initdata io = -1;
  199. static int __initdata irq = -1;
  200. static int __initdata dma = -1;
  201. static int __initdata dma2 = -1;
  202. static int __initdata mpu_io = -1;
  203. static int __initdata mpu_irq = -1;
  204. module_param(io, int, 0);
  205. module_param(irq, int, 0);
  206. module_param(dma, int, 0);
  207. module_param(dma2, int, 0);
  208. module_param(mpu_io, int, 0);
  209. module_param(mpu_irq, int, 0);
  210. static int __init init_opl3sa(void)
  211. {
  212. struct resource *ports;
  213. if (io == -1 || irq == -1 || dma == -1) {
  214. printk(KERN_ERR "opl3sa: dma, irq and io must be set.\n");
  215. return -EINVAL;
  216. }
  217. cfg.io_base = io;
  218. cfg.irq = irq;
  219. cfg.dma = dma;
  220. cfg.dma2 = dma2;
  221. cfg_mpu.io_base = mpu_io;
  222. cfg_mpu.irq = mpu_irq;
  223. ports = request_region(io + 4, 4, "ad1848");
  224. if (!ports)
  225. return -EBUSY;
  226. if (!request_region(0xf86, 2, "OPL3-SA"))/* Control port is busy */ {
  227. release_region(io + 4, 4);
  228. return 0;
  229. }
  230. if (!request_region(io, 4, "WSS config")) {
  231. release_region(0x86, 2);
  232. release_region(io + 4, 4);
  233. return 0;
  234. }
  235. if (probe_opl3sa_wss(&cfg, ports) == 0) {
  236. release_region(0xf86, 2);
  237. release_region(io, 4);
  238. release_region(io + 4, 4);
  239. return -ENODEV;
  240. }
  241. found_mpu=probe_opl3sa_mpu(&cfg_mpu);
  242. attach_opl3sa_wss(&cfg, ports);
  243. return 0;
  244. }
  245. static void __exit cleanup_opl3sa(void)
  246. {
  247. if(found_mpu)
  248. unload_opl3sa_mpu(&cfg_mpu);
  249. unload_opl3sa_wss(&cfg);
  250. }
  251. module_init(init_opl3sa);
  252. module_exit(cleanup_opl3sa);
  253. #ifndef MODULE
  254. static int __init setup_opl3sa(char *str)
  255. {
  256. /* io, irq, dma, dma2, mpu_io, mpu_irq */
  257. int ints[7];
  258. str = get_options(str, ARRAY_SIZE(ints), ints);
  259. io = ints[1];
  260. irq = ints[2];
  261. dma = ints[3];
  262. dma2 = ints[4];
  263. mpu_io = ints[5];
  264. mpu_irq = ints[6];
  265. return 1;
  266. }
  267. __setup("opl3sa=", setup_opl3sa);
  268. #endif
  269. MODULE_LICENSE("GPL");