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. free_all_irqs
  11. init_module
  12. cleanup_module
  13. tenmicrosec
  14. snd_set_irq_handler
  15. snd_release_irq
  16. sound_alloc_dma
  17. sound_open_dma
  18. sound_free_dma
  19. sound_close_dma
  20. request_sound_timer
  21. sound_stop_timer
  22. sound_alloc_dmap
  23. sound_free_dmap
  24. soud_map_buffer
  25. soundcard_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  * Created modular version by Peter Trattler (peter@sbox.tu-graz.ac.at)
  31  */
  32 
  33 #include "sound_config.h"
  34 
  35 #ifdef CONFIGURE_SOUNDCARD
  36 
  37 #include <linux/major.h>
  38 
  39 #ifndef EXCLUDE_PNP
  40 #include <linux/pnp.h>
  41 #endif
  42 
  43 static int      chrdev_registered = 0;
  44 
  45 static int      is_unloading = 0;
  46 
  47 /*
  48  * Table for permanently allocated memory (used when unloading the module)
  49  */
  50 caddr_t         sound_mem_blocks[1024];
  51 int             sound_num_blocks = 0;
  52 
  53 static int      soundcard_configured = 0;
  54 
  55 static struct fileinfo files[SND_NDEVS];
  56 
  57 static char     dma_alloc_map[8] =
  58 {0};
  59 
  60 #define DMA_MAP_UNAVAIL         0
  61 #define DMA_MAP_FREE            1
  62 #define DMA_MAP_BUSY            2
  63 
  64 int
  65 snd_ioctl_return (int *addr, int value)
     /* [previous][next][first][last][top][bottom][index][help] */
  66 {
  67   if (value < 0)
  68     return value;
  69 
  70   put_fs_long (value, (long *) &((addr)[0]));
  71   return 0;
  72 }
  73 
  74 static int
  75 sound_read (struct inode *inode, struct file *file, char *buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
  76 {
  77   int             dev;
  78 
  79   dev = inode->i_rdev;
  80   dev = MINOR (dev);
  81   files[dev].flags = file->f_flags;
  82 
  83   return sound_read_sw (dev, &files[dev], buf, count);
  84 }
  85 
  86 static int
  87 sound_write (struct inode *inode, struct file *file, const char *buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
  88 {
  89   int             dev;
  90 
  91   dev = inode->i_rdev;
  92   dev = MINOR (dev);
  93   files[dev].flags = file->f_flags;
  94 
  95   return sound_write_sw (dev, &files[dev], buf, count);
  96 }
  97 
  98 static int
  99 sound_lseek (struct inode *inode, struct file *file, off_t offset, int orig)
     /* [previous][next][first][last][top][bottom][index][help] */
 100 {
 101   return -EPERM;
 102 }
 103 
 104 static int
 105 sound_open (struct inode *inode, struct file *file)
     /* [previous][next][first][last][top][bottom][index][help] */
 106 {
 107   int             dev, retval;
 108   struct fileinfo tmp_file;
 109 
 110   if (is_unloading)
 111     {
 112       printk ("Sound: Driver partially removed. Can't open device\n");
 113       return -EBUSY;
 114     }
 115 
 116   dev = inode->i_rdev;
 117   dev = MINOR (dev);
 118 
 119   if (!soundcard_configured && dev != SND_DEV_CTL && dev != SND_DEV_STATUS)
 120     {
 121       printk ("SoundCard Error: The soundcard system has not been configured\n");
 122       return -ENXIO;
 123     }
 124 
 125   tmp_file.mode = 0;
 126   tmp_file.flags = file->f_flags;
 127 
 128   if ((tmp_file.flags & O_ACCMODE) == O_RDWR)
 129     tmp_file.mode = OPEN_READWRITE;
 130   if ((tmp_file.flags & O_ACCMODE) == O_RDONLY)
 131     tmp_file.mode = OPEN_READ;
 132   if ((tmp_file.flags & O_ACCMODE) == O_WRONLY)
 133     tmp_file.mode = OPEN_WRITE;
 134 
 135   if ((retval = sound_open_sw (dev, &tmp_file)) < 0)
 136     return retval;
 137 
 138 #ifdef MODULE
 139   MOD_INC_USE_COUNT;
 140 #endif
 141 
 142   memcpy ((char *) &files[dev], (char *) &tmp_file, sizeof (tmp_file));
 143   return retval;
 144 }
 145 
 146 static void
 147 sound_release (struct inode *inode, struct file *file)
     /* [previous][next][first][last][top][bottom][index][help] */
 148 {
 149   int             dev;
 150 
 151   dev = inode->i_rdev;
 152   dev = MINOR (dev);
 153   files[dev].flags = file->f_flags;
 154 
 155   sound_release_sw (dev, &files[dev]);
 156 #ifdef MODULE
 157   MOD_DEC_USE_COUNT;
 158 #endif
 159 }
 160 
 161 static int
 162 sound_ioctl (struct inode *inode, struct file *file,
     /* [previous][next][first][last][top][bottom][index][help] */
 163              unsigned int cmd, unsigned long arg)
 164 {
 165   int             dev, err;
 166 
 167   dev = inode->i_rdev;
 168   dev = MINOR (dev);
 169   files[dev].flags = file->f_flags;
 170 
 171   if (cmd & IOC_INOUT)
 172     {
 173       /*
 174          * Have to validate the address given by the process.
 175        */
 176       int             len;
 177 
 178       len = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
 179 
 180       if (cmd & IOC_IN)
 181         {
 182           if ((err = verify_area (VERIFY_READ, (void *) arg, len)) < 0)
 183             return err;
 184         }
 185 
 186       if (cmd & IOC_OUT)
 187         {
 188           if ((err = verify_area (VERIFY_WRITE, (void *) arg, len)) < 0)
 189             return err;
 190         }
 191 
 192     }
 193 
 194   err = sound_ioctl_sw (dev, &files[dev], cmd, (caddr_t) arg);
 195 
 196   return err;
 197 }
 198 
 199 static int
 200 sound_select (struct inode *inode, struct file *file, int sel_type, select_table * wait)
     /* [previous][next][first][last][top][bottom][index][help] */
 201 {
 202   int             dev;
 203 
 204   dev = inode->i_rdev;
 205   dev = MINOR (dev);
 206   files[dev].flags = file->f_flags;
 207 
 208   DEB (printk ("sound_select(dev=%d, type=0x%x)\n", dev, sel_type));
 209 
 210   switch (dev & 0x0f)
 211     {
 212 #ifndef EXCLUDE_SEQUENCER
 213     case SND_DEV_SEQ:
 214     case SND_DEV_SEQ2:
 215       return sequencer_select (dev, &files[dev], sel_type, wait);
 216       break;
 217 #endif
 218 
 219 #ifndef EXCLUDE_MIDI
 220     case SND_DEV_MIDIN:
 221       return MIDIbuf_select (dev, &files[dev], sel_type, wait);
 222       break;
 223 #endif
 224 
 225 #ifndef EXCLUDE_AUDIO
 226     case SND_DEV_DSP:
 227     case SND_DEV_DSP16:
 228     case SND_DEV_AUDIO:
 229       return audio_select (dev, &files[dev], sel_type, wait);
 230       break;
 231 #endif
 232 
 233     default:
 234       return 0;
 235     }
 236 
 237   return 0;
 238 }
 239 
 240 
 241 static struct file_operations sound_fops =
 242 {
 243   sound_lseek,
 244   sound_read,
 245   sound_write,
 246   NULL,                         /* sound_readdir */
 247   sound_select,
 248   sound_ioctl,
 249   NULL,
 250   sound_open,
 251   sound_release
 252 };
 253 
 254 void
 255 soundcard_init (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 256 {
 257 #ifndef MODULE
 258   register_chrdev (SOUND_MAJOR, "sound", &sound_fops);
 259   chrdev_registered = 1;
 260 #endif
 261 
 262   soundcard_configured = 1;
 263 
 264   sndtable_init (0);            /* Initialize call tables and
 265                                    * detect cards */
 266 
 267 #ifndef EXCLUDE_PNP
 268   sound_pnp_init ();
 269 #endif
 270 
 271   if (sndtable_get_cardcount () == 0)
 272     return;                     /* No cards detected */
 273 
 274 #ifndef EXCLUDE_AUDIO
 275   if (num_audiodevs)            /* Audio devices present */
 276     {
 277       DMAbuf_init (0);
 278       audio_init (0);
 279     }
 280 #endif
 281 
 282 #ifndef EXCLUDE_MIDI
 283   if (num_midis)
 284     MIDIbuf_init (0);
 285 #endif
 286 
 287 #ifndef EXCLUDE_SEQUENCER
 288   if (num_midis + num_synths)
 289     sequencer_init (0);
 290 #endif
 291 
 292 }
 293 
 294 static unsigned long irqs = 0;
 295 
 296 #ifdef MODULE
 297 static void
 298 free_all_irqs (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 299 {
 300   int             i;
 301 
 302   for (i = 0; i < 31; i++)
 303     if (irqs & (1ul << i))
 304       {
 305         printk ("Sound warning: IRQ%d was left allocated. Fixed.\n", i);
 306         snd_release_irq (i);
 307       }
 308   irqs = 0;
 309 }
 310 
 311 #endif
 312 
 313 static int      debugmem = 0;   /* switched off by default */
 314 
 315 static int      sound[20] =
 316 {0};
 317 
 318 int
 319 init_module (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 320 {
 321   int             err;
 322   int             ints[21];
 323   int             i;
 324 
 325   if (0 < 0)
 326     {
 327       printk ("Sound: Incompatible kernel (wrapper) version\n");
 328       return -EINVAL;
 329     }
 330 
 331   /*
 332      * "sound=" command line handling by Harald Milz.
 333    */
 334   i = 0;
 335   while (i < 20 && sound[i])
 336     ints[i + 1] = sound[i++];
 337   ints[0] = i;
 338 
 339   if (i)
 340     sound_setup ("sound=", ints);
 341 
 342   err = register_chrdev (SOUND_MAJOR, "sound", &sound_fops);
 343   if (err)
 344     {
 345       printk ("sound: driver already loaded/included in kernel\n");
 346       return err;
 347     }
 348 
 349   chrdev_registered = 1;
 350   soundcard_init ();
 351 
 352   if (sound_num_blocks >= 1024)
 353     printk ("Sound warning: Deallocation table was too small.\n");
 354 
 355   return 0;
 356 }
 357 
 358 #ifdef MODULE
 359 
 360 
 361 void
 362 cleanup_module (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 363 {
 364   if (MOD_IN_USE)
 365     printk ("sound: module busy -- remove delayed\n");
 366   else
 367     {
 368       int             i;
 369 
 370       if (chrdev_registered)
 371         unregister_chrdev (SOUND_MAJOR, "sound");
 372 
 373 #ifndef EXCLUDE_SEQUENCER
 374       sound_stop_timer ();
 375 #endif
 376       sound_unload_drivers ();
 377 
 378       for (i = 0; i < sound_num_blocks; i++)
 379         kfree (sound_mem_blocks[i]);
 380 
 381       free_all_irqs ();         /* If something was left allocated by accident */
 382 
 383       for (i = 0; i < 8; i++)
 384         if (dma_alloc_map[i] != DMA_MAP_UNAVAIL)
 385           {
 386             printk ("Sound: Hmm, DMA%d was left allocated\n", i);
 387             sound_free_dma (i);
 388           }
 389 
 390 #ifndef EXCLUDE_PNP
 391       sound_pnp_disconnect ();
 392 #endif
 393 
 394     }
 395 }
 396 #endif
 397 
 398 void
 399 tenmicrosec (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 400 {
 401   int             i;
 402 
 403   for (i = 0; i < 16; i++)
 404     inb (0x80);
 405 }
 406 
 407 int
 408 snd_set_irq_handler (int interrupt_level, void (*hndlr) (int, struct pt_regs *), char *name, sound_os_info * osp)
     /* [previous][next][first][last][top][bottom][index][help] */
 409 {
 410   int             retcode;
 411 
 412   retcode = request_irq (interrupt_level, hndlr, 0 /* SA_INTERRUPT */ , name);
 413   if (retcode < 0)
 414     {
 415       printk ("Sound: IRQ%d already in use\n", interrupt_level);
 416     }
 417   else
 418     irqs |= (1ul << interrupt_level);
 419 
 420   return retcode;
 421 }
 422 
 423 void
 424 snd_release_irq (int vect)
     /* [previous][next][first][last][top][bottom][index][help] */
 425 {
 426   irqs &= ~(1ul << vect);
 427   free_irq (vect);
 428 }
 429 
 430 int
 431 sound_alloc_dma (int chn, char *deviceID)
     /* [previous][next][first][last][top][bottom][index][help] */
 432 {
 433   int             err;
 434 
 435   if ((err = request_dma (chn, deviceID)) != 0)
 436     return err;
 437 
 438   dma_alloc_map[chn] = DMA_MAP_FREE;
 439 
 440   return 0;
 441 }
 442 
 443 int
 444 sound_open_dma (int chn, char *deviceID)
     /* [previous][next][first][last][top][bottom][index][help] */
 445 {
 446   unsigned long   flags;
 447 
 448   save_flags (flags);
 449   cli ();
 450 
 451   if (dma_alloc_map[chn] != DMA_MAP_FREE)
 452     {
 453       printk ("sound_open_dma: DMA channel %d busy or not allocated\n", chn);
 454       restore_flags (flags);
 455       return 1;
 456     }
 457 
 458   dma_alloc_map[chn] = DMA_MAP_BUSY;
 459   restore_flags (flags);
 460   return 0;
 461 }
 462 
 463 void
 464 sound_free_dma (int chn)
     /* [previous][next][first][last][top][bottom][index][help] */
 465 {
 466   if (dma_alloc_map[chn] != DMA_MAP_FREE)
 467     {
 468       printk ("sound_free_dma: Bad access to DMA channel %d\n", chn);
 469       return;
 470     }
 471   free_dma (chn);
 472   dma_alloc_map[chn] = DMA_MAP_UNAVAIL;
 473 }
 474 
 475 void
 476 sound_close_dma (int chn)
     /* [previous][next][first][last][top][bottom][index][help] */
 477 {
 478   unsigned long   flags;
 479 
 480   save_flags (flags);
 481   cli ();
 482 
 483   if (dma_alloc_map[chn] != DMA_MAP_BUSY)
 484     {
 485       printk ("sound_close_dma: Bad access to DMA channel %d\n", chn);
 486       restore_flags (flags);
 487       return;
 488     }
 489   dma_alloc_map[chn] = DMA_MAP_FREE;
 490   restore_flags (flags);
 491 }
 492 
 493 #ifndef EXCLUDE_SEQUENCER
 494 
 495 
 496 static struct timer_list seq_timer =
 497 {NULL, NULL, 0, 0, sequencer_timer};
 498 
 499 void
 500 request_sound_timer (int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 501 {
 502   extern unsigned long seq_time;
 503 
 504   if (count < 0)
 505     count = jiffies + (-count);
 506   else
 507     count += seq_time;
 508 
 509 
 510   {
 511     seq_timer.expires = ((count - jiffies)) + jiffies;
 512     add_timer (&seq_timer);
 513   };
 514 }
 515 
 516 void
 517 sound_stop_timer (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 518 {
 519   del_timer (&seq_timer);;
 520 }
 521 #endif
 522 
 523 #ifndef EXCLUDE_AUDIO
 524 
 525 #ifdef KMALLOC_DMA_BROKEN
 526 fatal_error__This_version_is_not_compatible_with_this_kernel;
 527 #endif
 528 
 529 static int      dma_buffsize = DSP_BUFFSIZE;
 530 
 531 int
 532 sound_alloc_dmap (int dev, struct dma_buffparms *dmap, int chan)
     /* [previous][next][first][last][top][bottom][index][help] */
 533 {
 534   char           *start_addr, *end_addr;
 535   int             i, dma_pagesize;
 536 
 537   if (dmap->raw_buf != NULL)
 538     return 0;                   /* Already done */
 539 
 540   if (dma_buffsize < 4096)
 541     dma_buffsize = 4096;
 542 
 543   if (chan < 4)
 544     dma_pagesize = 64 * 1024;
 545   else
 546     dma_pagesize = 128 * 1024;
 547 
 548   dmap->raw_buf = NULL;
 549 
 550   if (debugmem)
 551     printk ("sound: buffsize%d %lu\n", dev, audio_devs[dev]->buffsize);
 552 
 553   audio_devs[dev]->buffsize = dma_buffsize;
 554 
 555   if (audio_devs[dev]->buffsize > dma_pagesize)
 556     audio_devs[dev]->buffsize = dma_pagesize;
 557 
 558   start_addr = NULL;
 559 
 560 /*
 561  * Now loop until we get a free buffer. Try to get smaller buffer if
 562  * it fails.
 563  */
 564 
 565   while (start_addr == NULL && audio_devs[dev]->buffsize > PAGE_SIZE)
 566     {
 567       int             sz, size;
 568 
 569       for (sz = 0, size = PAGE_SIZE;
 570            size < audio_devs[dev]->buffsize;
 571            sz++, size <<= 1);
 572 
 573       audio_devs[dev]->buffsize = PAGE_SIZE * (1 << sz);
 574 
 575       if ((start_addr = (char *) __get_free_pages (GFP_ATOMIC, sz, MAX_DMA_ADDRESS)) == NULL)
 576         audio_devs[dev]->buffsize /= 2;
 577     }
 578 
 579   if (start_addr == NULL)
 580     {
 581       printk ("Sound error: Couldn't allocate DMA buffer\n");
 582       return -ENOMEM;
 583     }
 584   else
 585     {
 586       /* make some checks */
 587       end_addr = start_addr + audio_devs[dev]->buffsize - 1;
 588 
 589       if (debugmem)
 590         printk ("sound: start 0x%lx, end 0x%lx\n",
 591                 (long) start_addr, (long) end_addr);
 592 
 593       /* now check if it fits into the same dma-pagesize */
 594 
 595       if (((long) start_addr & ~(dma_pagesize - 1))
 596           != ((long) end_addr & ~(dma_pagesize - 1))
 597           || end_addr >= (char *) (MAX_DMA_ADDRESS))
 598         {
 599           printk (
 600                    "sound: kmalloc returned invalid address 0x%lx for %ld Bytes DMA-buffer\n",
 601                    (long) start_addr,
 602                    audio_devs[dev]->buffsize);
 603           return -EFAULT;
 604         }
 605     }
 606   dmap->raw_buf = start_addr;
 607   dmap->raw_buf_phys = virt_to_phys (start_addr);
 608 
 609   memset (dmap->raw_buf, 0x00, audio_devs[dev]->buffsize);
 610 
 611   for (i = MAP_NR (start_addr); i <= MAP_NR (end_addr); i++)
 612     {
 613       mem_map[i].reserved = 1;
 614     }
 615 
 616   return 0;
 617 }
 618 
 619 void
 620 sound_free_dmap (int dev, struct dma_buffparms *dmap)
     /* [previous][next][first][last][top][bottom][index][help] */
 621 {
 622   if (dmap->raw_buf == NULL)
 623     return;
 624   {
 625     int             sz, size, i;
 626     unsigned long   start_addr, end_addr;
 627 
 628     for (sz = 0, size = PAGE_SIZE;
 629          size < audio_devs[dev]->buffsize;
 630          sz++, size <<= 1);
 631 
 632     start_addr = (unsigned long) dmap->raw_buf;
 633     end_addr = start_addr + audio_devs[dev]->buffsize;
 634 
 635     for (i = MAP_NR (start_addr); i <= MAP_NR (end_addr); i++)
 636       {
 637         mem_map[i].reserved = 0;
 638       }
 639 
 640     free_pages ((unsigned long) dmap->raw_buf, sz);
 641   }
 642   dmap->raw_buf = NULL;
 643 }
 644 
 645 int
 646 soud_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc * info)
     /* [previous][next][first][last][top][bottom][index][help] */
 647 {
 648   printk ("Entered sound_map_buffer()\n");
 649   printk ("Exited sound_map_buffer()\n");
 650   return -EINVAL;
 651 }
 652 
 653 #else
 654 
 655 void
 656 soundcard_init (void)           /* Dummy version */
     /* [previous][next][first][last][top][bottom][index][help] */
 657 {
 658 }
 659 
 660 #endif
 661 
 662 #endif

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