5 * The low level driver for the Pro Audio Spectrum ADC/DAC.
7 * Copyright by Hannu Savolainen 1993
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are
11 * met: 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer. 2.
13 * Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <i386/isa/sound/sound_config.h>
33 #if defined(CONFIG_PAS) && defined(CONFIG_AUDIO)
34 #include <i386/isa/sound/pas_hw.h>
37 #define TRACE(WHAT) /* * * (WHAT) */
39 #define PAS_PCM_INTRBITS (0x08)
41 * Sample buffer timer interrupt enable
48 static u_long pcm_speed = 0; /* sampling rate */
49 static u_char pcm_channels = 1; /* channels (1 or 2) */
50 static u_char pcm_bits = 8; /* bits/sample (8 or 16) */
51 static u_char pcm_filter = 0; /* filter FLAG */
52 static u_char pcm_mode = PCM_NON;
53 static u_long pcm_count = 0;
54 static u_short pcm_bitsok = 8; /* mask of OK bits */
55 static int my_devnum = 0;
56 static int open_mode = 0;
59 pcm_set_speed(int arg)
69 foo = (1193180 + (arg / 2)) / arg;
77 tmp = pas_read(FILTER_FREQUENCY);
80 * Set anti-aliasing filters according to sample rate. You reall
81 * *NEED* to enable this feature for all normal recording unless you
82 * want to experiment with aliasing effects. These filters apply to
83 * the selected "recording" source. I (pfw) don't know the encoding
84 * of these 5 bits. The values shown come from the SDK found on
85 * ftp.uwp.edu:/pub/msdos/proaudio/.
87 #if !defined NO_AUTO_FILTER_SET
89 if (pcm_speed >= 2 * 17897)
91 else if (pcm_speed >= 2 * 15909)
93 else if (pcm_speed >= 2 * 11931)
95 else if (pcm_speed >= 2 * 8948)
97 else if (pcm_speed >= 2 * 5965)
99 else if (pcm_speed >= 2 * 2982)
106 pas_write(tmp & ~(F_F_PCM_RATE_COUNTER | F_F_PCM_BUFFER_COUNTER), FILTER_FREQUENCY);
107 pas_write(S_C_C_SAMPLE_RATE | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL);
108 pas_write(foo & 0xff, SAMPLE_RATE_TIMER);
109 pas_write((foo >> 8) & 0xff, SAMPLE_RATE_TIMER);
110 pas_write(tmp, FILTER_FREQUENCY);
118 pcm_set_channels(int arg)
121 if ((arg != 1) && (arg != 2))
124 if (arg != pcm_channels) {
125 pas_write(pas_read(PCM_CONTROL) ^ P_C_PCM_MONO, PCM_CONTROL);
128 pcm_set_speed(pcm_speed); /* The speed must be
135 pcm_set_bits(int arg)
137 if ((arg & pcm_bitsok) != arg)
140 if (arg != pcm_bits) {
141 pas_write(pas_read(SYSTEM_CONFIGURATION_2) ^ S_C_2_PCM_16_BIT, SYSTEM_CONFIGURATION_2);
149 pas_pcm_ioctl(int dev, u_int cmd, ioctl_arg arg, int local)
151 TRACE(printf("pas2_pcm.c: static int pas_pcm_ioctl(u_int cmd = %X, u_int arg = %X)\n", cmd, arg));
154 case SOUND_PCM_WRITE_RATE:
156 return pcm_set_speed((int) arg);
157 return *(int *) arg = pcm_set_speed((*(int *) arg));
160 case SOUND_PCM_READ_RATE:
163 return *(int *) arg = pcm_speed;
166 case SNDCTL_DSP_STEREO:
168 return pcm_set_channels((int) arg + 1) - 1;
169 return *(int *) arg = pcm_set_channels((*(int *) arg) + 1) - 1;
172 case SOUND_PCM_WRITE_CHANNELS:
174 return pcm_set_channels((int) arg);
175 return *(int *) arg = pcm_set_channels((*(int *) arg));
178 case SOUND_PCM_READ_CHANNELS:
181 return *(int *) arg = pcm_channels;
184 case SNDCTL_DSP_SETFMT:
186 return pcm_set_bits((int) arg);
187 return *(int *) arg = pcm_set_bits((*(int *) arg));
190 case SOUND_PCM_READ_BITS:
193 return *(int *) arg = pcm_bits;
195 case SOUND_PCM_WRITE_FILTER: /* NOT YET IMPLEMENTED */
196 if ((*(int *) arg) > 1)
198 pcm_filter = (*(int *) arg);
201 case SOUND_PCM_READ_FILTER:
202 return *(int *) arg = pcm_filter;
213 pas_pcm_reset(int dev)
215 TRACE(printf("pas2_pcm.c: static void pas_pcm_reset(void)\n"));
217 pas_write(pas_read(PCM_CONTROL) & ~P_C_PCM_ENABLE, PCM_CONTROL);
221 pas_pcm_open(int dev, int mode)
225 TRACE(printf("pas2_pcm.c: static int pas_pcm_open(int mode = %X)\n", mode));
227 if ((err = pas_set_intr(PAS_PCM_INTRBITS)) < 0)
238 pas_pcm_close(int dev)
242 TRACE(printf("pas2_pcm.c: static void pas_pcm_close(void)\n"));
247 pas_remove_intr(PAS_PCM_INTRBITS);
256 pas_pcm_output_block(int dev, u_long buf, int count,
257 int intrflag, int restart_dma)
261 TRACE(printf("pas2_pcm.c: static void pas_pcm_output_block(char *buf = %P, int count = %X)\n", buf, count));
264 if (audio_devs[dev]->dmachan1 > 3)
267 if (audio_devs[dev]->flags & DMA_AUTOMODE &&
270 return; /* Auto mode on. No need to react */
274 pas_write(pas_read(PCM_CONTROL) & ~P_C_PCM_ENABLE,
278 DMAbuf_start_dma(dev, buf, count, 1);
280 if (audio_devs[dev]->dmachan1 > 3)
283 if (count != pcm_count) {
284 pas_write(pas_read(FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
285 pas_write(S_C_C_SAMPLE_BUFFER | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL);
286 pas_write(count & 0xff, SAMPLE_BUFFER_COUNTER);
287 pas_write((count >> 8) & 0xff, SAMPLE_BUFFER_COUNTER);
288 pas_write(pas_read(FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
292 pas_write(pas_read(FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY);
294 pas_write(pas_read(PCM_CONTROL) | P_C_PCM_ENABLE | P_C_PCM_DAC_MODE, PCM_CONTROL);
303 pas_pcm_start_input(int dev, u_long buf, int count,
304 int intrflag, int restart_dma)
309 TRACE(printf("pas2_pcm.c: static void pas_pcm_start_input(char *buf = %P, int count = %X)\n", buf, count));
312 if (audio_devs[dev]->dmachan1 > 3)
315 if (audio_devs[my_devnum]->flags & DMA_AUTOMODE &&
318 return; /* Auto mode on. No need to react */
323 DMAbuf_start_dma(dev, buf, count, 0);
325 if (audio_devs[dev]->dmachan1 > 3)
328 if (count != pcm_count) {
329 pas_write(pas_read(FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
330 pas_write(S_C_C_SAMPLE_BUFFER | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL);
331 pas_write(count & 0xff, SAMPLE_BUFFER_COUNTER);
332 pas_write((count >> 8) & 0xff, SAMPLE_BUFFER_COUNTER);
333 pas_write(pas_read(FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
337 pas_write(pas_read(FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY);
339 pas_write((pas_read(PCM_CONTROL) | P_C_PCM_ENABLE) & ~P_C_PCM_DAC_MODE, PCM_CONTROL);
348 pas_audio_trigger (int dev, int state)
356 if (state & PCM_ENABLE_OUTPUT)
357 pas_write (pas_read (0xF8A) | 0x40 | 0x10, 0xF8A);
358 else if (state & PCM_ENABLE_INPUT)
359 pas_write ((pas_read (0xF8A) | 0x40) & ~0x10, 0xF8A);
361 pas_write (pas_read (0xF8A) & ~0x40, 0xF8A);
368 pas_pcm_prepare_for_input(int dev, int bsize, int bcount)
373 pas_pcm_prepare_for_output(int dev, int bsize, int bcount)
378 static struct audio_operations pas_pcm_operations =
380 "Pro Audio Spectrum",
382 AFMT_U8 | AFMT_S16_LE,
386 pas_pcm_output_block,
389 pas_pcm_prepare_for_input,
390 pas_pcm_prepare_for_output,
401 pas_pcm_init(struct address_info * hw_config)
404 if (pas_read(OPERATION_MODE_1) & O_M_1_PCM_TYPE)
407 pcm_set_speed(DSP_DEFAULT_SPEED);
409 if (num_audiodevs < MAX_AUDIO_DEV) {
410 audio_devs[my_devnum = num_audiodevs++] = &pas_pcm_operations;
411 audio_devs[my_devnum]->dmachan1 = hw_config->dma;
412 audio_devs[my_devnum]->buffsize = DSP_BUFFSIZE;
414 printf("PAS2: Too many PCM devices available\n");
420 pas_pcm_interrupt(u_char status, int cause)
422 if (cause == 1) { /* PCM buffer done */
424 * Halt the PCM first. Otherwise we don't have time to start
425 * a new block before the PCM chip proceeds to the next
429 if (!(audio_devs[my_devnum]->flags & DMA_AUTOMODE)) {
430 pas_write(pas_read(PCM_CONTROL) & ~P_C_PCM_ENABLE,
436 DMAbuf_outputintr(my_devnum, 1);
440 DMAbuf_inputintr(my_devnum);
444 printf("PAS: Unexpected PCM interrupt\n");