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