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

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