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/dev/pcmcia/esl.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 /*      $NetBSD: esl.c,v 1.10 2003/05/16 23:55:32 kristerw Exp $        */
    2 
    3 /*
    4  * Copyright (c) 2001 Jared D. McNeill <jmcneill@invisible.yi.org>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. All advertising materials mentioning features or use of this software
   16  *    must display the following acknowledgement:
   17  *      This product includes software developed by Jared D. McNeill.
   18  * 4. Neither the name of the author nor the names of any contributors may
   19  *    be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  *
   34  */
   35 
   36 #include <sys/cdefs.h>
   37 __KERNEL_RCSID(0, "$NetBSD: esl.c,v 1.10 2003/05/16 23:55:32 kristerw Exp $");
   38 
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/errno.h>
   42 #include <sys/ioctl.h>
   43 #include <sys/syslog.h>
   44 #include <sys/device.h>
   45 #include <sys/proc.h>
   46 #include <sys/kernel.h>
   47 #include <sys/audioio.h>
   48 
   49 #include <machine/cpu.h>
   50 #include <machine/intr.h>
   51 #include <machine/bus.h>
   52 #include <machine/pio.h>
   53 
   54 #include <dev/audio_if.h>
   55 #include <dev/auconv.h>
   56 #include <dev/mulaw.h>
   57 
   58 #include <dev/pcmcia/pcmciavar.h>
   59 
   60 #include <dev/isa/essreg.h>
   61 #include <dev/pcmcia/eslvar.h>
   62 
   63 int     esl_open(void *, int);
   64 void    esl_close(void *);
   65 int     esl_query_encoding(void *, struct audio_encoding *);
   66 int     esl_set_params(void *, int, int, struct audio_params *,
   67                                         struct audio_params *);
   68 int     esl_round_blocksize(void *, int);
   69 int     esl_halt_output(void *);
   70 int     esl_halt_input(void *);
   71 int     esl_speaker_ctl(void *, int);
   72 int     esl_getdev(void *, struct audio_device *);
   73 int     esl_set_port(void *, mixer_ctrl_t *);
   74 int     esl_get_port(void *, mixer_ctrl_t *);
   75 int     esl_query_devinfo(void *, mixer_devinfo_t *);
   76 int     esl_get_props(void *);
   77 int     esl_trigger_output(void *, void *, void *, int, void (*)(void *),
   78                                 void *, struct audio_params *);
   79 
   80 /* Supporting subroutines */
   81 int     esl_reset(struct esl_pcmcia_softc *);
   82 void    esl_setup(struct esl_pcmcia_softc *);
   83 void    esl_set_gain(struct esl_pcmcia_softc *, int, int);
   84 void    esl_speaker_on(struct esl_pcmcia_softc *);
   85 void    esl_speaker_off(struct esl_pcmcia_softc *);
   86 int     esl_identify(struct esl_pcmcia_softc *);
   87 int     esl_rdsp(struct esl_pcmcia_softc *);
   88 int     esl_wdsp(struct esl_pcmcia_softc *, u_char);
   89 u_char  esl_dsp_read_ready(struct esl_pcmcia_softc *);
   90 u_char  esl_dsp_write_ready(struct esl_pcmcia_softc *);
   91 u_char  esl_get_dsp_status(struct esl_pcmcia_softc *);
   92 u_char  esl_read_x_reg(struct esl_pcmcia_softc *, u_char);
   93 int     esl_write_x_reg(struct esl_pcmcia_softc *, u_char, u_char);
   94 void    esl_clear_xreg_bits(struct esl_pcmcia_softc *, u_char, u_char);
   95 void    esl_set_xreg_bits(struct esl_pcmcia_softc *, u_char, u_char);
   96 u_char  esl_read_mix_reg(struct esl_pcmcia_softc *, u_char);
   97 void    esl_write_mix_reg(struct esl_pcmcia_softc *, u_char, u_char);
   98 void    esl_clear_mreg_bits(struct esl_pcmcia_softc *, u_char, u_char);
   99 void    esl_set_mreg_bits(struct esl_pcmcia_softc *, u_char, u_char);
  100 void    esl_read_multi_mix_reg(struct esl_pcmcia_softc *, u_char,
  101                                     u_int8_t *, bus_size_t);
  102 u_int   esl_srtotc(u_int);
  103 u_int   esl_srtofc(u_int);
  104 
  105 struct audio_device esl_device = {
  106         "AudioDrive",
  107         "",
  108         "esl"
  109 };
  110 
  111 struct audio_hw_if esl_hw_if = {
  112         esl_open,
  113         esl_close,
  114         NULL,
  115         esl_query_encoding,
  116         esl_set_params,
  117         esl_round_blocksize,
  118         NULL,
  119         NULL,
  120         NULL,
  121         NULL,
  122         NULL,
  123         esl_halt_output,
  124         esl_halt_input,
  125         esl_speaker_ctl,
  126         esl_getdev,
  127         NULL,
  128         esl_set_port,
  129         esl_get_port,
  130         esl_query_devinfo,
  131         NULL,
  132         NULL,
  133         NULL,
  134         NULL,
  135         esl_get_props,
  136         esl_trigger_output,
  137         NULL,
  138         NULL,
  139 };
  140 
  141 static char *eslmodel[] = {
  142         "1688",
  143         "688",
  144 };
  145 
  146 int
  147 esl_open(void *hdl, int flags)
  148 {
  149 
  150         struct esl_pcmcia_softc *sc = hdl;
  151         int i;
  152 
  153         if (sc->sc_esl.sc_open != 0)
  154                 return (EBUSY);
  155 
  156         if ((*sc->sc_enable)(sc))
  157                 return (ENXIO);
  158 
  159         if (esl_reset(sc) != 0) {
  160                 printf("%s: esl_open: esl_reset failed\n",
  161                     sc->sc_esl.sc_dev.dv_xname);
  162                 return (ENXIO);
  163         }
  164 
  165         /* because we did a reset */
  166         esl_setup(sc);
  167 
  168         /* Set all mixer controls to sane values (since we just did a reset) */
  169         for (i = 0; i < ESS_MAX_NDEVS; i++)
  170                 esl_set_gain(sc, i, 1);
  171 
  172         sc->sc_esl.sc_open = 1;
  173 
  174         /* XXX: Delay a bit */
  175         delay(10000);
  176 
  177         return (0);
  178 }
  179 
  180 
  181 void
  182 esl_close(void *hdl)
  183 {
  184         struct esl_pcmcia_softc *sc = hdl;
  185 
  186         esl_speaker_off(sc);
  187 
  188         (*sc->sc_disable)(sc);
  189 
  190         sc->sc_esl.sc_open = 0;
  191 
  192         return;
  193 }
  194 
  195 int
  196 esl_query_encoding(void *hdl, struct audio_encoding *ae)
  197 {
  198 
  199         switch (ae->index) {
  200         case 0:
  201                 strcpy(ae->name, AudioEulinear);
  202                 ae->encoding = AUDIO_ENCODING_ULINEAR;
  203                 ae->precision = 8;
  204                 ae->flags = 0;
  205                 return (0);
  206         case 1:
  207                 strcpy(ae->name, AudioEmulaw);
  208                 ae->encoding = AUDIO_ENCODING_ULAW;
  209                 ae->precision = 8;
  210                 ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
  211                 return (0);
  212         case 2:
  213                 strcpy(ae->name, AudioEalaw);
  214                 ae->encoding = AUDIO_ENCODING_ALAW;
  215                 ae->precision = 8;
  216                 ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
  217                 return (0);
  218         case 3:
  219                 strcpy(ae->name, AudioEslinear);
  220                 ae->encoding = AUDIO_ENCODING_SLINEAR;
  221                 ae->precision = 8;
  222                 ae->flags = 0;
  223                 return (0);
  224         case 4:
  225                 strcpy(ae->name, AudioEslinear_le);
  226                 ae->encoding = AUDIO_ENCODING_SLINEAR_LE;
  227                 ae->precision = 16;
  228                 ae->flags = 0;
  229                 return (0);
  230         case 5:
  231                 strcpy(ae->name, AudioEulinear_le);
  232                 ae->encoding = AUDIO_ENCODING_ULINEAR_LE;
  233                 ae->precision = 16;
  234                 ae->flags = 0;
  235                 return (0);
  236         case 6:
  237                 strcpy(ae->name, AudioEslinear_be);
  238                 ae->encoding = AUDIO_ENCODING_SLINEAR_BE;
  239                 ae->precision = 16;
  240                 ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
  241                 return (0);
  242         case 7:
  243                 strcpy(ae->name, AudioEulinear_be);
  244                 ae->encoding = AUDIO_ENCODING_ULINEAR_BE;
  245                 ae->precision = 16;
  246                 ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
  247                 return (0);
  248         default:
  249                 return EINVAL;
  250         }
  251         return (0);
  252 }
  253 
  254 int
  255 esl_set_params(void *hdl, int setmode, int usemode,
  256                 struct audio_params *play, struct audio_params *rec)
  257 {
  258         struct esl_pcmcia_softc *sc = hdl;
  259         int rate;
  260 
  261         if (play->sample_rate < ESS_MINRATE ||
  262             play->sample_rate > ESS_MAXRATE ||
  263             (play->precision != 8 && play->precision != 16) ||
  264             (play->channels != 1 && play->channels != 2))
  265                 return (EINVAL);
  266 
  267         play->factor = 1;
  268         play->sw_code = NULL;
  269         switch (play->encoding) {
  270         case AUDIO_ENCODING_SLINEAR_BE:
  271         case AUDIO_ENCODING_ULINEAR_BE:
  272                 if (play->precision == 16)
  273                         play->sw_code = swap_bytes;
  274                 break;
  275         case AUDIO_ENCODING_SLINEAR_LE:
  276         case AUDIO_ENCODING_ULINEAR_LE:
  277                 break;
  278         case AUDIO_ENCODING_ULAW:
  279                 play->factor = 2;
  280                 play->sw_code = mulaw_to_ulinear16_le;
  281                 break;
  282         case AUDIO_ENCODING_ALAW:
  283                 play->factor = 2;
  284                 play->sw_code = alaw_to_ulinear16_le;
  285                 break;
  286         default:
  287                 return (EINVAL);
  288         }
  289 
  290         rate = play->sample_rate;
  291 
  292         esl_write_x_reg(sc, ESS_XCMD_SAMPLE_RATE, esl_srtotc(rate));
  293         esl_write_x_reg(sc, ESS_XCMD_FILTER_CLOCK, esl_srtofc(rate));
  294 
  295         return (0);
  296 }
  297 
  298 int
  299 esl_round_blocksize(void *hdl, int bs)
  300 {
  301 
  302         return ((bs / 128) * 128);
  303 }
  304 
  305 
  306 int
  307 esl_halt_output(void *hdl)
  308 {
  309         struct esl_pcmcia_softc *sc = hdl;
  310 
  311         if (sc->sc_esl.active) {
  312                 esl_clear_xreg_bits(sc, ESS_XCMD_AUDIO1_CTRL2,
  313                     ESS_AUDIO1_CTRL2_FIFO_ENABLE);
  314                 sc->sc_esl.active = 0;
  315         }
  316 
  317         return (0);
  318 }
  319 
  320 int
  321 esl_halt_input(void *hdl)
  322 {
  323 
  324         return (0);
  325 }
  326 
  327 int
  328 esl_speaker_ctl(void *hdl, int on)
  329 {
  330 
  331         return (0);
  332 }
  333 
  334 int
  335 esl_getdev(void *hdl, struct audio_device *ret)
  336 {
  337 
  338         *ret = esl_device;
  339         return (0);
  340 }
  341 
  342 int
  343 esl_set_port(void *hdl, mixer_ctrl_t *mc)
  344 {
  345         struct esl_pcmcia_softc *sc = hdl;
  346         int lgain, rgain;
  347 
  348         switch(mc->dev) {
  349         case ESS_MASTER_VOL:
  350         case ESS_DAC_PLAY_VOL:
  351         case ESS_SYNTH_PLAY_VOL:
  352                 if (mc->type != AUDIO_MIXER_VALUE)
  353                         return (EINVAL);
  354 
  355                 switch(mc->un.value.num_channels) {
  356                 case 1:
  357                         lgain = rgain = ESS_4BIT_GAIN(
  358                             mc->un.value.level[AUDIO_MIXER_LEVEL_MONO]);
  359                         break;
  360                 case 2:
  361                         lgain = ESS_4BIT_GAIN(
  362                             mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT]);
  363                         rgain = ESS_4BIT_GAIN(
  364                             mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]);
  365                         break;
  366                 default:
  367                         return (EINVAL);
  368                 }
  369                 sc->sc_esl.gain[mc->dev][ESS_LEFT] = lgain;
  370                 sc->sc_esl.gain[mc->dev][ESS_RIGHT] = rgain;
  371                 esl_set_gain(sc, mc->dev, 1);
  372                 return (0);
  373                 break;
  374         default:
  375                 break;
  376         }
  377 
  378         return (EINVAL);
  379 }
  380 
  381 int
  382 esl_get_port(void *hdl, mixer_ctrl_t *mc)
  383 {
  384         struct esl_pcmcia_softc *sc = hdl;
  385 
  386         switch(mc->dev) {
  387         case ESS_MASTER_VOL:
  388         case ESS_DAC_PLAY_VOL:
  389         case ESS_SYNTH_PLAY_VOL:
  390                 switch(mc->un.value.num_channels) {
  391                 case 1:
  392                         mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
  393                             sc->sc_esl.gain[mc->dev][ESS_LEFT];
  394                         break;
  395                 case 2:
  396                         mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
  397                             sc->sc_esl.gain[mc->dev][ESS_LEFT];
  398                         mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
  399                             sc->sc_esl.gain[mc->dev][ESS_RIGHT];
  400                         break;
  401                 default:
  402                         return (EINVAL);
  403                 }
  404                 return (0);
  405         default:
  406                 break;
  407         }
  408 
  409         return (EINVAL);
  410 }
  411 
  412 int
  413 esl_query_devinfo(void *hdl, mixer_devinfo_t *di)
  414 {
  415 
  416         switch(di->index) {
  417         case ESS_DAC_PLAY_VOL:
  418                 di->mixer_class = ESS_INPUT_CLASS;
  419                 di->next = di->prev = AUDIO_MIXER_LAST;
  420                 strcpy(di->label.name, AudioNdac);
  421                 di->type = AUDIO_MIXER_VALUE;
  422                 di->un.v.num_channels = 2;
  423                 strcpy(di->un.v.units.name, AudioNvolume);
  424                 return (0);
  425         case ESS_SYNTH_PLAY_VOL:
  426                 di->mixer_class = ESS_INPUT_CLASS;
  427                 di->next = di->prev = AUDIO_MIXER_LAST;
  428                 strcpy(di->label.name, AudioNfmsynth);
  429                 di->type = AUDIO_MIXER_VALUE;
  430                 di->un.v.num_channels = 2;
  431                 strcpy(di->un.v.units.name, AudioNvolume);
  432                 return (0);
  433         case ESS_INPUT_CLASS:
  434                 di->mixer_class = ESS_INPUT_CLASS;
  435                 di->next = di->prev = AUDIO_MIXER_LAST;
  436                 strcpy(di->label.name, AudioCinputs);
  437                 di->type = AUDIO_MIXER_CLASS;
  438                 return (0);
  439         case ESS_MASTER_VOL:
  440                 di->mixer_class = ESS_OUTPUT_CLASS;
  441                 di->next = di->prev = AUDIO_MIXER_LAST;
  442                 strcpy(di->label.name, AudioNmaster);
  443                 di->type = AUDIO_MIXER_VALUE;
  444                 di->un.v.num_channels = 2;
  445                 strcpy(di->un.v.units.name, AudioNvolume);
  446                 return (0);
  447         case ESS_OUTPUT_CLASS:
  448                 di->mixer_class = ESS_OUTPUT_CLASS;
  449                 di->next = di->prev = AUDIO_MIXER_LAST;
  450                 strcpy(di->label.name, AudioCoutputs);
  451                 di->type = AUDIO_MIXER_CLASS;
  452                 return (0);
  453         default:
  454                 break;
  455         }
  456 
  457         return (ENXIO);
  458 }
  459 
  460 int
  461 esl_get_props(void *hdl)
  462 {
  463 
  464         return (AUDIO_PROP_MMAP);
  465 }
  466 
  467 int
  468 esl_trigger_output(void *hdl, void *start, void *end, int blksize,
  469                    void (*intr)(void *), void *intrarg,
  470                    struct audio_params *param)
  471 {
  472         struct esl_pcmcia_softc *sc = hdl;
  473         bus_space_tag_t iot = sc->sc_pcioh.iot;
  474         bus_space_handle_t ioh = sc->sc_pcioh.ioh;
  475         int bs;
  476         int cnt;
  477         u_int8_t reg;
  478 
  479         if (sc->sc_esl.active) {
  480                 printf("%s: esl_trigger_output: already running\n",
  481                     sc->sc_esl.sc_dev.dv_xname);
  482                 return (1);
  483         }
  484 
  485         sc->sc_esl.active = 1;
  486         sc->sc_esl.intr = intr;
  487         sc->sc_esl.arg = intrarg;
  488 
  489         /* Stereo or Mono selection */
  490         reg = esl_read_x_reg(sc, ESS_XCMD_AUDIO_CTRL);
  491         if (param->channels == 2) {
  492                 reg &= ~ESS_AUDIO_CTRL_MONO;
  493                 reg |= ESS_AUDIO_CTRL_STEREO;
  494         } else {
  495                 reg |= ESS_AUDIO_CTRL_MONO;
  496                 reg &= ~ESS_AUDIO_CTRL_STEREO;
  497         }
  498         esl_write_x_reg(sc, ESS_XCMD_AUDIO_CTRL, reg);
  499 
  500         /* Program the FIFO (16-bit/8-bit, signed/unsigned, stereo/mono) */
  501         reg = esl_read_x_reg(sc, ESS_XCMD_AUDIO1_CTRL1);
  502         if (param->precision * param->factor == 16)
  503                 reg |= ESS_AUDIO1_CTRL1_FIFO_SIZE;
  504         else
  505                 reg &= ~ESS_AUDIO1_CTRL1_FIFO_SIZE;
  506         if (param->channels == 2)
  507                 reg |= ESS_AUDIO1_CTRL1_FIFO_STEREO;
  508         else
  509                 reg &= ~ESS_AUDIO1_CTRL1_FIFO_STEREO;
  510         if (param->encoding == AUDIO_ENCODING_SLINEAR_BE ||
  511             param->encoding == AUDIO_ENCODING_SLINEAR_LE)
  512                 reg |= ESS_AUDIO1_CTRL1_FIFO_SIGNED;
  513         else
  514                 reg &= ~ESS_AUDIO1_CTRL1_FIFO_SIGNED;
  515         reg |= ESS_AUDIO1_CTRL1_FIFO_CONNECT;
  516         esl_write_x_reg(sc, ESS_XCMD_AUDIO1_CTRL1, reg);
  517 
  518         /* Program transfer count registers with 2s complement of count */
  519         bs = -blksize;
  520         esl_write_x_reg(sc, ESS_XCMD_XFER_COUNTLO, bs);
  521         esl_write_x_reg(sc, ESS_XCMD_XFER_COUNTHI, bs >> 8);
  522 
  523         esl_wdsp(sc, ESS_ACMD_ENABLE_SPKR);
  524         reg = esl_read_x_reg(sc, ESS_XCMD_AUDIO1_CTRL2);
  525         reg &= ~(ESS_AUDIO1_CTRL2_DMA_READ | ESS_AUDIO1_CTRL2_ADC_ENABLE);
  526         reg |= ESS_AUDIO1_CTRL2_FIFO_ENABLE | ESS_AUDIO1_CTRL2_AUTO_INIT;
  527         esl_write_x_reg(sc, ESS_XCMD_AUDIO1_CTRL2, reg);
  528         cnt = (char *)end - (char *)start;
  529         if (cnt == 0)
  530                 printf("%s: no count left\n", sc->sc_esl.sc_dev.dv_xname);
  531 
  532         sc->sc_esl.sc_dmaaddr = sc->sc_esl.sc_dmastart = start;
  533         sc->sc_esl.sc_dmaend = end;
  534         sc->sc_esl.sc_blksize = blksize;
  535         sc->sc_esl.sc_blkpos = 0;
  536 
  537         /* XXX: Delay a bit */
  538         delay(10000);
  539 
  540         /* Prime the FIFO */
  541         bus_space_write_multi_1(iot, ioh, ESS_FIFO_WRITE, start, ESS_FIFO_SIZE);
  542         sc->sc_esl.sc_dmaaddr += ESS_FIFO_SIZE;
  543         sc->sc_esl.sc_blkpos += ESS_FIFO_SIZE;
  544 
  545         return (0);
  546 }
  547 
  548 /* Additional subroutines used by the above (NOT required by audio(9)) */
  549 
  550 int
  551 esl_init(struct esl_pcmcia_softc *sc)
  552 {
  553         const int ENABLE[] = { 0x0, 0x9, 0xb };
  554         const int ENABLE_ORDER[] = { 1, 1, 1, 2, 1, 2, 1, 1, 2, 1, 0, -1 };
  555         struct audio_attach_args aa;
  556         int i;
  557         int model;
  558         bus_space_tag_t iot = sc->sc_pcioh.iot;
  559         bus_space_handle_t ioh = sc->sc_pcioh.ioh;
  560         
  561         sc->sc_esl.sc_open = 0;
  562 
  563         /* Initialization sequence */
  564         for (i = 0; ENABLE_ORDER[i] != -1; i++)
  565                 bus_space_read_1(iot, ioh, ENABLE[i]);
  566         if (esl_reset(sc)) {
  567                 printf("%s: esl_init: esl_reset failed\n",
  568                     sc->sc_esl.sc_dev.dv_xname);
  569                 return (1);
  570         }
  571 
  572         if (esl_identify(sc)) {
  573                 printf("%s: esl_init: esl_identify failed\n",
  574                     sc->sc_esl.sc_dev.dv_xname);
  575                 return (1);
  576         }
  577 
  578         if (!sc->sc_esl.sc_version)
  579                 return (1);     /* Probably a Sound Blaster */
  580 
  581         model = ESS_UNSUPPORTED;
  582 
  583         switch (sc->sc_esl.sc_version & 0xfff0) {
  584         case 0x6880:
  585                 if ((sc->sc_esl.sc_version & 0x0f) >= 8) {
  586                         model = ESS_1688;
  587                 } else {
  588                         model = ESS_688;
  589                 }
  590                 break;
  591         }
  592 
  593         if (model == ESS_UNSUPPORTED) {
  594                 printf("%s: unknown model 0x%04x\n",
  595                     sc->sc_esl.sc_dev.dv_xname, sc->sc_esl.sc_version);
  596                 return (1);
  597         }
  598 
  599         printf("%s: ESS AudioDrive %s [version 0x%04x]\n",
  600             sc->sc_esl.sc_dev.dv_xname, eslmodel[model],
  601             sc->sc_esl.sc_version);
  602 
  603         /* Set volumes to 50% */
  604         for (i = 0; i < ESS_MAX_NDEVS; i++) {
  605                 sc->sc_esl.gain[i][ESS_LEFT] =
  606                     sc->sc_esl.gain[i][ESS_RIGHT] =
  607                     ESS_4BIT_GAIN(AUDIO_MAX_GAIN / 2);
  608                 esl_set_gain(sc, i, 1);
  609         }
  610 
  611         sc->sc_audiodev = audio_attach_mi(&esl_hw_if, sc, &sc->sc_esl.sc_dev);
  612 
  613         /* Attach the OPL device */
  614         aa.type = AUDIODEV_TYPE_OPL;
  615         aa.hwif = 0;
  616         aa.hdl = 0;
  617 
  618         sc->sc_opldev = config_found(&sc->sc_esl.sc_dev, &aa, audioprint);
  619 
  620         /* Disable speaker until device is opened */
  621         esl_speaker_off(sc);
  622 
  623         sc->sc_esl.sc_open = 0;
  624 
  625         return (0);
  626 }
  627 
  628 int
  629 esl_intr(void *hdl)
  630 {
  631         struct esl_pcmcia_softc *sc = hdl;
  632         bus_space_tag_t iot = sc->sc_pcioh.iot;
  633         bus_space_handle_t ioh = sc->sc_pcioh.ioh;
  634         u_int8_t reg;
  635         u_char *pos;
  636 
  637         /* Clear interrupt */
  638         reg = bus_space_read_1(iot, ioh, ESS_CLEAR_INTR);
  639 
  640         if (sc->sc_esl.active) {
  641                 reg = bus_space_read_1(iot, ioh, ESS_DSP_RW_STATUS);
  642                 while (reg & ESS_DSP_READ_HALF) {
  643                         pos = sc->sc_esl.sc_dmaaddr;
  644                         bus_space_write_multi_1(iot, ioh, ESS_FIFO_WRITE, pos,
  645                             ESS_FIFO_SIZE / 2);
  646 
  647                         sc->sc_esl.sc_blkpos += (ESS_FIFO_SIZE / 2);
  648                         if (sc->sc_esl.sc_blkpos >= sc->sc_esl.sc_blksize) {
  649                                 (*sc->sc_esl.intr)(sc->sc_esl.arg);
  650                                 sc->sc_esl.sc_blkpos -= sc->sc_esl.sc_blksize;
  651                         }
  652                         pos += (ESS_FIFO_SIZE / 2);
  653                         if (pos >= sc->sc_esl.sc_dmaend)
  654                                 pos = sc->sc_esl.sc_dmastart;
  655 
  656                         sc->sc_esl.sc_dmaaddr = pos;
  657                         reg = bus_space_read_1(iot, ioh, ESS_DSP_RW_STATUS);
  658                 }
  659         }
  660 
  661         return (1);
  662 }
  663 
  664 int
  665 esl_reset(struct esl_pcmcia_softc *sc)
  666 {
  667         bus_space_tag_t iot = sc->sc_pcioh.iot;
  668         bus_space_handle_t ioh = sc->sc_pcioh.ioh;
  669 
  670         bus_space_write_1(iot, ioh, ESS_DSP_RESET, ESS_RESET_EXT);
  671         delay(10000);   /* XXX: Ugly, but ess.c does this too */
  672         bus_space_write_1(iot, ioh, ESS_DSP_RESET, 0);
  673         if (esl_rdsp(sc) != ESS_MAGIC)
  674                 return (1);
  675 
  676         /* Enable access to the extended command set */
  677         esl_wdsp(sc, ESS_ACMD_ENABLE_EXT);
  678 
  679         return (0);
  680 }
  681 
  682 void
  683 esl_setup(struct esl_pcmcia_softc *sc)
  684 {
  685         u_char reg;
  686 
  687         /*
  688          * Configure IRQ. Set bit 5 of B1h high to enable interrupt on
  689          * FIFOHE, and keep bit 6 low.
  690          */
  691         reg = ESS_IRQ_CTRL_MASK | 0x20 | ESS_IRQ_CTRL_INTRA;
  692         esl_write_x_reg(sc, ESS_XCMD_IRQ_CTRL, reg);
  693 
  694         /*
  695          * "Config DRQ", well not really. Instead of configuring a DRQ,
  696          * we leave bits 7 and 5 of B2h low.
  697          */
  698         reg = 0x10 | 0x40;
  699         esl_write_x_reg(sc, ESS_XCMD_DRQ_CTRL, reg);
  700 
  701         return;
  702 }
  703 
  704 void
  705 esl_set_gain(struct esl_pcmcia_softc *sc, int port, int on)
  706 {
  707         int gain, left, right;
  708         int src;
  709 
  710         switch(port) {
  711         case ESS_MASTER_VOL:
  712                 src = ESS_MREG_VOLUME_MASTER;
  713                 break;
  714         case ESS_DAC_PLAY_VOL:
  715                 src = ESS_MREG_VOLUME_VOICE;
  716                 break;
  717         case ESS_SYNTH_PLAY_VOL:
  718                 src = ESS_MREG_VOLUME_SYNTH;
  719                 break;
  720         default:
  721                 return;
  722         }
  723 
  724         if (on) {
  725                 left = sc->sc_esl.gain[port][ESS_LEFT];
  726                 right = sc->sc_esl.gain[port][ESS_RIGHT];
  727         } else
  728                 left = right = 0;
  729 
  730         gain = ESS_STEREO_GAIN(left, right);
  731 
  732         esl_write_mix_reg(sc, src, gain);
  733 
  734         return;
  735 }
  736 
  737 void
  738 esl_speaker_on(struct esl_pcmcia_softc *sc)
  739 {
  740 
  741         /* Unmute the DAC */
  742         esl_set_gain(sc, ESS_DAC_PLAY_VOL, 1);
  743 
  744         return;
  745 }
  746 
  747 void
  748 esl_speaker_off(struct esl_pcmcia_softc *sc)
  749 {
  750 
  751         /* Mute the DAC */
  752         esl_set_gain(sc, ESS_DAC_PLAY_VOL, 0);
  753 
  754         return;
  755 }
  756 
  757 int
  758 esl_identify(struct esl_pcmcia_softc *sc)
  759 {
  760         u_char reg1, reg2;
  761         int i;
  762 
  763         esl_wdsp(sc, ESS_ACMD_LEGACY_ID);
  764         for (i = 1000, reg1 = reg2 = 0; i; i--)
  765                 if (esl_dsp_read_ready(sc)) {
  766                         if (reg1 == 0)
  767                                 reg1 = esl_rdsp(sc);
  768                         else
  769                                 reg2 = esl_rdsp(sc);
  770                 }       
  771 
  772         sc->sc_esl.sc_version = (reg1 << 8) + reg2;
  773 
  774         return (0);
  775 }
  776 
  777 /* Read a byte from the DSP */
  778 int
  779 esl_rdsp(struct esl_pcmcia_softc *sc)
  780 {
  781         bus_space_tag_t iot = sc->sc_pcioh.iot;
  782         bus_space_handle_t ioh = sc->sc_pcioh.ioh;
  783         int i;
  784 
  785         for (i = ESS_READ_TIMEOUT; i > 0; --i) {
  786                 if (esl_dsp_read_ready(sc)) {
  787                         i = bus_space_read_1(iot, ioh, ESS_DSP_READ);
  788                         return (i);
  789                 } else
  790                         delay(10);
  791         }
  792 
  793         printf("esl_rdsp: timed out\n");
  794         return (-1);
  795 }
  796 
  797 /* Write a byte to the DSP */
  798 int
  799 esl_wdsp(struct esl_pcmcia_softc *sc, u_char v)
  800 {
  801         bus_space_tag_t iot = sc->sc_pcioh.iot;
  802         bus_space_handle_t ioh = sc->sc_pcioh.ioh;
  803         int i;
  804 
  805         for (i = ESS_WRITE_TIMEOUT; i > 0; --i) {
  806                 if (esl_dsp_write_ready(sc)) {
  807                         bus_space_write_1(iot, ioh, ESS_DSP_WRITE, v);
  808                         return (0);
  809                 } else
  810                         delay(10);
  811         }
  812 
  813         printf("esl_wdsp(0x%02x): timed out\n", v);
  814         return (-1);
  815 }
  816 
  817 /* Get the read status of the DSP: 1 == Ready, 0 == Not Ready */
  818 u_char
  819 esl_dsp_read_ready(struct esl_pcmcia_softc *sc)
  820 {
  821 
  822         return ((esl_get_dsp_status(sc) & ESS_DSP_READ_READY) ? 1 : 0);
  823 }
  824 
  825 /* Get the write status of the DSP: 1 == Ready, 0 == Not Ready */
  826 u_char
  827 esl_dsp_write_ready(struct esl_pcmcia_softc *sc)
  828 {
  829 
  830         return ((esl_get_dsp_status(sc) & ESS_DSP_WRITE_BUSY) ? 0 : 1);
  831 }
  832 
  833 /* Return the status of the DSP */
  834 u_char
  835 esl_get_dsp_status(struct esl_pcmcia_softc *sc)
  836 {
  837 
  838         return (bus_space_read_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
  839             ESS_DSP_RW_STATUS));
  840 }
  841 
  842 /* Read a value from one of the extended registers */
  843 u_char
  844 esl_read_x_reg(struct esl_pcmcia_softc *sc, u_char reg)
  845 {
  846         int error;
  847 
  848         if ((error = esl_wdsp(sc, 0xC0)) == 0)
  849                 error = esl_wdsp(sc, reg);
  850         if (error)
  851                 printf("esl_read_x_reg: error reading 0x%02x\n", reg);
  852         return (esl_rdsp(sc));
  853 }
  854 
  855 /* Write a value to one of the extended registers */
  856 int
  857 esl_write_x_reg(struct esl_pcmcia_softc *sc, u_char reg, u_char val)
  858 {
  859         int error;
  860 
  861         if ((error = esl_wdsp(sc, reg)) == 0)
  862                 error = esl_wdsp(sc, val);
  863 
  864         return (error);
  865 }
  866 
  867 void
  868 esl_clear_xreg_bits(struct esl_pcmcia_softc *sc, u_char reg, u_char mask)
  869 {
  870 
  871         esl_write_x_reg(sc, reg, esl_read_x_reg(sc, reg) & ~mask);
  872 
  873         return;
  874 }
  875 
  876 void
  877 esl_set_xreg_bits(struct esl_pcmcia_softc *sc, u_char reg, u_char mask)
  878 {
  879 
  880         esl_write_x_reg(sc, reg, esl_read_x_reg(sc, reg) | mask);
  881 }
  882 
  883 u_char
  884 esl_read_mix_reg(struct esl_pcmcia_softc *sc, u_char reg)
  885 {
  886         bus_space_tag_t iot = sc->sc_pcioh.iot;
  887         bus_space_handle_t ioh = sc->sc_pcioh.ioh;
  888 #if 0
  889         int s;
  890 #endif
  891         u_char val;
  892 
  893 #if 0
  894         s = splaudio();
  895 #endif
  896         bus_space_write_1(iot, ioh, ESS_MIX_REG_SELECT, reg);
  897         val = bus_space_read_1(iot, ioh, ESS_MIX_REG_DATA);
  898 #if 0
  899         splx(s);
  900 #endif
  901 
  902         return (val);
  903 }
  904 
  905 void
  906 esl_write_mix_reg(struct esl_pcmcia_softc *sc, u_char reg, u_char val)
  907 {
  908         bus_space_tag_t iot = sc->sc_pcioh.iot;
  909         bus_space_handle_t ioh = sc->sc_pcioh.ioh;
  910 #if 0
  911         int s;
  912 #endif
  913 
  914 #if 0
  915         s = splaudio();
  916 #endif
  917         bus_space_write_1(iot, ioh, ESS_MIX_REG_SELECT, reg);
  918         bus_space_write_1(iot, ioh, ESS_MIX_REG_DATA, val);
  919 #if 0
  920         splx(s);
  921 #endif
  922 
  923         return;
  924 }
  925 
  926 void
  927 esl_clear_mreg_bits(struct esl_pcmcia_softc *sc, u_char reg, u_char mask)
  928 {
  929 
  930         esl_write_mix_reg(sc, reg, esl_read_mix_reg(sc, reg) & ~mask);
  931 
  932         return;
  933 }
  934 
  935 void
  936 esl_set_mreg_bits(struct esl_pcmcia_softc *sc, u_char reg, u_char mask)
  937 {
  938 
  939         esl_write_mix_reg(sc, reg, esl_read_mix_reg(sc, reg) | mask);
  940 
  941         return;
  942 }
  943 
  944 void
  945 esl_read_multi_mix_reg(struct esl_pcmcia_softc *sc, u_char reg,
  946                 u_int8_t *datap, bus_size_t count)
  947 {
  948         bus_space_tag_t iot = sc->sc_pcioh.iot;
  949         bus_space_handle_t ioh = sc->sc_pcioh.ioh;
  950 #if 0
  951         int s;
  952 #endif
  953 
  954 #if 0
  955         s = splaudio();
  956 #endif
  957         bus_space_write_1(iot, ioh, ESS_MIX_REG_SELECT, reg);
  958         bus_space_read_multi_1(iot, ioh, ESS_MIX_REG_DATA, datap, count);
  959 #if 0
  960         splx(s);
  961 #endif
  962 
  963         return;
  964 }
  965 
  966 /* Calculate the time constant for the requested sampling rate */
  967 u_int
  968 esl_srtotc(u_int rate)
  969 {
  970         u_int tc;
  971 
  972         /* The following formulas are from the ESS data sheet. */
  973         if (rate <= 22050)
  974                 tc = 128 - 397700L / rate;
  975         else
  976                 tc = 256 - 795500L / rate;
  977 
  978         return (tc);
  979 }
  980 
  981 /* Calculate the filter constant for the requested sampling rate */
  982 u_int
  983 esl_srtofc(u_int rate)
  984 {
  985 
  986         /* From dev/isa/ess.c:ess_srtofc() rev 1.53 */
  987         return (256 - 200279L / rate);
  988 }

Cache object: bfd6f7d906bf1a33ea6b359b4f2fd5a3


[ 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.