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

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [uclinux/] [uClinux-2.0.x/] [drivers/] [sound/] [audio.c] - Blame information for rev 199

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

Line No. Rev Author Line
1 199 simons
/*
2
 * sound/audio.c
3
 *
4
 * Device file manager for /dev/audio
5
 */
6
 
7
/*
8
 * Copyright (C) by Hannu Savolainen 1993-1996
9
 *
10
 * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
11
 * Version 2 (June 1991). See the "COPYING" file distributed with this software
12
 * for more info.
13
 */
14
#include <linux/config.h>
15
 
16
 
17
#include "sound_config.h"
18
 
19
#ifdef CONFIG_AUDIO
20
 
21
#include "ulaw.h"
22
#include "coproc.h"
23
 
24
#define ON              1
25
#define OFF             0
26
 
27
static int      audio_mode[MAX_AUDIO_DEV];
28
static int      dev_nblock[MAX_AUDIO_DEV];      /* 1 if in nonblocking mode */
29
 
30
#define         AM_NONE         0
31
#define         AM_WRITE        1
32
#define         AM_READ         2
33
 
34
static int      audio_format[MAX_AUDIO_DEV];
35
static int      local_conversion[MAX_AUDIO_DEV];
36
 
37
static int
38
set_format (int dev, long fmt)
39
{
40
  if (fmt != AFMT_QUERY)
41
    {
42
 
43
      local_conversion[dev] = 0;
44
 
45
      if (!(audio_devs[dev]->format_mask & fmt))        /* Not supported */
46
        if (fmt == AFMT_MU_LAW)
47
          {
48
            fmt = AFMT_U8;
49
            local_conversion[dev] = AFMT_MU_LAW;
50
          }
51
        else
52
          fmt = AFMT_U8;        /* This is always supported */
53
 
54
      audio_format[dev] = DMAbuf_ioctl (dev, SNDCTL_DSP_SETFMT, (caddr_t) fmt, 1);
55
    }
56
 
57
  if (local_conversion[dev])    /* This shadows the HW format */
58
    return local_conversion[dev];
59
 
60
  return audio_format[dev];
61
}
62
 
63
int
64
audio_open (int dev, struct fileinfo *file)
65
{
66
  int             ret;
67
  long            bits;
68
  int             dev_type = dev & 0x0f;
69
  int             mode = file->mode & O_ACCMODE;
70
 
71
  dev = dev >> 4;
72
 
73
  if (dev_type == SND_DEV_DSP16)
74
    bits = 16;
75
  else
76
    bits = 8;
77
 
78
  if ((ret = DMAbuf_open (dev, mode)) < 0)
79
    return ret;
80
 
81
  if (audio_devs[dev]->coproc)
82
    if ((ret = audio_devs[dev]->coproc->
83
         open (audio_devs[dev]->coproc->devc, COPR_PCM)) < 0)
84
      {
85
        audio_release (dev, file);
86
        printk ("Sound: Can't access coprocessor device\n");
87
 
88
        return ret;
89
      }
90
 
91
  local_conversion[dev] = 0;
92
 
93
  if (DMAbuf_ioctl (dev, SNDCTL_DSP_SETFMT, (caddr_t) bits, 1) != bits)
94
    {
95
      printk ("audio: Can't set number of bits on device %d\n", dev);
96
      audio_release (dev, file);
97
      return -(ENXIO);
98
    }
99
 
100
  if (dev_type == SND_DEV_AUDIO)
101
    {
102
      set_format (dev, AFMT_MU_LAW);
103
    }
104
  else
105
    set_format (dev, bits);
106
 
107
  audio_mode[dev] = AM_NONE;
108
  dev_nblock[dev] = 0;
109
 
110
  return ret;
111
}
112
 
113
void
114
sync_output (int dev)
115
{
116
  int             buf_no, buf_ptr, buf_size, p, i;
117
  char           *dma_buf;
118
  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
119
 
120
  if (DMAbuf_get_curr_buffer (dev, &buf_no, &dma_buf, &buf_ptr, &buf_size) >= 0)
121
    {
122
      DMAbuf_start_output (dev, buf_no, buf_ptr);
123
    }
124
 
125
/*
126
 * Clean all unused buffer fragments.
127
 */
128
 
129
  p = dmap->qtail;
130
 
131
  for (i = dmap->qlen + 1; i < dmap->nbufs; i++)
132
    {
133
      memset (dmap->raw_buf + p * dmap->fragment_size,
134
              dmap->neutral_byte,
135
              dmap->fragment_size);
136
 
137
      p = (p + 1) % dmap->nbufs;
138
    }
139
 
140
  dmap->flags |= DMA_CLEAN;
141
}
142
 
143
void
144
audio_release (int dev, struct fileinfo *file)
145
{
146
  int             mode;
147
 
148
  dev = dev >> 4;
149
  mode = file->mode & O_ACCMODE;
150
 
151
  audio_devs[dev]->dmap_out->closing = 1;
152
  audio_devs[dev]->dmap_in->closing = 1;
153
 
154
  sync_output (dev);
155
 
156
  if (audio_devs[dev]->coproc)
157
    audio_devs[dev]->coproc->close (audio_devs[dev]->coproc->devc, COPR_PCM);
158
  DMAbuf_release (dev, mode);
159
}
160
 
161
#if defined(NO_INLINE_ASM) || !defined(i386)
162
static void
163
translate_bytes (const unsigned char *table, unsigned char *buff, int n)
164
{
165
  unsigned long   i;
166
 
167
  if (n <= 0)
168
    return;
169
 
170
  for (i = 0; i < n; ++i)
171
    buff[i] = table[buff[i]];
172
}
173
 
174
#else
175
extern inline void
176
translate_bytes (const void *table, void *buff, int n)
177
{
178
  if (n > 0)
179
    {
180
      __asm__ ("cld\n"
181
               "1:\tlodsb\n\t"
182
               "xlatb\n\t"
183
               "stosb\n\t"
184
    "loop 1b\n\t":
185
    :      "b" ((long) table), "c" (n), "D" ((long) buff), "S" ((long) buff)
186
    :          "bx", "cx", "di", "si", "ax");
187
    }
188
}
189
 
190
#endif
191
 
192
int
193
audio_write (int dev, struct fileinfo *file, const char *buf, int count)
194
{
195
  int             c, p, l, buf_no, buf_ptr, buf_size;
196
  int             err;
197
  char           *dma_buf;
198
 
199
  dev = dev >> 4;
200
 
201
  p = 0;
202
  c = count;
203
 
204
  if (count < 0)
205
    return -EINVAL;
206
 
207
  if ((audio_mode[dev] & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX))
208
    {                           /* Direction change */
209
    }
210
 
211
  if (audio_devs[dev]->flags & DMA_DUPLEX)
212
    audio_mode[dev] |= AM_WRITE;
213
  else
214
    audio_mode[dev] = AM_WRITE;
215
 
216
  if (!count)                   /* Flush output */
217
    {
218
      sync_output (dev);
219
      return 0;
220
    }
221
 
222
  while (c)
223
    {
224
      if (DMAbuf_get_curr_buffer (dev, &buf_no, &dma_buf, &buf_ptr, &buf_size) < 0)
225
        {
226
          if ((buf_no = DMAbuf_getwrbuffer (dev, &dma_buf,
227
                                            &buf_size,
228
                                            dev_nblock[dev])) < 0)
229
            {
230
              /* Handle nonblocking mode */
231
              if (dev_nblock[dev] && buf_no == -(EAGAIN))
232
                return p;       /* No more space. Return # of accepted bytes */
233
              return buf_no;
234
            }
235
          buf_ptr = 0;
236
        }
237
 
238
      l = c;
239
      if (l > (buf_size - buf_ptr))
240
        l = (buf_size - buf_ptr);
241
 
242
      if (!audio_devs[dev]->d->copy_from_user)
243
        {                       /*
244
                                 * No device specific copy routine
245
                                 */
246
          memcpy_fromfs (&dma_buf[buf_ptr], &(buf)[p], l);
247
        }
248
      else
249
        audio_devs[dev]->d->copy_from_user (dev,
250
                                            dma_buf, buf_ptr, buf, p, l);
251
 
252
      if (local_conversion[dev] == AFMT_MU_LAW)
253
        {
254
          /*
255
           * This just allows interrupts while the conversion is running
256
           */
257
          sti ();
258
          translate_bytes (ulaw_dsp, (unsigned char *) &dma_buf[buf_ptr], l);
259
        }
260
 
261
      c -= l;
262
      p += l;
263
      buf_ptr += l;
264
 
265
      if (buf_ptr >= buf_size)
266
        {
267
          if ((err = DMAbuf_start_output (dev, buf_no, buf_ptr)) < 0)
268
            {
269
              return err;
270
            }
271
 
272
        }
273
      else
274
        DMAbuf_set_count (dev, buf_no, buf_ptr);
275
 
276
    }
277
 
278
  return count;
279
}
280
 
281
int
282
audio_read (int dev, struct fileinfo *file, char *buf, int count)
283
{
284
  int             c, p, l;
285
  char           *dmabuf;
286
  int             buf_no;
287
 
288
  dev = dev >> 4;
289
  p = 0;
290
  c = count;
291
 
292
  if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX))
293
    {
294
      sync_output (dev);
295
    }
296
 
297
  if (audio_devs[dev]->flags & DMA_DUPLEX)
298
    audio_mode[dev] |= AM_READ;
299
  else
300
    audio_mode[dev] = AM_READ;
301
 
302
  while (c)
303
    {
304
      if ((buf_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l,
305
                                        dev_nblock[dev])) < 0)
306
        {
307
          /* Nonblocking mode handling. Return current # of bytes */
308
 
309
          if (dev_nblock[dev] && buf_no == -(EAGAIN))
310
            return p;
311
 
312
          return buf_no;
313
        }
314
 
315
      if (l > c)
316
        l = c;
317
 
318
      /*
319
       * Insert any local processing here.
320
       */
321
 
322
      if (local_conversion[dev] == AFMT_MU_LAW)
323
        {
324
          /*
325
           * This just allows interrupts while the conversion is running
326
           */
327
          sti ();
328
 
329
          translate_bytes (dsp_ulaw, (unsigned char *) dmabuf, l);
330
        }
331
 
332
      memcpy_tofs (&(buf)[p], dmabuf, l);
333
 
334
      DMAbuf_rmchars (dev, buf_no, l);
335
 
336
      p += l;
337
      c -= l;
338
    }
339
 
340
  return count - c;
341
}
342
 
343
int
344
audio_ioctl (int dev, struct fileinfo *file,
345
             unsigned int cmd, caddr_t arg)
346
{
347
 
348
  dev = dev >> 4;
349
 
350
  if (((cmd >> 8) & 0xff) == 'C')
351
    {
352
      if (audio_devs[dev]->coproc)      /* Coprocessor ioctl */
353
        return audio_devs[dev]->coproc->ioctl (audio_devs[dev]->coproc->devc, cmd, arg, 0);
354
      else
355
        printk ("/dev/dsp%d: No coprocessor for this device\n", dev);
356
 
357
      return -(ENXIO);
358
    }
359
  else
360
    switch (cmd)
361
      {
362
      case SNDCTL_DSP_SYNC:
363
        if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
364
          return 0;
365
 
366
        sync_output (dev);
367
        return DMAbuf_ioctl (dev, cmd, arg, 0);
368
        break;
369
 
370
      case SNDCTL_DSP_POST:
371
        if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
372
          return 0;
373
        sync_output (dev);
374
        return 0;
375
        break;
376
 
377
      case SNDCTL_DSP_RESET:
378
        audio_mode[dev] = AM_NONE;
379
        return DMAbuf_ioctl (dev, cmd, arg, 0);
380
        break;
381
 
382
      case SNDCTL_DSP_GETFMTS:
383
        return snd_ioctl_return ((int *) arg, audio_devs[dev]->format_mask | AFMT_MU_LAW);
384
        break;
385
 
386
      case SNDCTL_DSP_SETFMT:
387
        return snd_ioctl_return ((int *) arg, set_format (dev, get_user ((int *) arg)));
388
 
389
      case SNDCTL_DSP_GETISPACE:
390
        if (!(audio_devs[dev]->open_mode & OPEN_READ))
391
          return 0;
392
        if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX))
393
          return -(EBUSY);
394
 
395
        {
396
          audio_buf_info  info;
397
 
398
          int             err = DMAbuf_ioctl (dev, cmd, (caddr_t) & info, 1);
399
 
400
          if (err < 0)
401
            return err;
402
 
403
          memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info));
404
          return 0;
405
        }
406
 
407
      case SNDCTL_DSP_GETOSPACE:
408
        if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
409
          return -EPERM;
410
        if ((audio_mode[dev] & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX))
411
          return -(EBUSY);
412
 
413
        {
414
          audio_buf_info  info;
415
          char           *dma_buf;
416
          int             buf_no, buf_ptr, buf_size;
417
 
418
          int             err = DMAbuf_ioctl (dev, cmd, (caddr_t) & info, 1);
419
 
420
          if (err < 0)
421
            return err;
422
 
423
          if (DMAbuf_get_curr_buffer (dev, &buf_no, &dma_buf, &buf_ptr, &buf_size) >= 0)
424
            info.bytes -= buf_ptr;
425
 
426
          memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info));
427
          return 0;
428
        }
429
 
430
      case SNDCTL_DSP_NONBLOCK:
431
        dev_nblock[dev] = 1;
432
        return 0;
433
        break;
434
 
435
      case SNDCTL_DSP_GETCAPS:
436
        {
437
          int             info = 1;     /* Revision level of this ioctl() */
438
 
439
          if (audio_devs[dev]->flags & DMA_DUPLEX)
440
            info |= DSP_CAP_DUPLEX;
441
 
442
          if (audio_devs[dev]->coproc)
443
            info |= DSP_CAP_COPROC;
444
 
445
          if (audio_devs[dev]->d->local_qlen)   /* Device has hidden buffers */
446
            info |= DSP_CAP_BATCH;
447
 
448
          if (audio_devs[dev]->d->trigger)      /* Supports SETTRIGGER */
449
            info |= DSP_CAP_TRIGGER;
450
 
451
          info |= DSP_CAP_MMAP;
452
 
453
          memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info));
454
          return 0;
455
        }
456
        break;
457
 
458
      default:
459
        return DMAbuf_ioctl (dev, cmd, arg, 0);
460
      }
461
}
462
 
463
void
464
audio_init (void)
465
{
466
  /*
467
     * NOTE! This routine could be called several times during boot.
468
   */
469
}
470
 
471
int
472
audio_select (int dev, struct fileinfo *file, int sel_type, select_table_handle * wait)
473
{
474
  char           *dma_buf;
475
  int             buf_no, buf_ptr, buf_size;
476
 
477
  dev = dev >> 4;
478
 
479
  switch (sel_type)
480
    {
481
    case SEL_IN:
482
      if (audio_mode[dev] & AM_WRITE && !(audio_devs[dev]->flags & DMA_DUPLEX))
483
        {
484
          return 0;              /* Not recording */
485
        }
486
 
487
      return DMAbuf_select (dev, file, sel_type, wait);
488
      break;
489
 
490
    case SEL_OUT:
491
      if (audio_mode[dev] & AM_READ && !(audio_devs[dev]->flags & DMA_DUPLEX))
492
        {
493
          return 0;              /* Wrong direction */
494
        }
495
 
496
      if (DMAbuf_get_curr_buffer (dev, &buf_no, &dma_buf, &buf_ptr, &buf_size) >= 0)
497
        {
498
          return 1;             /* There is space in the current buffer */
499
        }
500
 
501
      return DMAbuf_select (dev, file, sel_type, wait);
502
      break;
503
 
504
    case SEL_EX:
505
      return 0;
506
    }
507
 
508
  return 0;
509
}
510
 
511
 
512
#endif

powered by: WebSVN 2.1.0

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