OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [sound/] [pas2_pcm.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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 "sound_config.h"
20
 
21
#include "pas2.h"
22
 
23
#ifndef DEB
24
#define DEB(WHAT)
25
#endif
26
 
27
#define PAS_PCM_INTRBITS (0x08)
28
/*
29
 * Sample buffer timer interrupt enable
30
 */
31
 
32
#define PCM_NON 0
33
#define PCM_DAC 1
34
#define PCM_ADC 2
35
 
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;
46
 
47
static 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 = (596590 + (arg / 2)) / arg;
63
                arg = (596590 + (foo / 2)) / foo;
64
        }
65
        else
66
        {
67
                foo = (1193180 + (arg / 2)) / arg;
68
                arg = (1193180 + (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
        save_flags(flags);
105
        cli();
106
 
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);
112
 
113
        restore_flags(flags);
114
 
115
        return pcm_speed;
116
}
117
 
118
static int pcm_set_channels(int arg)
119
{
120
 
121
        if ((arg != 1) && (arg != 2))
122
                return pcm_channels;
123
 
124
        if (arg != pcm_channels)
125
        {
126
                pas_write(pas_read(0xF8A) ^ 0x20, 0xF8A);
127
 
128
                pcm_channels = arg;
129
                pcm_set_speed(pcm_speed);       /* The speed must be reinitialized */
130
        }
131
        return pcm_channels;
132
}
133
 
134
static int pcm_set_bits(int arg)
135
{
136
        if (arg == 0)
137
                return pcm_bits;
138
 
139
        if ((arg & pcm_bitsok) != arg)
140
                return pcm_bits;
141
 
142
        if (arg != pcm_bits)
143
        {
144
                pas_write(pas_read(0x8389) ^ 0x04, 0x8389);
145
 
146
                pcm_bits = arg;
147
        }
148
        return pcm_bits;
149
}
150
 
151
static int pas_audio_ioctl(int dev, unsigned int cmd, caddr_t arg)
152
{
153
        int val, ret;
154
 
155
        DEB(printk("pas2_pcm.c: static int pas_audio_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg));
156
 
157
        switch (cmd)
158
        {
159
        case SOUND_PCM_WRITE_RATE:
160
                if (get_user(val, (int *)arg))
161
                        return -EFAULT;
162
                ret = pcm_set_speed(val);
163
                break;
164
 
165
        case SOUND_PCM_READ_RATE:
166
                ret = pcm_speed;
167
                break;
168
 
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;
174
 
175
        case SOUND_PCM_WRITE_CHANNELS:
176
                if (get_user(val, (int *)arg))
177
                        return -EFAULT;
178
                ret = pcm_set_channels(val);
179
                break;
180
 
181
        case SOUND_PCM_READ_CHANNELS:
182
                ret = pcm_channels;
183
                break;
184
 
185
        case SNDCTL_DSP_SETFMT:
186
                if (get_user(val, (int *)arg))
187
                        return -EFAULT;
188
                ret = pcm_set_bits(val);
189
                break;
190
 
191
        case SOUND_PCM_READ_BITS:
192
                ret = pcm_bits;
193
                break;
194
 
195
        default:
196
                return -EINVAL;
197
        }
198
        return put_user(ret, (int *)arg);
199
}
200
 
201
static void pas_audio_reset(int dev)
202
{
203
        DEB(printk("pas2_pcm.c: static void pas_audio_reset(void)\n"));
204
 
205
        pas_write(pas_read(0xF8A) & ~0x40, 0xF8A);      /* Disable PCM */
206
}
207
 
208
static int pas_audio_open(int dev, int mode)
209
{
210
        int             err;
211
        unsigned long   flags;
212
 
213
        DEB(printk("pas2_pcm.c: static int pas_audio_open(int mode = %X)\n", mode));
214
 
215
        save_flags(flags);
216
        cli();
217
        if (pcm_busy)
218
        {
219
                restore_flags(flags);
220
                return -EBUSY;
221
        }
222
        pcm_busy = 1;
223
        restore_flags(flags);
224
 
225
        if ((err = pas_set_intr(PAS_PCM_INTRBITS)) < 0)
226
                return err;
227
 
228
 
229
        pcm_count = 0;
230
        open_mode = mode;
231
 
232
        return 0;
233
}
234
 
235
static void pas_audio_close(int dev)
236
{
237
        unsigned long   flags;
238
 
239
        DEB(printk("pas2_pcm.c: static void pas_audio_close(void)\n"));
240
 
241
        save_flags(flags);
242
        cli();
243
 
244
        pas_audio_reset(dev);
245
        pas_remove_intr(PAS_PCM_INTRBITS);
246
        pcm_mode = PCM_NON;
247
 
248
        pcm_busy = 0;
249
        restore_flags(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
        save_flags(flags);
269
        cli();
270
 
271
        pas_write(pas_read(0xF8A) & ~0x40,
272
                  0xF8A);
273
 
274
        /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */
275
 
276
        if (audio_devs[dev]->dmap_out->dma > 3)
277
                count >>= 1;
278
 
279
        if (count != pcm_count)
280
        {
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);
286
 
287
                pcm_count = count;
288
        }
289
        pas_write(pas_read(0x0B8A) | 0x80 | 0x40, 0x0B8A);
290
#ifdef NO_TRIGGER
291
        pas_write(pas_read(0xF8A) | 0x40 | 0x10, 0xF8A);
292
#endif
293
 
294
        pcm_mode = PCM_DAC;
295
 
296
        restore_flags(flags);
297
}
298
 
299
static void pas_audio_start_input(int dev, unsigned long buf, int count,
300
                      int intrflag)
301
{
302
        unsigned long   flags;
303
        int             cnt;
304
 
305
        DEB(printk("pas2_pcm.c: static void pas_audio_start_input(char *buf = %P, int count = %X)\n", buf, count));
306
 
307
        cnt = count;
308
        if (audio_devs[dev]->dmap_out->dma > 3)
309
                cnt >>= 1;
310
 
311
        if (audio_devs[pas_audiodev]->flags & DMA_AUTOMODE &&
312
            intrflag &&
313
            cnt == pcm_count)
314
                return;
315
 
316
        save_flags(flags);
317
        cli();
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
        restore_flags(flags);
342
}
343
 
344
#ifndef NO_TRIGGER
345
static void pas_audio_trigger(int dev, int state)
346
{
347
        unsigned long   flags;
348
 
349
        save_flags(flags);
350
        cli();
351
        state &= open_mode;
352
 
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);
359
 
360
        restore_flags(flags);
361
}
362
#endif
363
 
364
static int pas_audio_prepare_for_input(int dev, int bsize, int bcount)
365
{
366
        pas_audio_reset(dev);
367
        return 0;
368
}
369
 
370
static int pas_audio_prepare_for_output(int dev, int bsize, int bcount)
371
{
372
        pas_audio_reset(dev);
373
        return 0;
374
}
375
 
376
static struct audio_driver pas_audio_driver =
377
{
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
388
};
389
 
390
void __init pas_pcm_init(struct address_info *hw_config)
391
{
392
        DEB(printk("pas2_pcm.c: long pas_pcm_init()\n"));
393
 
394
        pcm_bitsok = 8;
395
        if (pas_read(0xEF8B) & 0x08)
396
                pcm_bitsok |= 16;
397
 
398
        pcm_set_speed(DSP_DEFAULT_SPEED);
399
 
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");
410
}
411
 
412
void pas_pcm_interrupt(unsigned char status, int cause)
413
{
414
        if (cause == 1)
415
        {
416
                /*
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
419
                 */
420
 
421
                if (!(audio_devs[pas_audiodev]->flags & DMA_AUTOMODE))
422
                        pas_write(pas_read(0xF8A) & ~0x40, 0xF8A);
423
 
424
                switch (pcm_mode)
425
                {
426
                        case PCM_DAC:
427
                                DMAbuf_outputintr(pas_audiodev, 1);
428
                                break;
429
 
430
                        case PCM_ADC:
431
                                DMAbuf_inputintr(pas_audiodev);
432
                                break;
433
 
434
                        default:
435
                                printk(KERN_WARNING "PAS: Unexpected PCM interrupt\n");
436
                }
437
        }
438
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.