pas2_pcm.c 8.7 KB

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