The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/port/devaudio.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  *      SB 16 driver
    3  */
    4 #include        "u.h"
    5 #include        "../port/lib.h"
    6 #include        "mem.h"
    7 #include        "dat.h"
    8 #include        "fns.h"
    9 #include        "../port/error.h"
   10 #include        "io.h"
   11 #include        "audio.h"
   12 
   13 typedef struct  AQueue  AQueue;
   14 typedef struct  Buf     Buf;
   15 
   16 enum
   17 {
   18         Qdir            = 0,
   19         Qaudio,
   20         Qvolume,
   21         Qstatus,
   22 
   23         Fmono           = 1,
   24         Fin             = 2,
   25         Fout            = 4,
   26 
   27         Aclosed         = 0,
   28         Aread,
   29         Awrite,
   30 
   31         Vaudio          = 0,
   32         Vsynth,
   33         Vcd,
   34         Vline,
   35         Vmic,
   36         Vspeaker,
   37         Vtreb,
   38         Vbass,
   39         Vspeed,
   40         Nvol,
   41 
   42         Speed           = 44100,
   43         Ncmd            = 50,           /* max volume command words */
   44 };
   45 
   46 Dirtab
   47 audiodir[] =
   48 {
   49         ".",    {Qdir, 0, QTDIR},               0,      DMDIR|0555,
   50         "audio",        {Qaudio},               0,      0666,
   51         "volume",       {Qvolume},              0,      0666,
   52         "audiostat",{Qstatus},          0,      0444,
   53 };
   54 
   55 struct  Buf
   56 {
   57         uchar*  virt;
   58         ulong   phys;
   59         Buf*    next;
   60 };
   61 struct  AQueue
   62 {
   63         Lock;
   64         Buf*    first;
   65         Buf*    last;
   66 };
   67 static  struct
   68 {
   69         QLock;
   70         Rendez  vous;
   71         int     buffered;               /* number of bytes en route */
   72         int     bufinit;                /* boolean if buffers allocated */
   73         int     curcount;               /* how much data in current buffer */
   74         int     active;         /* boolean dma running */
   75         int     intr;                   /* boolean an interrupt has happened */
   76         int     amode;          /* Aclosed/Aread/Awrite for /audio */
   77         int     rivol[Nvol];    /* right/left input/output volumes */
   78         int     livol[Nvol];
   79         int     rovol[Nvol];
   80         int     lovol[Nvol];
   81         int     major;          /* SB16 major version number (sb 4) */
   82         int     minor;          /* SB16 minor version number */
   83         ulong   totcount;       /* how many bytes processed since open */
   84         vlong   tottime;        /* time at which totcount bytes were processed */
   85 
   86         Buf     buf[Nbuf];              /* buffers and queues */
   87         AQueue  empty;
   88         AQueue  full;
   89         Buf*    current;
   90         Buf*    filling;
   91 } audio;
   92 
   93 static  struct
   94 {
   95         char*   name;
   96         int     flag;
   97         int     ilval;          /* initial values */
   98         int     irval;
   99 } volumes[] =
  100 {
  101 [Vaudio]                "audio",        Fout,           50,     50,
  102 [Vsynth]                "synth",        Fin|Fout,       0,      0,
  103 [Vcd]           "cd",           Fin|Fout,       0,      0,
  104 [Vline]         "line", Fin|Fout,       0,      0,
  105 [Vmic]          "mic",  Fin|Fout|Fmono, 0,      0,
  106 [Vspeaker]      "speaker",      Fout|Fmono,     0,      0,
  107 
  108 [Vtreb]         "treb",         Fout,           50,     50,
  109 [Vbass]         "bass",         Fout,           50,     50,
  110 
  111 [Vspeed]        "speed",        Fin|Fout|Fmono, Speed,  Speed,
  112                 0
  113 };
  114 
  115 static struct
  116 {
  117         Lock;
  118         int     reset;          /* io ports to the sound blaster */
  119         int     read;
  120         int     write;
  121         int     wstatus;
  122         int     rstatus;
  123         int     mixaddr;
  124         int     mixdata;
  125         int     clri8;
  126         int     clri16;
  127         int     clri401;
  128         int     dma;
  129 
  130         void    (*startdma)(void);
  131         void    (*intr)(void);
  132 } blaster;
  133 
  134 static  void    swab(uchar*);
  135 
  136 static  char    Emajor[]        = "soundblaster not responding/wrong version";
  137 static  char    Emode[]         = "illegal open mode";
  138 static  char    Evolume[]       = "illegal volume specifier";
  139 
  140 static  int
  141 sbcmd(int val)
  142 {
  143         int i, s;
  144 
  145         for(i=1<<16; i!=0; i--) {
  146                 s = inb(blaster.wstatus);
  147                 if((s & 0x80) == 0) {
  148                         outb(blaster.write, val);
  149                         return 0;
  150                 }
  151         }
  152 /*      print("#A: sbcmd (%#.2x) timeout\n", val);      /**/
  153         return 1;
  154 }
  155 
  156 static  int
  157 sbread(void)
  158 {
  159         int i, s;
  160 
  161         for(i=1<<16; i!=0; i--) {
  162                 s = inb(blaster.rstatus);
  163                 if((s & 0x80) != 0) {
  164                         return inb(blaster.read);
  165                 }
  166         }
  167 /*      print("#A: sbread did not respond\n");  /**/
  168         return -1;
  169 }
  170 
  171 static int
  172 ess1688w(int reg, int val)
  173 {
  174         if(sbcmd(reg) || sbcmd(val))
  175                 return 1;
  176 
  177         return 0;
  178 }
  179 
  180 static int
  181 ess1688r(int reg)
  182 {
  183         if(sbcmd(0xC0) || sbcmd(reg))
  184                 return -1;
  185 
  186         return sbread();
  187 }
  188 
  189 static  int
  190 mxcmd(int addr, int val)
  191 {
  192 
  193         outb(blaster.mixaddr, addr);
  194         outb(blaster.mixdata, val);
  195         return 1;
  196 }
  197 
  198 static  int
  199 mxread(int addr)
  200 {
  201         int s;
  202 
  203         outb(blaster.mixaddr, addr);
  204         s = inb(blaster.mixdata);
  205         return s;
  206 }
  207 
  208 static  void
  209 mxcmds(int s, int v)
  210 {
  211 
  212         if(v > 100)
  213                 v = 100;
  214         if(v < 0)
  215                 v = 0;
  216         mxcmd(s, (v*255)/100);
  217 }
  218 
  219 static  void
  220 mxcmdt(int s, int v)
  221 {
  222 
  223         if(v > 100)
  224                 v = 100;
  225         if(v <= 0)
  226                 mxcmd(s, 0);
  227         else
  228                 mxcmd(s, 255-100+v);
  229 }
  230 
  231 static  void
  232 mxcmdu(int s, int v)
  233 {
  234 
  235         if(v > 100)
  236                 v = 100;
  237         if(v <= 0)
  238                 v = 0;
  239         mxcmd(s, 128-50+v);
  240 }
  241 
  242 static  void
  243 mxvolume(void)
  244 {
  245         int *left, *right;
  246         int source;
  247 
  248         if(audio.amode == Aread){
  249                 left = audio.livol;
  250                 right = audio.rivol;
  251         }else{
  252                 left = audio.lovol;
  253                 right = audio.rovol;
  254         }
  255 
  256         ilock(&blaster);
  257 
  258         mxcmd(0x30, 255);               /* left master */
  259         mxcmd(0x31, 255);               /* right master */
  260         mxcmd(0x3f, 0);         /* left igain */
  261         mxcmd(0x40, 0);         /* right igain */
  262         mxcmd(0x41, 0);         /* left ogain */
  263         mxcmd(0x42, 0);         /* right ogain */
  264 
  265         mxcmds(0x32, left[Vaudio]);
  266         mxcmds(0x33, right[Vaudio]);
  267 
  268         mxcmds(0x34, left[Vsynth]);
  269         mxcmds(0x35, right[Vsynth]);
  270 
  271         mxcmds(0x36, left[Vcd]);
  272         mxcmds(0x37, right[Vcd]);
  273 
  274         mxcmds(0x38, left[Vline]);
  275         mxcmds(0x39, right[Vline]);
  276 
  277         mxcmds(0x3a, left[Vmic]);
  278         mxcmds(0x3b, left[Vspeaker]);
  279 
  280         mxcmdu(0x44, left[Vtreb]);
  281         mxcmdu(0x45, right[Vtreb]);
  282 
  283         mxcmdu(0x46, left[Vbass]);
  284         mxcmdu(0x47, right[Vbass]);
  285 
  286         source = 0;
  287         if(left[Vsynth])
  288                 source |= 1<<6;
  289         if(right[Vsynth])
  290                 source |= 1<<5;
  291         if(left[Vaudio])
  292                 source |= 1<<4;
  293         if(right[Vaudio])
  294                 source |= 1<<3;
  295         if(left[Vcd])
  296                 source |= 1<<2;
  297         if(right[Vcd])
  298                 source |= 1<<1;
  299         if(left[Vmic])
  300                 source |= 1<<0;
  301         if(audio.amode == Aread)
  302                 mxcmd(0x3c, 0);         /* output switch */
  303         else
  304                 mxcmd(0x3c, source);
  305         mxcmd(0x3d, source);            /* input left switch */
  306         mxcmd(0x3e, source);            /* input right switch */
  307         iunlock(&blaster);
  308 }
  309 
  310 static  Buf*
  311 getbuf(AQueue *q)
  312 {
  313         Buf *b;
  314 
  315         ilock(q);
  316         b = q->first;
  317         if(b)
  318                 q->first = b->next;
  319         iunlock(q);
  320 
  321         return b;
  322 }
  323 
  324 static  void
  325 putbuf(AQueue *q, Buf *b)
  326 {
  327 
  328         ilock(q);
  329         b->next = 0;
  330         if(q->first)
  331                 q->last->next = b;
  332         else
  333                 q->first = b;
  334         q->last = b;
  335         iunlock(q);
  336 }
  337 
  338 /*
  339  * move the dma to the next buffer
  340  */
  341 static  void
  342 contindma(void)
  343 {
  344         Buf *b;
  345 
  346         if(!audio.active)
  347                 goto shutdown;
  348 
  349         b = audio.current;
  350         if(b){
  351                 audio.totcount += Bufsize;
  352                 audio.tottime = todget(nil);
  353         }
  354         if(audio.amode == Aread) {
  355                 if(b){
  356                         putbuf(&audio.full, b);
  357                         audio.buffered += Bufsize;
  358                 }
  359                 b = getbuf(&audio.empty);
  360         } else {
  361                 if(b){
  362                         putbuf(&audio.empty, b);
  363                         audio.buffered -= Bufsize;
  364                 }
  365                 b = getbuf(&audio.full);
  366         }
  367         audio.current = b;
  368         if(b == 0)
  369                 goto shutdown;
  370 
  371         if(dmasetup(blaster.dma, b->virt, Bufsize, audio.amode == Aread) >= 0)
  372                 return;
  373         print("#A: dmasetup fail\n");
  374         putbuf(&audio.empty, b);
  375 
  376 shutdown:
  377         dmaend(blaster.dma);
  378         sbcmd(0xd9);                            /* exit at end of count */
  379         sbcmd(0xd5);                            /* pause */
  380         audio.curcount = 0;
  381         audio.active = 0;
  382 }
  383 
  384 /*
  385  * cause sb to get an interrupt per buffer.
  386  * start first dma
  387  */
  388 static  void
  389 sb16startdma(void)
  390 {
  391         ulong count;
  392         int speed;
  393 
  394         ilock(&blaster);
  395         dmaend(blaster.dma);
  396         if(audio.amode == Aread) {
  397                 sbcmd(0x42);                    /* input sampling rate */
  398                 speed = audio.livol[Vspeed];
  399         } else {
  400                 sbcmd(0x41);                    /* output sampling rate */
  401                 speed = audio.lovol[Vspeed];
  402         }
  403         sbcmd(speed>>8);
  404         sbcmd(speed);
  405 
  406         count = (Bufsize >> 1) - 1;
  407         if(audio.amode == Aread)
  408                 sbcmd(0xbe);                    /* A/D, autoinit */
  409         else
  410                 sbcmd(0xb6);                    /* D/A, autoinit */
  411         sbcmd(0x30);                            /* stereo, 16 bit */
  412         sbcmd(count);
  413         sbcmd(count>>8);
  414 
  415         audio.active = 1;
  416         contindma();
  417         iunlock(&blaster);
  418 }
  419 
  420 static int
  421 ess1688reset(void)
  422 {
  423         int i;
  424 
  425         outb(blaster.reset, 3);
  426         delay(1);                       /* >3 υs */
  427         outb(blaster.reset, 0);
  428         delay(1);
  429 
  430         i = sbread();
  431         if(i != 0xAA) {
  432                 print("#A: no response %#.2x\n", i);
  433                 return 1;
  434         }
  435 
  436         if(sbcmd(0xC6)){                /* extended mode */
  437                 print("#A: barf 3\n");
  438                 return 1;
  439         }
  440 
  441         return 0;
  442 }
  443 
  444 static  void
  445 ess1688startdma(void)
  446 {
  447         ulong count;
  448         int speed, x;
  449 
  450         ilock(&blaster);
  451         dmaend(blaster.dma);
  452 
  453         if(audio.amode == Awrite)
  454                 ess1688reset();
  455         if(audio.amode == Aread)
  456                 sbcmd(0xD3);                    /* speaker off */
  457 
  458         /*
  459          * Set the speed.
  460          */
  461         if(audio.amode == Aread)
  462                 speed = audio.livol[Vspeed];
  463         else
  464                 speed = audio.lovol[Vspeed];
  465         if(speed < 4000)
  466                 speed = 4000;
  467         else if(speed > 48000)
  468                 speed = 48000;
  469 
  470         if(speed > 22000)
  471                   x = 0x80|(256-(795500+speed/2)/speed);
  472         else
  473                   x = 128-(397700+speed/2)/speed;
  474         ess1688w(0xA1, x & 0xFF);
  475 
  476         speed = (speed * 9) / 20;
  477         x = 256 - 7160000 / (speed * 82);
  478         ess1688w(0xA2, x & 0xFF);
  479 
  480         if(audio.amode == Aread)
  481                 ess1688w(0xB8, 0x0E);           /* A/D, autoinit */
  482         else
  483                 ess1688w(0xB8, 0x04);           /* D/A, autoinit */
  484         x = ess1688r(0xA8) & ~0x03;
  485         ess1688w(0xA8, x|0x01);                 /* 2 channels */
  486         ess1688w(0xB9, 2);                      /* demand mode, 4 bytes per request */
  487 
  488         if(audio.amode == Awrite)
  489                 ess1688w(0xB6, 0);
  490         ess1688w(0xB7, 0x71);
  491         ess1688w(0xB7, 0xBC);
  492 
  493         x = ess1688r(0xB1) & 0x0F;
  494         ess1688w(0xB1, x|0x50);
  495         x = ess1688r(0xB2) & 0x0F;
  496         ess1688w(0xB2, x|0x50);
  497         if(audio.amode == Awrite)
  498                 sbcmd(0xD1);                    /* speaker on */
  499 
  500         count = -Bufsize;
  501         ess1688w(0xA4, count & 0xFF);
  502         ess1688w(0xA5, (count>>8) & 0xFF);
  503         x = ess1688r(0xB8);
  504         ess1688w(0xB8, x|0x05);
  505 
  506         audio.active = 1;
  507         contindma();
  508         iunlock(&blaster);
  509 }
  510 
  511 /*
  512  * if audio is stopped,
  513  * start it up again.
  514  */
  515 static  void
  516 pokeaudio(void)
  517 {
  518         if(!audio.active)
  519                 blaster.startdma();
  520 }
  521 
  522 static void
  523 sb16intr(void)
  524 {
  525         int stat, dummy;
  526 
  527         stat = mxread(0x82) & 7;                /* get irq status */
  528         if(stat) {
  529                 dummy = 0;
  530                 if(stat & 2) {
  531                         ilock(&blaster);
  532                         dummy = inb(blaster.clri16);
  533                         contindma();
  534                         iunlock(&blaster);
  535                         audio.intr = 1;
  536                         wakeup(&audio.vous);
  537                 }
  538                 if(stat & 1) {
  539                         dummy = inb(blaster.clri8);
  540                 }
  541                 if(stat & 4) {
  542                         dummy = inb(blaster.clri401);
  543                 }
  544                 USED(dummy);
  545         }
  546 }
  547 
  548 static void
  549 ess1688intr(void)
  550 {
  551         int dummy;
  552 
  553         if(audio.active){
  554                 ilock(&blaster);
  555                 contindma();
  556                 dummy = inb(blaster.clri8);
  557                 iunlock(&blaster);
  558                 audio.intr = 1;
  559                 wakeup(&audio.vous);
  560                 USED(dummy);
  561         }
  562         else
  563                 print("#A: unexpected ess1688 interrupt\n");
  564 }
  565 
  566 void
  567 audiosbintr(void)
  568 {
  569         /*
  570          * Carrera interrupt interface.
  571          */
  572         blaster.intr();
  573 }
  574 
  575 static void
  576 pcaudiosbintr(Ureg*, void*)
  577 {
  578         /*
  579          * x86 interrupt interface.
  580          */
  581         blaster.intr();
  582 }
  583 
  584 void
  585 audiodmaintr(void)
  586 {
  587 /*      print("#A: dma interrupt\n");   /**/
  588 }
  589 
  590 static int
  591 anybuf(void*)
  592 {
  593         return audio.intr;
  594 }
  595 
  596 /*
  597  * wait for some output to get
  598  * empty buffers back.
  599  */
  600 static void
  601 waitaudio(void)
  602 {
  603 
  604         audio.intr = 0;
  605         pokeaudio();
  606         tsleep(&audio.vous, anybuf, 0, 10000);
  607         if(audio.intr == 0) {
  608 /*              print("#A: audio timeout\n");   /**/
  609                 audio.active = 0;
  610                 pokeaudio();
  611         }
  612 }
  613 
  614 static void
  615 sbbufinit(void)
  616 {
  617         int i;
  618         uchar *p;
  619 
  620         p = (uchar*)(((ulong)xalloc((Nbuf+1) * Bufsize) + Bufsize-1) &
  621                 ~(Bufsize-1));
  622         if (p == nil)
  623                 panic("sbbufinit: no memory");
  624         for(i=0; i<Nbuf; i++) {
  625                 dcflush(p, Bufsize);
  626                 audio.buf[i].virt = UNCACHED(uchar, p);
  627                 audio.buf[i].phys = (ulong)PADDR(p);
  628                 p += Bufsize;
  629         }
  630 }
  631 
  632 static  void
  633 setempty(void)
  634 {
  635         int i;
  636 
  637         ilock(&blaster);
  638         audio.empty.first = 0;
  639         audio.empty.last = 0;
  640         audio.full.first = 0;
  641         audio.full.last = 0;
  642         audio.current = 0;
  643         audio.filling = 0;
  644         audio.buffered = 0;
  645         for(i=0; i<Nbuf; i++)
  646                 putbuf(&audio.empty, &audio.buf[i]);
  647         audio.totcount = 0;
  648         audio.tottime = 0LL;
  649         iunlock(&blaster);
  650 }
  651 
  652 static  void
  653 resetlevel(void)
  654 {
  655         int i;
  656 
  657         for(i=0; volumes[i].name; i++) {
  658                 audio.lovol[i] = volumes[i].ilval;
  659                 audio.rovol[i] = volumes[i].irval;
  660                 audio.livol[i] = volumes[i].ilval;
  661                 audio.rivol[i] = volumes[i].irval;
  662         }
  663 }
  664 
  665 static int
  666 ess1688(ISAConf* sbconf)
  667 {
  668         int i, major, minor;
  669 
  670         /*
  671          * Try for ESS1688.
  672          */
  673         sbcmd(0xE7);                    /* get version */
  674         major = sbread();
  675         minor = sbread();
  676         if(major != 0x68 || minor != 0x8B){
  677                 print("#A: model %#.2x %#.2x; not ESS1688 compatible\n", major, minor);
  678                 return 1;
  679         }
  680 
  681         ess1688reset();
  682 
  683         switch(sbconf->irq){
  684         case 2:
  685         case 9:
  686                 i = 0x50|(0<<2);
  687                 break;
  688         case 5:
  689                 i = 0x50|(1<<2);
  690                 break;
  691         case 7:
  692                 i = 0x50|(2<<2);
  693                 break;
  694         case 10:
  695                 i = 0x50|(3<<2);
  696                 break;
  697         default:
  698                 print("#A: bad ESS1688 irq %d\n", sbconf->irq);
  699                 return 1;
  700         }
  701         ess1688w(0xB1, i);
  702 
  703         switch(sbconf->dma){
  704         case 0:
  705                 i = 0x50|(1<<2);
  706                 break;
  707         case 1:
  708                 i = 0xF0|(2<<2);
  709                 break;
  710         case 3:
  711                 i = 0x50|(3<<2);
  712                 break;
  713         default:
  714                 print("#A: bad ESS1688 dma %lud\n", sbconf->dma);
  715                 return 1;
  716         }
  717         ess1688w(0xB2, i);
  718 
  719         ess1688reset();
  720 
  721         blaster.startdma = ess1688startdma;
  722         blaster.intr = ess1688intr;
  723 
  724         return 0;
  725 }
  726 
  727 static void
  728 audioinit(void)
  729 {
  730         ISAConf sbconf;
  731         int i, x;
  732         static int irq[] = {2,5,7,10};
  733 
  734         sbconf.port = 0x220;
  735         sbconf.dma = Dma;
  736         sbconf.irq = IrqAUDIO;
  737         if(isaconfig("audio", 0, &sbconf) == 0)
  738                 return;
  739         if(sbconf.type == nil ||
  740                 (cistrcmp(sbconf.type, "sb16") != 0 && 
  741                  cistrcmp(sbconf.type, "ess1688") != 0))
  742                 return;
  743         switch(sbconf.port){
  744         case 0x220:
  745         case 0x240:
  746         case 0x260:
  747         case 0x280:
  748                 break;
  749         default:
  750                 print("#A: bad port %#lux\n", sbconf.port);
  751                 return;
  752         }
  753 
  754         if(ioalloc(sbconf.port, 0x10, 0, "audio") < 0){
  755                 print("#A: cannot ioalloc range %lux+0x10\n", sbconf.port);
  756                 return;
  757         }
  758         if(ioalloc(sbconf.port+0x100, 1, 0, "audio.mpu401") < 0){
  759                 iofree(sbconf.port);
  760                 print("#A: cannot ioalloc range %lux+0x01\n", sbconf.port+0x100);
  761                 return;
  762         }
  763 
  764         switch(sbconf.irq){
  765         case 2:
  766         case 5:
  767         case 7:
  768         case 9:
  769         case 10:
  770                 break;
  771         default:
  772                 print("#A: bad irq %d\n", sbconf.irq);
  773                 iofree(sbconf.port);
  774                 iofree(sbconf.port+0x100);
  775                 return;
  776         }
  777 
  778         blaster.reset = sbconf.port + 0x6;
  779         blaster.read = sbconf.port + 0xa;
  780         blaster.write = sbconf.port + 0xc;
  781         blaster.wstatus = sbconf.port + 0xc;
  782         blaster.rstatus = sbconf.port + 0xe;
  783         blaster.mixaddr = sbconf.port + 0x4;
  784         blaster.mixdata = sbconf.port + 0x5;
  785         blaster.clri8 = sbconf.port + 0xe;
  786         blaster.clri16 = sbconf.port + 0xf;
  787         blaster.clri401 = sbconf.port + 0x100;
  788         blaster.dma = sbconf.dma;
  789 
  790         blaster.startdma = sb16startdma;
  791         blaster.intr = sb16intr;
  792 
  793         audio.amode = Aclosed;
  794         resetlevel();
  795 
  796         outb(blaster.reset, 1);
  797         delay(1);                       /* >3 υs */
  798         outb(blaster.reset, 0);
  799         delay(1);
  800 
  801         i = sbread();
  802         if(i != 0xaa) {
  803                 print("#A: no response #%.2x\n", i);
  804                 iofree(sbconf.port);
  805                 iofree(sbconf.port+0x100);
  806                 return;
  807         }
  808 
  809         sbcmd(0xe1);                    /* get version */
  810         audio.major = sbread();
  811         audio.minor = sbread();
  812 
  813         if(audio.major != 4) {
  814                 if(audio.major != 3 || audio.minor != 1 || ess1688(&sbconf)){
  815                         print("#A: model %#.2x %#.2x; not SB 16 compatible\n",
  816                                 audio.major, audio.minor);
  817                         iofree(sbconf.port);
  818                         iofree(sbconf.port+0x100);
  819                         return;
  820                 }
  821                 audio.major = 4;
  822         }
  823 
  824         /*
  825          * initialize the mixer
  826          */
  827         mxcmd(0x00, 0);                 /* Reset mixer */
  828         mxvolume();
  829 
  830         /*
  831          * Attempt to set IRQ/DMA channels.
  832          * On old ISA boards, these registers are writable.
  833          * On Plug-n-Play boards, these are read-only.
  834          *
  835          * To accomodate both, we write to the registers,
  836          * but then use the contents in case the write is
  837          * disallowed.
  838          */
  839         mxcmd(0x80,                     /* irq */
  840                 (sbconf.irq==2)? 1:
  841                 (sbconf.irq==5)? 2:
  842                 (sbconf.irq==7)? 4:
  843                 (sbconf.irq==9)? 1:
  844                 (sbconf.irq==10)? 8:
  845                 0);
  846 
  847         mxcmd(0x81, 1<<blaster.dma);    /* dma */
  848 
  849         x = mxread(0x81);
  850         for(i=5; i<=7; i++)
  851                 if(x & (1<<i)){
  852                         blaster.dma = i;
  853                         break;
  854                 }
  855 
  856         x = mxread(0x80);
  857         for(i=0; i<=3; i++)
  858                 if(x & (1<<i)){
  859                         sbconf.irq = irq[i];
  860                         break;
  861                 }
  862 
  863         seteisadma(blaster.dma, audiodmaintr);
  864         setvec(Int0vec+sbconf.irq, pcaudiosbintr, 0);
  865 }
  866 
  867 static Chan*
  868 audioattach(char *param)
  869 {
  870         return devattach('A', param);
  871 }
  872 
  873 static Walkqid*
  874 audiowalk(Chan *c, Chan *nc, char **name, int nname)
  875 {
  876         return devwalk(c, nc, name, nname, audiodir, nelem(audiodir), devgen);
  877 }
  878 
  879 static int
  880 audiostat(Chan *c, uchar *db, int n)
  881 {
  882         audiodir[Qaudio].length = audio.buffered;
  883         return devstat(c, db, n, audiodir, nelem(audiodir), devgen);
  884 }
  885 
  886 static Chan*
  887 audioopen(Chan *c, int omode)
  888 {
  889         int amode;
  890 
  891         if(audio.major != 4)
  892                 error(Emajor);
  893 
  894         switch((ulong)c->qid.path) {
  895         default:
  896                 error(Eperm);
  897                 break;
  898 
  899         case Qstatus:
  900                 if((omode&7) != OREAD)
  901                         error(Eperm);
  902         case Qvolume:
  903         case Qdir:
  904                 break;
  905 
  906         case Qaudio:
  907                 amode = Awrite;
  908                 if((omode&7) == OREAD)
  909                         amode = Aread;
  910                 qlock(&audio);
  911                 if(audio.amode != Aclosed){
  912                         qunlock(&audio);
  913                         error(Einuse);
  914                 }
  915                 if(audio.bufinit == 0) {
  916                         audio.bufinit = 1;
  917                         sbbufinit();
  918                 }
  919                 audio.amode = amode;
  920                 setempty();
  921                 audio.curcount = 0;
  922                 qunlock(&audio);
  923                 mxvolume();
  924                 break;
  925         }
  926         c = devopen(c, omode, audiodir, nelem(audiodir), devgen);
  927         c->mode = openmode(omode);
  928         c->flag |= COPEN;
  929         c->offset = 0;
  930 
  931         return c;
  932 }
  933 
  934 static void
  935 audioclose(Chan *c)
  936 {
  937         Buf *b;
  938 
  939         switch((ulong)c->qid.path) {
  940         default:
  941                 error(Eperm);
  942                 break;
  943 
  944         case Qdir:
  945         case Qvolume:
  946         case Qstatus:
  947                 break;
  948 
  949         case Qaudio:
  950                 if(c->flag & COPEN) {
  951                         qlock(&audio);
  952                         if(audio.amode == Awrite) {
  953                                 /* flush out last partial buffer */
  954                                 b = audio.filling;
  955                                 if(b) {
  956                                         audio.filling = 0;
  957                                         memset(b->virt+audio.curcount, 0, Bufsize-audio.curcount);
  958                                         audio.buffered += Bufsize-audio.curcount;
  959                                         swab(b->virt);
  960                                         putbuf(&audio.full, b);
  961                                 }
  962                                 if(!audio.active && audio.full.first)
  963                                         pokeaudio();
  964                         }
  965                         audio.amode = Aclosed;
  966                         if(waserror()){
  967                                 qunlock(&audio);
  968                                 nexterror();
  969                         }
  970                         while(audio.active)
  971                                 waitaudio();
  972                         setempty();
  973                         poperror();
  974                         qunlock(&audio);
  975                 }
  976                 break;
  977         }
  978 }
  979 
  980 static long
  981 audioread(Chan *c, void *v, long n, vlong off)
  982 {
  983         int liv, riv, lov, rov;
  984         long m, n0;
  985         char buf[300];
  986         Buf *b;
  987         int j;
  988         ulong offset = off;
  989         char *a;
  990 
  991         n0 = n;
  992         a = v;
  993         switch((ulong)c->qid.path) {
  994         default:
  995                 error(Eperm);
  996                 break;
  997 
  998         case Qdir:
  999                 return devdirread(c, a, n, audiodir, nelem(audiodir), devgen);
 1000 
 1001         case Qaudio:
 1002                 if(audio.amode != Aread)
 1003                         error(Emode);
 1004                 qlock(&audio);
 1005                 if(waserror()){
 1006                         qunlock(&audio);
 1007                         nexterror();
 1008                 }
 1009                 while(n > 0) {
 1010                         b = audio.filling;
 1011                         if(b == 0) {
 1012                                 b = getbuf(&audio.full);
 1013                                 if(b == 0) {
 1014                                         waitaudio();
 1015                                         continue;
 1016                                 }
 1017                                 audio.filling = b;
 1018                                 swab(b->virt);
 1019                                 audio.curcount = 0;
 1020                         }
 1021                         m = Bufsize-audio.curcount;
 1022                         if(m > n)
 1023                                 m = n;
 1024                         memmove(a, b->virt+audio.curcount, m);
 1025 
 1026                         audio.curcount += m;
 1027                         n -= m;
 1028                         a += m;
 1029                         audio.buffered -= m;
 1030                         if(audio.curcount >= Bufsize) {
 1031                                 audio.filling = 0;
 1032                                 putbuf(&audio.empty, b);
 1033                         }
 1034                 }
 1035                 poperror();
 1036                 qunlock(&audio);
 1037                 break;
 1038 
 1039         case Qstatus:
 1040                 buf[0] = 0;
 1041                 snprint(buf, sizeof(buf), "bufsize %6d buffered %6d offset  %10lud time %19lld\n",
 1042                         Bufsize, audio.buffered, audio.totcount, audio.tottime);
 1043                 return readstr(offset, a, n, buf);
 1044 
 1045         case Qvolume:
 1046                 j = 0;
 1047                 buf[0] = 0;
 1048                 for(m=0; volumes[m].name; m++){
 1049                         liv = audio.livol[m];
 1050                         riv = audio.rivol[m];
 1051                         lov = audio.lovol[m];
 1052                         rov = audio.rovol[m];
 1053                         j += snprint(buf+j, sizeof(buf)-j, "%s", volumes[m].name);
 1054                         if((volumes[m].flag & Fmono) || liv==riv && lov==rov){
 1055                                 if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) && liv==lov)
 1056                                         j += snprint(buf+j, sizeof(buf)-j, " %d", liv);
 1057                                 else{
 1058                                         if(volumes[m].flag & Fin)
 1059                                                 j += snprint(buf+j, sizeof(buf)-j,
 1060                                                         " in %d", liv);
 1061                                         if(volumes[m].flag & Fout)
 1062                                                 j += snprint(buf+j, sizeof(buf)-j,
 1063                                                         " out %d", lov);
 1064                                 }
 1065                         }else{
 1066                                 if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) &&
 1067                                     liv==lov && riv==rov)
 1068                                         j += snprint(buf+j, sizeof(buf)-j,
 1069                                                 " left %d right %d",
 1070                                                 liv, riv);
 1071                                 else{
 1072                                         if(volumes[m].flag & Fin)
 1073                                                 j += snprint(buf+j, sizeof(buf)-j,
 1074                                                         " in left %d right %d",
 1075                                                         liv, riv);
 1076                                         if(volumes[m].flag & Fout)
 1077                                                 j += snprint(buf+j, sizeof(buf)-j,
 1078                                                         " out left %d right %d",
 1079                                                         lov, rov);
 1080                                 }
 1081                         }
 1082                         j += snprint(buf+j, sizeof(buf)-j, "\n");
 1083                 }
 1084                 return readstr(offset, a, n, buf);
 1085         }
 1086         return n0-n;
 1087 }
 1088 
 1089 static long
 1090 audiowrite(Chan *c, void *vp, long n, vlong)
 1091 {
 1092         long m, n0;
 1093         int i, v, left, right, in, out;
 1094         Cmdbuf *cb;
 1095         Buf *b;
 1096         char *a;
 1097 
 1098         a = vp;
 1099         n0 = n;
 1100         switch((ulong)c->qid.path) {
 1101         default:
 1102                 error(Eperm);
 1103                 break;
 1104 
 1105         case Qvolume:
 1106                 v = Vaudio;
 1107                 left = 1;
 1108                 right = 1;
 1109                 in = 1;
 1110                 out = 1;
 1111                 cb = parsecmd(vp, n);
 1112                 if(waserror()){
 1113                         free(cb);
 1114                         nexterror();
 1115                 }
 1116 
 1117                 for(i = 0; i < cb->nf; i++){
 1118                         /*
 1119                          * a number is volume
 1120                          */
 1121                         if(cb->f[i][0] >= '' && cb->f[i][0] <= '9') {
 1122                                 m = strtoul(cb->f[i], 0, 10);
 1123                                 if(left && out)
 1124                                         audio.lovol[v] = m;
 1125                                 if(left && in)
 1126                                         audio.livol[v] = m;
 1127                                 if(right && out)
 1128                                         audio.rovol[v] = m;
 1129                                 if(right && in)
 1130                                         audio.rivol[v] = m;
 1131                                 mxvolume();
 1132                                 goto cont0;
 1133                         }
 1134 
 1135                         for(m=0; volumes[m].name; m++) {
 1136                                 if(strcmp(cb->f[i], volumes[m].name) == 0) {
 1137                                         v = m;
 1138                                         in = 1;
 1139                                         out = 1;
 1140                                         left = 1;
 1141                                         right = 1;
 1142                                         goto cont0;
 1143                                 }
 1144                         }
 1145 
 1146                         if(strcmp(cb->f[i], "reset") == 0) {
 1147                                 resetlevel();
 1148                                 mxvolume();
 1149                                 goto cont0;
 1150                         }
 1151                         if(strcmp(cb->f[i], "in") == 0) {
 1152                                 in = 1;
 1153                                 out = 0;
 1154                                 goto cont0;
 1155                         }
 1156                         if(strcmp(cb->f[i], "out") == 0) {
 1157                                 in = 0;
 1158                                 out = 1;
 1159                                 goto cont0;
 1160                         }
 1161                         if(strcmp(cb->f[i], "left") == 0) {
 1162                                 left = 1;
 1163                                 right = 0;
 1164                                 goto cont0;
 1165                         }
 1166                         if(strcmp(cb->f[i], "right") == 0) {
 1167                                 left = 0;
 1168                                 right = 1;
 1169                                 goto cont0;
 1170                         }
 1171                         error(Evolume);
 1172                         break;
 1173                 cont0:;
 1174                 }
 1175                 free(cb);
 1176                 poperror();
 1177                 break;
 1178 
 1179         case Qaudio:
 1180                 if(audio.amode != Awrite)
 1181                         error(Emode);
 1182                 qlock(&audio);
 1183                 if(waserror()){
 1184                         qunlock(&audio);
 1185                         nexterror();
 1186                 }
 1187                 while(n > 0) {
 1188                         b = audio.filling;
 1189                         if(b == 0) {
 1190                                 b = getbuf(&audio.empty);
 1191                                 if(b == 0) {
 1192                                         waitaudio();
 1193                                         continue;
 1194                                 }
 1195                                 audio.filling = b;
 1196                                 audio.curcount = 0;
 1197                         }
 1198 
 1199                         m = Bufsize-audio.curcount;
 1200                         if(m > n)
 1201                                 m = n;
 1202                         memmove(b->virt+audio.curcount, a, m);
 1203 
 1204                         audio.curcount += m;
 1205                         n -= m;
 1206                         a += m;
 1207                         audio.buffered += m;
 1208                         if(audio.curcount >= Bufsize) {
 1209                                 audio.filling = 0;
 1210                                 swab(b->virt);
 1211                                 putbuf(&audio.full, b);
 1212                                 pokeaudio();
 1213                         }
 1214                 }
 1215                 poperror();
 1216                 qunlock(&audio);
 1217                 break;
 1218         }
 1219         return n0 - n;
 1220 }
 1221 
 1222 static  void
 1223 swab(uchar *a)
 1224 {
 1225         ulong *p, *ep, b;
 1226 
 1227         if(!SBswab){
 1228                 USED(a);
 1229                 return;
 1230         }
 1231         p = (ulong*)a;
 1232         ep = p + (Bufsize>>2);
 1233         while(p < ep) {
 1234                 b = *p;
 1235                 b = (b>>24) | (b<<24) |
 1236                         ((b&0xff0000) >> 8) |
 1237                         ((b&0x00ff00) << 8);
 1238                 *p++ = b;
 1239         }
 1240 }
 1241 
 1242 Dev audiodevtab = {
 1243         'A',
 1244         "audio",
 1245 
 1246         devreset,
 1247         audioinit,
 1248         devshutdown,
 1249         audioattach,
 1250         audiowalk,
 1251         audiostat,
 1252         audioopen,
 1253         devcreate,
 1254         audioclose,
 1255         audioread,
 1256         devbread,
 1257         audiowrite,
 1258         devbwrite,
 1259         devremove,
 1260         devwstat,
 1261 };

Cache object: 0708c015c826b08aae89223bc210f9c7


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.