root/drivers/sound/sb16_dsp.c

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

DEFINITIONS

This source file includes following definitions.
  1. sb_dsp_command01
  2. dsp_set_speed
  3. dsp_set_stereo
  4. dsp_set_bits
  5. sb16_dsp_ioctl
  6. sb16_dsp_open
  7. sb16_dsp_close
  8. sb16_dsp_output_block
  9. actually_output_block
  10. sb16_dsp_start_input
  11. actually_start_input
  12. sb16_dsp_prepare_for_input
  13. sb16_dsp_prepare_for_output
  14. sb16_dsp_trigger
  15. dsp_cleanup
  16. sb16_dsp_reset
  17. sb16_dsp_halt
  18. set_irq_hw
  19. sb16_dsp_init
  20. sb16_dsp_detect
  21. unload_sb16
  22. sb16_dsp_interrupt

   1 /*
   2  * sound/sb16_dsp.c
   3  *
   4  * The low level driver for the SoundBlaster DSP chip.
   5  *
   6  * (C) 1993 J. Schubert (jsb@sth.ruhr-uni-bochum.de)
   7  *
   8  * based on SB-driver by (C) Hannu Savolainen
   9  *
  10  * Redistribution and use in source and binary forms, with or without
  11  * modification, are permitted provided that the following conditions are
  12  * met: 1. Redistributions of source code must retain the above copyright
  13  * notice, this list of conditions and the following disclaimer. 2.
  14  * Redistributions in binary form must reproduce the above copyright notice,
  15  * this list of conditions and the following disclaimer in the documentation
  16  * and/or other materials provided with the distribution.
  17  *
  18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
  19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
  22  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  25  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28  * SUCH DAMAGE.
  29  *
  30  */
  31 
  32 #define DEB(x)
  33 #define DEB1(x)
  34 /*
  35  * #define DEB_DMARES
  36  */
  37 #include "sound_config.h"
  38 #include "sb.h"
  39 #include "sb_mixer.h"
  40 
  41 #if defined(CONFIG_SB) && defined(CONFIG_AUDIO)
  42 
  43 extern int      sbc_base;
  44 extern sound_os_info *sb_osp;
  45 
  46 static int      sb16_dsp_ok = 0;
  47 static int      dsp_16bit = 0;
  48 static int      dsp_stereo = 0;
  49 static int      dsp_current_speed = 8000;
  50 static int      dsp_busy = 0;
  51 static int      dma16, dma8;
  52 static int      trigger_bits = 0;
  53 static unsigned long dsp_count = 0;
  54 
  55 static int      irq_mode = IMODE_NONE;
  56 static int      my_dev = 0;
  57 
  58 static volatile int intr_active = 0;
  59 
  60 static int      sb16_dsp_open (int dev, int mode);
  61 static void     sb16_dsp_close (int dev);
  62 static void     sb16_dsp_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart);
  63 static void     sb16_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart);
  64 static int      sb16_dsp_ioctl (int dev, unsigned int cmd, ioctl_arg arg, int local);
  65 static int      sb16_dsp_prepare_for_input (int dev, int bsize, int bcount);
  66 static int      sb16_dsp_prepare_for_output (int dev, int bsize, int bcount);
  67 static void     sb16_dsp_reset (int dev);
  68 static void     sb16_dsp_halt (int dev);
  69 static void     sb16_dsp_trigger (int dev, int bits);
  70 static int      dsp_set_speed (int);
  71 static int      dsp_set_stereo (int);
  72 static void     dsp_cleanup (void);
  73 int             sb_reset_dsp (void);
  74 
  75 static struct audio_operations sb16_dsp_operations =
  76 {
  77   "SoundBlaster 16",
  78   DMA_AUTOMODE,
  79   AFMT_U8 | AFMT_S16_LE,
  80   NULL,
  81   sb16_dsp_open,
  82   sb16_dsp_close,
  83   sb16_dsp_output_block,
  84   sb16_dsp_start_input,
  85   sb16_dsp_ioctl,
  86   sb16_dsp_prepare_for_input,
  87   sb16_dsp_prepare_for_output,
  88   sb16_dsp_reset,
  89   sb16_dsp_halt,
  90   NULL,
  91   NULL,
  92   NULL,
  93   NULL,
  94   sb16_dsp_trigger
  95 };
  96 
  97 static int
  98 sb_dsp_command01 (unsigned char val)
     /* [previous][next][first][last][top][bottom][index][help] */
  99 {
 100   int             i = 1 << 16;
 101 
 102   while (--i & (!inb (DSP_STATUS) & 0x80));
 103   if (!i)
 104     printk ("SB16 sb_dsp_command01 Timeout\n");
 105   return sb_dsp_command (val);
 106 }
 107 
 108 static int
 109 dsp_set_speed (int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 110 {
 111   DEB (printk ("dsp_set_speed(%d)\n", mode));
 112   if (mode)
 113     {
 114       if (mode < 5000)
 115         mode = 5000;
 116       if (mode > 44100)
 117         mode = 44100;
 118       dsp_current_speed = mode;
 119     }
 120   return mode;
 121 }
 122 
 123 static int
 124 dsp_set_stereo (int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 125 {
 126   DEB (printk ("dsp_set_stereo(%d)\n", mode));
 127 
 128   dsp_stereo = mode;
 129 
 130   return mode;
 131 }
 132 
 133 static int
 134 dsp_set_bits (int arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 135 {
 136   DEB (printk ("dsp_set_bits(%d)\n", arg));
 137 
 138   if (arg)
 139     switch (arg)
 140       {
 141       case 8:
 142         dsp_16bit = 0;
 143         break;
 144       case 16:
 145         dsp_16bit = 1;
 146         break;
 147       default:
 148         dsp_16bit = 0;
 149       }
 150   return dsp_16bit ? 16 : 8;
 151 }
 152 
 153 static int
 154 sb16_dsp_ioctl (int dev, unsigned int cmd, ioctl_arg arg, int local)
     /* [previous][next][first][last][top][bottom][index][help] */
 155 {
 156   switch (cmd)
 157     {
 158     case SOUND_PCM_WRITE_RATE:
 159       if (local)
 160         return dsp_set_speed ((int) arg);
 161       return snd_ioctl_return ((int *) arg, dsp_set_speed (get_fs_long ((long *) arg)));
 162 
 163     case SOUND_PCM_READ_RATE:
 164       if (local)
 165         return dsp_current_speed;
 166       return snd_ioctl_return ((int *) arg, dsp_current_speed);
 167 
 168     case SNDCTL_DSP_STEREO:
 169       if (local)
 170         return dsp_set_stereo ((int) arg);
 171       return snd_ioctl_return ((int *) arg, dsp_set_stereo (get_fs_long ((long *) arg)));
 172 
 173     case SOUND_PCM_WRITE_CHANNELS:
 174       if (local)
 175         return dsp_set_stereo ((int) arg - 1) + 1;
 176       return snd_ioctl_return ((int *) arg, dsp_set_stereo (get_fs_long ((long *) arg) - 1) + 1);
 177 
 178     case SOUND_PCM_READ_CHANNELS:
 179       if (local)
 180         return dsp_stereo + 1;
 181       return snd_ioctl_return ((int *) arg, dsp_stereo + 1);
 182 
 183     case SNDCTL_DSP_SETFMT:
 184       if (local)
 185         return dsp_set_bits ((int) arg);
 186       return snd_ioctl_return ((int *) arg, dsp_set_bits (get_fs_long ((long *) arg)));
 187 
 188     case SOUND_PCM_READ_BITS:
 189       if (local)
 190         return dsp_16bit ? 16 : 8;
 191       return snd_ioctl_return ((int *) arg, dsp_16bit ? 16 : 8);
 192 
 193     case SOUND_PCM_WRITE_FILTER:        /*
 194                                          * NOT YET IMPLEMENTED
 195                                          */
 196       if (get_fs_long ((long *) arg) > 1)
 197         return snd_ioctl_return ((int *) arg, -EINVAL);
 198     default:
 199       return -EINVAL;
 200     }
 201 
 202   return -EINVAL;
 203 }
 204 
 205 static int
 206 sb16_dsp_open (int dev, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 207 {
 208   int             retval;
 209 
 210   DEB (printk ("sb16_dsp_open()\n"));
 211   if (!sb16_dsp_ok)
 212     {
 213       printk ("SB16 Error: SoundBlaster board not installed\n");
 214       return -ENXIO;
 215     }
 216 
 217   if (intr_active)
 218     return -EBUSY;
 219 
 220   retval = sb_get_irq ();
 221   if (retval < 0)
 222     return retval;
 223 
 224   sb_reset_dsp ();
 225 
 226   if (dma16 != dma8)
 227     if (sound_open_dma (dma16, "SB16 (16bit)"))
 228       {
 229         printk ("SB16: Unable to grab DMA%d\n", dma16);
 230         sb_free_irq ();
 231         return -EBUSY;
 232       }
 233 
 234   irq_mode = IMODE_NONE;
 235   dsp_busy = 1;
 236   trigger_bits = 0;
 237 
 238   return 0;
 239 }
 240 
 241 static void
 242 sb16_dsp_close (int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 243 {
 244   unsigned long   flags;
 245 
 246   DEB (printk ("sb16_dsp_close()\n"));
 247   sb_dsp_command01 (0xd9);
 248   sb_dsp_command01 (0xd5);
 249 
 250   save_flags (flags);
 251   cli ();
 252 
 253   audio_devs[dev]->dmachan1 = dma8;
 254 
 255   if (dma16 != dma8)
 256     sound_close_dma (dma16);
 257   sb_free_irq ();
 258   dsp_cleanup ();
 259   dsp_busy = 0;
 260   restore_flags (flags);
 261 }
 262 
 263 static unsigned long trg_buf;
 264 static int      trg_bytes;
 265 static int      trg_intrflag;
 266 static int      trg_restart;
 267 
 268 static void
 269 sb16_dsp_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
     /* [previous][next][first][last][top][bottom][index][help] */
 270 {
 271   trg_buf = buf;
 272   trg_bytes = count;
 273   trg_intrflag = intrflag;
 274   trg_restart = dma_restart;
 275   irq_mode = IMODE_OUTPUT;
 276 }
 277 
 278 static void
 279 actually_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
     /* [previous][next][first][last][top][bottom][index][help] */
 280 {
 281   unsigned long   flags, cnt;
 282 
 283   cnt = count;
 284   if (dsp_16bit)
 285     cnt >>= 1;
 286   cnt--;
 287 
 288 #ifdef DEB_DMARES
 289   printk ("output_block: %x %d %d\n", buf, count, intrflag);
 290   if (intrflag)
 291     {
 292       int             pos, chan = audio_devs[dev]->dmachan;
 293 
 294       save_flags (flags);
 295       cli ();
 296       clear_dma_ff (chan);
 297       disable_dma (chan);
 298       pos = get_dma_residue (chan);
 299       enable_dma (chan);
 300       restore_flags (flags);
 301       printk ("dmapos=%d %x\n", pos, pos);
 302     }
 303 #endif
 304   if (audio_devs[dev]->flags & DMA_AUTOMODE &&
 305       intrflag &&
 306       cnt == dsp_count)
 307     {
 308       irq_mode = IMODE_OUTPUT;
 309       intr_active = 1;
 310       return;                   /*
 311                                  * Auto mode on. No need to react
 312                                  */
 313     }
 314   save_flags (flags);
 315   cli ();
 316 
 317   if (dma_restart)
 318     {
 319       sb16_dsp_halt (dev);
 320       DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
 321     }
 322   sb_dsp_command (0x41);
 323   sb_dsp_command ((unsigned char) ((dsp_current_speed >> 8) & 0xff));
 324   sb_dsp_command ((unsigned char) (dsp_current_speed & 0xff));
 325   sb_dsp_command ((unsigned char) (dsp_16bit ? 0xb6 : 0xc6));
 326   dsp_count = cnt;
 327   sb_dsp_command ((unsigned char) ((dsp_stereo ? 0x20 : 0) +
 328                                    (dsp_16bit ? 0x10 : 0)));
 329   sb_dsp_command01 ((unsigned char) (cnt & 0xff));
 330   sb_dsp_command ((unsigned char) (cnt >> 8));
 331 
 332   irq_mode = IMODE_OUTPUT;
 333   intr_active = 1;
 334   restore_flags (flags);
 335 }
 336 
 337 static void
 338 sb16_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
     /* [previous][next][first][last][top][bottom][index][help] */
 339 {
 340   trg_buf = buf;
 341   trg_bytes = count;
 342   trg_intrflag = intrflag;
 343   trg_restart = dma_restart;
 344   irq_mode = IMODE_INPUT;
 345 }
 346 
 347 static void
 348 actually_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
     /* [previous][next][first][last][top][bottom][index][help] */
 349 {
 350   unsigned long   flags, cnt;
 351 
 352   cnt = count;
 353   if (dsp_16bit)
 354     cnt >>= 1;
 355   cnt--;
 356 
 357 #ifdef DEB_DMARES
 358   printk ("start_input: %x %d %d\n", buf, count, intrflag);
 359   if (intrflag)
 360     {
 361       int             pos, chan = audio_devs[dev]->dmachan;
 362 
 363       save_flags (flags);
 364       cli ();
 365       clear_dma_ff (chan);
 366       disable_dma (chan);
 367       pos = get_dma_residue (chan);
 368       enable_dma (chan);
 369       restore_flags (flags);
 370       printk ("dmapos=%d %x\n", pos, pos);
 371     }
 372 #endif
 373   if (audio_devs[dev]->flags & DMA_AUTOMODE &&
 374       intrflag &&
 375       cnt == dsp_count)
 376     {
 377       irq_mode = IMODE_INPUT;
 378       intr_active = 1;
 379       return;                   /*
 380                                  * Auto mode on. No need to react
 381                                  */
 382     }
 383   save_flags (flags);
 384   cli ();
 385 
 386   if (dma_restart)
 387     {
 388       sb_reset_dsp ();
 389       DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
 390     }
 391 
 392   sb_dsp_command (0x42);
 393   sb_dsp_command ((unsigned char) ((dsp_current_speed >> 8) & 0xff));
 394   sb_dsp_command ((unsigned char) (dsp_current_speed & 0xff));
 395   sb_dsp_command ((unsigned char) (dsp_16bit ? 0xbe : 0xce));
 396   dsp_count = cnt;
 397   sb_dsp_command ((unsigned char) ((dsp_stereo ? 0x20 : 0) +
 398                                    (dsp_16bit ? 0x10 : 0)));
 399   sb_dsp_command01 ((unsigned char) (cnt & 0xff));
 400   sb_dsp_command ((unsigned char) (cnt >> 8));
 401 
 402   irq_mode = IMODE_INPUT;
 403   intr_active = 1;
 404   restore_flags (flags);
 405 }
 406 
 407 static int
 408 sb16_dsp_prepare_for_input (int dev, int bsize, int bcount)
     /* [previous][next][first][last][top][bottom][index][help] */
 409 {
 410   audio_devs[my_dev]->dmachan1 = dsp_16bit ? dma16 : dma8;
 411   dsp_count = 0;
 412   dsp_cleanup ();
 413   trigger_bits = 0;
 414   sb_dsp_command (0xd4);
 415   return 0;
 416 }
 417 
 418 static int
 419 sb16_dsp_prepare_for_output (int dev, int bsize, int bcount)
     /* [previous][next][first][last][top][bottom][index][help] */
 420 {
 421   audio_devs[my_dev]->dmachan1 = dsp_16bit ? dma16 : dma8;
 422   dsp_count = 0;
 423   dsp_cleanup ();
 424   trigger_bits = 0;
 425   sb_dsp_command (0xd4);
 426   return 0;
 427 }
 428 
 429 static void
 430 sb16_dsp_trigger (int dev, int bits)
     /* [previous][next][first][last][top][bottom][index][help] */
 431 {
 432   trigger_bits = bits;
 433 
 434   if (!bits)
 435     sb_dsp_command (0xd0);      /* Halt DMA */
 436   else if (bits & irq_mode)
 437     switch (irq_mode)
 438       {
 439       case IMODE_INPUT:
 440         actually_start_input (my_dev, trg_buf, trg_bytes,
 441                               trg_intrflag, trg_restart);
 442         break;
 443 
 444       case IMODE_OUTPUT:
 445         actually_output_block (my_dev, trg_buf, trg_bytes,
 446                                trg_intrflag, trg_restart);
 447         break;
 448       }
 449 }
 450 
 451 static void
 452 dsp_cleanup (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 453 {
 454   irq_mode = IMODE_NONE;
 455   intr_active = 0;
 456 }
 457 
 458 static void
 459 sb16_dsp_reset (int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 460 {
 461   unsigned long   flags;
 462 
 463   save_flags (flags);
 464   cli ();
 465 
 466   sb_reset_dsp ();
 467   dsp_cleanup ();
 468 
 469   restore_flags (flags);
 470 }
 471 
 472 static void
 473 sb16_dsp_halt (int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 474 {
 475   if (dsp_16bit)
 476     {
 477       sb_dsp_command01 (0xd9);
 478       sb_dsp_command01 (0xd5);
 479     }
 480   else
 481     {
 482       sb_dsp_command01 (0xda);
 483       sb_dsp_command01 (0xd0);
 484     }
 485   /* DMAbuf_reset_dma (dev); */
 486 }
 487 
 488 static void
 489 set_irq_hw (int level)
     /* [previous][next][first][last][top][bottom][index][help] */
 490 {
 491   int             ival;
 492 
 493   switch (level)
 494     {
 495     case 5:
 496       ival = 2;
 497       break;
 498     case 7:
 499       ival = 4;
 500       break;
 501     case 9:
 502       ival = 1;
 503       break;
 504     case 10:
 505       ival = 8;
 506       break;
 507     default:
 508       printk ("SB16_IRQ_LEVEL %d does not exist\n", level);
 509       return;
 510     }
 511   sb_setmixer (IRQ_NR, ival);
 512 }
 513 
 514 long
 515 sb16_dsp_init (long mem_start, struct address_info *hw_config)
     /* [previous][next][first][last][top][bottom][index][help] */
 516 {
 517   extern int      sbc_major, sbc_minor;
 518 
 519   if (sbc_major < 4)
 520     return mem_start;           /* Not a SB16 */
 521 
 522   sprintf (sb16_dsp_operations.name, "SoundBlaster 16 %d.%d", sbc_major, sbc_minor);
 523 
 524   conf_printf (sb16_dsp_operations.name, hw_config);
 525 
 526   if (num_audiodevs < MAX_AUDIO_DEV)
 527     {
 528       audio_devs[my_dev = num_audiodevs++] = &sb16_dsp_operations;
 529       audio_devs[my_dev]->dmachan1 = dma8;
 530       audio_devs[my_dev]->buffsize = DSP_BUFFSIZE;
 531 
 532       if (sound_alloc_dma (dma8, "SB16 (8bit)"))
 533         {
 534           printk ("SB16: Unable to grab DMA%d\n", dma8);
 535         }
 536 
 537       if (dma16 != dma8)
 538         if (sound_alloc_dma (dma16, "SB16 (16bit)"))
 539           {
 540             printk ("SB16: Unable to grab DMA%d\n", dma16);
 541           }
 542     }
 543   else
 544     printk ("SB: Too many DSP devices available\n");
 545   sb16_dsp_ok = 1;
 546   return mem_start;
 547 }
 548 
 549 int
 550 sb16_dsp_detect (struct address_info *hw_config)
     /* [previous][next][first][last][top][bottom][index][help] */
 551 {
 552   struct address_info *sb_config;
 553   extern int      sbc_major, Jazz16_detected;
 554 
 555   extern void     Jazz16_set_dma16 (int dma);
 556 
 557   if (sb16_dsp_ok)
 558     return 1;                   /* Can't drive two cards */
 559 
 560   if (Jazz16_detected)
 561     {
 562       Jazz16_set_dma16 (hw_config->dma);
 563       return 0;
 564     }
 565 
 566   if (!(sb_config = sound_getconf (SNDCARD_SB)))
 567     {
 568       printk ("SB16 Error: Plain SB not configured\n");
 569       return 0;
 570     }
 571 
 572   /*
 573    * sb_setmixer(OPSW,0xf); if(sb_getmixer(OPSW)!=0xf) return 0;
 574    */
 575 
 576   if (!sb_reset_dsp ())
 577     return 0;
 578 
 579   if (sbc_major < 4)            /* Set by the plain SB driver */
 580     return 0;                   /* Not a SB16 */
 581 
 582   if (hw_config->dma < 4)
 583     if (hw_config->dma != sb_config->dma)
 584       {
 585         printk ("SB16 Error: Invalid DMA channel %d/%d\n",
 586                 sb_config->dma, hw_config->dma);
 587         return 0;
 588       }
 589 
 590   dma16 = hw_config->dma;
 591   dma8 = sb_config->dma;
 592   set_irq_hw (sb_config->irq);
 593   sb_setmixer (DMA_NR, (1 << hw_config->dma) | (1 << sb_config->dma));
 594 
 595   DEB (printk ("SoundBlaster 16: IRQ %d DMA %d OK\n", sb_config->irq, hw_config->dma));
 596 
 597   /*
 598      * dsp_showmessage(0xe3,99);
 599    */
 600   sb16_dsp_ok = 1;
 601   return 1;
 602 }
 603 
 604 void
 605 unload_sb16 (struct address_info *hw_config)
     /* [previous][next][first][last][top][bottom][index][help] */
 606 {
 607 
 608   sound_free_dma (dma8);
 609 
 610   if (dma16 != dma8)
 611     sound_free_dma (dma16);
 612 }
 613 
 614 void
 615 sb16_dsp_interrupt (int unused)
     /* [previous][next][first][last][top][bottom][index][help] */
 616 {
 617   int             data;
 618 
 619   data = inb (DSP_DATA_AVL16);  /*
 620                                    * Interrupt acknowledge
 621                                  */
 622 
 623   if (intr_active)
 624     switch (irq_mode)
 625       {
 626       case IMODE_OUTPUT:
 627         DMAbuf_outputintr (my_dev, 1);
 628         break;
 629 
 630       case IMODE_INPUT:
 631         DMAbuf_inputintr (my_dev);
 632         break;
 633 
 634       default:
 635         printk ("SoundBlaster: Unexpected interrupt\n");
 636       }
 637 }
 638 
 639 #endif

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