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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [drivers/] [sound/] [pas2_pcm.c] - Blame information for rev 1626

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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