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