root/dev/isa/aria.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ariaprobe
  2. aria_prometheus_kludge
  3. aria_do_kludge
  4. ariaattach
  5. ariaopen
  6. aria_getdev
  7. aria_printsc
  8. aria_set_sr
  9. aria_get_sr
  10. aria_query_encoding
  11. aria_set_format
  12. aria_get_encoding
  13. aria_get_precision
  14. aria_set_channels
  15. aria_get_channels
  16. aria_set_out_port
  17. aria_get_out_port
  18. aria_set_in_port
  19. aria_get_in_port
  20. aria_speaker_ctl
  21. aria_round_blocksize
  22. aria_commit_settings
  23. ariaclose
  24. aria_reset
  25. aria_putdspmem
  26. aria_getdspmem
  27. aria_sendcmd
  28. aria_halt_input
  29. aria_halt_output
  30. aria_cont
  31. aria_start_input
  32. aria_start_output
  33. aria_intr
  34. aria_setfd
  35. aria_mixer_set_port
  36. aria_mixer_get_port
  37. aria_mixer_query_devinfo

    1 /*      $OpenBSD: aria.c,v 1.13 2006/05/11 18:50:18 miod Exp $ */
    2 
    3 /*
    4  * Copyright (c) 1995, 1996 Roland C. Dowdeswell.  All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  * 3. All advertising materials mentioning features or use of this software
   15  *    must display the following acknowledgement:
   16  *      This product includes software developed by Roland C. Dowdeswell.
   17  * 4. The name of the authors may not be used to endorse or promote products
   18  *      derived from this software without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
   21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   23  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 /*
   33  * TODO:
   34  *  o   Test the driver on cards other than a single
   35  *      Prometheus Aria 16.
   36  *  o   Look into where aria_prometheus_kludge() belongs.
   37  *  o   Add some dma code.  It accomplishes its goal by
   38  *      direct IO at the moment.
   39  *  o   Look into return values on aria_set_sr(), if there is
   40  *      no matching rate.  (I think that this behaves in the
   41  *      same way as sbdsp.c)
   42  *  o   Different programs should be able to open the device
   43  *      with O_RDONLY and O_WRONLY at the same time.  But I
   44  *      do not see support for this in /sys/dev/audio.c, so
   45  *      I cannot effectively code it.
   46  *  o   Separate the debugging code, with a #define.
   47  *      Write more into aria_printsc().
   48  *  o   Rework the mixer interface.
   49  *       o   Deal with the lvls better.  We need to do better mapping
   50  *           between logarithmic scales and the one byte that
   51  *           we are passed.
   52  *       o   Deal better with cards that have no mixer.
   53  *
   54  * roland@imrryr.org
   55  * update from http://www.imrryr.org/NetBSD/hacks/aria/
   56  */
   57 
   58 #include "aria.h"
   59 #if NARIA > 0
   60 
   61 #include <sys/param.h>
   62 #include <sys/systm.h>
   63 #include <sys/errno.h>
   64 #include <sys/ioctl.h>
   65 #include <sys/syslog.h>
   66 #include <sys/device.h>
   67 #include <sys/proc.h>
   68 #include <sys/buf.h>
   69 
   70 #include <machine/cpu.h>
   71 #include <machine/pio.h>
   72 
   73 #include <sys/audioio.h>
   74 #include <dev/audio_if.h>
   75 
   76 #include <dev/mulaw.h>
   77 #include <dev/isa/isavar.h>
   78 #include <dev/isa/isadmavar.h>
   79 
   80 #include <dev/isa/ariareg.h>
   81 
   82 #define FREAD 1
   83 #define FWRITE 2
   84 
   85 #ifdef AUDIO_DEBUG
   86 extern void Dprintf(const char *, ...);
   87 #define DPRINTF(x)      if (ariadebug) Dprintf x
   88 int     ariadebug = 0;
   89 #else
   90 #define DPRINTF(x)
   91 #endif
   92 
   93 struct aria_mixdev_info {
   94         u_char  num_channels;
   95         u_char  level[2];
   96         u_char  mute;
   97 };
   98 
   99 struct aria_mixmaster {
  100         u_char num_channels;
  101         u_char level[2];
  102         u_char treble[2];
  103         u_char bass[2];
  104 };
  105 
  106 struct aria_softc {
  107         struct  device sc_dev;          /* base device */
  108         struct  isadev sc_id;           /* ISA device */
  109         void    *sc_ih;                 /* interrupt vectoring */
  110 
  111         u_short sc_iobase;              /* I/O port base address */
  112         u_short sc_irq;                 /* interrupt */
  113         u_short sc_drq;                 /* dma chan */
  114 
  115         u_short sc_open;                /* reference count of open calls */
  116         u_short sc_play;                /* non-paused play chans 2**chan */
  117         u_short sc_record;              /* non-paused record chans 2**chan */
  118         u_short sc_change;              /* to keep track of changes of a type */
  119         u_short gain[2];                /* left/right gain (play) */
  120         u_int   spkr_state;             /* non-null is on */
  121 
  122         u_long  sc_rate;                /* Sample rate for input and output */
  123         u_int   sc_encoding;            /* audio encoding -- ulaw/linear */
  124         int     sc_chans;               /* # of channels */
  125         int     sc_precision;           /* # bits per sample */
  126 
  127         u_long  sc_interrupts;          /* number of interrupts taken */
  128         void    (*sc_rintr)(void *);    /* record transfer completion intr handler */
  129         void    (*sc_pintr)(void *);    /* play transfer completion intr handler */
  130         void    *sc_rarg;               /* arg for sc_rintr() */
  131         void    *sc_parg;               /* arg for sc_pintr() */
  132 
  133         int     sc_blocksize;           /* literal dio block size */
  134         void    *sc_rdiobuffer;         /* record: where the next samples should be */
  135         void    *sc_pdiobuffer;         /* play:   where the next samples are */
  136 
  137         u_short sc_hardware;            /* bit field of hardware present */
  138 #define ARIA_TELEPHONE  0x0001          /* has telephone input */
  139 #define ARIA_MIXER      0x0002          /* has SC18075 digital mixer */
  140 #define ARIA_MODEL      0x0004          /* is SC18025 (=0) or SC18026 (=1) */
  141 
  142         struct aria_mixdev_info aria_mix[6];
  143         struct aria_mixmaster ariamix_master;
  144         u_char  aria_mix_source;
  145 };
  146 
  147 struct {
  148         int sendcmd;
  149         int wmidi;
  150 } ariaerr;
  151 
  152 
  153 
  154 int     ariaprobe();
  155 void    ariaattach(struct device *, struct device *, void *);
  156 void    ariaclose(void *);
  157 int     ariaopen(dev_t, int);
  158 int     aria_getdev(void *, struct audio_device *);
  159 
  160 void    aria_do_kludge(u_short, u_short, u_short, u_short, u_short);
  161 void    aria_prometheus_kludge(struct isa_attach_args *);
  162 
  163 int     aria_set_sr(void *, u_long);
  164 u_long  aria_get_sr(void *);
  165 int     aria_query_encoding(void *, struct audio_encoding *);
  166 int     aria_set_format(void *, u_int, u_int);
  167 int     aria_get_encoding(void *);
  168 int     aria_get_precision(void *);
  169 int     aria_set_channels(void *, int);
  170 int     aria_get_channels(void *);
  171 int     aria_round_blocksize(void *, int);
  172 int     aria_set_out_port(void *, int);
  173 int     aria_get_out_port(void *);
  174 int     aria_set_in_port(void *, int);
  175 int     aria_get_in_port(void *);
  176 int     aria_speaker_ctl(void *, int);
  177 int     aria_commit_settings(void *);
  178 
  179 int     aria_start_output(void *, void *, int, void (*)(), void *);
  180 int     aria_start_input(void *, void *, int, void (*)(), void *);
  181 
  182 int     aria_halt_input(void *);
  183 int     aria_halt_output(void *);
  184 int     aria_cont(void *);
  185 
  186 int     aria_sendcmd(u_short, u_short, int, int, int);
  187 
  188 u_short aria_getdspmem(u_short, u_short);
  189 u_short aria_putdspmem(u_short, u_short, u_short);
  190 
  191 int     aria_intr(void *);
  192 short   ariaversion(struct aria_softc *);
  193 
  194 int     aria_setfd(void *, int);
  195 
  196 void    aria_mix_write(struct aria_softc *, int, int);
  197 int     aria_mix_read(struct aria_softc *, int);
  198 
  199 int     aria_mixer_set_port(void *, mixer_ctrl_t *);
  200 int     aria_mixer_get_port(void *, mixer_ctrl_t *);
  201 int     aria_mixer_query_devinfo(void *, mixer_devinfo_t *);
  202 
  203 /*
  204  * Mixer defines...
  205  */
  206 
  207 struct cfattach aria_ca = {
  208         sizeof(struct aria_softc), ariaprobe, ariaattach
  209 };
  210 
  211 struct cfdriver aria_cd = {
  212         NULL, "aria", DV_DULL
  213 };
  214 
  215 struct audio_device aria_device = {
  216         "Aria 16(se)",
  217         "x",
  218         "aria"
  219 };
  220 
  221 /*
  222  * Define our interface to the higher level audio driver.
  223  */
  224 
  225 struct audio_hw_if aria_hw_if = {
  226         ariaopen,
  227         ariaclose,
  228         NULL,
  229         aria_set_sr,
  230         aria_get_sr,
  231         aria_set_sr,
  232         aria_get_sr,
  233         aria_query_encoding,
  234         aria_set_format,
  235         aria_get_encoding,
  236         aria_get_precision,
  237         aria_set_channels,
  238         aria_get_channels,
  239         aria_round_blocksize,
  240         aria_set_out_port,
  241         aria_get_out_port,
  242         aria_set_in_port,
  243         aria_get_in_port,
  244         aria_commit_settings,
  245         mulaw_expand,
  246         mulaw_compress,
  247         aria_start_output,
  248         aria_start_input,
  249         aria_halt_input,
  250         aria_halt_output,
  251         aria_cont,
  252         aria_cont,
  253         aria_speaker_ctl,
  254         aria_getdev,
  255         aria_setfd,
  256         aria_mixer_set_port,
  257         aria_mixer_get_port,
  258         aria_mixer_query_devinfo,
  259         1,      /* full-duplex */
  260         0,
  261         NULL,
  262         NULL
  263 };
  264 
  265 /*
  266  * Probe / attach routines.
  267  */
  268 
  269 /*
  270  * Probe for the aria hardware.
  271  */
  272 int
  273 ariaprobe(parent, self, aux)
  274         struct device *parent, *self;
  275         void *aux;
  276 {
  277         register struct aria_softc *sc = (void *)self;
  278         register struct isa_attach_args *ia = aux;
  279         struct cfdata *cf = sc->sc_dev.dv_cfdata;
  280         register u_short iobase = ia->ia_iobase;
  281         static u_char irq_conf[11] = {
  282             -1, -1, 0x01, -1, -1, 0x02, -1, 0x04, -1, 0x01, 0x08
  283         };
  284         int i,j;
  285         int flags = cf->cf_flags;
  286 
  287         if (!ARIA_BASE_VALID(ia->ia_iobase)) {
  288                 printf("aria: configured iobase %d invalid\n", ia->ia_iobase);
  289                 return 0;
  290         }
  291         sc->sc_iobase = iobase;
  292                 
  293         if (!ARIA_IRQ_VALID(ia->ia_irq)) {
  294                 printf("aria: configured irq %d invalid\n", ia->ia_irq);
  295                 return 0;
  296         }
  297 
  298         sc->sc_irq = ia->ia_irq;
  299 
  300         if (flags & ARIAR_PROMETHEUS_KLUDGE)
  301                 aria_prometheus_kludge(ia);
  302 
  303         if (aria_reset(sc) != 0) {
  304                 DPRINTF(("aria: aria probe failed\n"));
  305                 return 0;
  306         }
  307 
  308         ia->ia_iosize = ARIADSP_NPORT;
  309         return 1;
  310 }
  311 
  312 
  313 
  314 /*
  315  * I didn't call this a kludge for
  316  * nothing.  This is cribbed from
  317  * ariainit, the author of that
  318  * disassembled some code to discover
  319  * how to set up the initial values of
  320  * the card.  Without this, the card
  321  * is dead. (It will not respond to _any_
  322  * input at all.)
  323  *
  324  * ariainit can be found (ftp) at:
  325  * ftp://ftp.wi.leidenuniv.nl/pub/audio/aria/programming/contrib/ariainit.zip
  326  * currently.
  327  */
  328 
  329 void
  330 aria_prometheus_kludge(ia)
  331         register struct isa_attach_args *ia;
  332 {
  333         int     i, j;
  334         u_short end;
  335         u_short rba = ia->ia_iobase;
  336 
  337         DPRINTF(("aria_prometheus_kludge\n"));
  338 
  339 /* Begin Config Sequence */
  340 
  341         outb(0x204, 0x4c);
  342         outb(0x205, 0x42);
  343         outb(0x206, 0x00);
  344         outw(0x200, 0x0f);
  345         outb(0x201, 0x00);
  346         outw(0x200, 0x02);
  347         outb(0x201, rba>>2);
  348 
  349 /* These next three lines set up the iobase, and the irq; and disable the drq.  */
  350 
  351         aria_do_kludge(0x111, ((ia->ia_iobase-0x280)>>2)+0xA0, 0xbf, 0xa0, rba);
  352         aria_do_kludge(0x011, ia->ia_irq-6, 0xf8, 0x00, rba);
  353         aria_do_kludge(0x011, 0x00, 0xef, 0x00, rba);
  354 
  355 /* The rest of these lines just disable everything else */
  356 
  357         aria_do_kludge(0x113, 0x00, 0x88, 0x00, rba);
  358         aria_do_kludge(0x013, 0x00, 0xf8, 0x00, rba);
  359         aria_do_kludge(0x013, 0x00, 0xef, 0x00, rba);
  360         aria_do_kludge(0x117, 0x00, 0x88, 0x00, rba);
  361         aria_do_kludge(0x017, 0x00, 0xff, 0x00, rba);
  362 
  363 /* End Sequence */
  364 
  365         outb(0x200, 0x0f);
  366         end = inb(rba);
  367         outw(0x200, 0x0f);
  368         outb(0x201, end|0x80);
  369         inb(0x200);
  370 /*
  371  * This delay is necessary for some reason,
  372  * at least it would crash, and sometimes not
  373  * probe properly if it did not exist.
  374  */
  375         delay(1000000);
  376 }
  377 
  378 void
  379 aria_do_kludge(func, bits, and, or, rba)
  380         u_short func;
  381         u_short bits;
  382         u_short and;
  383         u_short or;
  384         u_short rba;
  385 {
  386         u_int i;
  387         if (func & 0x100) {
  388                 func &= ~0x100;
  389                 if (bits) {
  390                         outw(0x200, func-1);
  391                         outb(0x201, bits);
  392                 }
  393         } else
  394                 or |= bits;
  395 
  396         outb(0x200, func);
  397         i = inb(rba);
  398         outw(0x200, func);
  399         outb(0x201, (i&and) | or);
  400 }
  401 
  402 /*
  403  * Attach hardware to driver, attach hardware driver to audio
  404  * pseudo-device driver.
  405  */
  406 void
  407 ariaattach(parent, self, aux)
  408         struct device *parent, *self;
  409         void *aux;
  410 {
  411         register struct aria_softc *sc = (struct aria_softc *)self;
  412         struct isa_attach_args *ia = (struct isa_attach_args *)aux;
  413         register u_short iobase = ia->ia_iobase;
  414         register u_short i;
  415         int err;
  416         
  417         sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
  418             IPL_AUDIO, aria_intr, sc, sc->sc_dev.dv_xname);
  419 
  420         i = aria_getdspmem(iobase, ARIAA_HARDWARE_A);
  421 
  422         sc->sc_hardware  = 0;
  423         sc->sc_hardware |= ((i>>13)&0x01==1)?ARIA_TELEPHONE:0;
  424         sc->sc_hardware |= (((i>>5)&0x07)==0x04)?ARIA_MIXER:0;
  425         sc->sc_hardware |= (aria_getdspmem(iobase, ARIAA_MODEL_A)==1)?ARIA_MODEL:0;
  426 
  427         sc->sc_open       = 0;
  428         sc->sc_play       = 0;
  429         sc->sc_record     = 0;
  430         sc->sc_rate       = 7875;
  431         sc->sc_chans      = 1;
  432         sc->sc_change     = 1;
  433         sc->sc_blocksize  = 1024;
  434         sc->sc_precision  = 8;
  435         sc->sc_rintr      = 0;
  436         sc->sc_rarg       = 0;
  437         sc->sc_pintr      = 0;
  438         sc->sc_parg       = 0;
  439         sc->gain[0]       = 127;
  440         sc->gain[1]       = 127;
  441 
  442         for (i=0; i<6; i++) {
  443                 if (i == ARIAMIX_TEL_LVL)
  444                         sc->aria_mix[i].num_channels = 1;
  445                 else
  446                         sc->aria_mix[i].num_channels = 2;
  447                 sc->aria_mix[i].level[0] = 127;
  448                 sc->aria_mix[i].level[1] = 127;
  449         }
  450 
  451         sc->ariamix_master.num_channels = 2;
  452         sc->ariamix_master.level[0] = 222;
  453         sc->ariamix_master.level[1] = 222;
  454         sc->ariamix_master.bass[0] = 127;
  455         sc->ariamix_master.bass[1] = 127;
  456         sc->ariamix_master.treble[0] = 127;
  457         sc->ariamix_master.treble[1] = 127;
  458         sc->aria_mix_source = 0;
  459 
  460         sc->sc_change = 1;
  461         aria_commit_settings(sc); /* so that my cdplayer is at the 'right' vol */
  462 
  463         printf(": dsp %s", (ARIA_MODEL&sc->sc_hardware)?"SC18026":"SC18025");
  464         if (ARIA_TELEPHONE&sc->sc_hardware)
  465                 printf(", tel");
  466         if (ARIA_MIXER&sc->sc_hardware)
  467                 printf(", SC18075 mixer");
  468         printf("\n");
  469 
  470         snprintf(aria_device.version, sizeof aria_device.version, "%s",
  471             (ARIA_MODEL&sc->sc_hardware?"SC18026":"SC18025"));
  472 
  473         if ((err = audio_hardware_attach(&aria_hw_if, sc)) != 0)
  474                 printf("aria: could not attach to audio pseudo-device driver (%d)\n", err);
  475 }
  476 
  477 /*
  478  * Various routines to interface to higher level audio driver
  479  */
  480 
  481 int
  482 ariaopen(dev, flags)
  483         dev_t dev;
  484         int flags;
  485 {
  486         struct aria_softc *sc;
  487         register u_short iobase = sc->sc_iobase;
  488         int unit = AUDIOUNIT(dev);
  489         short err;
  490 
  491         DPRINTF(("ariaopen() called\n"));
  492     
  493         if (unit >= aria_cd.cd_ndevs)
  494                 return ENXIO;
  495     
  496         sc = aria_cd.cd_devs[unit];
  497 
  498         if (!sc || sc->sc_open != 0)
  499                 return ENXIO;
  500     
  501         sc->sc_open  = 0;
  502         if (flags&FREAD)
  503                 sc->sc_open |= ARIAR_OPEN_RECORD;
  504         if (flags&FWRITE)
  505                 sc->sc_open |= ARIAR_OPEN_PLAY;
  506         sc->sc_play  = 0;
  507         sc->sc_record= 0;
  508         sc->sc_rintr = 0;
  509         sc->sc_rarg  = 0;
  510         sc->sc_pintr = 0;
  511         sc->sc_parg  = 0;
  512         sc->sc_change= 1;
  513 
  514         return 0;
  515 }
  516 
  517 int
  518 aria_getdev(addr, retp)
  519         void *addr;
  520         struct audio_device *retp;
  521 {
  522         *retp = aria_device;
  523         return 0;
  524 }
  525 
  526 #ifdef AUDIO_DEBUG
  527 void
  528 aria_printsc(struct aria_softc *sc)
  529 {
  530         printf("open %x dmachan %d irq %d iobase %x nintr %d\n", sc->sc_open, sc->sc_drq,
  531                 sc->sc_irq, sc->sc_iobase, sc->sc_interrupts);
  532         printf("irate %d encoding %x chans %d\n", sc->sc_rate, sc->encoding,
  533                 sc->sc_chans);
  534         printf("\n");
  535 }
  536 #endif
  537 
  538 
  539 /*
  540  * Various routines to interface to higher level audio driver
  541  */
  542 
  543 int
  544 aria_set_sr(addr, sr)
  545         void *addr;
  546         u_long sr;
  547 {
  548         struct aria_softc *sc = addr;
  549 
  550         if (sr<=9000)
  551                 sr = 7875;
  552         else if (sr<=15000)
  553                 sr = 11025;
  554         else if (sr<=20000)
  555                 sr = 15750;
  556         else if (sr<=25000)
  557                 sr = 22050;
  558         else if (sr<=40000)
  559                 sr = 31500;
  560         else
  561                 sr = 44100;
  562 
  563         sc->sc_rate = sr;
  564         return 0;
  565 }
  566 
  567 u_long
  568 aria_get_sr(addr)
  569         void *addr;
  570 {
  571         struct aria_softc *sc = addr;
  572         return sc->sc_rate;
  573 }
  574 
  575 int
  576 aria_query_encoding(addr, fp)
  577     void *addr;
  578     struct audio_encoding *fp;
  579 {
  580         register struct aria_softc *sc = addr;
  581 
  582         switch (fp->index) {
  583                 case 0:
  584                         strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
  585                         fp->format_id = AUDIO_ENCODING_ULAW;
  586                         break;
  587                 case 1:
  588                         strlcpy(fp->name, AudioEpcm16, sizeof fp->name);
  589                         fp->format_id = AUDIO_ENCODING_PCM16;
  590                         break;
  591                 default:
  592                         return(EINVAL);
  593                 /*NOTREACHED*/
  594         }
  595 
  596         return (0);
  597 }
  598 
  599 int
  600 aria_set_format(addr, enc, precision)
  601         void *addr;
  602         u_int enc, prec;
  603 {
  604         register struct aria_softc *sc = addr;
  605 
  606         DPRINTF(("aria_set_format\n"));
  607 
  608         switch(enc){
  609         case AUDIO_ENCODING_ULAW:
  610         case AUDIO_ENCODING_PCM16:
  611         case AUDIO_ENCODING_PCM8:
  612                 break;
  613         default:
  614                 return (EINVAL);
  615         }
  616 
  617         if (prec!=8 && prec!=16)
  618                 return (EINVAL);
  619 
  620         if (sc->encoding!=AUDIO_ENCODING_PCM16 && prec==16)
  621                 return (EINVAL);
  622 
  623         sc->sc_encoding = enc;
  624         sc->sc_precision = prec;
  625         return (0);
  626 }
  627 
  628 int
  629 aria_get_encoding(addr)
  630         void *addr;
  631 {
  632         register struct aria_softc *sc = addr;
  633 
  634         DPRINTF(("aria_get_encoding\n"));
  635 
  636         return(sc->encoding);
  637 }
  638 
  639 int
  640 aria_get_precision(addr)
  641         void *addr;
  642 {
  643         struct aria_softc *sc = addr;
  644 
  645         DPRINTF(("aria_get_precision\n"));
  646 
  647         return sc->sc_precision;
  648 }
  649 
  650 int
  651 aria_set_channels(addr, chans)
  652         void *addr;
  653         int chans;
  654 {
  655         struct aria_softc *sc = addr;
  656 
  657         DPRINTF(("aria_set_channels\n"));
  658 
  659         if (chans != 1 && chans != 2)
  660                 return EINVAL;
  661 
  662         sc->sc_chans = chans;
  663 
  664         return(0);
  665 }
  666 
  667 int
  668 aria_get_channels(addr)
  669         void *addr;
  670 {
  671         struct aria_softc *sc = addr;
  672 
  673         DPRINTF(("aria_get_channels\n"));
  674 
  675         return sc->sc_chans;
  676 }
  677 
  678 /*
  679  * There is only one way to output on
  680  * this card.
  681  */
  682 int
  683 aria_set_out_port(addr, port)
  684         void *addr;
  685         int port;
  686 {
  687         DPRINTF(("aria_set_out_port\n"));
  688         return(0);
  689 }
  690 
  691 int
  692 aria_get_out_port(addr)
  693         void *addr;
  694 {
  695         DPRINTF(("aria_get_out_port\n"));
  696         return(ARIAMIX_OUT_LVL);
  697 }
  698 
  699 
  700 int
  701 aria_set_in_port(addr, port)
  702         void *addr;
  703         int port;
  704 {
  705         register struct aria_softc *sc = addr;
  706 
  707         DPRINTF(("aria_set_in_port\n"));
  708 
  709         if (port<0 || port>6)
  710                 return ENXIO;
  711 
  712         sc->aria_mix_source = port;
  713         return(0);
  714 }
  715 
  716 int
  717 aria_get_in_port(addr)
  718         void *addr;
  719 {
  720         register struct aria_softc *sc = addr;
  721 
  722         DPRINTF(("aria_get_in_port\n"));
  723 
  724         return(sc->aria_mix_source);
  725 }
  726 
  727 /*
  728  * XXX -- to be done
  729  *  I should probably just add a mixer thing, and
  730  *  access it through here.
  731  */
  732 int
  733 aria_speaker_ctl(addr, newstate)
  734         void *addr;
  735         int newstate;
  736 {
  737         return(0);
  738 }
  739 
  740 /*
  741  * Store blocksize in words (what the chipset
  742  * understands), but report and take values
  743  * in bytes.
  744  */
  745 
  746 int
  747 aria_round_blocksize(addr, blk)
  748         void *addr;
  749         int blk;
  750 {
  751         int i;
  752         struct aria_softc *sc = addr;
  753         for (i=64; i<1024; i*=2)
  754                 if (blk <= i)
  755                         break;
  756         sc->sc_blocksize = i;
  757         sc->sc_change = 1;
  758         return(i);
  759 }
  760 
  761 /*
  762  * This is where all of the twiddling goes on.
  763  */
  764 
  765 int
  766 aria_commit_settings(addr)
  767         void *addr;
  768 {
  769         struct aria_softc *sc = addr;
  770         register u_short iobase = sc->sc_iobase;
  771         u_char tones[16] = { 7, 6, 5, 4, 3, 2, 1, 0, 8, 9, 10, 11, 12, 13, 14, 15 };
  772         u_short format;
  773         u_short left, right;
  774         u_short samp;
  775         u_char i;
  776 
  777         DPRINTF(("aria_commit_settings\n"));
  778 
  779         switch (sc->sc_rate) {
  780                 case  7875: format = 0x00; samp = 0x60; break;
  781                 case 11025: format = 0x00; samp = 0x40; break;
  782                 case 15750: format = 0x10; samp = 0x60; break;
  783                 case 22050: format = 0x10; samp = 0x40; break;
  784                 case 31500: format = 0x10; samp = 0x20; break;
  785                 case 44100: format = 0x20; samp = 0x00; break;
  786                 default:    format = 0x00; samp = 0x40; break;
  787         }
  788 
  789         format |= (sc->sc_chans==2)?1:0;
  790         format |= (sc->sc_precision==16)?2:0;
  791 
  792         aria_sendcmd(iobase, ARIADSPC_FORMAT, format, -1, -1);
  793         outw(iobase+ARIADSP_CONTROL, (inw(iobase+ARIADSP_STATUS)&~0x60)|samp); /* Addition parm for sample rate */
  794 
  795         if (sc->sc_hardware&ARIA_MIXER) {
  796                 for (i=0; i<6; i++) {
  797                         u_char source;
  798                         switch(i) {
  799                         case ARIAMIX_MIC_LVL:     source = 0x0001; break;
  800                         case ARIAMIX_CD_LVL:      source = 0x0002; break;
  801                         case ARIAMIX_LINE_IN_LVL: source = 0x0008; break;
  802                         case ARIAMIX_TEL_LVL:     source = 0x0020; break;
  803                         case ARIAMIX_AUX_LVL:     source = 0x0010; break;
  804                         case ARIAMIX_DAC_LVL:     source = 0x0004; break;
  805                         default:               source = 0x0000; break;
  806                         }
  807                                 
  808                         if (source != 0x0000 && source != 0x0004) {
  809                                 if (sc->aria_mix[i].mute == 1)
  810                                         aria_sendcmd(iobase, ARIADSPC_INPMONMODE, source, 3, -1);
  811                                 else
  812                                         aria_sendcmd(iobase, ARIADSPC_INPMONMODE, source, (sc->aria_mix[i].num_channels==2)?0:1, -1); 
  813 
  814                                 aria_sendcmd(iobase, ARIADSPC_INPMONMODE, 0x8000|source, (sc->aria_mix[i].num_channels==2)?0:1, -1);
  815                                 aria_sendcmd(iobase, ARIADSPC_MIXERVOL, source, sc->aria_mix[i].level[0] << 7, sc->aria_mix[i].level[1] << 7);
  816                         }
  817 
  818                         if (sc->aria_mix_source == i) {
  819                                 aria_sendcmd(iobase, ARIADSPC_ADCSOURCE, source, -1, -1);
  820 
  821                                 if (sc->sc_open & ARIAR_OPEN_RECORD)
  822                                         aria_sendcmd(iobase, ARIADSPC_ADCCONTROL, 1, -1, -1);
  823                                 else 
  824                                         aria_sendcmd(iobase, ARIADSPC_ADCCONTROL, 0, -1, -1);
  825                         }
  826                 }
  827 
  828                 if (sc->sc_chans==2) {
  829                         aria_sendcmd(iobase, ARIADSPC_CHAN_VOL, (sc->gain[0]+sc->gain[1])/2, -1, -1);
  830                         aria_sendcmd(iobase, ARIADSPC_CHAN_PAN, (sc->gain[0]-sc->gain[1])/4+0x40, -1, -1);
  831                 } else {
  832                         aria_sendcmd(iobase, ARIADSPC_CHAN_VOL, sc->gain[0], -1, -1);
  833                         aria_sendcmd(iobase, ARIADSPC_CHAN_PAN, 0x40, -1, -1);
  834                 }
  835 
  836                 /* aria_sendcmd(iobase, ARIADSPC_MASMONMODE, (sc->ariamix_master.num_channels==2)?0:1 | (1<<8), -1, -1); */
  837                 aria_sendcmd(iobase, ARIADSPC_MASMONMODE, (sc->ariamix_master.num_channels==2)?0:1, -1, -1);
  838 
  839                 aria_sendcmd(iobase, ARIADSPC_MIXERVOL, 0x0004, sc->ariamix_master.level[0] << 7, sc->ariamix_master.level[1] << 7);
  840 
  841                 /* Convert treb/bass from byte to soundcard style */
  842 
  843                 left  = tones[(sc->ariamix_master.bass[0]>>4)&0x0f]<<8 | tones[(sc->ariamix_master.treble[0]>>4)&0x0f];
  844                 right = tones[(sc->ariamix_master.bass[1]>>4)&0x0f]<<8 | tones[(sc->ariamix_master.treble[1]>>4)&0x0f];
  845 
  846                 aria_sendcmd(iobase, ARIADSPC_TONE, left, right, -1);
  847         }
  848 
  849         if (sc->sc_change != 0)
  850                 aria_sendcmd(iobase, ARIADSPC_BLOCKSIZE, sc->sc_blocksize/2, -1, -1);
  851 
  852 /*
  853  * If we think that the card is recording or playing, start it up again here.
  854  * Some of the previous commands turn the channels off.
  855  */
  856 
  857         if (sc->sc_record&(1<<ARIAR_RECORD_CHAN)) {
  858                 aria_sendcmd(iobase, ARIADSPC_START_REC, ARIAR_PLAY_CHAN, -1, -1);
  859                 sc->sc_play |= (1<<ARIAR_RECORD_CHAN);
  860         }
  861 
  862         if (sc->sc_play&(1<<ARIAR_PLAY_CHAN)) {
  863                 aria_sendcmd(iobase, ARIADSPC_START_PLAY, ARIAR_PLAY_CHAN, -1, -1);
  864                 sc->sc_play |= (1<<ARIAR_PLAY_CHAN);
  865         }
  866 
  867         sc->sc_change = 0;
  868 
  869         return(0);
  870 }
  871 
  872 void
  873 ariaclose(addr)
  874         void *addr;
  875 {
  876         struct aria_softc *sc = addr;
  877         register u_int iobase = sc->sc_iobase;
  878 
  879         DPRINTF(("aria_close sc=0x%x\n", sc));
  880 
  881         sc->spkr_state = SPKR_OFF;
  882         sc->sc_rintr = 0;
  883         sc->sc_pintr = 0;
  884         sc->sc_rdiobuffer = 0;
  885         sc->sc_pdiobuffer = 0;
  886 
  887         if (sc->sc_play&(1<<ARIAR_PLAY_CHAN) && sc->sc_open & ARIAR_OPEN_PLAY) {
  888                 aria_sendcmd(iobase, ARIADSPC_STOP_PLAY, ARIAR_PLAY_CHAN, -1, -1);
  889                 sc->sc_play &= ~(1<<ARIAR_PLAY_CHAN);
  890         }
  891 
  892         if (sc->sc_record&(1<<ARIAR_RECORD_CHAN) && sc->sc_open & ARIAR_OPEN_RECORD) {
  893                 aria_sendcmd(iobase, ARIADSPC_STOP_REC, ARIAR_RECORD_CHAN, -1, -1);
  894                 sc->sc_record &= ~(1<<ARIAR_RECORD_CHAN);
  895         }
  896 
  897         sc->sc_open = 0;
  898 
  899         if (aria_reset(sc) != 0) {
  900                 delay(500);
  901                 aria_reset(sc);
  902         }
  903 }
  904 
  905 /*
  906  * Reset the hardware.
  907  */
  908 
  909 int
  910 aria_reset(sc)
  911         register struct aria_softc *sc;
  912 {
  913         register u_short iobase = sc->sc_iobase;
  914         int fail=0;
  915 
  916         outw(iobase + ARIADSP_CONTROL, ARIAR_ARIA_SYNTH|ARIAR_SR22K|ARIAR_DSPINTWR);
  917         aria_putdspmem(iobase, 0x6102, 0);
  918 
  919         fail |= aria_sendcmd(iobase, ARIADSPC_SYSINIT, 0x0000, 0x0000, 0x0000);
  920 
  921         while (aria_getdspmem(iobase, ARIAA_TASK_A) != 1)
  922                 ;
  923 
  924         outw(iobase+ARIADSP_CONTROL, ARIAR_ARIA_SYNTH|ARIAR_SR22K|ARIAR_DSPINTWR|ARIAR_PCINTWR);
  925         fail |= aria_sendcmd(iobase, ARIADSPC_MODE, ARIAV_MODE_NO_SYNTH,-1,-1);
  926 
  927         return (fail);
  928 }
  929 
  930 /*
  931  * Lower-level routines
  932  */
  933 
  934 u_short
  935 aria_putdspmem(iobase, loc, val)
  936         register u_short iobase;
  937         register u_short loc;
  938         register u_short val;
  939 {
  940         outw(iobase + ARIADSP_DMAADDRESS, loc);
  941         outw(iobase + ARIADSP_DMADATA, val);
  942 }
  943 
  944 u_short
  945 aria_getdspmem(iobase, loc)
  946         register u_short iobase;
  947         register u_short loc;
  948 {
  949         outw(iobase+ARIADSP_DMAADDRESS, loc);
  950         return inw(iobase+ARIADSP_DMADATA);
  951 }
  952 
  953 /*
  954  * aria_sendcmd()
  955  *  each full DSP command is unified into this
  956  *  function.
  957  */
  958 
  959 int
  960 aria_sendcmd(iobase, command, arg1, arg2, arg3)
  961         u_short iobase;
  962         u_short command;
  963         int arg1;
  964         int arg2;
  965         int arg3;
  966 {
  967         int i, fail = 0;
  968 
  969         for (i = ARIAR_NPOLL; (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY) != 0 && i>0; i-- )
  970                 ;
  971 
  972         fail |= (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY)==0?0:1;
  973         outw(iobase + ARIADSP_WRITE, (u_short) command); 
  974 
  975         if (arg1 != -1) {
  976                 for (i = ARIAR_NPOLL; (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY) != 0 && i>0; i-- )
  977                         ;
  978 
  979                 fail |= (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY)==0?0:2;
  980                 outw(iobase + ARIADSP_WRITE, (u_short) arg1); 
  981         }
  982 
  983         if (arg2 != -1) {
  984                 for (i = ARIAR_NPOLL; (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY) != 0 && i>0; i-- )
  985                         ;
  986 
  987                 fail |= (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY)==0?0:4;
  988                 outw(iobase + ARIADSP_WRITE, (u_short) arg2); 
  989         }
  990 
  991         if (arg3 != -1) {
  992                 for (i = ARIAR_NPOLL; (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY) != 0 && i>0; i-- )
  993                         ;
  994 
  995                 fail |= (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY)==0?0:8;
  996                 outw(iobase + ARIADSP_WRITE, (u_short) arg3); 
  997         }
  998 
  999         for (i = ARIAR_NPOLL; (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY) != 0 && i>0; i-- )
 1000                 ;
 1001 
 1002         fail |= (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY)==0?0:16;
 1003         outw(iobase + ARIADSP_WRITE, (u_short) ARIADSPC_TERM); 
 1004         
 1005 #ifdef AUDIO_DEBUG
 1006         if (fail) {
 1007                 ++ariaerr.sendcmd;
 1008                 DPRINTF(("aria_sendcmd: failure=(%d) cmd=(0x%x) fail=(0x%x)\n", ariaerr.sendcmd, command, fail));
 1009                 return -1;
 1010         }
 1011 #else
 1012         if (fail != 0) {
 1013                 ++ariaerr.sendcmd;
 1014                 return -1;
 1015         }
 1016 #endif
 1017 
 1018         return 0;
 1019 }
 1020 
 1021 int
 1022 aria_halt_input(addr)
 1023         void *addr;
 1024 {
 1025         register struct aria_softc *sc = addr;
 1026 
 1027         DPRINTF(("aria_halt_input\n"));
 1028 
 1029         if (sc->sc_record&(1<<0)) {
 1030                 aria_sendcmd(sc->sc_iobase, ARIADSPC_STOP_REC, 0, -1, -1);
 1031                 sc->sc_record &= ~(1<<0);
 1032         }
 1033 
 1034         return(0);
 1035 }
 1036 
 1037 int
 1038 aria_halt_output(addr)
 1039         void *addr;
 1040 {
 1041         register struct aria_softc *sc = addr;
 1042 
 1043         DPRINTF(("aria_halt_output\n"));
 1044 
 1045         if (sc->sc_play & (1<<1)) {
 1046                 aria_sendcmd(sc->sc_iobase, ARIADSPC_STOP_PLAY, 1, -1, -1);
 1047                 sc->sc_play &= ~(1<<1);
 1048         }
 1049 
 1050         return(0);
 1051 }
 1052 
 1053 /*
 1054  * This is not called in dev/audio.c?
 1055  */
 1056 int
 1057 aria_cont(addr)
 1058         void *addr;
 1059 {
 1060         register struct aria_softc *sc = addr;
 1061 
 1062         DPRINTF(("aria_cont\n"));
 1063 
 1064         if (!(sc->sc_record&(1<<0)) && (sc->sc_open&ARIAR_OPEN_RECORD)) {
 1065                 aria_sendcmd(sc->sc_iobase, ARIADSPC_START_REC,  ARIAR_RECORD_CHAN, -1, -1);
 1066                 sc->sc_record |= ~(1<<ARIAR_RECORD_CHAN);
 1067         }
 1068 
 1069         if (!(sc->sc_play&(1<<ARIAR_PLAY_CHAN)) && (sc->sc_open&ARIAR_OPEN_PLAY)) {
 1070                 aria_sendcmd(sc->sc_iobase, ARIADSPC_START_PLAY, 1, -1, -1);
 1071                 sc->sc_play |= ~(1<<ARIAR_PLAY_CHAN);
 1072         }
 1073 
 1074         return(0);
 1075 }
 1076 
 1077 /*
 1078  * Here we just set up the buffers.  If we receive
 1079  * an interrupt without these set, it is ignored.
 1080  */
 1081 
 1082 int
 1083 aria_start_input(addr, p, cc, intr, arg)
 1084         void *addr;
 1085         void *p;
 1086         int cc;
 1087         void (*intr)();
 1088         void *arg;
 1089 {
 1090         register struct aria_softc *sc = addr;
 1091         register int i;
 1092 
 1093         DPRINTF(("aria_start_input %d @ %x\n", cc, p));
 1094 
 1095         if (cc != sc->sc_blocksize) {
 1096                 DPRINTF(("aria_start_input reqsize %d not sc_blocksize %d\n",
 1097                         cc, sc->sc_blocksize));
 1098                 return EINVAL;
 1099         }
 1100 
 1101         sc->sc_rarg = arg;
 1102         sc->sc_rintr = intr;
 1103         sc->sc_rdiobuffer = p;
 1104 
 1105         if (!(sc->sc_record&(1<<0))) {
 1106                 aria_sendcmd(sc->sc_iobase, ARIADSPC_START_REC,  0, -1, -1);
 1107                 sc->sc_record |= (1<<0);
 1108         }
 1109 
 1110         return 0;
 1111 }
 1112 
 1113 int
 1114 aria_start_output(addr, p, cc, intr, arg)
 1115         void *addr;
 1116         void *p;
 1117         int cc;
 1118         void (*intr)();
 1119         void *arg;
 1120 {
 1121         register struct aria_softc *sc = addr;
 1122         register int i;
 1123 
 1124         DPRINTF(("aria_start_output %d @ %x\n", cc, p));
 1125 
 1126         if (cc != sc->sc_blocksize) {
 1127                 DPRINTF(("aria_start_output reqsize %d not sc_blocksize %d\n",
 1128                         cc, sc->sc_blocksize));
 1129                 return EINVAL;
 1130         }
 1131 
 1132         sc->sc_parg = arg;
 1133         sc->sc_pintr = intr;
 1134         sc->sc_pdiobuffer = p;
 1135 
 1136         if (!(sc->sc_play&(1<<1))) {
 1137                 aria_sendcmd(sc->sc_iobase, ARIADSPC_START_PLAY,  1, -1, -1);
 1138                 sc->sc_play |= (1<<1);
 1139         }
 1140 
 1141         return 0;
 1142 }
 1143 
 1144 /*
 1145  * Process an interrupt.  This should be a
 1146  * request (from the card) to write or read
 1147  * samples.
 1148  */
 1149 int
 1150 aria_intr(arg)
 1151         void *arg;
 1152 {
 1153         register struct  aria_softc *sc = arg;
 1154         register u_short iobase = sc->sc_iobase;
 1155         register u_short *pdata = sc->sc_pdiobuffer;
 1156         register u_short *rdata = sc->sc_rdiobuffer;
 1157         u_short address;
 1158         int i;
 1159 
 1160         if (inw(iobase) & 1 != 0x1) 
 1161                 return 0;  /* not for us */
 1162 
 1163         sc->sc_interrupts++;
 1164 
 1165         DPRINTF(("aria_intr\n"));
 1166 
 1167         if ((sc->sc_open & ARIAR_OPEN_PLAY) && (pdata!=NULL)) {
 1168                 DPRINTF(("aria_intr play=(%x)\n", pdata));
 1169                 address = 0x8000 - 2*(sc->sc_blocksize);
 1170                 address+= aria_getdspmem(iobase, ARIAA_PLAY_FIFO_A);
 1171                 outw(iobase+ARIADSP_DMAADDRESS, address);
 1172                 outsw(iobase + ARIADSP_DMADATA, pdata, sc->sc_blocksize/2);
 1173                 if (sc->sc_pintr != NULL)
 1174                         (*sc->sc_pintr)(sc->sc_parg);
 1175         }
 1176 
 1177         if ((sc->sc_open & ARIAR_OPEN_RECORD) && (rdata!=NULL)) {
 1178                 DPRINTF(("aria_intr record=(%x)\n", rdata));
 1179                 address = 0x8000 - (sc->sc_blocksize);
 1180                 address+= aria_getdspmem(iobase, ARIAA_REC_FIFO_A);
 1181                 outw(iobase+ARIADSP_DMAADDRESS, address);
 1182                 insw(iobase + ARIADSP_DMADATA, rdata, sc->sc_blocksize/2);
 1183                 if (sc->sc_rintr != NULL)
 1184                         (*sc->sc_rintr)(sc->sc_rarg);
 1185         }
 1186 
 1187         aria_sendcmd(iobase, ARIADSPC_TRANSCOMPLETE, -1, -1, -1);
 1188 
 1189         return 1;
 1190 }
 1191 
 1192 int
 1193 aria_setfd(addr, flag)
 1194         void *addr;
 1195         int flag;
 1196 {
 1197 /*
 1198  * okay return yes.  I'll assume that it will only
 1199  * ask when the file open read/write...  Or before...
 1200  */
 1201         return(0);
 1202 }
 1203 
 1204 int
 1205 aria_mixer_set_port(addr, cp)
 1206     void *addr;
 1207     mixer_ctrl_t *cp;
 1208 {
 1209         register struct aria_softc *sc = addr;
 1210         int error = EINVAL;
 1211 
 1212         DPRINTF(("aria_mixer_set_port\n"));
 1213 
 1214         if (!(ARIA_MIXER&sc->sc_hardware))  /* This could be done better, no mixer still has some controls. */
 1215                 return ENXIO;
 1216 
 1217         if (cp->type == AUDIO_MIXER_VALUE) {
 1218                 register mixer_level_t *mv = &cp->un.value;
 1219                 switch (cp->dev) {
 1220                 case ARIAMIX_MIC_LVL:
 1221                         if (mv->num_channels == 1 || mv->num_channels == 2) {
 1222                                 sc->aria_mix[ARIAMIX_MIC_LVL].num_channels = mv->num_channels;
 1223                                 sc->aria_mix[ARIAMIX_MIC_LVL].level[0] = mv->level[0];
 1224                                 sc->aria_mix[ARIAMIX_MIC_LVL].level[1] = mv->level[1];
 1225                                 error = 0;
 1226                         }
 1227                         break;
 1228         
 1229                 case ARIAMIX_LINE_IN_LVL:
 1230                         if (mv->num_channels == 1 || mv->num_channels == 2) {
 1231                                 sc->aria_mix[ARIAMIX_LINE_IN_LVL].num_channels = mv->num_channels;
 1232                                 sc->aria_mix[ARIAMIX_LINE_IN_LVL].level[0] = mv->level[0];
 1233                                 sc->aria_mix[ARIAMIX_LINE_IN_LVL].level[1] = mv->level[1];
 1234                                 error = 0;
 1235                         }
 1236                         break;
 1237         
 1238                 case ARIAMIX_CD_LVL:
 1239                         if (mv->num_channels == 1 || mv->num_channels == 2) {
 1240                                 sc->aria_mix[ARIAMIX_CD_LVL].num_channels = mv->num_channels;
 1241                                 sc->aria_mix[ARIAMIX_CD_LVL].level[0] = mv->level[0];
 1242                                 sc->aria_mix[ARIAMIX_CD_LVL].level[1] = mv->level[1];
 1243                                 error = 0;
 1244                         }
 1245                         break;
 1246         
 1247                 case ARIAMIX_TEL_LVL:
 1248                         if (mv->num_channels == 1) {
 1249                                 sc->aria_mix[ARIAMIX_TEL_LVL].num_channels = mv->num_channels;
 1250                                 sc->aria_mix[ARIAMIX_TEL_LVL].level[0] = mv->level[0];
 1251                                 error = 0;
 1252                         }
 1253                         break;
 1254         
 1255                 case ARIAMIX_DAC_LVL:
 1256                         if (mv->num_channels == 1 || mv->num_channels == 2) {
 1257                                 sc->aria_mix[ARIAMIX_DAC_LVL].num_channels = mv->num_channels;
 1258                                 sc->aria_mix[ARIAMIX_DAC_LVL].level[0] = mv->level[0];
 1259                                 sc->aria_mix[ARIAMIX_DAC_LVL].level[1] = mv->level[1];
 1260                                 error = 0;
 1261                         }
 1262                         break;
 1263 
 1264                 case ARIAMIX_AUX_LVL:
 1265                         if (mv->num_channels == 1 || mv->num_channels == 2) {
 1266                                 sc->aria_mix[ARIAMIX_AUX_LVL].num_channels = mv->num_channels;
 1267                                 sc->aria_mix[ARIAMIX_AUX_LVL].level[0] = mv->level[0];
 1268                                 sc->aria_mix[ARIAMIX_AUX_LVL].level[1] = mv->level[1];
 1269                                 error = 0;
 1270                         }
 1271                         break;
 1272         
 1273                 case ARIAMIX_MASTER_LVL:
 1274                         if (mv->num_channels == 1 || mv->num_channels == 2) {
 1275                                 sc->ariamix_master.num_channels = mv->num_channels;
 1276                                 sc->ariamix_master.level[0] = mv->level[0];
 1277                                 sc->ariamix_master.level[1] = mv->level[1];
 1278                                 error = 0;
 1279                         }
 1280                         break;
 1281         
 1282                 case ARIAMIX_MASTER_TREBLE:
 1283                         if (mv->num_channels == 2) {
 1284                                 sc->ariamix_master.treble[0] = (mv->level[0]==0)?1:mv->level[0];
 1285                                 sc->ariamix_master.treble[1] = (mv->level[1]==0)?1:mv->level[1];
 1286                                 error = 0;
 1287                         }
 1288                         break;
 1289                 case ARIAMIX_MASTER_BASS:
 1290                         if (mv->num_channels == 2) {
 1291                                 sc->ariamix_master.bass[0] = (mv->level[0]==0)?1:mv->level[0];
 1292                                 sc->ariamix_master.bass[1] = (mv->level[1]==0)?1:mv->level[1];
 1293                                 error = 0;
 1294                         }
 1295                         break;
 1296                 case ARIAMIX_OUT_LVL:
 1297                         if (mv->num_channels == 1 || mv->num_channels == 2) {
 1298                                 sc->gain[0] = mv->level[0];
 1299                                 sc->gain[1] = mv->level[1];
 1300                                 error = 0;
 1301                         }
 1302                         break;
 1303                 default:
 1304                 }
 1305         }
 1306 
 1307         if (cp->type == AUDIO_MIXER_ENUM)
 1308                 switch(cp->dev) {
 1309                 case ARIAMIX_RECORD_SOURCE:
 1310                         if (cp->un.ord>=0 && cp->un.ord<=6) {
 1311                                 sc->aria_mix_source = cp->un.ord;
 1312                                 error = 0;
 1313                         }
 1314                         break;
 1315 
 1316                 case ARIAMIX_MIC_MUTE:
 1317                         if (cp->un.ord == 0 || cp->un.ord == 1) {
 1318                                 sc->aria_mix[ARIAMIX_MIC_LVL].mute = cp->un.ord;
 1319                                 error = 0;
 1320                         }
 1321                         break;
 1322 
 1323                 case ARIAMIX_LINE_IN_MUTE:
 1324                         if (cp->un.ord == 0 || cp->un.ord == 1) {
 1325                                 sc->aria_mix[ARIAMIX_LINE_IN_LVL].mute = cp->un.ord;
 1326                                 error = 0;
 1327                         }
 1328                         break;
 1329 
 1330                 case ARIAMIX_CD_MUTE:
 1331                         if (cp->un.ord == 0 || cp->un.ord == 1) {
 1332                                 sc->aria_mix[ARIAMIX_CD_LVL].mute = cp->un.ord;
 1333                                 error = 0;
 1334                         }
 1335                         break;
 1336 
 1337                 case ARIAMIX_DAC_MUTE:
 1338                         if (cp->un.ord == 0 || cp->un.ord == 1) {
 1339                                 sc->aria_mix[ARIAMIX_DAC_LVL].mute = cp->un.ord;
 1340                                 error = 0;
 1341                         }
 1342                         break;
 1343 
 1344                 case ARIAMIX_AUX_MUTE:
 1345                         if (cp->un.ord == 0 || cp->un.ord == 1) {
 1346                                 sc->aria_mix[ARIAMIX_AUX_LVL].mute = cp->un.ord;
 1347                                 error = 0;
 1348                         }
 1349                         break;
 1350 
 1351                 case ARIAMIX_TEL_MUTE:
 1352                         if (cp->un.ord == 0 || cp->un.ord == 1) {
 1353                                 sc->aria_mix[ARIAMIX_TEL_LVL].mute = cp->un.ord;
 1354                                 error = 0;
 1355                         }
 1356                         break;
 1357 
 1358                 default:
 1359                         return ENXIO;
 1360                         /* NOTREACHED */
 1361                 }
 1362 
 1363         return(error);
 1364 }
 1365 
 1366 int
 1367 aria_mixer_get_port(addr, cp)
 1368     void *addr;
 1369     mixer_ctrl_t *cp;
 1370 {
 1371         register struct aria_softc *sc = addr;
 1372         int error = EINVAL;
 1373 
 1374         DPRINTF(("aria_mixer_get_port\n"));
 1375 
 1376         if (!(ARIA_MIXER&sc->sc_hardware))  /* This could be done better, no mixer still has some controls. */
 1377                 return ENXIO;
 1378 
 1379         switch (cp->dev) {
 1380         case ARIAMIX_MIC_LVL:
 1381                 if (cp->type == AUDIO_MIXER_VALUE) {
 1382                         cp->un.value.num_channels = sc->aria_mix[ARIAMIX_MIC_LVL].num_channels;
 1383                         cp->un.value.level[0] = sc->aria_mix[ARIAMIX_MIC_LVL].level[0];
 1384                         cp->un.value.level[1] = sc->aria_mix[ARIAMIX_MIC_LVL].level[1];
 1385                         error = 0;
 1386                 }
 1387                 break;
 1388                         
 1389         case ARIAMIX_LINE_IN_LVL:
 1390                 if (cp->type == AUDIO_MIXER_VALUE) {
 1391                         cp->un.value.num_channels = sc->aria_mix[ARIAMIX_LINE_IN_LVL].num_channels;
 1392                         cp->un.value.level[0] = sc->aria_mix[ARIAMIX_LINE_IN_LVL].level[0];
 1393                         cp->un.value.level[1] = sc->aria_mix[ARIAMIX_LINE_IN_LVL].level[1];
 1394                         error = 0;
 1395                 }
 1396                 break;
 1397 
 1398         case ARIAMIX_CD_LVL:
 1399                 if (cp->type == AUDIO_MIXER_VALUE) {
 1400                         cp->un.value.num_channels = sc->aria_mix[ARIAMIX_CD_LVL].num_channels;
 1401                         cp->un.value.level[0] = sc->aria_mix[ARIAMIX_CD_LVL].level[0];
 1402                         cp->un.value.level[1] = sc->aria_mix[ARIAMIX_CD_LVL].level[1];
 1403                         error = 0;
 1404                 }
 1405                 break;
 1406 
 1407         case ARIAMIX_TEL_LVL:
 1408                 if (cp->type == AUDIO_MIXER_VALUE) {
 1409                         cp->un.value.num_channels = sc->aria_mix[ARIAMIX_TEL_LVL].num_channels;
 1410                         cp->un.value.level[0] = sc->aria_mix[ARIAMIX_TEL_LVL].level[0];
 1411                         error = 0;
 1412                 }
 1413                 break;
 1414         case ARIAMIX_DAC_LVL:
 1415                 if (cp->type == AUDIO_MIXER_VALUE) {
 1416                         cp->un.value.num_channels = sc->aria_mix[ARIAMIX_DAC_LVL].num_channels;
 1417                         cp->un.value.level[0] = sc->aria_mix[ARIAMIX_DAC_LVL].level[0];
 1418                         cp->un.value.level[1] = sc->aria_mix[ARIAMIX_DAC_LVL].level[1];
 1419                         error = 0;
 1420                 }
 1421                 break;
 1422 
 1423         case ARIAMIX_AUX_LVL:
 1424                 if (cp->type == AUDIO_MIXER_VALUE) {
 1425                         cp->un.value.num_channels = sc->aria_mix[ARIAMIX_AUX_LVL].num_channels;
 1426                         cp->un.value.level[0] = sc->aria_mix[ARIAMIX_AUX_LVL].level[0];
 1427                         cp->un.value.level[1] = sc->aria_mix[ARIAMIX_AUX_LVL].level[1];
 1428                         error = 0;
 1429                 }
 1430                 break;
 1431 
 1432         case ARIAMIX_MIC_MUTE:
 1433                 if (cp->type == AUDIO_MIXER_ENUM) {
 1434                         cp->un.ord = sc->aria_mix[ARIAMIX_MIC_LVL].mute;
 1435                         error = 0;
 1436                 }
 1437                 break;
 1438 
 1439         case ARIAMIX_LINE_IN_MUTE:
 1440                 if (cp->type == AUDIO_MIXER_ENUM) {
 1441                         cp->un.ord = sc->aria_mix[ARIAMIX_LINE_IN_LVL].mute;
 1442                         error = 0;
 1443                 }
 1444                 break;
 1445 
 1446         case ARIAMIX_CD_MUTE:
 1447                 if (cp->type == AUDIO_MIXER_ENUM) {
 1448                         cp->un.ord = sc->aria_mix[ARIAMIX_CD_LVL].mute;
 1449                         error = 0;
 1450                 }
 1451                 break;
 1452 
 1453         case ARIAMIX_DAC_MUTE:
 1454                 if (cp->type == AUDIO_MIXER_ENUM) {
 1455                         cp->un.ord = sc->aria_mix[ARIAMIX_DAC_LVL].mute;
 1456                         error = 0;
 1457                 }
 1458                 break;
 1459 
 1460         case ARIAMIX_AUX_MUTE:
 1461                 if (cp->type == AUDIO_MIXER_ENUM) {
 1462                         cp->un.ord = sc->aria_mix[ARIAMIX_AUX_LVL].mute;
 1463                         error = 0;
 1464                 }
 1465                 break;
 1466 
 1467         case ARIAMIX_TEL_MUTE:
 1468                 if (cp->type == AUDIO_MIXER_ENUM) {
 1469                         cp->un.ord = sc->aria_mix[ARIAMIX_TEL_LVL].mute;
 1470                         error = 0;
 1471                 }
 1472                 break;
 1473 
 1474         case ARIAMIX_MASTER_LVL:
 1475                 if (cp->type == AUDIO_MIXER_VALUE) {
 1476                         cp->un.value.num_channels = sc->ariamix_master.num_channels;
 1477                         cp->un.value.level[0] = sc->ariamix_master.level[0];
 1478                         cp->un.value.level[1] = sc->ariamix_master.level[1];
 1479                         error = 0;
 1480                 }
 1481                 break;
 1482 
 1483         case ARIAMIX_MASTER_TREBLE:
 1484                 if (cp->type == AUDIO_MIXER_VALUE) {
 1485                         cp->un.value.num_channels = 2;
 1486                         cp->un.value.level[0] = sc->ariamix_master.treble[0];
 1487                         cp->un.value.level[1] = sc->ariamix_master.treble[1];
 1488                         error = 0;
 1489                 }
 1490                 break;
 1491 
 1492         case ARIAMIX_MASTER_BASS:
 1493                 if (cp->type == AUDIO_MIXER_VALUE) {
 1494                         cp->un.value.num_channels = 2;
 1495                         cp->un.value.level[0] = sc->ariamix_master.bass[0];
 1496                         cp->un.value.level[1] = sc->ariamix_master.bass[1];
 1497                         error = 0;
 1498                 }
 1499                 break;
 1500 
 1501         case ARIAMIX_OUT_LVL:
 1502                 if (cp->type == AUDIO_MIXER_VALUE) {
 1503                         cp->un.value.num_channels = sc->sc_chans;
 1504                         cp->un.value.level[0] = sc->gain[0];
 1505                         cp->un.value.level[1] = sc->gain[1];
 1506                         error = 0;
 1507                 }
 1508                 break;
 1509         case ARIAMIX_RECORD_SOURCE:
 1510                 if (cp->type == AUDIO_MIXER_ENUM) {
 1511                         cp->un.ord = sc->aria_mix_source;
 1512                         error = 0;
 1513                 }
 1514                 break;
 1515 
 1516         default:
 1517                 return ENXIO;
 1518                 /* NOT REACHED */
 1519         }
 1520 
 1521         return(error);
 1522 }
 1523 
 1524 int
 1525 aria_mixer_query_devinfo(addr, dip)
 1526            void *addr;
 1527            register mixer_devinfo_t *dip;
 1528 {
 1529 
 1530         register struct aria_softc *sc = addr;
 1531 
 1532         DPRINTF(("aria_mixer_query_devinfo\n"));
 1533 
 1534         if (!(ARIA_MIXER&sc->sc_hardware))  /* This could be done better, no mixer still has some controls. */
 1535                 return ENXIO;
 1536 
 1537         dip->prev = dip->next = AUDIO_MIXER_LAST;
 1538 
 1539         switch(dip->index) {
 1540         case ARIAMIX_MIC_LVL:
 1541                 dip->type = AUDIO_MIXER_VALUE;
 1542                 dip->mixer_class = ARIAMIX_INPUT_CLASS;
 1543                 dip->next = ARIAMIX_MIC_MUTE;
 1544                 strlcpy(dip->label.name, AudioNmicrophone,
 1545                     sizeof dip->label.name);
 1546                 dip->un.v.num_channels = 2;
 1547                 strlcpy(dip->un.v.units.name, AudioNvolume,
 1548                     sizeof dip->un.v.units.name);
 1549                 break;
 1550 
 1551         case ARIAMIX_LINE_IN_LVL:
 1552                 dip->type = AUDIO_MIXER_VALUE;
 1553                 dip->mixer_class = ARIAMIX_INPUT_CLASS;
 1554                 dip->next = ARIAMIX_LINE_IN_MUTE;
 1555                 strlcpy(dip->label.name, AudioNline, sizeof dip->label.name);
 1556                 dip->un.v.num_channels = 2;
 1557                 strlcpy(dip->un.v.units.name, AudioNvolume,
 1558                     sizeof dip->un.v.units.name);
 1559                 break;
 1560 
 1561         case ARIAMIX_CD_LVL:
 1562                 dip->type = AUDIO_MIXER_VALUE;
 1563                 dip->mixer_class = ARIAMIX_INPUT_CLASS;
 1564                 dip->next = ARIAMIX_CD_MUTE;
 1565                 strlcpy(dip->label.name, AudioNcd, sizeof dip->label.name);
 1566                 dip->un.v.num_channels = 2;
 1567                 strlcpy(dip->un.v.units.name, AudioNvolume,
 1568                     sizeof dip->un.v.units.name);
 1569                 break;
 1570 
 1571         case ARIAMIX_TEL_LVL:
 1572                 dip->type = AUDIO_MIXER_VALUE;
 1573                 dip->mixer_class = ARIAMIX_INPUT_CLASS;
 1574                 dip->next = ARIAMIX_TEL_MUTE;
 1575                 strlcpy(dip->label.name, "telephone", sizeof dip->label.name);
 1576                 dip->un.v.num_channels = 1;
 1577                 strlcpy(dip->un.v.units.name, AudioNvolume,
 1578                     sizeof dip->un.v.units.name);
 1579                 break;
 1580 
 1581         case ARIAMIX_DAC_LVL:
 1582                 dip->type = AUDIO_MIXER_VALUE;
 1583                 dip->mixer_class = ARIAMIX_INPUT_CLASS;
 1584                 dip->next = ARIAMIX_DAC_MUTE;
 1585                 strlcpy(dip->label.name, AudioNdac, sizeof dip->label.name);
 1586                 dip->un.v.num_channels = 1;
 1587                 strlcpy(dip->un.v.units.name, AudioNvolume,
 1588                     sizeof dip->un.v.units.name);
 1589                 break;
 1590 
 1591         case ARIAMIX_AUX_LVL:
 1592                 dip->type = AUDIO_MIXER_VALUE;
 1593                 dip->mixer_class = ARIAMIX_INPUT_CLASS;
 1594                 dip->next = ARIAMIX_AUX_MUTE;
 1595                 strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
 1596                 dip->un.v.num_channels = 1;
 1597                 strlcpy(dip->un.v.units.name, AudioNvolume,
 1598                     sizeof dip->un.v.units.name);
 1599                 break;
 1600 
 1601         case ARIAMIX_MIC_MUTE:
 1602                 dip->prev = ARIAMIX_MIC_LVL;
 1603                 goto mode;
 1604 
 1605         case ARIAMIX_LINE_IN_MUTE:
 1606                 dip->prev = ARIAMIX_LINE_IN_LVL;
 1607                 goto mode;
 1608         
 1609         case ARIAMIX_CD_MUTE:
 1610                 dip->prev = ARIAMIX_CD_LVL;
 1611                 goto mode;
 1612         
 1613         case ARIAMIX_DAC_MUTE:
 1614                 dip->prev = ARIAMIX_DAC_LVL;
 1615                 goto mode;
 1616 
 1617         case ARIAMIX_AUX_MUTE:
 1618                 dip->prev = ARIAMIX_AUX_LVL;
 1619                 goto mode;
 1620 
 1621         case ARIAMIX_TEL_MUTE:
 1622                 dip->prev = ARIAMIX_TEL_LVL;
 1623                 goto mode;
 1624 
 1625 mode:
 1626                 dip->mixer_class = ARIAMIX_INPUT_CLASS;
 1627                 dip->type = AUDIO_MIXER_ENUM;
 1628                 strlcpy(dip->label.name, AudioNmute, sizeof dip->label.name);
 1629                 dip->un.e.num_mem = 2;
 1630                 strlcpy(dip->un.e.member[0].label.name, AudioNoff,
 1631                     sizeof dip->un.e.member[0].label.name);
 1632                 dip->un.e.member[0].ord = 0;
 1633                 strlcpy(dip->un.e.member[1].label.name, AudioNon,
 1634                     sizeof dip->un.e.member[0].label.name);
 1635                 dip->un.e.member[1].ord = 1;
 1636                 break;
 1637 
 1638         case ARIAMIX_MASTER_LVL:
 1639                 dip->type = AUDIO_MIXER_VALUE;
 1640                 dip->mixer_class = ARIAMIX_OUTPUT_CLASS;
 1641                 dip->next = ARIAMIX_MASTER_TREBLE;
 1642                 strlcpy(dip->label.name, AudioNvolume, sizeof dip->label.name);
 1643                 dip->un.v.num_channels = 2;
 1644                 strlcpy(dip->un.v.units.name, AudioNvolume,
 1645                     sizeof dip->un.v.units.name);
 1646                 break;
 1647 
 1648         case ARIAMIX_MASTER_TREBLE:
 1649                 dip->type = AUDIO_MIXER_VALUE;
 1650                 dip->mixer_class = ARIAMIX_OUTPUT_CLASS;
 1651                 dip->prev = ARIAMIX_MASTER_LVL;
 1652                 dip->next = ARIAMIX_MASTER_BASS;
 1653                 strlcpy(dip->label.name, AudioNmaster, sizeof dip->label.name);
 1654                 dip->un.v.num_channels = 2;
 1655                 strlcpy(dip->un.v.units.name, AudioNtreble,
 1656                     sizeof dip->un.v.units.name);
 1657                 break;
 1658 
 1659         case ARIAMIX_MASTER_BASS:
 1660                 dip->type = AUDIO_MIXER_VALUE;
 1661                 dip->mixer_class = ARIAMIX_OUTPUT_CLASS;
 1662                 dip->prev = ARIAMIX_MASTER_TREBLE;
 1663                 strlcpy(dip->label.name, AudioNmaster, sizeof dip->label.name);
 1664                 dip->un.v.num_channels = 2;
 1665                 strlcpy(dip->un.v.units.name, AudioNbass,
 1666                     sizeof dip->un.v.units.name);
 1667                 break;
 1668 
 1669         case ARIAMIX_OUT_LVL:
 1670                 dip->type = AUDIO_MIXER_VALUE;
 1671                 dip->mixer_class = ARIAMIX_OUTPUT_CLASS;
 1672                 strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
 1673                 dip->un.v.num_channels = 2;
 1674                 strlcpy(dip->un.v.units.name, AudioNvolume,
 1675                     sizeof dip->un.v.units.name);
 1676                 break;
 1677 
 1678         case ARIAMIX_RECORD_SOURCE:
 1679                 dip->mixer_class = ARIAMIX_RECORD_CLASS;
 1680                 dip->type = AUDIO_MIXER_ENUM;
 1681                 strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
 1682                 dip->un.e.num_mem = 6;
 1683                 strlcpy(dip->un.e.member[0].label.name, AudioNoutput,
 1684                     sizeof dip->un.e.member[0].label.name);
 1685                 dip->un.e.member[0].ord = ARIAMIX_AUX_LVL;
 1686                 strlcpy(dip->un.e.member[1].label.name, AudioNmicrophone,
 1687                     sizeof dip->un.e.member[0].label.name);
 1688                 dip->un.e.member[1].ord = ARIAMIX_MIC_LVL;
 1689                 strlcpy(dip->un.e.member[2].label.name, AudioNdac,
 1690                     sizeof dip->un.e.member[0].label.name);
 1691                 dip->un.e.member[2].ord = ARIAMIX_DAC_LVL;
 1692                 strlcpy(dip->un.e.member[3].label.name, AudioNline,
 1693                     sizeof dip->un.e.member[0].label.name);
 1694                 dip->un.e.member[3].ord = ARIAMIX_LINE_IN_LVL;
 1695                 strlcpy(dip->un.e.member[3].label.name, AudioNcd,
 1696                     sizeof dip->un.e.member[0].label.name);
 1697                 dip->un.e.member[4].ord = ARIAMIX_CD_LVL;
 1698                 strlcpy(dip->un.e.member[3].label.name, "telephone",
 1699                     sizeof dip->un.e.member[0].label.name);
 1700                 dip->un.e.member[5].ord = ARIAMIX_TEL_LVL;
 1701                 break;
 1702 
 1703         case ARIAMIX_INPUT_CLASS:
 1704                 dip->type = AUDIO_MIXER_CLASS;
 1705                 dip->mixer_class = ARIAMIX_INPUT_CLASS;
 1706                 strlcpy(dip->label.name, AudioCInputs, sizeof dip->label.name);
 1707                 break;
 1708 
 1709         case ARIAMIX_OUTPUT_CLASS:
 1710                 dip->type = AUDIO_MIXER_CLASS;
 1711                 dip->mixer_class = ARIAMIX_OUTPUT_CLASS;
 1712                 strlcpy(dip->label.name, AudioCOutputs,
 1713                     sizeof dip->label.name);
 1714                 break;
 1715 
 1716         case ARIAMIX_RECORD_CLASS:
 1717                 dip->type = AUDIO_MIXER_CLASS;
 1718                 dip->mixer_class = ARIAMIX_RECORD_CLASS;
 1719                 strlcpy(dip->label.name, AudioCRecord, sizeof dip->label.name);
 1720                 break;
 1721 
 1722         case ARIAMIX_EQ_CLASS:
 1723                 dip->type = AUDIO_MIXER_CLASS;
 1724                 dip->mixer_class = ARIAMIX_EQ_CLASS;
 1725                 strlcpy(dip->label.name, AudioCEqualization,
 1726                     sizeof dip->label.name);
 1727                 break;
 1728 
 1729         default:
 1730                 return ENXIO;
 1731                 /*NOTREACHED*/
 1732         }
 1733         return 0;
 1734 }
 1735 
 1736 #endif /* NARIA */

/* [<][>][^][v][top][bottom][index][help] */