Import 2.3.18pre1
[davej-history.git] / drivers / sound / pas2_pcm.c
blobdc49d04b54432b95fb44b124207b2c3689f4e1d4
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.
17 #include <linux/config.h>
19 #include "sound_config.h"
21 #ifdef CONFIG_PAS
22 #ifdef CONFIG_AUDIO
24 #ifndef DEB
25 #define DEB(WHAT)
26 #endif
28 #define PAS_PCM_INTRBITS (0x08)
30 * Sample buffer timer interrupt enable
33 #define PCM_NON 0
34 #define PCM_DAC 1
35 #define PCM_ADC 2
37 static unsigned long pcm_speed = 0; /* sampling rate */
38 static unsigned char pcm_channels = 1; /* channels (1 or 2) */
39 static unsigned char pcm_bits = 8; /* bits/sample (8 or 16) */
40 static unsigned char pcm_filter = 0; /* filter FLAG */
41 static unsigned char pcm_mode = PCM_NON;
42 static unsigned long pcm_count = 0;
43 static unsigned short pcm_bitsok = 8; /* mask of OK bits */
44 static int pcm_busy = 0;
45 int pas_audiodev = -1;
46 static int open_mode = 0;
48 static int pcm_set_speed(int arg)
50 int foo, tmp;
51 unsigned long flags;
53 if (arg == 0)
54 return pcm_speed;
56 if (arg > 44100)
57 arg = 44100;
58 if (arg < 5000)
59 arg = 5000;
61 if (pcm_channels & 2)
63 foo = (596590 + (arg / 2)) / arg;
64 arg = (596590 + (foo / 2)) / foo;
66 else
68 foo = (1193180 + (arg / 2)) / arg;
69 arg = (1193180 + (foo / 2)) / foo;
72 pcm_speed = arg;
74 tmp = pas_read(0x0B8A);
77 * Set anti-aliasing filters according to sample rate. You really *NEED*
78 * to enable this feature for all normal recording unless you want to
79 * experiment with aliasing effects.
80 * These filters apply to the selected "recording" source.
81 * I (pfw) don't know the encoding of these 5 bits. The values shown
82 * come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/.
84 * I cleared bit 5 of these values, since that bit controls the master
85 * mute flag. (Olav Wölfelschneider)
88 #if !defined NO_AUTO_FILTER_SET
89 tmp &= 0xe0;
90 if (pcm_speed >= 2 * 17897)
91 tmp |= 0x01;
92 else if (pcm_speed >= 2 * 15909)
93 tmp |= 0x02;
94 else if (pcm_speed >= 2 * 11931)
95 tmp |= 0x09;
96 else if (pcm_speed >= 2 * 8948)
97 tmp |= 0x11;
98 else if (pcm_speed >= 2 * 5965)
99 tmp |= 0x19;
100 else if (pcm_speed >= 2 * 2982)
101 tmp |= 0x04;
102 pcm_filter = tmp;
103 #endif
105 save_flags(flags);
106 cli();
108 pas_write(tmp & ~(0x40 | 0x80), 0x0B8A);
109 pas_write(0x00 | 0x30 | 0x04, 0x138B);
110 pas_write(foo & 0xff, 0x1388);
111 pas_write((foo >> 8) & 0xff, 0x1388);
112 pas_write(tmp, 0x0B8A);
114 restore_flags(flags);
116 return pcm_speed;
119 static int pcm_set_channels(int arg)
122 if ((arg != 1) && (arg != 2))
123 return pcm_channels;
125 if (arg != pcm_channels)
127 pas_write(pas_read(0xF8A) ^ 0x20, 0xF8A);
129 pcm_channels = arg;
130 pcm_set_speed(pcm_speed); /* The speed must be reinitialized */
132 return pcm_channels;
135 static int pcm_set_bits(int arg)
137 if (arg == 0)
138 return pcm_bits;
140 if ((arg & pcm_bitsok) != arg)
141 return pcm_bits;
143 if (arg != pcm_bits)
145 pas_write(pas_read(0x8389) ^ 0x04, 0x8389);
147 pcm_bits = arg;
149 return pcm_bits;
152 static int pas_audio_ioctl(int dev, unsigned int cmd, caddr_t arg)
154 int val, ret;
156 DEB(printk("pas2_pcm.c: static int pas_audio_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg));
158 switch (cmd)
160 case SOUND_PCM_WRITE_RATE:
161 if (get_user(val, (int *)arg))
162 return -EFAULT;
163 ret = pcm_set_speed(val);
164 break;
166 case SOUND_PCM_READ_RATE:
167 ret = pcm_speed;
168 break;
170 case SNDCTL_DSP_STEREO:
171 if (get_user(val, (int *)arg))
172 return -EFAULT;
173 ret = pcm_set_channels(val + 1) - 1;
174 break;
176 case SOUND_PCM_WRITE_CHANNELS:
177 if (get_user(val, (int *)arg))
178 return -EFAULT;
179 ret = pcm_set_channels(val);
180 break;
182 case SOUND_PCM_READ_CHANNELS:
183 ret = pcm_channels;
184 break;
186 case SNDCTL_DSP_SETFMT:
187 if (get_user(val, (int *)arg))
188 return -EFAULT;
189 ret = pcm_set_bits(val);
190 break;
192 case SOUND_PCM_READ_BITS:
193 ret = pcm_bits;
194 break;
196 default:
197 return -EINVAL;
199 return put_user(ret, (int *)arg);
202 static void pas_audio_reset(int dev)
204 DEB(printk("pas2_pcm.c: static void pas_audio_reset(void)\n"));
206 pas_write(pas_read(0xF8A) & ~0x40, 0xF8A); /* Disable PCM */
209 static int pas_audio_open(int dev, int mode)
211 int err;
212 unsigned long flags;
214 DEB(printk("pas2_pcm.c: static int pas_audio_open(int mode = %X)\n", mode));
216 save_flags(flags);
217 cli();
218 if (pcm_busy)
220 restore_flags(flags);
221 return -EBUSY;
223 pcm_busy = 1;
224 restore_flags(flags);
226 if ((err = pas_set_intr(PAS_PCM_INTRBITS)) < 0)
227 return err;
230 pcm_count = 0;
231 open_mode = mode;
233 return 0;
236 static void pas_audio_close(int dev)
238 unsigned long flags;
240 DEB(printk("pas2_pcm.c: static void pas_audio_close(void)\n"));
242 save_flags(flags);
243 cli();
245 pas_audio_reset(dev);
246 pas_remove_intr(PAS_PCM_INTRBITS);
247 pcm_mode = PCM_NON;
249 pcm_busy = 0;
250 restore_flags(flags);
253 static void pas_audio_output_block(int dev, unsigned long buf, int count,
254 int intrflag)
256 unsigned long flags, cnt;
258 DEB(printk("pas2_pcm.c: static void pas_audio_output_block(char *buf = %P, int count = %X)\n", buf, count));
260 cnt = count;
261 if (audio_devs[dev]->dmap_out->dma > 3)
262 cnt >>= 1;
264 if (audio_devs[dev]->flags & DMA_AUTOMODE &&
265 intrflag &&
266 cnt == pcm_count)
267 return;
269 save_flags(flags);
270 cli();
272 pas_write(pas_read(0xF8A) & ~0x40,
273 0xF8A);
275 /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */
277 if (audio_devs[dev]->dmap_out->dma > 3)
278 count >>= 1;
280 if (count != pcm_count)
282 pas_write(pas_read(0x0B8A) & ~0x80, 0x0B8A);
283 pas_write(0x40 | 0x30 | 0x04, 0x138B);
284 pas_write(count & 0xff, 0x1389);
285 pas_write((count >> 8) & 0xff, 0x1389);
286 pas_write(pas_read(0x0B8A) | 0x80, 0x0B8A);
288 pcm_count = count;
290 pas_write(pas_read(0x0B8A) | 0x80 | 0x40, 0x0B8A);
291 #ifdef NO_TRIGGER
292 pas_write(pas_read(0xF8A) | 0x40 | 0x10, 0xF8A);
293 #endif
295 pcm_mode = PCM_DAC;
297 restore_flags(flags);
300 static void pas_audio_start_input(int dev, unsigned long buf, int count,
301 int intrflag)
303 unsigned long flags;
304 int cnt;
306 DEB(printk("pas2_pcm.c: static void pas_audio_start_input(char *buf = %P, int count = %X)\n", buf, count));
308 cnt = count;
309 if (audio_devs[dev]->dmap_out->dma > 3)
310 cnt >>= 1;
312 if (audio_devs[pas_audiodev]->flags & DMA_AUTOMODE &&
313 intrflag &&
314 cnt == pcm_count)
315 return;
317 save_flags(flags);
318 cli();
320 /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */
322 if (audio_devs[dev]->dmap_out->dma > 3)
323 count >>= 1;
325 if (count != pcm_count)
327 pas_write(pas_read(0x0B8A) & ~0x80, 0x0B8A);
328 pas_write(0x40 | 0x30 | 0x04, 0x138B);
329 pas_write(count & 0xff, 0x1389);
330 pas_write((count >> 8) & 0xff, 0x1389);
331 pas_write(pas_read(0x0B8A) | 0x80, 0x0B8A);
333 pcm_count = count;
335 pas_write(pas_read(0x0B8A) | 0x80 | 0x40, 0x0B8A);
336 #ifdef NO_TRIGGER
337 pas_write((pas_read(0xF8A) | 0x40) & ~0x10, 0xF8A);
338 #endif
340 pcm_mode = PCM_ADC;
342 restore_flags(flags);
345 #ifndef NO_TRIGGER
346 static void pas_audio_trigger(int dev, int state)
348 unsigned long flags;
350 save_flags(flags);
351 cli();
352 state &= open_mode;
354 if (state & PCM_ENABLE_OUTPUT)
355 pas_write(pas_read(0xF8A) | 0x40 | 0x10, 0xF8A);
356 else if (state & PCM_ENABLE_INPUT)
357 pas_write((pas_read(0xF8A) | 0x40) & ~0x10, 0xF8A);
358 else
359 pas_write(pas_read(0xF8A) & ~0x40, 0xF8A);
361 restore_flags(flags);
363 #endif
365 static int pas_audio_prepare_for_input(int dev, int bsize, int bcount)
367 pas_audio_reset(dev);
368 return 0;
371 static int pas_audio_prepare_for_output(int dev, int bsize, int bcount)
373 pas_audio_reset(dev);
374 return 0;
377 static struct audio_driver pas_audio_driver =
379 pas_audio_open,
380 pas_audio_close,
381 pas_audio_output_block,
382 pas_audio_start_input,
383 pas_audio_ioctl,
384 pas_audio_prepare_for_input,
385 pas_audio_prepare_for_output,
386 pas_audio_reset,
387 NULL,
388 NULL,
389 NULL,
390 NULL,
391 pas_audio_trigger
394 void pas_pcm_init(struct address_info *hw_config)
396 DEB(printk("pas2_pcm.c: long pas_pcm_init()\n"));
398 pcm_bitsok = 8;
399 if (pas_read(0xEF8B) & 0x08)
400 pcm_bitsok |= 16;
402 pcm_set_speed(DSP_DEFAULT_SPEED);
404 if ((pas_audiodev = sound_install_audiodrv(AUDIO_DRIVER_VERSION,
405 "Pro Audio Spectrum",
406 &pas_audio_driver,
407 sizeof(struct audio_driver),
408 DMA_AUTOMODE,
409 AFMT_U8 | AFMT_S16_LE,
410 NULL,
411 hw_config->dma,
412 hw_config->dma)) < 0)
413 printk(KERN_WARNING "PAS16: Too many PCM devices available\n");
416 void pas_pcm_interrupt(unsigned char status, int cause)
418 if (cause == 1)
421 * Halt the PCM first. Otherwise we don't have time to start a new
422 * block before the PCM chip proceeds to the next sample
425 if (!(audio_devs[pas_audiodev]->flags & DMA_AUTOMODE))
426 pas_write(pas_read(0xF8A) & ~0x40, 0xF8A);
428 switch (pcm_mode)
430 case PCM_DAC:
431 DMAbuf_outputintr(pas_audiodev, 1);
432 break;
434 case PCM_ADC:
435 DMAbuf_inputintr(pas_audiodev);
436 break;
438 default:
439 printk(KERN_WARNING "PAS: Unexpected PCM interrupt\n");
444 #endif
445 #endif