pas2_pcm.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. /*
  2. * pas2_pcm.c Audio routines for PAS16
  3. *
  4. *
  5. * Copyright (C) by Hannu Savolainen 1993-1997
  6. *
  7. * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  8. * Version 2 (June 1991). See the "COPYING" file distributed with this software
  9. * for more info.
  10. *
  11. *
  12. * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed)
  13. * Alan Cox : Swatted a double allocation of device bug. Made a few
  14. * more things module options.
  15. * Bartlomiej Zolnierkiewicz : Added __init to pas_pcm_init()
  16. */
  17. #include <linux/init.h>
  18. #include <linux/spinlock.h>
  19. #include <linux/timex.h>
  20. #include "sound_config.h"
  21. #include "pas2.h"
  22. #ifndef DEB
  23. #define DEB(WHAT)
  24. #endif
  25. #define PAS_PCM_INTRBITS (0x08)
  26. /*
  27. * Sample buffer timer interrupt enable
  28. */
  29. #define PCM_NON 0
  30. #define PCM_DAC 1
  31. #define PCM_ADC 2
  32. static unsigned long pcm_speed; /* sampling rate */
  33. static unsigned char pcm_channels = 1; /* channels (1 or 2) */
  34. static unsigned char pcm_bits = 8; /* bits/sample (8 or 16) */
  35. static unsigned char pcm_filter; /* filter FLAG */
  36. static unsigned char pcm_mode = PCM_NON;
  37. static unsigned long pcm_count;
  38. static unsigned short pcm_bitsok = 8; /* mask of OK bits */
  39. static int pcm_busy;
  40. int pas_audiodev = -1;
  41. static int open_mode;
  42. extern spinlock_t pas_lock;
  43. static int pcm_set_speed(int arg)
  44. {
  45. int foo, tmp;
  46. unsigned long flags;
  47. if (arg == 0)
  48. return pcm_speed;
  49. if (arg > 44100)
  50. arg = 44100;
  51. if (arg < 5000)
  52. arg = 5000;
  53. if (pcm_channels & 2)
  54. {
  55. foo = ((CLOCK_TICK_RATE / 2) + (arg / 2)) / arg;
  56. arg = ((CLOCK_TICK_RATE / 2) + (foo / 2)) / foo;
  57. }
  58. else
  59. {
  60. foo = (CLOCK_TICK_RATE + (arg / 2)) / arg;
  61. arg = (CLOCK_TICK_RATE + (foo / 2)) / foo;
  62. }
  63. pcm_speed = arg;
  64. tmp = pas_read(0x0B8A);
  65. /*
  66. * Set anti-aliasing filters according to sample rate. You really *NEED*
  67. * to enable this feature for all normal recording unless you want to
  68. * experiment with aliasing effects.
  69. * These filters apply to the selected "recording" source.
  70. * I (pfw) don't know the encoding of these 5 bits. The values shown
  71. * come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/.
  72. *
  73. * I cleared bit 5 of these values, since that bit controls the master
  74. * mute flag. (Olav Wölfelschneider)
  75. *
  76. */
  77. #if !defined NO_AUTO_FILTER_SET
  78. tmp &= 0xe0;
  79. if (pcm_speed >= 2 * 17897)
  80. tmp |= 0x01;
  81. else if (pcm_speed >= 2 * 15909)
  82. tmp |= 0x02;
  83. else if (pcm_speed >= 2 * 11931)
  84. tmp |= 0x09;
  85. else if (pcm_speed >= 2 * 8948)
  86. tmp |= 0x11;
  87. else if (pcm_speed >= 2 * 5965)
  88. tmp |= 0x19;
  89. else if (pcm_speed >= 2 * 2982)
  90. tmp |= 0x04;
  91. pcm_filter = tmp;
  92. #endif
  93. spin_lock_irqsave(&pas_lock, flags);
  94. pas_write(tmp & ~(0x40 | 0x80), 0x0B8A);
  95. pas_write(0x00 | 0x30 | 0x04, 0x138B);
  96. pas_write(foo & 0xff, 0x1388);
  97. pas_write((foo >> 8) & 0xff, 0x1388);
  98. pas_write(tmp, 0x0B8A);
  99. spin_unlock_irqrestore(&pas_lock, flags);
  100. return pcm_speed;
  101. }
  102. static int pcm_set_channels(int arg)
  103. {
  104. if ((arg != 1) && (arg != 2))
  105. return pcm_channels;
  106. if (arg != pcm_channels)
  107. {
  108. pas_write(pas_read(0xF8A) ^ 0x20, 0xF8A);
  109. pcm_channels = arg;
  110. pcm_set_speed(pcm_speed); /* The speed must be reinitialized */
  111. }
  112. return pcm_channels;
  113. }
  114. static int pcm_set_bits(int arg)
  115. {
  116. if (arg == 0)
  117. return pcm_bits;
  118. if ((arg & pcm_bitsok) != arg)
  119. return pcm_bits;
  120. if (arg != pcm_bits)
  121. {
  122. pas_write(pas_read(0x8389) ^ 0x04, 0x8389);
  123. pcm_bits = arg;
  124. }
  125. return pcm_bits;
  126. }
  127. static int pas_audio_ioctl(int dev, unsigned int cmd, void __user *arg)
  128. {
  129. int val, ret;
  130. int __user *p = arg;
  131. DEB(printk("pas2_pcm.c: static int pas_audio_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg));
  132. switch (cmd)
  133. {
  134. case SOUND_PCM_WRITE_RATE:
  135. if (get_user(val, p))
  136. return -EFAULT;
  137. ret = pcm_set_speed(val);
  138. break;
  139. case SOUND_PCM_READ_RATE:
  140. ret = pcm_speed;
  141. break;
  142. case SNDCTL_DSP_STEREO:
  143. if (get_user(val, p))
  144. return -EFAULT;
  145. ret = pcm_set_channels(val + 1) - 1;
  146. break;
  147. case SOUND_PCM_WRITE_CHANNELS:
  148. if (get_user(val, p))
  149. return -EFAULT;
  150. ret = pcm_set_channels(val);
  151. break;
  152. case SOUND_PCM_READ_CHANNELS:
  153. ret = pcm_channels;
  154. break;
  155. case SNDCTL_DSP_SETFMT:
  156. if (get_user(val, p))
  157. return -EFAULT;
  158. ret = pcm_set_bits(val);
  159. break;
  160. case SOUND_PCM_READ_BITS:
  161. ret = pcm_bits;
  162. break;
  163. default:
  164. return -EINVAL;
  165. }
  166. return put_user(ret, p);
  167. }
  168. static void pas_audio_reset(int dev)
  169. {
  170. DEB(printk("pas2_pcm.c: static void pas_audio_reset(void)\n"));
  171. pas_write(pas_read(0xF8A) & ~0x40, 0xF8A); /* Disable PCM */
  172. }
  173. static int pas_audio_open(int dev, int mode)
  174. {
  175. int err;
  176. unsigned long flags;
  177. DEB(printk("pas2_pcm.c: static int pas_audio_open(int mode = %X)\n", mode));
  178. spin_lock_irqsave(&pas_lock, flags);
  179. if (pcm_busy)
  180. {
  181. spin_unlock_irqrestore(&pas_lock, flags);
  182. return -EBUSY;
  183. }
  184. pcm_busy = 1;
  185. spin_unlock_irqrestore(&pas_lock, flags);
  186. if ((err = pas_set_intr(PAS_PCM_INTRBITS)) < 0)
  187. return err;
  188. pcm_count = 0;
  189. open_mode = mode;
  190. return 0;
  191. }
  192. static void pas_audio_close(int dev)
  193. {
  194. unsigned long flags;
  195. DEB(printk("pas2_pcm.c: static void pas_audio_close(void)\n"));
  196. spin_lock_irqsave(&pas_lock, flags);
  197. pas_audio_reset(dev);
  198. pas_remove_intr(PAS_PCM_INTRBITS);
  199. pcm_mode = PCM_NON;
  200. pcm_busy = 0;
  201. spin_unlock_irqrestore(&pas_lock, flags);
  202. }
  203. static void pas_audio_output_block(int dev, unsigned long buf, int count,
  204. int intrflag)
  205. {
  206. unsigned long flags, cnt;
  207. DEB(printk("pas2_pcm.c: static void pas_audio_output_block(char *buf = %P, int count = %X)\n", buf, count));
  208. cnt = count;
  209. if (audio_devs[dev]->dmap_out->dma > 3)
  210. cnt >>= 1;
  211. if (audio_devs[dev]->flags & DMA_AUTOMODE &&
  212. intrflag &&
  213. cnt == pcm_count)
  214. return;
  215. spin_lock_irqsave(&pas_lock, flags);
  216. pas_write(pas_read(0xF8A) & ~0x40,
  217. 0xF8A);
  218. /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */
  219. if (audio_devs[dev]->dmap_out->dma > 3)
  220. count >>= 1;
  221. if (count != pcm_count)
  222. {
  223. pas_write(pas_read(0x0B8A) & ~0x80, 0x0B8A);
  224. pas_write(0x40 | 0x30 | 0x04, 0x138B);
  225. pas_write(count & 0xff, 0x1389);
  226. pas_write((count >> 8) & 0xff, 0x1389);
  227. pas_write(pas_read(0x0B8A) | 0x80, 0x0B8A);
  228. pcm_count = count;
  229. }
  230. pas_write(pas_read(0x0B8A) | 0x80 | 0x40, 0x0B8A);
  231. #ifdef NO_TRIGGER
  232. pas_write(pas_read(0xF8A) | 0x40 | 0x10, 0xF8A);
  233. #endif
  234. pcm_mode = PCM_DAC;
  235. spin_unlock_irqrestore(&pas_lock, flags);
  236. }
  237. static void pas_audio_start_input(int dev, unsigned long buf, int count,
  238. int intrflag)
  239. {
  240. unsigned long flags;
  241. int cnt;
  242. DEB(printk("pas2_pcm.c: static void pas_audio_start_input(char *buf = %P, int count = %X)\n", buf, count));
  243. cnt = count;
  244. if (audio_devs[dev]->dmap_out->dma > 3)
  245. cnt >>= 1;
  246. if (audio_devs[pas_audiodev]->flags & DMA_AUTOMODE &&
  247. intrflag &&
  248. cnt == pcm_count)
  249. return;
  250. spin_lock_irqsave(&pas_lock, flags);
  251. /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */
  252. if (audio_devs[dev]->dmap_out->dma > 3)
  253. count >>= 1;
  254. if (count != pcm_count)
  255. {
  256. pas_write(pas_read(0x0B8A) & ~0x80, 0x0B8A);
  257. pas_write(0x40 | 0x30 | 0x04, 0x138B);
  258. pas_write(count & 0xff, 0x1389);
  259. pas_write((count >> 8) & 0xff, 0x1389);
  260. pas_write(pas_read(0x0B8A) | 0x80, 0x0B8A);
  261. pcm_count = count;
  262. }
  263. pas_write(pas_read(0x0B8A) | 0x80 | 0x40, 0x0B8A);
  264. #ifdef NO_TRIGGER
  265. pas_write((pas_read(0xF8A) | 0x40) & ~0x10, 0xF8A);
  266. #endif
  267. pcm_mode = PCM_ADC;
  268. spin_unlock_irqrestore(&pas_lock, flags);
  269. }
  270. #ifndef NO_TRIGGER
  271. static void pas_audio_trigger(int dev, int state)
  272. {
  273. unsigned long flags;
  274. spin_lock_irqsave(&pas_lock, flags);
  275. state &= open_mode;
  276. if (state & PCM_ENABLE_OUTPUT)
  277. pas_write(pas_read(0xF8A) | 0x40 | 0x10, 0xF8A);
  278. else if (state & PCM_ENABLE_INPUT)
  279. pas_write((pas_read(0xF8A) | 0x40) & ~0x10, 0xF8A);
  280. else
  281. pas_write(pas_read(0xF8A) & ~0x40, 0xF8A);
  282. spin_unlock_irqrestore(&pas_lock, flags);
  283. }
  284. #endif
  285. static int pas_audio_prepare_for_input(int dev, int bsize, int bcount)
  286. {
  287. pas_audio_reset(dev);
  288. return 0;
  289. }
  290. static int pas_audio_prepare_for_output(int dev, int bsize, int bcount)
  291. {
  292. pas_audio_reset(dev);
  293. return 0;
  294. }
  295. static struct audio_driver pas_audio_driver =
  296. {
  297. .owner = THIS_MODULE,
  298. .open = pas_audio_open,
  299. .close = pas_audio_close,
  300. .output_block = pas_audio_output_block,
  301. .start_input = pas_audio_start_input,
  302. .ioctl = pas_audio_ioctl,
  303. .prepare_for_input = pas_audio_prepare_for_input,
  304. .prepare_for_output = pas_audio_prepare_for_output,
  305. .halt_io = pas_audio_reset,
  306. .trigger = pas_audio_trigger
  307. };
  308. void __init pas_pcm_init(struct address_info *hw_config)
  309. {
  310. DEB(printk("pas2_pcm.c: long pas_pcm_init()\n"));
  311. pcm_bitsok = 8;
  312. if (pas_read(0xEF8B) & 0x08)
  313. pcm_bitsok |= 16;
  314. pcm_set_speed(DSP_DEFAULT_SPEED);
  315. if ((pas_audiodev = sound_install_audiodrv(AUDIO_DRIVER_VERSION,
  316. "Pro Audio Spectrum",
  317. &pas_audio_driver,
  318. sizeof(struct audio_driver),
  319. DMA_AUTOMODE,
  320. AFMT_U8 | AFMT_S16_LE,
  321. NULL,
  322. hw_config->dma,
  323. hw_config->dma)) < 0)
  324. printk(KERN_WARNING "PAS16: Too many PCM devices available\n");
  325. }
  326. void pas_pcm_interrupt(unsigned char status, int cause)
  327. {
  328. if (cause == 1)
  329. {
  330. /*
  331. * Halt the PCM first. Otherwise we don't have time to start a new
  332. * block before the PCM chip proceeds to the next sample
  333. */
  334. if (!(audio_devs[pas_audiodev]->flags & DMA_AUTOMODE))
  335. pas_write(pas_read(0xF8A) & ~0x40, 0xF8A);
  336. switch (pcm_mode)
  337. {
  338. case PCM_DAC:
  339. DMAbuf_outputintr(pas_audiodev, 1);
  340. break;
  341. case PCM_ADC:
  342. DMAbuf_inputintr(pas_audiodev);
  343. break;
  344. default:
  345. printk(KERN_WARNING "PAS: Unexpected PCM interrupt\n");
  346. }
  347. }
  348. }