home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.0 / LINUX-1.0 / LINUX-1 / linux / drivers / sound / pas2_pcm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-14  |  10.5 KB  |  429 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)        /* (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)
  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)
  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)
  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)
  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)
  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)
  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)
  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, 
  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, 
  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)
  328. {
  329.   return 0;
  330. }
  331. static int
  332. pas_pcm_prepare_for_output (int dev, int bsize, int bcount)
  333. {
  334.   return 0;
  335. }
  336.  
  337. static struct audio_operations pas_pcm_operations =
  338. {
  339.   "Pro Audio Spectrum",
  340.   pas_pcm_open,            /* */
  341.   pas_pcm_close,        /* */
  342.   pas_pcm_output_block,        /* */
  343.   pas_pcm_start_input,        /* */
  344.   pas_pcm_ioctl,        /* */
  345.   pas_pcm_prepare_for_input,    /* */
  346.   pas_pcm_prepare_for_output,    /* */
  347.   pas_pcm_reset,        /* */
  348.   pas_pcm_reset,        /* halt_xfer */
  349.   NULL,                /* has_output_drained */
  350.   NULL                /* copy_from_user */
  351. };
  352.  
  353. long
  354. pas_pcm_init (long mem_start, struct address_info *hw_config)
  355. {
  356.   TRACE (printk ("pas2_pcm.c: long pas_pcm_init(long mem_start = %X)\n", mem_start));
  357.  
  358.   pcm_bitsok = 8;
  359.   if (pas_read (OPERATION_MODE_1) & O_M_1_PCM_TYPE)
  360.     pcm_bitsok |= 16;
  361.  
  362.   pcm_set_speed (DSP_DEFAULT_SPEED);
  363.  
  364.   if (num_dspdevs < MAX_DSP_DEV)
  365.     {
  366.       dsp_devs[my_devnum = num_dspdevs++] = &pas_pcm_operations;
  367.       sound_dsp_dmachan[my_devnum] = hw_config->dma;
  368. #ifndef PAS_NO_AUTODMA
  369.       if (hw_config->dma > 3)
  370.     {
  371.       sound_buffcounts[my_devnum] = 1;
  372.       sound_buffsizes[my_devnum] = 2 * 65536;
  373.       sound_dma_automode[my_devnum] = 1;
  374.     }
  375.       else
  376.     {
  377.       sound_buffcounts[my_devnum] = 1;
  378.       sound_buffsizes[my_devnum] = DSP_BUFFSIZE;
  379.       sound_dma_automode[my_devnum] = 1;
  380.     }
  381. #else
  382.       sound_buffcounts[my_devnum] = 2;
  383.       sound_buffsizes[my_devnum] = DSP_BUFFSIZE;
  384.       sound_dma_automode[my_devnum] = 0;
  385. #endif
  386.     }
  387.   else
  388.     printk ("PAS2: Too many PCM devices available\n");
  389.  
  390.   return mem_start;
  391. }
  392.  
  393. void
  394. pas_pcm_interrupt (unsigned char status, int cause)
  395. {
  396.   if (cause == 1)        /* PCM buffer done */
  397.     {
  398.       /*
  399.        * Halt the PCM first. Otherwise we don't have time to start a new
  400.        * block before the PCM chip proceeds to the next sample
  401.        */
  402.  
  403.       if (!sound_dma_automode[my_devnum])
  404.     {
  405.       pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE,
  406.              PCM_CONTROL);
  407.     }
  408.  
  409.       switch (pcm_mode)
  410.     {
  411.  
  412.     case PCM_DAC:
  413.       DMAbuf_outputintr (my_devnum, 1);
  414.       break;
  415.  
  416.     case PCM_ADC:
  417.       DMAbuf_inputintr (my_devnum);
  418.       break;
  419.  
  420.     default:
  421.       printk ("PAS: Unexpected PCM interrupt\n");
  422.     }
  423.     }
  424. }
  425.  
  426. #endif
  427.  
  428. #endif
  429.