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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * sound/maui.c
  3.  *
  4.  * The low level driver for Turtle Beach Maui and Tropez.
  5.  *
  6.  *
  7.  * Copyright (C) by Hannu Savolainen 1993-1997
  8.  *
  9.  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  10.  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  11.  * for more info.
  12.  *
  13.  * Changes:
  14.  * Alan Cox General clean up, use kernel IRQ 
  15.  * system
  16.  * Christoph Hellwig Adapted to module_init/module_exit
  17.  * Bartlomiej Zolnierkiewicz
  18.  * Added __init to download_code()
  19.  *
  20.  * Status:
  21.  * Andrew J. Kroll Tested 06/01/1999 with:
  22.  * * OSWF.MOT File Version: 1.15
  23.  * * OSWF.MOT File Dated: 09/12/94
  24.  * * Older versions will cause problems.
  25.  */
  26. #include <linux/config.h>
  27. #include <linux/module.h>
  28. #include <linux/init.h>
  29. #define USE_SEQ_MACROS
  30. #define USE_SIMPLE_MACROS
  31. #include "sound_config.h"
  32. #include "sound_firmware.h"
  33. #include "mpu401.h"
  34. static int      maui_base = 0x330;
  35. static volatile int irq_ok = 0;
  36. static int     *maui_osp;
  37. #define HOST_DATA_PORT (maui_base + 2)
  38. #define HOST_STAT_PORT (maui_base + 3)
  39. #define HOST_CTRL_PORT (maui_base + 3)
  40. #define STAT_TX_INTR 0x40
  41. #define STAT_TX_AVAIL 0x20
  42. #define STAT_TX_IENA 0x10
  43. #define STAT_RX_INTR 0x04
  44. #define STAT_RX_AVAIL 0x02
  45. #define STAT_RX_IENA 0x01
  46. static int      (*orig_load_patch) (int dev, int format, const char *addr,
  47.       int offs, int count, int pmgr_flag) = NULL;
  48. #include "maui_boot.h"
  49. static int maui_wait(int mask)
  50. {
  51. int i;
  52. /*
  53.  * Perform a short initial wait without sleeping
  54.  */
  55. for (i = 0; i < 100; i++)
  56. if (inb(HOST_STAT_PORT) & mask)
  57. return 1;
  58. /*
  59.  * Wait up to 15 seconds with sleeping
  60.  */
  61. for (i = 0; i < 150; i++) {
  62. if (inb(HOST_STAT_PORT) & mask)
  63. return 1;
  64. current->state = TASK_INTERRUPTIBLE;
  65. schedule_timeout(HZ / 10);
  66. if (signal_pending(current))
  67. return 0;
  68. }
  69. return 0;
  70. }
  71. static int maui_read(void)
  72. {
  73. if (maui_wait(STAT_RX_AVAIL))
  74. return inb(HOST_DATA_PORT);
  75. return -1;
  76. }
  77. static int maui_write(unsigned char data)
  78. {
  79. if (maui_wait(STAT_TX_AVAIL)) {
  80. outb((data), HOST_DATA_PORT);
  81. return 1;
  82. }
  83. printk(KERN_WARNING "Maui: Write timeoutn");
  84. return 0;
  85. }
  86. static void mauiintr(int irq, void *dev_id, struct pt_regs *dummy)
  87. {
  88. irq_ok = 1;
  89. }
  90. static int __init download_code(void)
  91. {
  92. int i, lines = 0;
  93. int eol_seen = 0, done = 0;
  94. int skip = 1;
  95. printk(KERN_INFO "Code download (%d bytes): ", maui_osLen);
  96. for (i = 0; i < maui_osLen; i++) {
  97. if (maui_os[i] != 'r') {
  98. if (!skip || (maui_os[i] == 'S' && (i == 0 || maui_os[i - 1] == 'n'))) {
  99. skip = 0;
  100. if (maui_os[i] == 'n')
  101. eol_seen = skip = 1;
  102. else if (maui_os[i] == 'S') {
  103. if (maui_os[i + 1] == '8')
  104. done = 1;
  105. if (!maui_write(0xF1))
  106. goto failure;
  107. if (!maui_write('S'))
  108. goto failure;
  109. } else {
  110. if (!maui_write(maui_os[i]))
  111. goto failure;
  112. }
  113. if (eol_seen) {
  114. int c = 0;
  115. int n;
  116. eol_seen = 0;
  117. for (n = 0; n < 2; n++) {
  118. if (maui_wait(STAT_RX_AVAIL)) {
  119. c = inb(HOST_DATA_PORT);
  120. break;
  121. }
  122. }
  123. if (c != 0x80) {
  124. printk("Download not acknowledgedn");
  125. return 0;
  126. }
  127. else if (!(lines++ % 10))
  128. printk(".");
  129. if (done) {
  130. printk("n");
  131. printk(KERN_INFO "Download completen");
  132. return 1;
  133. }
  134. }
  135. }
  136. }
  137. }
  138. failure:
  139. printk("n");
  140. printk(KERN_ERR "Download failed!!!n");
  141. return 0;
  142. }
  143. static int __init maui_init(int irq)
  144. {
  145. unsigned char bits;
  146. switch (irq) {
  147. case 9:
  148. bits = 0x00;
  149. break;
  150. case 5:
  151. bits = 0x08;
  152. break;
  153. case 12:
  154. bits = 0x10;
  155. break;
  156. case 15:
  157. bits = 0x18;
  158. break;
  159. default:
  160. printk(KERN_ERR "Maui: Invalid IRQ %dn", irq);
  161. return 0;
  162. }
  163. outb((0x00), HOST_CTRL_PORT); /* Reset */
  164. outb((bits), HOST_DATA_PORT); /* Set the IRQ bits */
  165. outb((bits | 0x80), HOST_DATA_PORT); /* Set the IRQ bits again? */
  166. outb((0x80), HOST_CTRL_PORT); /* Leave reset */
  167. outb((0x80), HOST_CTRL_PORT); /* Leave reset */
  168. outb((0xD0), HOST_CTRL_PORT); /* Cause interrupt */
  169. #ifdef CONFIG_SMP
  170. {
  171. int i;
  172. for (i = 0; i < 1000000 && !irq_ok; i++)
  173. ;
  174. if (!irq_ok)
  175. return 0;
  176. }
  177. #endif
  178. outb((0x80), HOST_CTRL_PORT); /* Leave reset */
  179. printk(KERN_INFO "Turtle Beach Maui initializationn");
  180. if (!download_code())
  181. return 0;
  182. outb((0xE0), HOST_CTRL_PORT); /* Normal operation */
  183. /* Select mpu401 mode */
  184. maui_write(0xf0);
  185. maui_write(1);
  186. if (maui_read() != 0x80) {
  187. maui_write(0xf0);
  188. maui_write(1);
  189. if (maui_read() != 0x80)
  190. printk(KERN_ERR "Maui didn't acknowledge set HW mode commandn");
  191. }
  192. printk(KERN_INFO "Maui initialized OKn");
  193. return 1;
  194. }
  195. static int maui_short_wait(int mask) {
  196. int i;
  197. for (i = 0; i < 1000; i++) {
  198. if (inb(HOST_STAT_PORT) & mask) {
  199. return 1;
  200. }
  201. }
  202. return 0;
  203. }
  204. static int maui_load_patch(int dev, int format, const char *addr,
  205. int offs, int count, int pmgr_flag)
  206. {
  207. struct sysex_info header;
  208. unsigned long left, src_offs;
  209. int hdr_size = (unsigned long) &header.data[0] - (unsigned long) &header;
  210. int i;
  211. if (format == SYSEX_PATCH) /* Handled by midi_synth.c */
  212. return orig_load_patch(dev, format, addr, offs, count, pmgr_flag);
  213. if (format != MAUI_PATCH)
  214. {
  215.   printk(KERN_WARNING "Maui: Unknown patch formatn");
  216. }
  217. if (count < hdr_size) {
  218. /*   printk("Maui error: Patch header too shortn");*/
  219.   return -EINVAL;
  220. }
  221. count -= hdr_size;
  222. /*
  223.  * Copy the header from user space but ignore the first bytes which have
  224.  * been transferred already.
  225.  */
  226. if(copy_from_user(&((char *) &header)[offs], &(addr)[offs], hdr_size - offs))
  227. return -EFAULT;
  228. if (count < header.len) {
  229.   printk(KERN_ERR "Maui warning: Host command record too short (%d<%d)n", count, (int) header.len);
  230.   header.len = count;
  231. }
  232. left = header.len;
  233. src_offs = 0;
  234. for (i = 0; i < left; i++) {
  235. unsigned char   data;
  236. if(get_user(*(unsigned char *) &data, (unsigned char *) &((addr)[hdr_size + i])))
  237. return -EFAULT;
  238. if (i == 0 && !(data & 0x80))
  239. return -EINVAL;
  240. if (maui_write(data) == -1)
  241. return -EIO;
  242. }
  243. if ((i = maui_read()) != 0x80) {
  244. if (i != -1)
  245. printk("Maui: Error status %02xn", i);
  246. return -EIO;
  247. }
  248. return 0;
  249. }
  250. static int __init probe_maui(struct address_info *hw_config)
  251. {
  252. int i;
  253. int tmp1, tmp2, ret;
  254. if (check_region(hw_config->io_base, 8))
  255. return 0;
  256. maui_base = hw_config->io_base;
  257. maui_osp = hw_config->osp;
  258. if (request_irq(hw_config->irq, mauiintr, 0, "Maui", NULL) < 0)
  259. return 0;
  260. /*
  261.  * Initialize the processor if necessary
  262.  */
  263. if (maui_osLen > 0) {
  264. if (!(inb(HOST_STAT_PORT) & STAT_TX_AVAIL) ||
  265. !maui_write(0x9F) || /* Report firmware version */
  266. !maui_short_wait(STAT_RX_AVAIL) ||
  267. maui_read() == -1 || maui_read() == -1)
  268. if (!maui_init(hw_config->irq)) {
  269. free_irq(hw_config->irq, NULL);
  270. return 0;
  271. }
  272. }
  273. if (!maui_write(0xCF)) /* Report hardware version */ {
  274. printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)n");
  275. free_irq(hw_config->irq, NULL);
  276. return 0;
  277. }
  278. if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1) {
  279. printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)n");
  280. free_irq(hw_config->irq, NULL);
  281. return 0;
  282. }
  283. if (tmp1 == 0xff || tmp2 == 0xff) {
  284. free_irq(hw_config->irq, NULL);
  285. return 0;
  286. }
  287. printk(KERN_DEBUG "WaveFront hardware version %d.%dn", tmp1, tmp2);
  288. if (!maui_write(0x9F)) /* Report firmware version */
  289. return 0;
  290. if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1)
  291. return 0;
  292. printk(KERN_DEBUG "WaveFront firmware version %d.%dn", tmp1, tmp2);
  293. if (!maui_write(0x85)) /* Report free DRAM */
  294. return 0;
  295. tmp1 = 0;
  296. for (i = 0; i < 4; i++) {
  297. tmp1 |= maui_read() << (7 * i);
  298. }
  299. printk(KERN_DEBUG "Available DRAM %dkn", tmp1 / 1024);
  300. for (i = 0; i < 1000; i++)
  301. if (probe_mpu401(hw_config))
  302. break;
  303. ret = probe_mpu401(hw_config);
  304. if (ret)
  305. request_region(hw_config->io_base + 2, 6, "Maui");
  306. return ret;
  307. }
  308. static void __init attach_maui(struct address_info *hw_config)
  309. {
  310. int this_dev;
  311. conf_printf("Maui", hw_config);
  312. hw_config->irq *= -1;
  313. hw_config->name = "Maui";
  314. attach_mpu401(hw_config, THIS_MODULE);
  315. if (hw_config->slots[1] != -1) /* The MPU401 driver installed itself */ {
  316. struct synth_operations *synth;
  317. this_dev = hw_config->slots[1];
  318. /*
  319.  * Intercept patch loading calls so that they can be handled
  320.  * by the Maui driver.
  321.  */
  322. synth = midi_devs[this_dev]->converter;
  323. synth->id = "MAUI";
  324. if (synth != NULL) {
  325. orig_load_patch = synth->load_patch;
  326. synth->load_patch = &maui_load_patch;
  327. } else
  328. printk(KERN_ERR "Maui: Can't install patch loadern");
  329. }
  330. }
  331. static void __exit unload_maui(struct address_info *hw_config)
  332. {
  333. int irq = hw_config->irq;
  334. release_region(hw_config->io_base + 2, 6);
  335. unload_mpu401(hw_config);
  336. if (irq < 0)
  337. irq = -irq;
  338. if (irq > 0)
  339. free_irq(irq, NULL);
  340. }
  341. static int fw_load = 0;
  342. static struct address_info cfg;
  343. static int __initdata io = -1;
  344. static int __initdata irq = -1;
  345. MODULE_PARM(io,"i");
  346. MODULE_PARM(irq,"i");
  347. /*
  348.  * Install a Maui card. Needs mpu401 loaded already.
  349.  */
  350. static int __init init_maui(void)
  351. {
  352. printk(KERN_INFO "Turtle beach Maui and Tropez driver, Copyright (C) by Hannu Savolainen 1993-1996n");
  353. cfg.io_base = io;
  354. cfg.irq = irq;
  355. if (cfg.io_base == -1 || cfg.irq == -1) {
  356. printk(KERN_INFO "maui: irq and io must be set.n");
  357. return -EINVAL;
  358. }
  359. if (maui_os == NULL) {
  360. fw_load = 1;
  361. maui_osLen = mod_firmware_load("/etc/sound/oswf.mot", (char **) &maui_os);
  362. }
  363. if (probe_maui(&cfg) == 0)
  364. return -ENODEV;
  365. attach_maui(&cfg);
  366. return 0;
  367. }
  368. static void __exit cleanup_maui(void)
  369. {
  370. if (fw_load && maui_os)
  371. vfree(maui_os);
  372. unload_maui(&cfg);
  373. }
  374. module_init(init_maui);
  375. module_exit(cleanup_maui);
  376. #ifndef MODULE
  377. static int __init setup_maui(char *str)
  378. {
  379.         /* io, irq */
  380. int ints[3];
  381. str = get_options(str, ARRAY_SIZE(ints), ints);
  382. io = ints[1];
  383. irq = ints[2];
  384. return 1;
  385. }
  386. __setup("maui=", setup_maui);
  387. #endif
  388. MODULE_LICENSE("GPL");