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. wait_data_avail
  3. read_dsp
  4. dsp_ini2
  5. dsp_set_speed
  6. dsp_set_stereo
  7. dsp_set_bits
  8. sb16_dsp_ioctl
  9. sb16_dsp_open
  10. sb16_dsp_close
  11. sb16_dsp_output_block
  12. sb16_dsp_start_input
  13. sb16_dsp_prepare_for_input
  14. sb16_dsp_prepare_for_output
  15. dsp_cleanup
  16. sb16_dsp_reset
  17. sb16_dsp_halt
  18. set_irq_hw
  19. sb16_dsp_init
  20. sb16_dsp_detect
  21. 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(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_AUDIO) && !defined(EXCLUDE_SBPRO)
  42 
  43 extern int sbc_base;
  44 
  45 static int sb16_dsp_ok = 0;     /* Set to 1 after successful initialization */
  46 static int dsp_16bit = 0;
  47 static int dsp_stereo = 0;
  48 static int dsp_current_speed = 8000;/*DSP_DEFAULT_SPEED;*/
  49 static int dsp_busy  = 0;
  50 static int dma16, dma8;
  51 static unsigned long dsp_count = 0;
  52 
  53 static int irq_mode = IMODE_NONE;       /* IMODE_INPUT, IMODE_OUTPUT or
  54                                            IMODE_NONE */
  55 static int my_dev = 0;
  56 
  57 static volatile int intr_active = 0;
  58 
  59 static int sb16_dsp_open (int dev, int mode);
  60 static void sb16_dsp_close (int dev);
  61 static void sb16_dsp_output_block (int dev, unsigned long buf, int count,int intrflag, int dma_restart);
  62 static void sb16_dsp_start_input (int dev, unsigned long buf, int count,int intrflag, int dma_restart);
  63 static int sb16_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg,int local);
  64 static int sb16_dsp_prepare_for_input (int dev, int bsize, int bcount);
  65 static int sb16_dsp_prepare_for_output (int dev, int bsize, int bcount);
  66 static void sb16_dsp_reset (int dev);
  67 static void sb16_dsp_halt (int dev);
  68 static int dsp_set_speed (int);
  69 static int dsp_set_stereo (int);
  70 static void dsp_cleanup (void);
  71 int sb_reset_dsp (void);
  72 
  73 static struct audio_operations sb16_dsp_operations =
  74 {
  75   "SoundBlaster 16",
  76   sb16_dsp_open,
  77   sb16_dsp_close,
  78   sb16_dsp_output_block,
  79   sb16_dsp_start_input,
  80   sb16_dsp_ioctl,
  81   sb16_dsp_prepare_for_input,
  82   sb16_dsp_prepare_for_output,
  83   sb16_dsp_reset,
  84   sb16_dsp_halt,
  85   NULL,
  86   NULL
  87 };
  88 
  89 static int sb_dsp_command01 (unsigned char val)
     /* [previous][next][first][last][top][bottom][index][help] */
  90 {
  91   int i=1<<16;
  92 
  93   while(--i & (!INB (DSP_STATUS) & 0x80));
  94   if(!i)
  95     printk("SB16 sb_dsp_command01 Timeout\n");
  96   return sb_dsp_command(val);
  97 }
  98 
  99 static int wait_data_avail(int t)
     /* [previous][next][first][last][top][bottom][index][help] */
 100 {
 101   int loopc=5000000;
 102   t+=GET_TIME();
 103   do {
 104     if(INB(DSP_DATA_AVAIL) & 0x80)
 105       return 1;
 106   } while(--loopc && GET_TIME()<t);
 107   printk("!data_avail l=%d\n",loopc);
 108   return 0;
 109 }
 110 
 111 static int read_dsp(int t)
     /* [previous][next][first][last][top][bottom][index][help] */
 112 {
 113   if(!wait_data_avail(t))
 114     return -1;
 115   else
 116     return INB(DSP_READ);
 117 }                                                                       
 118 
 119 static int dsp_ini2(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 120 {
 121 #if 0
 122   /* sb_setmixer(0x83, sb_getmixer(0x83) | 0x03);       */
 123   sb_dsp_command(0xe2);
 124   sb_dsp_command(0x76); /* E0 ??? */
 125   sb_dsp_command(0xe2);
 126   sb_dsp_command(0x30); /* A0 ??? */
 127   sb_dsp_command(0xe4);
 128   sb_dsp_command(0xaa);
 129   sb_dsp_command(0xe8);
 130   if(read_dsp(100)!=0xaa)
 131     printk("Error dsp_ini2\n");
 132 #endif
 133   return 0;
 134 }
 135 /*
 136 static char *dsp_getmessage(unsigned char command,int maxn)
 137 {
 138   static char buff[100];
 139   int n=0;
 140 
 141   sb_dsp_command(command);
 142   while(n<maxn && wait_data_avail(2)) {
 143     buff[++n]=INB(DSP_READ);
 144     if(!buff[n])
 145       break;
 146   }
 147   buff[0]=n;
 148   return buff;
 149 }
 150 
 151 static void dsp_showmessage(unsigned char command,int len)
 152 {
 153   int n;
 154   unsigned char *c;
 155   c=dsp_getmessage(command,len);
 156   printk("DSP C=%x l=%d,lr=%d b=",command,len,c[0]);
 157   for(n=1;n<=c[0];n++)
 158     if(c[n]>=' ' & c[n]<='z')
 159       printk("%c",c[n]);
 160     else
 161       printk("|%x|",c[n]);
 162   printk("\n");
 163 }
 164 */
 165 static int dsp_set_speed(int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 166 {
 167 DEB(printk("dsp_set_speed(%d)\n",mode));
 168   if (mode)
 169   {
 170     if (mode < 5000) mode = 5000;
 171     if (mode > 44100) mode = 44100;
 172     dsp_current_speed=mode;
 173   }
 174   return mode;
 175 }
 176 
 177 static int dsp_set_stereo(int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 178 {
 179 DEB(printk("dsp_set_stereo(%d)\n",mode));
 180 
 181   if (mode) dsp_stereo=mode;
 182 
 183   return mode;
 184 }
 185 
 186 static int dsp_set_bits(int arg) {
     /* [previous][next][first][last][top][bottom][index][help] */
 187 DEB(printk("dsp_set_bits(%d)\n",arg));
 188 
 189   if (arg)
 190   switch(arg) {
 191   case 8:
 192     dsp_16bit=0; break;
 193   case 16:
 194     dsp_16bit=1; break;
 195   default:
 196     return RET_ERROR(EINVAL);
 197   }
 198   return dsp_16bit? 16:8;
 199 }
 200 
 201 static int
 202 sb16_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg,int local)
     /* [previous][next][first][last][top][bottom][index][help] */
 203 {
 204   switch (cmd) {
 205   case SOUND_PCM_WRITE_RATE:
 206     if(local)
 207       return dsp_set_speed(arg);
 208     return IOCTL_OUT (arg, dsp_set_speed (IOCTL_IN (arg)));
 209     
 210   case SOUND_PCM_READ_RATE:
 211     if(local)
 212       return dsp_current_speed;
 213     return IOCTL_OUT (arg, dsp_current_speed);
 214     
 215   case SNDCTL_DSP_STEREO:
 216     if (local)
 217       return dsp_set_stereo(arg);
 218     return IOCTL_OUT (arg, dsp_set_stereo(IOCTL_IN(arg)));
 219     
 220   case SOUND_PCM_WRITE_CHANNELS:
 221     if (local)
 222       return dsp_set_stereo(arg-1)+1;
 223     return IOCTL_OUT (arg, dsp_set_stereo(IOCTL_IN (arg)-1))+1;
 224     
 225   case SOUND_PCM_READ_CHANNELS:
 226     if (local)
 227       return dsp_stereo+1;
 228     return IOCTL_OUT (arg, dsp_stereo+1);
 229     
 230   case SNDCTL_DSP_SAMPLESIZE:
 231     if (local)
 232       return dsp_set_bits (arg);
 233     return IOCTL_OUT (arg, dsp_set_bits (IOCTL_IN (arg)));
 234     
 235   case SOUND_PCM_READ_BITS:
 236     if (local)
 237       return dsp_16bit?16:8;
 238     return IOCTL_OUT (arg, dsp_16bit?16:8);
 239     
 240   case SOUND_PCM_WRITE_FILTER:  /* NOT YET IMPLEMENTED */
 241     if (IOCTL_IN (arg) > 1)
 242       return IOCTL_OUT (arg, RET_ERROR (EINVAL));
 243   default:
 244     return RET_ERROR (EINVAL);
 245   }
 246   
 247   return RET_ERROR (EINVAL);
 248 }
 249 
 250 static int
 251 sb16_dsp_open (int dev, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 252 {
 253   int retval;
 254 
 255 DEB(printk("sb16_dsp_open()\n"));
 256   if (!sb16_dsp_ok)
 257     {
 258       printk ("SB16 Error: SoundBlaster board not installed\n");
 259       return RET_ERROR(ENODEV);
 260     }
 261 
 262   if (intr_active)
 263     return RET_ERROR(EBUSY);
 264 
 265   retval = sb_get_irq ();
 266   if (retval<0)
 267     return retval;
 268 
 269   if (ALLOC_DMA_CHN (dma8))
 270     {
 271       printk ("SB16: Unable to grab DMA%d\n", dma8);
 272       sb_free_irq();
 273       return RET_ERROR(EBUSY);
 274     }
 275 
 276   if (dma16 != dma8)
 277   if (ALLOC_DMA_CHN (dma16))
 278     {
 279       printk ("SB16: Unable to grab DMA%d\n", dma16);
 280       sb_free_irq();
 281       RELEASE_DMA_CHN (dma8);
 282       return RET_ERROR(EBUSY);
 283     }
 284 
 285   dsp_ini2();
 286 
 287   irq_mode = IMODE_NONE;
 288   dsp_busy = 1;
 289 
 290   return 0;
 291 }
 292 
 293 static void
 294 sb16_dsp_close (int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 295 {
 296   unsigned long   flags;
 297 DEB(printk("sb16_dsp_close()\n"));
 298   sb_dsp_command01(0xd9);
 299   sb_dsp_command01(0xd5);
 300 
 301   DISABLE_INTR (flags);
 302   RELEASE_DMA_CHN (dma8);
 303 
 304   if (dma16 != dma8)
 305      RELEASE_DMA_CHN (dma16);
 306   sb_free_irq ();
 307   dsp_cleanup ();
 308   dsp_busy = 0;
 309   RESTORE_INTR (flags);
 310 }
 311 
 312 static void
 313 sb16_dsp_output_block (int dev, unsigned long buf, int count,int intrflag, int dma_restart)
     /* [previous][next][first][last][top][bottom][index][help] */
 314 {
 315   unsigned long   flags, cnt;
 316 
 317   cnt = count;
 318   if (dsp_16bit)
 319     cnt >>= 1;
 320   cnt--;
 321 
 322 #ifdef DEB_DMARES
 323   printk("output_block: %x %d %d\n",buf,count,intrflag);
 324   if(intrflag) {
 325     int pos,chan=sound_dsp_dmachan[dev];
 326     DISABLE_INTR (flags);
 327     clear_dma_ff(chan);
 328     disable_dma(chan);
 329     pos=get_dma_residue(chan);
 330     enable_dma(chan);
 331     RESTORE_INTR (flags);
 332     printk("dmapos=%d %x\n",pos,pos);
 333   }
 334 #endif
 335   if (sound_dma_automode[dev] &&
 336       intrflag &&
 337       cnt == dsp_count) {
 338     irq_mode = IMODE_OUTPUT;
 339     intr_active = 1;
 340     return;                     /* Auto mode on. No need to react */
 341   }
 342   DISABLE_INTR (flags);
 343   
 344   if (dma_restart)
 345   {
 346      sb16_dsp_halt(dev);
 347      DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
 348   }
 349   sb_dsp_command (0x41);
 350   sb_dsp_command ((unsigned char)((dsp_current_speed >> 8) & 0xff));
 351   sb_dsp_command ((unsigned char)(dsp_current_speed & 0xff));
 352   sb_dsp_command ((unsigned char)(dsp_16bit ? 0xb6 : 0xc6));
 353   sb_dsp_command ((unsigned char)((dsp_stereo ? 0x20 : 0) + 
 354                                   (dsp_16bit ? 0x10:0)));
 355   sb_dsp_command01 ((unsigned char)(cnt&0xff));
 356   sb_dsp_command ((unsigned char)(cnt>>8));
 357   /* sb_dsp_command (0);
 358   sb_dsp_command (0); */
 359   
 360   RESTORE_INTR (flags);
 361   dsp_count=cnt;
 362   irq_mode = IMODE_OUTPUT;
 363   intr_active = 1;
 364 }
 365 
 366 static void
 367 sb16_dsp_start_input (int dev, unsigned long buf, int count,int intrflag, int dma_restart)
     /* [previous][next][first][last][top][bottom][index][help] */
 368 {
 369   unsigned long   flags, cnt;
 370 
 371   cnt = count;
 372   if (dsp_16bit)
 373     cnt >>= 1;
 374   cnt--;
 375 
 376 #ifdef DEB_DMARES
 377 printk("start_input: %x %d %d\n",buf,count,intrflag);
 378   if(intrflag) {
 379     int pos,chan=sound_dsp_dmachan[dev];
 380     DISABLE_INTR (flags);
 381     clear_dma_ff(chan);
 382     disable_dma(chan);
 383     pos=get_dma_residue(chan);
 384     enable_dma(chan);
 385     RESTORE_INTR (flags);
 386     printk("dmapos=%d %x\n",pos,pos);
 387   }
 388 #endif
 389   if (sound_dma_automode[dev] &&
 390       intrflag &&
 391       cnt == dsp_count) {
 392     irq_mode = IMODE_INPUT;
 393     intr_active = 1;
 394     return;                     /* Auto mode on. No need to react */
 395   }
 396   DISABLE_INTR (flags);
 397   
 398   if (dma_restart) 
 399   {
 400       sb16_dsp_halt(dev);
 401       DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
 402   }
 403 
 404   sb_dsp_command (0x42);
 405   sb_dsp_command ((unsigned char)((dsp_current_speed >> 8) & 0xff));
 406   sb_dsp_command ((unsigned char)(dsp_current_speed & 0xff));
 407   sb_dsp_command ((unsigned char)(dsp_16bit ? 0xbe : 0xce));
 408   sb_dsp_command ((unsigned char)((dsp_stereo ? 0x20 : 0) + 
 409                         (dsp_16bit ? 0x10:0)));
 410   sb_dsp_command01 ((unsigned char)(cnt&0xff));
 411   sb_dsp_command ((unsigned char)(cnt>>8));
 412   
 413   /* sb_dsp_command (0);
 414   sb_dsp_command (0); */
 415   RESTORE_INTR (flags);
 416   dsp_count=cnt;
 417   irq_mode = IMODE_INPUT;
 418   intr_active = 1;
 419 }
 420 
 421 static int
 422 sb16_dsp_prepare_for_input (int dev, int bsize, int bcount)
     /* [previous][next][first][last][top][bottom][index][help] */
 423 {
 424   sound_dsp_dmachan[my_dev] = dsp_16bit? dma16:dma8;
 425   dsp_count = 0;
 426   dsp_cleanup ();
 427   return 0;
 428 }
 429 
 430 static int
 431 sb16_dsp_prepare_for_output (int dev, int bsize, int bcount)
     /* [previous][next][first][last][top][bottom][index][help] */
 432 {
 433   sound_dsp_dmachan[my_dev] = dsp_16bit? dma16:dma8;
 434   dsp_count = 0;
 435   dsp_cleanup ();
 436   return 0;
 437 }
 438 
 439 static void
 440 dsp_cleanup (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 441 {
 442   irq_mode = IMODE_NONE;
 443   intr_active = 0;
 444 }
 445 
 446 static void
 447 sb16_dsp_reset (int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 448 {
 449   unsigned long flags;
 450 
 451   DISABLE_INTR (flags);
 452 
 453   sb_reset_dsp ();
 454   dsp_cleanup ();
 455 
 456   RESTORE_INTR (flags);
 457 }
 458 
 459 static void
 460 sb16_dsp_halt (int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 461 {
 462   sb_dsp_command01(0xd9);
 463   sb_dsp_command01(0xd5);
 464 }
 465 
 466 static void
 467 set_irq_hw(int level) {
     /* [previous][next][first][last][top][bottom][index][help] */
 468   int ival;
 469   switch(level) {
 470   case 5:
 471     ival=2; break;
 472   case 7:
 473     ival=4; break;
 474   case 10:
 475     ival=8; break;
 476   default:
 477     printk("SB16_IRQ_LEVEL %d does not exist\n",level);
 478     return;
 479   }
 480   sb_setmixer(IRQ_NR,ival);
 481 }
 482 
 483 long
 484 sb16_dsp_init (long mem_start, struct address_info *hw_config)
     /* [previous][next][first][last][top][bottom][index][help] */
 485 {
 486   int             i, major, minor;
 487 
 488   major = minor = 0;
 489   sb_dsp_command (0xe1);                /* Get version */
 490   
 491   for (i = 1000; i; i--) {
 492     if (INB (DSP_DATA_AVAIL) & 0x80)
 493       {                 /* wait for Data Ready */
 494         if (major == 0)
 495           major = INB (DSP_READ);
 496         else
 497           {
 498             minor = INB (DSP_READ);
 499             break;
 500           }
 501       }
 502   }
 503 
 504 #ifndef SCO 
 505   sprintf (sb16_dsp_operations.name, "SoundBlaster 16 %d.%d", major, minor);
 506 #endif
 507   
 508   printk (" <%s>", sb16_dsp_operations.name);
 509   
 510   if (num_dspdevs < MAX_DSP_DEV)
 511     {
 512       dsp_devs[my_dev = num_dspdevs++] = &sb16_dsp_operations;
 513       sound_dsp_dmachan[my_dev] = hw_config->dma;
 514       sound_buffcounts[my_dev] = 1;
 515       sound_buffsizes[my_dev] = DSP_BUFFSIZE;
 516       sound_dma_automode[my_dev] = 1;
 517     }
 518   else
 519     printk ("SB: Too many DSP devices available\n");
 520   sb16_dsp_ok = 1;
 521   return mem_start;
 522 }
 523 
 524 int
 525 sb16_dsp_detect (struct address_info *hw_config)
     /* [previous][next][first][last][top][bottom][index][help] */
 526 {
 527   struct address_info *sb_config;
 528 
 529   if (sb16_dsp_ok)
 530     return 1;                   /* Already initialized */
 531 
 532   if (!(sb_config=sound_getconf(SNDCARD_SB)))
 533   {
 534         printk("SB16 Error: Plain SB not configured\n");
 535         return 0;
 536   }
 537 
 538   if (sbc_base != hw_config->io_base)
 539      printk("Warning! SB16 I/O != SB I/O\n");
 540 
 541   /* sb_setmixer(OPSW,0xf);
 542   if(sb_getmixer(OPSW)!=0xf)
 543     return 0; */
 544   
 545   if (!sb_reset_dsp ())
 546     return 0;
 547 
 548   if (hw_config->irq != sb_config->irq)
 549   {
 550      printk("SB16 Error: Invalid IRQ number %d/%d\n",
 551              sb_config->irq, hw_config->irq);
 552      return 0;
 553   }
 554 
 555   if (hw_config->dma < 4)
 556      if (hw_config->dma != sb_config->dma)
 557      {
 558         printk("SB16 Error: Invalid DMA channel %d/%d\n",
 559                 sb_config->dma, hw_config->dma);
 560         return 0;
 561      }
 562 
 563   dma16 = hw_config->dma;
 564   dma8 = sb_config->dma;
 565   set_irq_hw(hw_config->irq);
 566   sb_setmixer(DMA_NR, (1<<hw_config->dma) | (1<<sb_config->dma));
 567 
 568   DEB(printk ("SoundBlaster 16: IRQ %d DMA %d OK\n",hw_config->irq,hw_config->dma));
 569   
 570 /*
 571   dsp_showmessage(0xe3,99);
 572 */
 573   sb16_dsp_ok = 1;
 574   return 1;
 575 }
 576 
 577 void
 578 sb16_dsp_interrupt (int unused)
     /* [previous][next][first][last][top][bottom][index][help] */
 579 {
 580     int data;
 581     data = INB (DSP_DATA_AVL16);        /* Interrupt acknowledge */
 582 
 583     if (intr_active)
 584       switch (irq_mode)
 585         {
 586         case IMODE_OUTPUT:
 587           intr_active = 0;
 588           DMAbuf_outputintr (my_dev, 1);
 589           break;
 590           
 591         case IMODE_INPUT:
 592           intr_active = 0;
 593           DMAbuf_inputintr (my_dev);
 594           break;
 595           
 596         default:
 597           printk ("SoundBlaster: Unexpected interrupt\n");
 598         }
 599 }
 600 #endif

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