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

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