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_prepare_for_input
  11. pas_pcm_prepare_for_output
  12. pas_pcm_init
  13. pas_pcm_interrupt

   1 #define _PAS2_PCM_C_
   2 /*
   3  * linux/kernel/chr_drv/sound/pas2_pcm.c
   4  * 
   5  * The low level driver for the Pro Audio Spectrum ADC/DAC.
   6  * 
   7  * Copyright by Hannu Savolainen 1993
   8  * 
   9  * Redistribution and use in source and binary forms, with or without
  10  * modification, are permitted provided that the following conditions are
  11  * met: 1. Redistributions of source code must retain the above copyright
  12  * notice, this list of conditions and the following disclaimer. 2.
  13  * Redistributions in binary form must reproduce the above copyright notice,
  14  * this list of conditions and the following disclaimer in the documentation
  15  * and/or other materials provided with the distribution.
  16  * 
  17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
  18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  20  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
  21  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  23  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  24  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27  * SUCH DAMAGE.
  28  * 
  29  */
  30 
  31 #include "sound_config.h"
  32 
  33 #ifdef CONFIGURE_SOUNDCARD
  34 
  35 #include "pas.h"
  36 
  37 #if !defined(EXCLUDE_PAS) && !defined(EXCLUDE_AUDIO)
  38 
  39 #define TRACE(WHAT)             /* (WHAT) */
  40 
  41 #define PAS_PCM_INTRBITS (0x08)
  42 /* Sample buffer timer interrupt enable */
  43 
  44 #define PCM_NON 0
  45 #define PCM_DAC 1
  46 #define PCM_ADC 2
  47 
  48 static unsigned long pcm_speed = 0;     /* sampling rate */
  49 static unsigned char pcm_channels = 1;  /* channels/sample (1 or 2) */
  50 static unsigned char pcm_bits = 8;      /* bits/sample (8 or 16) */
  51 static unsigned char pcm_filter = 0;    /* filter FLAG */
  52 static unsigned char pcm_mode = PCM_NON;
  53 static unsigned long pcm_count = 0;
  54 static unsigned short pcm_bitsok = 8;   /* mask of OK bits */
  55 static int      my_devnum = 0;
  56 
  57 int
  58 pcm_set_speed (int arg)
     /* [previous][next][first][last][top][bottom][index][help] */
  59 {
  60   int             foo, tmp;
  61   unsigned long   flags;
  62 
  63   if (arg > 44100)
  64     arg = 44100;
  65   if (arg < 5000)
  66     arg = 5000;
  67 
  68   foo = 1193180 / arg;
  69   arg = 1193180 / foo;
  70 
  71   if (pcm_channels & 2)
  72     foo = foo >> 1;
  73 
  74   pcm_speed = arg;
  75 
  76   tmp = pas_read (FILTER_FREQUENCY);
  77 
  78   DISABLE_INTR (flags);
  79 
  80   pas_write (tmp & ~(F_F_PCM_RATE_COUNTER | F_F_PCM_BUFFER_COUNTER), FILTER_FREQUENCY);
  81   pas_write (S_C_C_SAMPLE_RATE | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL);
  82   pas_write (foo & 0xff, SAMPLE_RATE_TIMER);
  83   pas_write ((foo >> 8) & 0xff, SAMPLE_RATE_TIMER);
  84   pas_write (tmp, FILTER_FREQUENCY);
  85 
  86   RESTORE_INTR (flags);
  87 
  88   return pcm_speed;
  89 }
  90 
  91 int
  92 pcm_set_channels (int arg)
     /* [previous][next][first][last][top][bottom][index][help] */
  93 {
  94 
  95   if ((arg != 1) && (arg != 2))
  96     return pcm_channels;
  97 
  98   if (arg != pcm_channels)
  99     {
 100       pas_write (pas_read (PCM_CONTROL) ^ P_C_PCM_MONO, PCM_CONTROL);
 101 
 102       pcm_channels = arg;
 103       pcm_set_speed (pcm_speed);/* The speed must be reinitialized */
 104     }
 105 
 106   return pcm_channels;
 107 }
 108 
 109 int
 110 pcm_set_bits (int arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 111 {
 112   if ((arg & pcm_bitsok) != arg)
 113     return pcm_bits;
 114 
 115   if (arg != pcm_bits)
 116     {
 117       pas_write (pas_read (SYSTEM_CONFIGURATION_2) ^ S_C_2_PCM_16_BIT, SYSTEM_CONFIGURATION_2);
 118 
 119       pcm_bits = arg;
 120     }
 121 
 122   return pcm_bits;
 123 }
 124 
 125 static int
 126 pas_pcm_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
     /* [previous][next][first][last][top][bottom][index][help] */
 127 {
 128   TRACE (printk ("pas2_pcm.c: static int pas_pcm_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg));
 129 
 130   switch (cmd)
 131     {
 132     case SOUND_PCM_WRITE_RATE:
 133       if (local)
 134         return pcm_set_speed (arg);
 135       return IOCTL_OUT (arg, pcm_set_speed (IOCTL_IN (arg)));
 136       break;
 137 
 138     case SOUND_PCM_READ_RATE:
 139       if (local)
 140         return pcm_speed;
 141       return IOCTL_OUT (arg, pcm_speed);
 142       break;
 143 
 144     case SNDCTL_DSP_STEREO:
 145       if (local)
 146         return pcm_set_channels (arg + 1) - 1;
 147       return IOCTL_OUT (arg, pcm_set_channels (IOCTL_IN (arg) + 1) - 1);
 148       break;
 149 
 150     case SOUND_PCM_WRITE_CHANNELS:
 151       return IOCTL_OUT (arg, pcm_set_channels (IOCTL_IN (arg)));
 152       break;
 153 
 154     case SOUND_PCM_READ_CHANNELS:
 155       if (local)
 156         return pcm_channels;
 157       return IOCTL_OUT (arg, pcm_channels);
 158       break;
 159 
 160     case SNDCTL_DSP_SAMPLESIZE:
 161       if (local)
 162         return pcm_set_bits (arg);
 163       return IOCTL_OUT (arg, pcm_set_bits (IOCTL_IN (arg)));
 164       break;
 165 
 166     case SOUND_PCM_READ_BITS:
 167       if (local)
 168         return pcm_bits;
 169       return IOCTL_OUT (arg, pcm_bits);
 170 
 171     case SOUND_PCM_WRITE_FILTER:        /* NOT YET IMPLEMENTED */
 172       if (IOCTL_IN (arg) > 1)
 173         return IOCTL_OUT (arg, RET_ERROR (EINVAL));
 174       break;
 175 
 176       pcm_filter = IOCTL_IN (arg);
 177     case SOUND_PCM_READ_FILTER:
 178       return IOCTL_OUT (arg, pcm_filter);
 179       break;
 180 
 181     default:
 182       return RET_ERROR (EINVAL);
 183     }
 184 
 185   return RET_ERROR (EINVAL);
 186 }
 187 
 188 static void
 189 pas_pcm_reset (int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 190 {
 191   TRACE (printk ("pas2_pcm.c: static void pas_pcm_reset(void)\n"));
 192 
 193   pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE, PCM_CONTROL);
 194 }
 195 
 196 static int
 197 pas_pcm_open (int dev, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 198 {
 199   int             err;
 200 
 201   TRACE (printk ("pas2_pcm.c: static int pas_pcm_open(int mode = %X)\n", mode));
 202 
 203   if ((err = pas_set_intr (PAS_PCM_INTRBITS)) < 0)
 204     return err;
 205 
 206   if (!DMAbuf_open_dma (dev))
 207     {
 208       pas_remove_intr (PAS_PCM_INTRBITS);
 209       return RET_ERROR (EBUSY);
 210     }
 211 
 212   pcm_count = 0;
 213 
 214   return 0;
 215 }
 216 
 217 static void
 218 pas_pcm_close (int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 219 {
 220   unsigned long   flags;
 221 
 222   TRACE (printk ("pas2_pcm.c: static void pas_pcm_close(void)\n"));
 223 
 224   DISABLE_INTR (flags);
 225 
 226   pas_pcm_reset (dev);
 227   DMAbuf_close_dma (dev);
 228   pas_remove_intr (PAS_PCM_INTRBITS);
 229   pcm_mode = PCM_NON;
 230 
 231   RESTORE_INTR (flags);
 232 }
 233 
 234 static void
 235 pas_pcm_output_block (int dev, unsigned long buf, int count, 
     /* [previous][next][first][last][top][bottom][index][help] */
 236                       int intrflag, int restart_dma)
 237 {
 238   unsigned long   flags, cnt;
 239 
 240   TRACE (printk ("pas2_pcm.c: static void pas_pcm_output_block(char *buf = %P, int count = %X)\n", buf, count));
 241 
 242   cnt = count;
 243   if (sound_dsp_dmachan[dev] > 3)
 244     cnt >>= 1;
 245 
 246   if (sound_dma_automode[dev] &&
 247       intrflag &&
 248       cnt == pcm_count)
 249     return;                     /* Auto mode on. No need to react */
 250 
 251   DISABLE_INTR (flags);
 252 
 253   pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE,
 254              PCM_CONTROL);
 255 
 256   if (restart_dma) 
 257      DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
 258 
 259   if (sound_dsp_dmachan[dev] > 3)
 260     count >>= 1;
 261 
 262   if (count != pcm_count)
 263     {
 264       pas_write (pas_read (FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
 265       pas_write (S_C_C_SAMPLE_BUFFER | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL);
 266       pas_write (count & 0xff, SAMPLE_BUFFER_COUNTER);
 267       pas_write ((count >> 8) & 0xff, SAMPLE_BUFFER_COUNTER);
 268       pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
 269 
 270       pcm_count = count;
 271     }
 272   pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY);
 273   pas_write (pas_read (PCM_CONTROL) | P_C_PCM_ENABLE | P_C_PCM_DAC_MODE, PCM_CONTROL);
 274 
 275   pcm_mode = PCM_DAC;
 276 
 277   RESTORE_INTR (flags);
 278 }
 279 
 280 static void
 281 pas_pcm_start_input (int dev, unsigned long buf, int count, 
     /* [previous][next][first][last][top][bottom][index][help] */
 282                      int intrflag, int restart_dma)
 283 {
 284   unsigned long   flags;
 285   int             cnt;
 286 
 287   TRACE (printk ("pas2_pcm.c: static void pas_pcm_start_input(char *buf = %P, int count = %X)\n", buf, count));
 288 
 289   cnt = count;
 290   if (sound_dsp_dmachan[dev] > 3)
 291     cnt >>= 1;
 292 
 293   if (sound_dma_automode[my_devnum] &&
 294       intrflag &&
 295       cnt == pcm_count)
 296     return;                     /* Auto mode on. No need to react */
 297 
 298   DISABLE_INTR (flags);
 299 
 300   if (restart_dma)
 301      DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
 302 
 303   if (sound_dsp_dmachan[dev] > 3)
 304     count >>= 1;
 305 
 306   if (count != pcm_count)
 307     {
 308       pas_write (pas_read (FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
 309       pas_write (S_C_C_SAMPLE_BUFFER | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL);
 310       pas_write (count & 0xff, SAMPLE_BUFFER_COUNTER);
 311       pas_write ((count >> 8) & 0xff, SAMPLE_BUFFER_COUNTER);
 312       pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
 313 
 314       pcm_count = count;
 315     }
 316   pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY);
 317   pas_write ((pas_read (PCM_CONTROL) | P_C_PCM_ENABLE) & ~P_C_PCM_DAC_MODE, PCM_CONTROL);
 318 
 319   pcm_mode = PCM_ADC;
 320 
 321   RESTORE_INTR (flags);
 322 }
 323 
 324 static int
 325 pas_pcm_prepare_for_input (int dev, int bsize, int bcount)
     /* [previous][next][first][last][top][bottom][index][help] */
 326 {
 327   return 0;
 328 }
 329 static int
 330 pas_pcm_prepare_for_output (int dev, int bsize, int bcount)
     /* [previous][next][first][last][top][bottom][index][help] */
 331 {
 332   return 0;
 333 }
 334 
 335 static struct audio_operations pas_pcm_operations =
 336 {
 337   "Pro Audio Spectrum",
 338   pas_pcm_open,                 /* */
 339   pas_pcm_close,                /* */
 340   pas_pcm_output_block,         /* */
 341   pas_pcm_start_input,          /* */
 342   pas_pcm_ioctl,                /* */
 343   pas_pcm_prepare_for_input,    /* */
 344   pas_pcm_prepare_for_output,   /* */
 345   pas_pcm_reset,                /* */
 346   pas_pcm_reset,                /* halt_xfer */
 347   NULL,                         /* has_output_drained */
 348   NULL                          /* copy_from_user */
 349 };
 350 
 351 long
 352 pas_pcm_init (long mem_start, struct address_info *hw_config)
     /* [previous][next][first][last][top][bottom][index][help] */
 353 {
 354   TRACE (printk ("pas2_pcm.c: long pas_pcm_init(long mem_start = %X)\n", mem_start));
 355 
 356   pcm_bitsok = 8;
 357   if (pas_read (OPERATION_MODE_1) & O_M_1_PCM_TYPE)
 358     pcm_bitsok |= 16;
 359 
 360   pcm_set_speed (DSP_DEFAULT_SPEED);
 361 
 362   if (num_dspdevs < MAX_DSP_DEV)
 363     {
 364       dsp_devs[my_devnum = num_dspdevs++] = &pas_pcm_operations;
 365       sound_dsp_dmachan[my_devnum] = hw_config->dma;
 366 #ifndef PAS_NO_AUTODMA
 367       if (hw_config->dma > 3)
 368         {
 369           sound_buffcounts[my_devnum] = 1;
 370           sound_buffsizes[my_devnum] = 2 * 65536;
 371           sound_dma_automode[my_devnum] = 1;
 372         }
 373       else
 374         {
 375           sound_buffcounts[my_devnum] = 1;
 376           sound_buffsizes[my_devnum] = DSP_BUFFSIZE;
 377           sound_dma_automode[my_devnum] = 1;
 378         }
 379 #else
 380           sound_buffcounts[my_devnum] = 2;
 381           sound_buffsizes[my_devnum] = DSP_BUFFSIZE;
 382           sound_dma_automode[my_devnum] = 0;
 383 #endif
 384     }
 385   else
 386     printk ("PAS2: Too many PCM devices available\n");
 387 
 388   return mem_start;
 389 }
 390 
 391 void
 392 pas_pcm_interrupt (unsigned char status, int cause)
     /* [previous][next][first][last][top][bottom][index][help] */
 393 {
 394   if (cause == 1)               /* PCM buffer done */
 395     {
 396       /*
 397        * Halt the PCM first. Otherwise we don't have time to start a new
 398        * block before the PCM chip proceeds to the next sample
 399        */
 400 
 401       if (!sound_dma_automode[my_devnum])
 402         {
 403           pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE,
 404                      PCM_CONTROL);
 405         }
 406 
 407       switch (pcm_mode)
 408         {
 409 
 410         case PCM_DAC:
 411           DMAbuf_outputintr (my_devnum, 1);
 412           break;
 413 
 414         case PCM_ADC:
 415           DMAbuf_inputintr (my_devnum);
 416           break;
 417 
 418         default:
 419           printk ("PAS: Unexpected PCM interrupt\n");
 420         }
 421     }
 422 }
 423 
 424 #endif
 425 
 426 #endif

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