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

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