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

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