root/drivers/sound/pas2_pcm.c

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

DEFINITIONS

This source file includes following definitions.
  1. pcm_set_speed
  2. pcm_set_channels
  3. pcm_set_bits
  4. pas_pcm_ioctl
  5. pas_pcm_reset
  6. pas_pcm_open
  7. pas_pcm_close
  8. pas_pcm_output_block
  9. pas_pcm_start_input
  10. pas_pcm_trigger
  11. pas_pcm_prepare_for_input
  12. pas_pcm_prepare_for_output
  13. pas_pcm_init
  14. pas_pcm_interrupt

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

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