root/drivers/sound/soundcard.c

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

DEFINITIONS

This source file includes following definitions.
  1. snd_ioctl_return
  2. sound_read
  3. sound_write
  4. sound_lseek
  5. sound_open
  6. sound_release
  7. sound_ioctl
  8. sound_select
  9. soundcard_init
  10. tenmicrosec
  11. snd_set_irq_handler
  12. snd_release_irq
  13. request_sound_timer
  14. sound_stop_timer
  15. valid_dma_page
  16. sound_mem_init
  17. soundcard_init
  18. sound_mem_init

   1 /*
   2  * linux/kernel/chr_drv/sound/soundcard.c
   3  *
   4  * Soundcard driver for Linux
   5  *
   6  * Copyright by Hannu Savolainen 1993
   7  *
   8  * Redistribution and use in source and binary forms, with or without
   9  * modification, are permitted provided that the following conditions are
  10  * met: 1. Redistributions of source code must retain the above copyright
  11  * notice, this list of conditions and the following disclaimer. 2.
  12  * Redistributions in binary form must reproduce the above copyright notice,
  13  * this list of conditions and the following disclaimer in the documentation
  14  * and/or other materials provided with the distribution.
  15  *
  16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
  17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
  20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  23  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  26  * SUCH DAMAGE.
  27  *
  28  */
  29 
  30 #include "sound_config.h"
  31 
  32 #ifdef CONFIGURE_SOUNDCARD
  33 
  34 #include <linux/major.h>
  35 
  36 static int      soundcards_installed = 0;       /* Number of installed
  37 
  38                                                  * soundcards */
  39 static int      soundcard_configured = 0;
  40 
  41 static struct fileinfo files[SND_NDEVS];
  42 
  43 int
  44 snd_ioctl_return (int *addr, int value)
     /* [previous][next][first][last][top][bottom][index][help] */
  45 {
  46   if (value < 0)
  47     return value;
  48 
  49   PUT_WORD_TO_USER (addr, 0, value);
  50   return 0;
  51 }
  52 
  53 static int
  54 sound_read (struct inode *inode, struct file *file, char *buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
  55 {
  56   int             dev;
  57 
  58   dev = inode->i_rdev;
  59   dev = MINOR (dev);
  60 
  61   return sound_read_sw (dev, &files[dev], buf, count);
  62 }
  63 
  64 static int
  65 sound_write (struct inode *inode, struct file *file, char *buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
  66 {
  67   int             dev;
  68 
  69   dev = inode->i_rdev;
  70   dev = MINOR (dev);
  71 
  72   return sound_write_sw (dev, &files[dev], buf, count);
  73 }
  74 
  75 static int
  76 sound_lseek (struct inode *inode, struct file *file, off_t offset, int orig)
     /* [previous][next][first][last][top][bottom][index][help] */
  77 {
  78   return RET_ERROR (EPERM);
  79 }
  80 
  81 static int
  82 sound_open (struct inode *inode, struct file *file)
     /* [previous][next][first][last][top][bottom][index][help] */
  83 {
  84   int             dev;
  85 
  86   dev = inode->i_rdev;
  87   dev = MINOR (dev);
  88 
  89   if (!soundcard_configured && dev != SND_DEV_CTL && dev != SND_DEV_STATUS)
  90     {
  91       printk ("SoundCard Error: The soundcard system has not been configured\n");
  92       return RET_ERROR (ENXIO);
  93     }
  94 
  95   files[dev].mode = 0;
  96 
  97   if ((file->f_flags & O_ACCMODE) == O_RDWR)
  98     files[dev].mode = OPEN_READWRITE;
  99   if ((file->f_flags & O_ACCMODE) == O_RDONLY)
 100     files[dev].mode = OPEN_READ;
 101   if ((file->f_flags & O_ACCMODE) == O_WRONLY)
 102     files[dev].mode = OPEN_WRITE;
 103 
 104   return sound_open_sw (dev, &files[dev]);
 105 }
 106 
 107 static void
 108 sound_release (struct inode *inode, struct file *file)
     /* [previous][next][first][last][top][bottom][index][help] */
 109 {
 110   int             dev;
 111 
 112   dev = inode->i_rdev;
 113   dev = MINOR (dev);
 114 
 115   sound_release_sw (dev, &files[dev]);
 116 }
 117 
 118 static int
 119 sound_ioctl (struct inode *inode, struct file *file,
     /* [previous][next][first][last][top][bottom][index][help] */
 120              unsigned int cmd, unsigned long arg)
 121 {
 122   int             dev;
 123 
 124   dev = inode->i_rdev;
 125   dev = MINOR (dev);
 126 
 127   return sound_ioctl_sw (dev, &files[dev], cmd, arg);
 128 }
 129 
 130 static int
 131 sound_select (struct inode *inode, struct file *file, int sel_type, select_table * wait)
     /* [previous][next][first][last][top][bottom][index][help] */
 132 {
 133   int             dev;
 134 
 135   dev = inode->i_rdev;
 136   dev = MINOR (dev);
 137 
 138   DEB (printk ("sound_select(dev=%d, type=0x%x)\n", dev, sel_type));
 139 
 140   switch (dev & 0x0f)
 141     {
 142 #ifndef EXCLUDE_SEQUENCER
 143     case SND_DEV_SEQ:
 144       return sequencer_select (dev, &files[dev], sel_type, wait);
 145       break;
 146 #endif
 147 
 148 #ifndef EXCLUDE_MIDI
 149     case SND_DEV_MIDIN:
 150       return MIDIbuf_select (dev, &files[dev], sel_type, wait);
 151       break;
 152 #endif
 153 
 154     default:
 155       return 0;
 156     }
 157 
 158   return 0;
 159 }
 160 
 161 static struct file_operations sound_fops =
 162 {
 163   sound_lseek,
 164   sound_read,
 165   sound_write,
 166   NULL,                         /* sound_readdir */
 167   sound_select,
 168   sound_ioctl,
 169   NULL,
 170   sound_open,
 171   sound_release
 172 };
 173 
 174 long
 175 soundcard_init (long mem_start)
     /* [previous][next][first][last][top][bottom][index][help] */
 176 {
 177   register_chrdev (SOUND_MAJOR, "sound", &sound_fops);
 178 
 179   soundcard_configured = 1;
 180 
 181   mem_start = sndtable_init (mem_start);        /* Initialize call tables and
 182                                                  * detect cards */
 183 
 184   if (!(soundcards_installed = sndtable_get_cardcount ()))
 185     return mem_start;           /* No cards detected */
 186 
 187 #ifndef EXCLUDE_AUDIO
 188   if (num_audiodevs)            /* Audio devices present */
 189     {
 190       mem_start = DMAbuf_init (mem_start);
 191       mem_start = audio_init (mem_start);
 192     }
 193 #endif
 194 
 195 #ifndef EXCLUDE_MIDI
 196   if (num_midis)
 197     mem_start = MIDIbuf_init (mem_start);
 198 #endif
 199 
 200 #ifndef EXCLUDE_SEQUENCER
 201   if (num_midis + num_synths)
 202     mem_start = sequencer_init (mem_start);
 203 #endif
 204 
 205   return mem_start;
 206 }
 207 
 208 void
 209 tenmicrosec (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 210 {
 211   int             i;
 212 
 213   for (i = 0; i < 16; i++)
 214     inb (0x80);
 215 }
 216 
 217 int
 218 snd_set_irq_handler (int interrupt_level, void (*hndlr) (int))
     /* [previous][next][first][last][top][bottom][index][help] */
 219 {
 220   int             retcode;
 221 
 222   struct sigaction sa;
 223 
 224   sa.sa_handler = hndlr;
 225 
 226 #ifdef SND_SA_INTERRUPT
 227   sa.sa_flags = SA_INTERRUPT;
 228 #else
 229   sa.sa_flags = 0;
 230 #endif
 231 
 232   sa.sa_mask = 0;
 233   sa.sa_restorer = NULL;
 234 
 235   retcode = irqaction (interrupt_level, &sa);
 236 
 237   if (retcode < 0)
 238     {
 239       printk ("Sound: IRQ%d already in use\n", interrupt_level);
 240     }
 241 
 242   return retcode;
 243 }
 244 
 245 void
 246 snd_release_irq (int vect)
     /* [previous][next][first][last][top][bottom][index][help] */
 247 {
 248   free_irq (vect);
 249 }
 250 
 251 #ifndef EXCLUDE_SEQUENCER
 252 void
 253 request_sound_timer (int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 254 {
 255   extern unsigned long seq_time;
 256 
 257 #if 1
 258   if (count < 0)
 259     count = jiffies + (-count);
 260   else
 261     count += seq_time;
 262   timer_table[SOUND_TIMER].fn = sequencer_timer;
 263   timer_table[SOUND_TIMER].expires = count;
 264   timer_active |= 1 << SOUND_TIMER;
 265 #endif
 266 }
 267 
 268 #endif
 269 
 270 void
 271 sound_stop_timer (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 272 {
 273 #if 1
 274   timer_table[SOUND_TIMER].expires = 0;
 275   timer_active &= ~(1 << SOUND_TIMER);
 276 #endif
 277 }
 278 
 279 #ifndef EXCLUDE_AUDIO
 280 static int
 281 valid_dma_page (unsigned long addr, unsigned long dev_buffsize, unsigned long dma_pagesize)
     /* [previous][next][first][last][top][bottom][index][help] */
 282 {
 283   if (((addr & (dma_pagesize - 1)) + dev_buffsize) <= dma_pagesize)
 284     return 1;
 285   else
 286     return 0;
 287 }
 288 
 289 void
 290 sound_mem_init (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 291 {
 292   int             i, dev;
 293   unsigned long   start_addr, end_addr, mem_ptr, dma_pagesize;
 294   struct dma_buffparms *dmap;
 295 
 296   mem_ptr = high_memory;
 297 
 298   /* Some sanity checks */
 299 
 300   if (mem_ptr > (16 * 1024 * 1024))
 301     mem_ptr = 16 * 1024 * 1024; /* Limit to 16M */
 302 
 303   for (dev = 0; dev < num_audiodevs; dev++)     /* Enumerate devices */
 304     if (audio_devs[dev]->buffcount > 0 && audio_devs[dev]->dmachan >= 0)
 305       {
 306         dmap = audio_devs[dev]->dmap;
 307 
 308         if (audio_devs[dev]->flags & DMA_AUTOMODE)
 309           audio_devs[dev]->buffcount = 1;
 310 
 311         if (audio_devs[dev]->dmachan > 3 && audio_devs[dev]->buffsize > 65536)
 312           dma_pagesize = 131072;/* 128k */
 313         else
 314           dma_pagesize = 65536;
 315 
 316         /* More sanity checks */
 317 
 318         if (audio_devs[dev]->buffsize > dma_pagesize)
 319           audio_devs[dev]->buffsize = dma_pagesize;
 320         audio_devs[dev]->buffsize &= 0xfffff000;        /* Truncate to n*4k */
 321         if (audio_devs[dev]->buffsize < 4096)
 322           audio_devs[dev]->buffsize = 4096;
 323 
 324         /* Now allocate the buffers */
 325 
 326         for (dmap->raw_count = 0; dmap->raw_count < audio_devs[dev]->buffcount; dmap->raw_count++)
 327           {
 328             start_addr = mem_ptr - audio_devs[dev]->buffsize;
 329             if (!valid_dma_page (start_addr, audio_devs[dev]->buffsize, dma_pagesize))
 330               start_addr &= ~(dma_pagesize - 1);        /* Align address to
 331                                                          * dma_pagesize */
 332 
 333             end_addr = start_addr + audio_devs[dev]->buffsize - 1;
 334 
 335             dmap->raw_buf[dmap->raw_count] = (char *) start_addr;
 336             dmap->raw_buf_phys[dmap->raw_count] = start_addr;
 337             mem_ptr = start_addr;
 338 
 339             for (i = MAP_NR (start_addr); i <= MAP_NR (end_addr); i++)
 340               {
 341                 if (mem_map[i])
 342                   panic ("sound_mem_init: Page not free (driver incompatible with kernel).\n");
 343 
 344                 mem_map[i] = MAP_PAGE_RESERVED;
 345               }
 346           }
 347       }                         /* for dev */
 348 }
 349 
 350 #endif
 351 
 352 #else
 353 
 354 long
 355 soundcard_init (long mem_start) /* Dummy version */
     /* [previous][next][first][last][top][bottom][index][help] */
 356 {
 357   return mem_start;
 358 }
 359 
 360 #endif
 361 
 362 #if !defined(CONFIGURE_SOUNDCARD) || defined(EXCLUDE_AUDIO)
 363 void
 364 sound_mem_init (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 365 {
 366   /* Dummy version */
 367 }
 368 
 369 #endif

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