root/drivers/sound/audio.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. set_format
  2. audio_open
  3. sync_output
  4. audio_release
  5. translate_bytes
  6. translate_bytes
  7. audio_write
  8. audio_read
  9. audio_ioctl
  10. audio_init
  11. audio_select

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

/* [previous][next][first][last][top][bottom][index][help] */