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

Linux/Unix编程

开发平台:

Unix_Linux

  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. #undef  SB_OK
  25. #include "sound_config.h"
  26. #include "ad1848.h"
  27. #include "mpu401.h"
  28. #ifdef SB_OK
  29. #include "sb.h"
  30. static int sb_initialized = 0;
  31. #endif
  32. static int kilroy_was_here = 0; /* Don't detect twice */
  33. static int mpu_initialized = 0;
  34. static int *opl3sa_osp = NULL;
  35. static unsigned char opl3sa_read(int addr)
  36. {
  37. unsigned long flags;
  38. unsigned char tmp;
  39. save_flags(flags);
  40. cli();
  41. outb((0x1d), 0xf86); /* password */
  42. outb(((unsigned char) addr), 0xf86); /* address */
  43. tmp = inb(0xf87); /* data */
  44. restore_flags(flags);
  45. return tmp;
  46. }
  47. static void opl3sa_write(int addr, int data)
  48. {
  49. unsigned long flags;
  50. save_flags(flags);
  51. cli();
  52. outb((0x1d), 0xf86); /* password */
  53. outb(((unsigned char) addr), 0xf86); /* address */
  54. outb(((unsigned char) data), 0xf87); /* data */
  55. restore_flags(flags);
  56. }
  57. static int __init opl3sa_detect(void)
  58. {
  59. int tmp;
  60. if (((tmp = opl3sa_read(0x01)) & 0xc4) != 0x04)
  61. {
  62. DDB(printk("OPL3-SA detect error 1 (%x)n", opl3sa_read(0x01)));
  63. /* return 0; */
  64. }
  65. /*
  66.  * Check that the password feature has any effect
  67.  */
  68. if (inb(0xf87) == tmp)
  69. {
  70. DDB(printk("OPL3-SA detect failed 2 (%x/%x)n", tmp, inb(0xf87)));
  71. return 0;
  72. }
  73. tmp = (opl3sa_read(0x04) & 0xe0) >> 5;
  74. if (tmp != 0 && tmp != 1)
  75. {
  76. DDB(printk("OPL3-SA detect failed 3 (%d)n", tmp));
  77. return 0;
  78. }
  79. DDB(printk("OPL3-SA mode %x detectedn", tmp));
  80. opl3sa_write(0x01, 0x00); /* Disable MSS */
  81. opl3sa_write(0x02, 0x00); /* Disable SB */
  82. opl3sa_write(0x03, 0x00); /* Disable MPU */
  83. return 1;
  84. }
  85. /*
  86.  *    Probe and attach routines for the Windows Sound System mode of
  87.  *     OPL3-SA
  88.  */
  89. static int __init probe_opl3sa_wss(struct address_info *hw_config)
  90. {
  91. int ret;
  92. unsigned char tmp = 0x24; /* WSS enable */
  93. if (check_region(0xf86, 2)) /* Control port is busy */
  94. return 0;
  95. /*
  96.  * Check if the IO port returns valid signature. The original MS Sound
  97.  * system returns 0x04 while some cards (OPL3-SA for example)
  98.  * return 0x00.
  99.  */
  100. if (check_region(hw_config->io_base, 8))
  101. {
  102. printk(KERN_ERR "OPL3-SA: MSS I/O port conflict (%x)n", hw_config->io_base);
  103. return 0;
  104. }
  105. opl3sa_osp = hw_config->osp;
  106. if (!opl3sa_detect())
  107. {
  108. printk(KERN_ERR "OSS: OPL3-SA chip not foundn");
  109. return 0;
  110. }
  111. switch (hw_config->io_base)
  112. {
  113. case 0x530:
  114. tmp |= 0x00;
  115. break;
  116. case 0xe80:
  117. tmp |= 0x08;
  118. break;
  119. case 0xf40:
  120. tmp |= 0x10;
  121. break;
  122. case 0x604:
  123. tmp |= 0x18;
  124. break;
  125. default:
  126. printk(KERN_ERR "OSS: Unsupported OPL3-SA/WSS base %xn", hw_config->io_base);
  127.   return 0;
  128. }
  129. opl3sa_write(0x01, tmp); /* WSS setup register */
  130. kilroy_was_here = 1;
  131. ret = probe_ms_sound(hw_config);
  132. if (ret)
  133. request_region(0xf86, 2, "OPL3-SA");
  134. return ret;
  135. }
  136. static void __init attach_opl3sa_wss(struct address_info *hw_config)
  137. {
  138. int nm = num_mixers;
  139. /* FIXME */
  140. attach_ms_sound(hw_config, THIS_MODULE);
  141. if (num_mixers > nm) /* A mixer was installed */
  142. {
  143. AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_CD);
  144. AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH);
  145. AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE);
  146. }
  147. }
  148. static int __init probe_opl3sa_mpu(struct address_info *hw_config)
  149. {
  150. unsigned char conf;
  151. static signed char irq_bits[] = {
  152. -1, -1, -1, -1, -1, 1, -1, 2, -1, 3, 4
  153. };
  154. if (!kilroy_was_here)
  155. return 0; /* OPL3-SA has not been detected earlier */
  156. if (mpu_initialized)
  157. {
  158. DDB(printk("OPL3-SA: MPU mode already initializedn"));
  159. return 0;
  160. }
  161. if (hw_config->irq > 10)
  162. {
  163. printk(KERN_ERR "OPL3-SA: Bad MPU IRQ %dn", hw_config->irq);
  164. return 0;
  165. }
  166. if (irq_bits[hw_config->irq] == -1)
  167. {
  168. printk(KERN_ERR "OPL3-SA: Bad MPU IRQ %dn", hw_config->irq);
  169. return 0;
  170. }
  171. switch (hw_config->io_base)
  172. {
  173. case 0x330:
  174. conf = 0x00;
  175. break;
  176. case 0x332:
  177. conf = 0x20;
  178. break;
  179. case 0x334:
  180. conf = 0x40;
  181. break;
  182. case 0x300:
  183. conf = 0x60;
  184. break;
  185. default:
  186. return 0; /* Invalid port */
  187. }
  188. conf |= 0x83; /* MPU & OPL3 (synth) & game port enable */
  189. conf |= irq_bits[hw_config->irq] << 2;
  190. opl3sa_write(0x03, conf);
  191. mpu_initialized = 1;
  192. hw_config->name = "OPL3-SA (MPU401)";
  193. return probe_uart401(hw_config, THIS_MODULE);
  194. }
  195. static void __exit unload_opl3sa_wss(struct address_info *hw_config)
  196. {
  197. int dma2 = hw_config->dma2;
  198. if (dma2 == -1)
  199. dma2 = hw_config->dma;
  200. release_region(0xf86, 2);
  201. release_region(hw_config->io_base, 4);
  202. ad1848_unload(hw_config->io_base + 4,
  203.       hw_config->irq,
  204.       hw_config->dma,
  205.       dma2,
  206.       0);
  207. sound_unload_audiodev(hw_config->slots[0]);
  208. }
  209. static inline void __exit unload_opl3sa_mpu(struct address_info *hw_config)
  210. {
  211. unload_uart401(hw_config);
  212. }
  213. #ifdef SB_OK
  214. static inline void __exit unload_opl3sa_sb(struct address_info *hw_config)
  215. {
  216. sb_dsp_unload(hw_config);
  217. }
  218. #endif
  219. static int found_mpu;
  220. static struct address_info cfg;
  221. static struct address_info cfg_mpu;
  222. static int __initdata io = -1;
  223. static int __initdata irq = -1;
  224. static int __initdata dma = -1;
  225. static int __initdata dma2 = -1;
  226. static int __initdata mpu_io = -1;
  227. static int __initdata mpu_irq = -1;
  228. MODULE_PARM(io,"i");
  229. MODULE_PARM(irq,"i");
  230. MODULE_PARM(dma,"i");
  231. MODULE_PARM(dma2,"i");
  232. MODULE_PARM(mpu_io,"i");
  233. MODULE_PARM(mpu_irq,"i");
  234. static int __init init_opl3sa(void)
  235. {
  236. if (io == -1 || irq == -1 || dma == -1) {
  237. printk(KERN_ERR "opl3sa: dma, irq and io must be set.n");
  238. return -EINVAL;
  239. }
  240. cfg.io_base = io;
  241. cfg.irq = irq;
  242. cfg.dma = dma;
  243. cfg.dma2 = dma2;
  244. cfg_mpu.io_base = mpu_io;
  245. cfg_mpu.irq = mpu_irq;
  246. if (probe_opl3sa_wss(&cfg) == 0)
  247. return -ENODEV;
  248. found_mpu=probe_opl3sa_mpu(&cfg_mpu);
  249. attach_opl3sa_wss(&cfg);
  250. return 0;
  251. }
  252. static void __exit cleanup_opl3sa(void)
  253. {
  254. if(found_mpu)
  255. unload_opl3sa_mpu(&cfg_mpu);
  256. unload_opl3sa_wss(&cfg);
  257. }
  258. module_init(init_opl3sa);
  259. module_exit(cleanup_opl3sa);
  260. #ifndef MODULE
  261. static int __init setup_opl3sa(char *str)
  262. {
  263. /* io, irq, dma, dma2, mpu_io, mpu_irq */
  264. int ints[7];
  265. str = get_options(str, ARRAY_SIZE(ints), ints);
  266. io = ints[1];
  267. irq = ints[2];
  268. dma = ints[3];
  269. dma2 = ints[4];
  270. mpu_io = ints[5];
  271. mpu_irq = ints[6];
  272. return 1;
  273. }
  274. __setup("opl3sa=", setup_opl3sa);
  275. #endif
  276. MODULE_LICENSE("GPL");