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. audio_release
  4. translate_bytes
  5. translate_bytes
  6. audio_write
  7. audio_read
  8. audio_ioctl
  9. audio_init
  10. audio_select

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

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