- pre5:
[davej-history.git] / drivers / sound / pas2_pcm.c
blob50b53fa174e7cc649c00bdace0aec2b21a3c581a
1 /*
2 * pas2_pcm.c Audio routines for PAS16
5 * Copyright (C) by Hannu Savolainen 1993-1997
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.
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()
18 #include <linux/init.h>
19 #include "sound_config.h"
21 #include "pas2.h"
23 #ifndef DEB
24 #define DEB(WHAT)
25 #endif
27 #define PAS_PCM_INTRBITS (0x08)
29 * Sample buffer timer interrupt enable
32 #define PCM_NON 0
33 #define PCM_DAC 1
34 #define PCM_ADC 2
36 static unsigned long pcm_speed = 0; /* sampling rate */
37 static unsigned char pcm_channels = 1; /* channels (1 or 2) */
38 static unsigned char pcm_bits = 8; /* bits/sample (8 or 16) */
39 static unsigned char pcm_filter = 0; /* filter FLAG */
40 static unsigned char pcm_mode = PCM_NON;
41 static unsigned long pcm_count = 0;
42 static unsigned short pcm_bitsok = 8; /* mask of OK bits */
43 static int pcm_busy = 0;
44 int pas_audiodev = -1;
45 static int open_mode = 0;
47 static int pcm_set_speed(int arg)
49 int foo, tmp;
50 unsigned long flags;
52 if (arg == 0)
53 return pcm_speed;
55 if (arg > 44100)
56 arg = 44100;
57 if (arg < 5000)
58 arg = 5000;
60 if (pcm_channels & 2)
62 foo = (596590 + (arg / 2)) / arg;
63 arg = (596590 + (foo / 2)) / foo;
65 else
67 foo = (1193180 + (arg / 2)) / arg;
68 arg = (1193180 + (foo / 2)) / foo;
71 pcm_speed = arg;
73 tmp = pas_read(0x0B8A);
76 * Set anti-aliasing filters according to sample rate. You really *NEED*
77 * to enable this feature for all normal recording unless you want to
78 * experiment with aliasing effects.
79 * These filters apply to the selected "recording" source.
80 * I (pfw) don't know the encoding of these 5 bits. The values shown
81 * come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/.
83 * I cleared bit 5 of these values, since that bit controls the master
84 * mute flag. (Olav Wölfelschneider)
87 #if !defined NO_AUTO_FILTER_SET
88 tmp &= 0xe0;
89 if (pcm_speed >= 2 * 17897)
90 tmp |= 0x01;
91 else if (pcm_speed >= 2 * 15909)
92 tmp |= 0x02;
93 else if (pcm_speed >= 2 * 11931)
94 tmp |= 0x09;
95 else if (pcm_speed >= 2 * 8948)
96 tmp |= 0x11;
97 else if (pcm_speed >= 2 * 5965)
98 tmp |= 0x19;
99 else if (pcm_speed >= 2 * 2982)
100 tmp |= 0x04;
101 pcm_filter = tmp;
102 #endif
104 save_flags(flags);
105 cli();
107 pas_write(tmp & ~(0x40 | 0x80), 0x0B8A);
108 pas_write(0x00 | 0x30 | 0x04, 0x138B);
109 pas_write(foo & 0xff, 0x1388);
110 pas_write((foo >> 8) & 0xff, 0x1388);
111 pas_write(tmp, 0x0B8A);
113 restore_flags(flags);
115 return pcm_speed;
118 static int pcm_set_channels(int arg)
121 if ((arg != 1) && (arg != 2))
122 return pcm_channels;
124 if (arg != pcm_channels)
126 pas_write(pas_read(0xF8A) ^ 0x20, 0xF8A);
128 pcm_channels = arg;
129 pcm_set_speed(pcm_speed); /* The speed must be reinitialized */
131 return pcm_channels;
134 static int pcm_set_bits(int arg)
136 if (arg == 0)
137 return pcm_bits;
139 if ((arg & pcm_bitsok) != arg)
140 return pcm_bits;
142 if (arg != pcm_bits)
144 pas_write(pas_read(0x8389) ^ 0x04, 0x8389);
146 pcm_bits = arg;
148 return pcm_bits;
151 static int pas_audio_ioctl(int dev, unsigned int cmd, caddr_t arg)
153 int val, ret;
155 DEB(printk("pas2_pcm.c: static int pas_audio_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg));
157 switch (cmd)
159 case SOUND_PCM_WRITE_RATE:
160 if (get_user(val, (int *)arg))
161 return -EFAULT;
162 ret = pcm_set_speed(val);
163 break;
165 case SOUND_PCM_READ_RATE:
166 ret = pcm_speed;
167 break;
169 case SNDCTL_DSP_STEREO:
170 if (get_user(val, (int *)arg))
171 return -EFAULT;
172 ret = pcm_set_channels(val + 1) - 1;
173 break;
175 case SOUND_PCM_WRITE_CHANNELS:
176 if (get_user(val, (int *)arg))
177 return -EFAULT;
178 ret = pcm_set_channels(val);
179 break;
181 case SOUND_PCM_READ_CHANNELS:
182 ret = pcm_channels;
183 break;
185 case SNDCTL_DSP_SETFMT:
186 if (get_user(val, (int *)arg))
187 return -EFAULT;
188 ret = pcm_set_bits(val);
189 break;
191 case SOUND_PCM_READ_BITS:
192 ret = pcm_bits;
193 break;
195 default:
196 return -EINVAL;
198 return put_user(ret, (int *)arg);
201 static void pas_audio_reset(int dev)
203 DEB(printk("pas2_pcm.c: static void pas_audio_reset(void)\n"));
205 pas_write(pas_read(0xF8A) & ~0x40, 0xF8A); /* Disable PCM */
208 static int pas_audio_open(int dev, int mode)
210 int err;
211 unsigned long flags;
213 DEB(printk("pas2_pcm.c: static int pas_audio_open(int mode = %X)\n", mode));
215 save_flags(flags);
216 cli();
217 if (pcm_busy)
219 restore_flags(flags);
220 return -EBUSY;
222 pcm_busy = 1;
223 restore_flags(flags);
225 if ((err = pas_set_intr(PAS_PCM_INTRBITS)) < 0)
226 return err;
229 pcm_count = 0;
230 open_mode = mode;
232 return 0;
235 static void pas_audio_close(int dev)
237 unsigned long flags;
239 DEB(printk("pas2_pcm.c: static void pas_audio_close(void)\n"));
241 save_flags(flags);
242 cli();
244 pas_audio_reset(dev);
245 pas_remove_intr(PAS_PCM_INTRBITS);
246 pcm_mode = PCM_NON;
248 pcm_busy = 0;
249 restore_flags(flags);
252 static void pas_audio_output_block(int dev, unsigned long buf, int count,
253 int intrflag)
255 unsigned long flags, cnt;
257 DEB(printk("pas2_pcm.c: static void pas_audio_output_block(char *buf = %P, int count = %X)\n", buf, count));
259 cnt = count;
260 if (audio_devs[dev]->dmap_out->dma > 3)
261 cnt >>= 1;
263 if (audio_devs[dev]->flags & DMA_AUTOMODE &&
264 intrflag &&
265 cnt == pcm_count)
266 return;
268 save_flags(flags);
269 cli();
271 pas_write(pas_read(0xF8A) & ~0x40,
272 0xF8A);
274 /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */
276 if (audio_devs[dev]->dmap_out->dma > 3)
277 count >>= 1;
279 if (count != pcm_count)
281 pas_write(pas_read(0x0B8A) & ~0x80, 0x0B8A);
282 pas_write(0x40 | 0x30 | 0x04, 0x138B);
283 pas_write(count & 0xff, 0x1389);
284 pas_write((count >> 8) & 0xff, 0x1389);
285 pas_write(pas_read(0x0B8A) | 0x80, 0x0B8A);
287 pcm_count = count;
289 pas_write(pas_read(0x0B8A) | 0x80 | 0x40, 0x0B8A);
290 #ifdef NO_TRIGGER
291 pas_write(pas_read(0xF8A) | 0x40 | 0x10, 0xF8A);
292 #endif
294 pcm_mode = PCM_DAC;
296 restore_flags(flags);
299 static void pas_audio_start_input(int dev, unsigned long buf, int count,
300 int intrflag)
302 unsigned long flags;
303 int cnt;
305 DEB(printk("pas2_pcm.c: static void pas_audio_start_input(char *buf = %P, int count = %X)\n", buf, count));
307 cnt = count;
308 if (audio_devs[dev]->dmap_out->dma > 3)
309 cnt >>= 1;
311 if (audio_devs[pas_audiodev]->flags & DMA_AUTOMODE &&
312 intrflag &&
313 cnt == pcm_count)
314 return;
316 save_flags(flags);
317 cli();
319 /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */
321 if (audio_devs[dev]->dmap_out->dma > 3)
322 count >>= 1;
324 if (count != pcm_count)
326 pas_write(pas_read(0x0B8A) & ~0x80, 0x0B8A);
327 pas_write(0x40 | 0x30 | 0x04, 0x138B);
328 pas_write(count & 0xff, 0x1389);
329 pas_write((count >> 8) & 0xff, 0x1389);
330 pas_write(pas_read(0x0B8A) | 0x80, 0x0B8A);
332 pcm_count = count;
334 pas_write(pas_read(0x0B8A) | 0x80 | 0x40, 0x0B8A);
335 #ifdef NO_TRIGGER
336 pas_write((pas_read(0xF8A) | 0x40) & ~0x10, 0xF8A);
337 #endif
339 pcm_mode = PCM_ADC;
341 restore_flags(flags);
344 #ifndef NO_TRIGGER
345 static void pas_audio_trigger(int dev, int state)
347 unsigned long flags;
349 save_flags(flags);
350 cli();
351 state &= open_mode;
353 if (state & PCM_ENABLE_OUTPUT)
354 pas_write(pas_read(0xF8A) | 0x40 | 0x10, 0xF8A);
355 else if (state & PCM_ENABLE_INPUT)
356 pas_write((pas_read(0xF8A) | 0x40) & ~0x10, 0xF8A);
357 else
358 pas_write(pas_read(0xF8A) & ~0x40, 0xF8A);
360 restore_flags(flags);
362 #endif
364 static int pas_audio_prepare_for_input(int dev, int bsize, int bcount)
366 pas_audio_reset(dev);
367 return 0;
370 static int pas_audio_prepare_for_output(int dev, int bsize, int bcount)
372 pas_audio_reset(dev);
373 return 0;
376 static struct audio_driver pas_audio_driver =
378 owner: THIS_MODULE,
379 open: pas_audio_open,
380 close: pas_audio_close,
381 output_block: pas_audio_output_block,
382 start_input: pas_audio_start_input,
383 ioctl: pas_audio_ioctl,
384 prepare_for_input: pas_audio_prepare_for_input,
385 prepare_for_output: pas_audio_prepare_for_output,
386 halt_io: pas_audio_reset,
387 trigger: pas_audio_trigger
390 void __init pas_pcm_init(struct address_info *hw_config)
392 DEB(printk("pas2_pcm.c: long pas_pcm_init()\n"));
394 pcm_bitsok = 8;
395 if (pas_read(0xEF8B) & 0x08)
396 pcm_bitsok |= 16;
398 pcm_set_speed(DSP_DEFAULT_SPEED);
400 if ((pas_audiodev = sound_install_audiodrv(AUDIO_DRIVER_VERSION,
401 "Pro Audio Spectrum",
402 &pas_audio_driver,
403 sizeof(struct audio_driver),
404 DMA_AUTOMODE,
405 AFMT_U8 | AFMT_S16_LE,
406 NULL,
407 hw_config->dma,
408 hw_config->dma)) < 0)
409 printk(KERN_WARNING "PAS16: Too many PCM devices available\n");
412 void pas_pcm_interrupt(unsigned char status, int cause)
414 if (cause == 1)
417 * Halt the PCM first. Otherwise we don't have time to start a new
418 * block before the PCM chip proceeds to the next sample
421 if (!(audio_devs[pas_audiodev]->flags & DMA_AUTOMODE))
422 pas_write(pas_read(0xF8A) & ~0x40, 0xF8A);
424 switch (pcm_mode)
426 case PCM_DAC:
427 DMAbuf_outputintr(pas_audiodev, 1);
428 break;
430 case PCM_ADC:
431 DMAbuf_inputintr(pas_audiodev);
432 break;
434 default:
435 printk(KERN_WARNING "PAS: Unexpected PCM interrupt\n");