maui.c 9.8 KB

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