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  * 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       if (local)
 152         return pcm_set_channels (arg);
 153       return IOCTL_OUT (arg, pcm_set_channels (IOCTL_IN (arg)));
 154       break;
 155 
 156     case SOUND_PCM_READ_CHANNELS:
 157       if (local)
 158         return pcm_channels;
 159       return IOCTL_OUT (arg, pcm_channels);
 160       break;
 161 
 162     case SNDCTL_DSP_SAMPLESIZE:
 163       if (local)
 164         return pcm_set_bits (arg);
 165       return IOCTL_OUT (arg, pcm_set_bits (IOCTL_IN (arg)));
 166       break;
 167 
 168     case SOUND_PCM_READ_BITS:
 169       if (local)
 170         return pcm_bits;
 171       return IOCTL_OUT (arg, pcm_bits);
 172 
 173     case SOUND_PCM_WRITE_FILTER:        /* NOT YET IMPLEMENTED */
 174       if (IOCTL_IN (arg) > 1)
 175         return IOCTL_OUT (arg, RET_ERROR (EINVAL));
 176       break;
 177 
 178       pcm_filter = IOCTL_IN (arg);
 179     case SOUND_PCM_READ_FILTER:
 180       return IOCTL_OUT (arg, pcm_filter);
 181       break;
 182 
 183     default:
 184       return RET_ERROR (EINVAL);
 185     }
 186 
 187   return RET_ERROR (EINVAL);
 188 }
 189 
 190 static void
 191 pas_pcm_reset (int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 192 {
 193   TRACE (printk ("pas2_pcm.c: static void pas_pcm_reset(void)\n"));
 194 
 195   pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE, PCM_CONTROL);
 196 }
 197 
 198 static int
 199 pas_pcm_open (int dev, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 200 {
 201   int             err;
 202 
 203   TRACE (printk ("pas2_pcm.c: static int pas_pcm_open(int mode = %X)\n", mode));
 204 
 205   if ((err = pas_set_intr (PAS_PCM_INTRBITS)) < 0)
 206     return err;
 207 
 208   if (!DMAbuf_open_dma (dev))
 209     {
 210       pas_remove_intr (PAS_PCM_INTRBITS);
 211       return RET_ERROR (EBUSY);
 212     }
 213 
 214   pcm_count = 0;
 215 
 216   return 0;
 217 }
 218 
 219 static void
 220 pas_pcm_close (int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 221 {
 222   unsigned long   flags;
 223 
 224   TRACE (printk ("pas2_pcm.c: static void pas_pcm_close(void)\n"));
 225 
 226   DISABLE_INTR (flags);
 227 
 228   pas_pcm_reset (dev);
 229   DMAbuf_close_dma (dev);
 230   pas_remove_intr (PAS_PCM_INTRBITS);
 231   pcm_mode = PCM_NON;
 232 
 233   RESTORE_INTR (flags);
 234 }
 235 
 236 static void
 237 pas_pcm_output_block (int dev, unsigned long buf, int count,
     /* [previous][next][first][last][top][bottom][index][help] */
 238                       int intrflag, int restart_dma)
 239 {
 240   unsigned long   flags, cnt;
 241 
 242   TRACE (printk ("pas2_pcm.c: static void pas_pcm_output_block(char *buf = %P, int count = %X)\n", buf, count));
 243 
 244   cnt = count;
 245   if (sound_dsp_dmachan[dev] > 3)
 246     cnt >>= 1;
 247 
 248   if (sound_dma_automode[dev] &&
 249       intrflag &&
 250       cnt == pcm_count)
 251     return;                     /* Auto mode on. No need to react */
 252 
 253   DISABLE_INTR (flags);
 254 
 255   pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE,
 256              PCM_CONTROL);
 257 
 258   if (restart_dma)
 259     DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
 260 
 261   if (sound_dsp_dmachan[dev] > 3)
 262     count >>= 1;
 263 
 264   if (count != pcm_count)
 265     {
 266       pas_write (pas_read (FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
 267       pas_write (S_C_C_SAMPLE_BUFFER | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL);
 268       pas_write (count & 0xff, SAMPLE_BUFFER_COUNTER);
 269       pas_write ((count >> 8) & 0xff, SAMPLE_BUFFER_COUNTER);
 270       pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
 271 
 272       pcm_count = count;
 273     }
 274   pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY);
 275   pas_write (pas_read (PCM_CONTROL) | P_C_PCM_ENABLE | P_C_PCM_DAC_MODE, PCM_CONTROL);
 276 
 277   pcm_mode = PCM_DAC;
 278 
 279   RESTORE_INTR (flags);
 280 }
 281 
 282 static void
 283 pas_pcm_start_input (int dev, unsigned long buf, int count,
     /* [previous][next][first][last][top][bottom][index][help] */
 284                      int intrflag, int restart_dma)
 285 {
 286   unsigned long   flags;
 287   int             cnt;
 288 
 289   TRACE (printk ("pas2_pcm.c: static void pas_pcm_start_input(char *buf = %P, int count = %X)\n", buf, count));
 290 
 291   cnt = count;
 292   if (sound_dsp_dmachan[dev] > 3)
 293     cnt >>= 1;
 294 
 295   if (sound_dma_automode[my_devnum] &&
 296       intrflag &&
 297       cnt == pcm_count)
 298     return;                     /* Auto mode on. No need to react */
 299 
 300   DISABLE_INTR (flags);
 301 
 302   if (restart_dma)
 303     DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
 304 
 305   if (sound_dsp_dmachan[dev] > 3)
 306     count >>= 1;
 307 
 308   if (count != pcm_count)
 309     {
 310       pas_write (pas_read (FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
 311       pas_write (S_C_C_SAMPLE_BUFFER | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL);
 312       pas_write (count & 0xff, SAMPLE_BUFFER_COUNTER);
 313       pas_write ((count >> 8) & 0xff, SAMPLE_BUFFER_COUNTER);
 314       pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
 315 
 316       pcm_count = count;
 317     }
 318   pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY);
 319   pas_write ((pas_read (PCM_CONTROL) | P_C_PCM_ENABLE) & ~P_C_PCM_DAC_MODE, PCM_CONTROL);
 320 
 321   pcm_mode = PCM_ADC;
 322 
 323   RESTORE_INTR (flags);
 324 }
 325 
 326 static int
 327 pas_pcm_prepare_for_input (int dev, int bsize, int bcount)
     /* [previous][next][first][last][top][bottom][index][help] */
 328 {
 329   return 0;
 330 }
 331 static int
 332 pas_pcm_prepare_for_output (int dev, int bsize, int bcount)
     /* [previous][next][first][last][top][bottom][index][help] */
 333 {
 334   return 0;
 335 }
 336 
 337 static struct audio_operations pas_pcm_operations =
 338 {
 339   "Pro Audio Spectrum",
 340   NOTHING_SPECIAL,
 341   pas_pcm_open,
 342   pas_pcm_close,
 343   pas_pcm_output_block,
 344   pas_pcm_start_input,
 345   pas_pcm_ioctl,
 346   pas_pcm_prepare_for_input,
 347   pas_pcm_prepare_for_output,
 348   pas_pcm_reset,
 349   pas_pcm_reset,                /* halt_xfer */
 350   NULL,                         /* has_output_drained */
 351   NULL                          /* copy_from_user */
 352 };
 353 
 354 long
 355 pas_pcm_init (long mem_start, struct address_info *hw_config)
     /* [previous][next][first][last][top][bottom][index][help] */
 356 {
 357   TRACE (printk ("pas2_pcm.c: long pas_pcm_init(long mem_start = %X)\n", mem_start));
 358 
 359   pcm_bitsok = 8;
 360   if (pas_read (OPERATION_MODE_1) & O_M_1_PCM_TYPE)
 361     pcm_bitsok |= 16;
 362 
 363   pcm_set_speed (DSP_DEFAULT_SPEED);
 364 
 365   if (num_dspdevs < MAX_DSP_DEV)
 366     {
 367       dsp_devs[my_devnum = num_dspdevs++] = &pas_pcm_operations;
 368       sound_dsp_dmachan[my_devnum] = hw_config->dma;
 369 #ifndef PAS_NO_AUTODMA
 370       if (hw_config->dma > 3)
 371         {
 372           sound_buffcounts[my_devnum] = 1;
 373           sound_buffsizes[my_devnum] = 2 * 65536;
 374           sound_dma_automode[my_devnum] = 1;
 375         }
 376       else
 377         {
 378           sound_buffcounts[my_devnum] = 1;
 379           sound_buffsizes[my_devnum] = DSP_BUFFSIZE;
 380           sound_dma_automode[my_devnum] = 1;
 381         }
 382 #else
 383       sound_buffcounts[my_devnum] = 2;
 384       sound_buffsizes[my_devnum] = DSP_BUFFSIZE;
 385       sound_dma_automode[my_devnum] = 0;
 386 #endif
 387     }
 388   else
 389     printk ("PAS2: Too many PCM devices available\n");
 390 
 391   return mem_start;
 392 }
 393 
 394 void
 395 pas_pcm_interrupt (unsigned char status, int cause)
     /* [previous][next][first][last][top][bottom][index][help] */
 396 {
 397   if (cause == 1)               /* PCM buffer done */
 398     {
 399       /*
 400        * Halt the PCM first. Otherwise we don't have time to start a new
 401        * block before the PCM chip proceeds to the next sample
 402        */
 403 
 404       if (!sound_dma_automode[my_devnum])
 405         {
 406           pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE,
 407                      PCM_CONTROL);
 408         }
 409 
 410       switch (pcm_mode)
 411         {
 412 
 413         case PCM_DAC:
 414           DMAbuf_outputintr (my_devnum, 1);
 415           break;
 416 
 417         case PCM_ADC:
 418           DMAbuf_inputintr (my_devnum);
 419           break;
 420 
 421         default:
 422           printk ("PAS: Unexpected PCM interrupt\n");
 423         }
 424     }
 425 }
 426 
 427 #endif
 428 
 429 #endif

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