home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / drivers / sound / pas2_pcm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-19  |  11.0 KB  |  454 lines

  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)
  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 really *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.   DISABLE_INTR (flags);
  107.  
  108.   pas_write (tmp & ~(F_F_PCM_RATE_COUNTER | F_F_PCM_BUFFER_COUNTER), FILTER_FREQUENCY);
  109.   pas_write (S_C_C_SAMPLE_RATE | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL);
  110.   pas_write (foo & 0xff, SAMPLE_RATE_TIMER);
  111.   pas_write ((foo >> 8) & 0xff, SAMPLE_RATE_TIMER);
  112.   pas_write (tmp, FILTER_FREQUENCY);
  113.  
  114.   RESTORE_INTR (flags);
  115.  
  116.   return pcm_speed;
  117. }
  118.  
  119. int
  120. pcm_set_channels (int arg)
  121. {
  122.  
  123.   if ((arg != 1) && (arg != 2))
  124.     return pcm_channels;
  125.  
  126.   if (arg != pcm_channels)
  127.     {
  128.       pas_write (pas_read (PCM_CONTROL) ^ P_C_PCM_MONO, PCM_CONTROL);
  129.  
  130.       pcm_channels = arg;
  131.       pcm_set_speed (pcm_speed);/*
  132.                      * The speed must be reinitialized
  133.                      */
  134.     }
  135.  
  136.   return pcm_channels;
  137. }
  138.  
  139. int
  140. pcm_set_bits (int arg)
  141. {
  142.   if ((arg & pcm_bitsok) != arg)
  143.     return pcm_bits;
  144.  
  145.   if (arg != pcm_bits)
  146.     {
  147.       pas_write (pas_read (SYSTEM_CONFIGURATION_2) ^ S_C_2_PCM_16_BIT, SYSTEM_CONFIGURATION_2);
  148.  
  149.       pcm_bits = arg;
  150.     }
  151.  
  152.   return pcm_bits;
  153. }
  154.  
  155. static int
  156. pas_pcm_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
  157. {
  158.   TRACE (printk ("pas2_pcm.c: static int pas_pcm_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg));
  159.  
  160.   switch (cmd)
  161.     {
  162.     case SOUND_PCM_WRITE_RATE:
  163.       if (local)
  164.     return pcm_set_speed (arg);
  165.       return IOCTL_OUT (arg, pcm_set_speed (IOCTL_IN (arg)));
  166.       break;
  167.  
  168.     case SOUND_PCM_READ_RATE:
  169.       if (local)
  170.     return pcm_speed;
  171.       return IOCTL_OUT (arg, pcm_speed);
  172.       break;
  173.  
  174.     case SNDCTL_DSP_STEREO:
  175.       if (local)
  176.     return pcm_set_channels (arg + 1) - 1;
  177.       return IOCTL_OUT (arg, pcm_set_channels (IOCTL_IN (arg) + 1) - 1);
  178.       break;
  179.  
  180.     case SOUND_PCM_WRITE_CHANNELS:
  181.       if (local)
  182.     return pcm_set_channels (arg);
  183.       return IOCTL_OUT (arg, pcm_set_channels (IOCTL_IN (arg)));
  184.       break;
  185.  
  186.     case SOUND_PCM_READ_CHANNELS:
  187.       if (local)
  188.     return pcm_channels;
  189.       return IOCTL_OUT (arg, pcm_channels);
  190.       break;
  191.  
  192.     case SNDCTL_DSP_SETFMT:
  193.       if (local)
  194.     return pcm_set_bits (arg);
  195.       return IOCTL_OUT (arg, pcm_set_bits (IOCTL_IN (arg)));
  196.       break;
  197.  
  198.     case SOUND_PCM_READ_BITS:
  199.       if (local)
  200.     return pcm_bits;
  201.       return IOCTL_OUT (arg, pcm_bits);
  202.  
  203.     case SOUND_PCM_WRITE_FILTER:    /*
  204.                      * NOT YET IMPLEMENTED
  205.                      */
  206.       if (IOCTL_IN (arg) > 1)
  207.     return IOCTL_OUT (arg, RET_ERROR (EINVAL));
  208.       break;
  209.  
  210.       pcm_filter = IOCTL_IN (arg);
  211.     case SOUND_PCM_READ_FILTER:
  212.       return IOCTL_OUT (arg, pcm_filter);
  213.       break;
  214.  
  215.     default:
  216.       return RET_ERROR (EINVAL);
  217.     }
  218.  
  219.   return RET_ERROR (EINVAL);
  220. }
  221.  
  222. static void
  223. pas_pcm_reset (int dev)
  224. {
  225.   TRACE (printk ("pas2_pcm.c: static void pas_pcm_reset(void)\n"));
  226.  
  227.   pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE, PCM_CONTROL);
  228. }
  229.  
  230. static int
  231. pas_pcm_open (int dev, int mode)
  232. {
  233.   int             err;
  234.  
  235.   TRACE (printk ("pas2_pcm.c: static int pas_pcm_open(int mode = %X)\n", mode));
  236.  
  237.   if ((err = pas_set_intr (PAS_PCM_INTRBITS)) < 0)
  238.     return err;
  239.  
  240.   if (DMAbuf_open_dma (dev) < 0)
  241.     {
  242.       pas_remove_intr (PAS_PCM_INTRBITS);
  243.       return RET_ERROR (EBUSY);
  244.     }
  245.  
  246.   pcm_count = 0;
  247.  
  248.   return 0;
  249. }
  250.  
  251. static void
  252. pas_pcm_close (int dev)
  253. {
  254.   unsigned long   flags;
  255.  
  256.   TRACE (printk ("pas2_pcm.c: static void pas_pcm_close(void)\n"));
  257.  
  258.   DISABLE_INTR (flags);
  259.  
  260.   pas_pcm_reset (dev);
  261.   DMAbuf_close_dma (dev);
  262.   pas_remove_intr (PAS_PCM_INTRBITS);
  263.   pcm_mode = PCM_NON;
  264.  
  265.   RESTORE_INTR (flags);
  266. }
  267.  
  268. static void
  269. pas_pcm_output_block (int dev, unsigned long buf, int count,
  270.               int intrflag, int restart_dma)
  271. {
  272.   unsigned long   flags, cnt;
  273.  
  274.   TRACE (printk ("pas2_pcm.c: static void pas_pcm_output_block(char *buf = %P, int count = %X)\n", buf, count));
  275.  
  276.   cnt = count;
  277.   if (audio_devs[dev]->dmachan > 3)
  278.     cnt >>= 1;
  279.  
  280.   if (audio_devs[dev]->flags & DMA_AUTOMODE &&
  281.       intrflag &&
  282.       cnt == pcm_count)
  283.     return;            /*
  284.                  * Auto mode on. No need to react
  285.                  */
  286.  
  287.   DISABLE_INTR (flags);
  288.  
  289.   pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE,
  290.          PCM_CONTROL);
  291.  
  292.   if (restart_dma)
  293.     DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
  294.  
  295.   if (audio_devs[dev]->dmachan > 3)
  296.     count >>= 1;
  297.  
  298.   if (count != pcm_count)
  299.     {
  300.       pas_write (pas_read (FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
  301.       pas_write (S_C_C_SAMPLE_BUFFER | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL);
  302.       pas_write (count & 0xff, SAMPLE_BUFFER_COUNTER);
  303.       pas_write ((count >> 8) & 0xff, SAMPLE_BUFFER_COUNTER);
  304.       pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
  305.  
  306.       pcm_count = count;
  307.     }
  308.   pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY);
  309.   pas_write (pas_read (PCM_CONTROL) | P_C_PCM_ENABLE | P_C_PCM_DAC_MODE, PCM_CONTROL);
  310.  
  311.   pcm_mode = PCM_DAC;
  312.  
  313.   RESTORE_INTR (flags);
  314. }
  315.  
  316. static void
  317. pas_pcm_start_input (int dev, unsigned long buf, int count,
  318.              int intrflag, int restart_dma)
  319. {
  320.   unsigned long   flags;
  321.   int             cnt;
  322.  
  323.   TRACE (printk ("pas2_pcm.c: static void pas_pcm_start_input(char *buf = %P, int count = %X)\n", buf, count));
  324.  
  325.   cnt = count;
  326.   if (audio_devs[dev]->dmachan > 3)
  327.     cnt >>= 1;
  328.  
  329.   if (audio_devs[my_devnum]->flags & DMA_AUTOMODE &&
  330.       intrflag &&
  331.       cnt == pcm_count)
  332.     return;            /*
  333.                  * Auto mode on. No need to react
  334.                  */
  335.  
  336.   DISABLE_INTR (flags);
  337.  
  338.   if (restart_dma)
  339.     DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
  340.  
  341.   if (audio_devs[dev]->dmachan > 3)
  342.     count >>= 1;
  343.  
  344.   if (count != pcm_count)
  345.     {
  346.       pas_write (pas_read (FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
  347.       pas_write (S_C_C_SAMPLE_BUFFER | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL);
  348.       pas_write (count & 0xff, SAMPLE_BUFFER_COUNTER);
  349.       pas_write ((count >> 8) & 0xff, SAMPLE_BUFFER_COUNTER);
  350.       pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
  351.  
  352.       pcm_count = count;
  353.     }
  354.   pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY);
  355.   pas_write ((pas_read (PCM_CONTROL) | P_C_PCM_ENABLE) & ~P_C_PCM_DAC_MODE, PCM_CONTROL);
  356.  
  357.   pcm_mode = PCM_ADC;
  358.  
  359.   RESTORE_INTR (flags);
  360. }
  361.  
  362. static int
  363. pas_pcm_prepare_for_input (int dev, int bsize, int bcount)
  364. {
  365.   return 0;
  366. }
  367. static int
  368. pas_pcm_prepare_for_output (int dev, int bsize, int bcount)
  369. {
  370.   return 0;
  371. }
  372.  
  373. static struct audio_operations pas_pcm_operations =
  374. {
  375.   "Pro Audio Spectrum",
  376.   DMA_AUTOMODE,
  377.   AFMT_U8 | AFMT_S16_LE,
  378.   NULL,
  379.   pas_pcm_open,
  380.   pas_pcm_close,
  381.   pas_pcm_output_block,
  382.   pas_pcm_start_input,
  383.   pas_pcm_ioctl,
  384.   pas_pcm_prepare_for_input,
  385.   pas_pcm_prepare_for_output,
  386.   pas_pcm_reset,
  387.   pas_pcm_reset,
  388.   NULL,
  389.   NULL
  390. };
  391.  
  392. long
  393. pas_pcm_init (long mem_start, struct address_info *hw_config)
  394. {
  395.   TRACE (printk ("pas2_pcm.c: long pas_pcm_init(long mem_start = %X)\n", mem_start));
  396.  
  397.   pcm_bitsok = 8;
  398.   if (pas_read (OPERATION_MODE_1) & O_M_1_PCM_TYPE)
  399.     pcm_bitsok |= 16;
  400.  
  401.   pcm_set_speed (DSP_DEFAULT_SPEED);
  402.  
  403.   if (num_audiodevs < MAX_AUDIO_DEV)
  404.     {
  405.       audio_devs[my_devnum = num_audiodevs++] = &pas_pcm_operations;
  406.       audio_devs[my_devnum]->dmachan = hw_config->dma;
  407.       audio_devs[my_devnum]->buffcount = 1;
  408.       audio_devs[my_devnum]->buffsize = 2 * DSP_BUFFSIZE;
  409.     }
  410.   else
  411.     printk ("PAS2: Too many PCM devices available\n");
  412.  
  413.   return mem_start;
  414. }
  415.  
  416. void
  417. pas_pcm_interrupt (unsigned char status, int cause)
  418. {
  419.   if (cause == 1)        /*
  420.                  * PCM buffer done
  421.                  */
  422.     {
  423.       /*
  424.        * Halt the PCM first. Otherwise we don't have time to start a new
  425.        * block before the PCM chip proceeds to the next sample
  426.        */
  427.  
  428.       if (!(audio_devs[my_devnum]->flags & DMA_AUTOMODE))
  429.     {
  430.       pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE,
  431.              PCM_CONTROL);
  432.     }
  433.  
  434.       switch (pcm_mode)
  435.     {
  436.  
  437.     case PCM_DAC:
  438.       DMAbuf_outputintr (my_devnum, 1);
  439.       break;
  440.  
  441.     case PCM_ADC:
  442.       DMAbuf_inputintr (my_devnum);
  443.       break;
  444.  
  445.     default:
  446.       printk ("PAS: Unexpected PCM interrupt\n");
  447.     }
  448.     }
  449. }
  450.  
  451. #endif
  452.  
  453. #endif
  454.