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/ic/ad1848.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: ad1848.c,v 1.33 2020/02/29 05:51:11 isaki Exp $        */
    2 
    3 /*-
    4  * Copyright (c) 1999, 2008 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Ken Hornstein and John Kohl.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 /*
   32  * Copyright (c) 1994 John Brezak
   33  * Copyright (c) 1991-1993 Regents of the University of California.
   34  * All rights reserved.
   35  *
   36  * Redistribution and use in source and binary forms, with or without
   37  * modification, are permitted provided that the following conditions
   38  * are met:
   39  * 1. Redistributions of source code must retain the above copyright
   40  *    notice, this list of conditions and the following disclaimer.
   41  * 2. Redistributions in binary form must reproduce the above copyright
   42  *    notice, this list of conditions and the following disclaimer in the
   43  *    documentation and/or other materials provided with the distribution.
   44  * 3. All advertising materials mentioning features or use of this software
   45  *    must display the following acknowledgement:
   46  *      This product includes software developed by the Computer Systems
   47  *      Engineering Group at Lawrence Berkeley Laboratory.
   48  * 4. Neither the name of the University nor of the Laboratory may be used
   49  *    to endorse or promote products derived from this software without
   50  *    specific prior written permission.
   51  *
   52  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   55  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   56  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   57  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   58  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   59  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   60  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   61  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   62  * SUCH DAMAGE.
   63  *
   64  */
   65 
   66 /*
   67  * Copyright by Hannu Savolainen 1994
   68  *
   69  * Redistribution and use in source and binary forms, with or without
   70  * modification, are permitted provided that the following conditions are
   71  * met: 1. Redistributions of source code must retain the above copyright
   72  * notice, this list of conditions and the following disclaimer. 2.
   73  * Redistributions in binary form must reproduce the above copyright notice,
   74  * this list of conditions and the following disclaimer in the documentation
   75  * and/or other materials provided with the distribution.
   76  *
   77  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
   78  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   79  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   80  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   81  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   82  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   83  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   84  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   85  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   86  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   87  * SUCH DAMAGE.
   88  *
   89  */
   90 /*
   91  * Portions of this code are from the VOXware support for the ad1848
   92  * by Hannu Savolainen <hannu@voxware.pp.fi>
   93  *
   94  * Portions also ripped from the SoundBlaster driver for NetBSD.
   95  */
   96 
   97 #include <sys/cdefs.h>
   98 __KERNEL_RCSID(0, "$NetBSD: ad1848.c,v 1.33 2020/02/29 05:51:11 isaki Exp $");
   99 
  100 #include <sys/param.h>
  101 #include <sys/systm.h>
  102 #include <sys/errno.h>
  103 #include <sys/ioctl.h>
  104 #include <sys/device.h>
  105 #include <sys/fcntl.h>
  106 /*#include <sys/syslog.h>*/
  107 /*#include <sys/proc.h>*/
  108 
  109 #include <sys/cpu.h>
  110 #include <sys/bus.h>
  111 
  112 #include <sys/audioio.h>
  113 #include <dev/audio/audio_if.h>
  114 
  115 #include <dev/ic/ad1848reg.h>
  116 #include <dev/ic/cs4231reg.h>
  117 #include <dev/ic/cs4237reg.h>
  118 #include <dev/ic/ad1848var.h>
  119 #if 0
  120 #include <dev/isa/cs4231var.h>
  121 #endif
  122 
  123 /*
  124  * AD1845 on some machines don't match the AD1845 doc
  125  * and defining AD1845_HACK to 1 works around the problems.
  126  * options AD1845_HACK=0  should work if you have ``correct'' one.
  127  */
  128 #ifndef AD1845_HACK
  129 #define AD1845_HACK     1       /* weird mixer, can't play slinear_be */
  130 #endif
  131 
  132 #ifdef AUDIO_DEBUG
  133 #define DPRINTF(x)      if (ad1848debug) printf x
  134 int     ad1848debug = 0;
  135 void ad1848_dump_regs(struct ad1848_softc *);
  136 #else
  137 #define DPRINTF(x)
  138 #endif
  139 
  140 /* The HW supports more frequencies but I chose several major ones. */
  141 static const struct audio_format ad1848_formats[] = {
  142         {
  143                 .mode           = AUMODE_PLAY | AUMODE_RECORD,
  144                 .encoding       = AUDIO_ENCODING_SLINEAR_LE,
  145                 .validbits      = 16,
  146                 .precision      = 16,
  147                 .channels       = 2,
  148                 .channel_mask   = AUFMT_STEREO,
  149                 .frequency_type = 6,
  150                 .frequency      = { 8000, 11025, 16000, 22050, 44100, 48000 },
  151         },
  152 };
  153 #define AD1848_NFORMATS __arraycount(ad1848_formats)
  154 
  155 /*
  156  * Initial values for the indirect registers of CS4248/AD1848.
  157  */
  158 static const int ad1848_init_values[] = {
  159     GAIN_12|INPUT_MIC_GAIN_ENABLE,      /* Left Input Control */
  160     GAIN_12|INPUT_MIC_GAIN_ENABLE,      /* Right Input Control */
  161     ATTEN_12,                           /* Left Aux #1 Input Control */
  162     ATTEN_12,                           /* Right Aux #1 Input Control */
  163     ATTEN_12,                           /* Left Aux #2 Input Control */
  164     ATTEN_12,                           /* Right Aux #2 Input Control */
  165     /* bits 5-0 are attenuation select */
  166     ATTEN_12,                           /* Left DAC output Control */
  167     ATTEN_12,                           /* Right DAC output Control */
  168     CLOCK_XTAL1|FMT_PCM8,               /* Clock and Data Format */
  169     SINGLE_DMA|AUTO_CAL_ENABLE,         /* Interface Config */
  170     INTERRUPT_ENABLE,                   /* Pin control */
  171     0x00,                               /* Test and Init */
  172     MODE2,                              /* Misc control */
  173     ATTEN_0<<2,                         /* Digital Mix Control */
  174     0,                                  /* Upper base Count */
  175     0,                                  /* Lower base Count */
  176 
  177     /* These are for CS4231 &c. only (additional registers): */
  178     0,                                  /* Alt feature 1 */
  179     0,                                  /* Alt feature 2 */
  180     ATTEN_12,                           /* Left line in */
  181     ATTEN_12,                           /* Right line in */
  182     0,                                  /* Timer low */
  183     0,                                  /* Timer high */
  184     0,                                  /* unused */
  185     0,                                  /* unused */
  186     0,                                  /* IRQ status */
  187     0,                                  /* unused */
  188                         /* Mono input (a.k.a speaker) (mic) Control */
  189     MONO_INPUT_MUTE|ATTEN_6,            /* mute speaker by default */
  190     0,                                  /* unused */
  191     0,                                  /* record format */
  192     0,                                  /* Crystal Clock Select */
  193     0,                                  /* upper record count */
  194     0                                   /* lower record count */
  195 };
  196 
  197 
  198 int
  199 ad1848_to_vol(mixer_ctrl_t *cp, struct ad1848_volume *vol)
  200 {
  201 
  202         if (cp->un.value.num_channels == 1) {
  203                 vol->left =
  204                 vol->right = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
  205                 return 1;
  206         }
  207         else if (cp->un.value.num_channels == 2) {
  208                 vol->left  = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
  209                 vol->right = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
  210                 return 1;
  211         }
  212         return 0;
  213 }
  214 
  215 int
  216 ad1848_from_vol(mixer_ctrl_t *cp, struct ad1848_volume *vol)
  217 {
  218 
  219         if (cp->un.value.num_channels == 1) {
  220                 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = vol->left;
  221                 return 1;
  222         }
  223         else if (cp->un.value.num_channels == 2) {
  224                 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = vol->left;
  225                 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = vol->right;
  226                 return 1;
  227         }
  228         return 0;
  229 }
  230 
  231 
  232 int
  233 ad_read(struct ad1848_softc *sc, int reg)
  234 {
  235         int x;
  236 
  237         ADWRITE(sc, AD1848_IADDR, (reg & 0xff) | sc->MCE_bit);
  238         x = ADREAD(sc, AD1848_IDATA);
  239         /*  printf("(%02x<-%02x) ", reg|sc->MCE_bit, x); */
  240         return x;
  241 }
  242 
  243 void
  244 ad_write(struct ad1848_softc *sc, int reg, int data)
  245 {
  246 
  247         ADWRITE(sc, AD1848_IADDR, (reg & 0xff) | sc->MCE_bit);
  248         ADWRITE(sc, AD1848_IDATA, data & 0xff);
  249         /* printf("(%02x->%02x) ", reg|sc->MCE_bit, data); */
  250 }
  251 
  252 /*
  253  * extended registers (mode 3) require an additional level of
  254  * indirection through CS_XREG (I23).
  255  */
  256 
  257 int
  258 ad_xread(struct ad1848_softc *sc, int reg)
  259 {
  260         int x;
  261 
  262         ADWRITE(sc, AD1848_IADDR, CS_XREG | sc->MCE_bit);
  263         ADWRITE(sc, AD1848_IDATA, (reg | ALT_F3_XRAE) & 0xff);
  264         x = ADREAD(sc, AD1848_IDATA);
  265 
  266         return x;
  267 }
  268 
  269 void
  270 ad_xwrite(struct ad1848_softc *sc, int reg, int val)
  271 {
  272 
  273         ADWRITE(sc, AD1848_IADDR, CS_XREG | sc->MCE_bit);
  274         ADWRITE(sc, AD1848_IDATA, (reg | ALT_F3_XRAE) & 0xff);
  275         ADWRITE(sc, AD1848_IDATA, val & 0xff);
  276 }
  277 
  278 static void
  279 ad_set_MCE(struct ad1848_softc *sc, int state)
  280 {
  281 
  282         if (state)
  283                 sc->MCE_bit = MODE_CHANGE_ENABLE;
  284         else
  285                 sc->MCE_bit = 0;
  286         ADWRITE(sc, AD1848_IADDR, sc->MCE_bit);
  287 }
  288 
  289 static void
  290 wait_for_calibration(struct ad1848_softc *sc)
  291 {
  292         int timeout;
  293 
  294         DPRINTF(("ad1848: Auto calibration started.\n"));
  295         /*
  296          * Wait until the auto calibration process has finished.
  297          *
  298          * 1) Wait until the chip becomes ready (reads don't return 0x80).
  299          * 2) Wait until the ACI bit of I11 gets on and then off.
  300          *    Because newer chips are fast we may never see the ACI
  301          *    bit go on.  Just delay a little instead.
  302          */
  303         timeout = 10000;
  304         while (timeout > 0 && ADREAD(sc, AD1848_IADDR) == SP_IN_INIT) {
  305                 delay(10);
  306                 timeout--;
  307         }
  308         if (timeout <= 0) {
  309                 DPRINTF(("ad1848: Auto calibration timed out(1).\n"));
  310         }
  311 
  312         /* Set register addr */
  313         ADWRITE(sc, AD1848_IADDR, SP_TEST_AND_INIT);
  314         /* Wait for address to appear when read back. */
  315         timeout = 100000;
  316         while (timeout > 0 &&
  317                (ADREAD(sc, AD1848_IADDR)&SP_IADDR_MASK) != SP_TEST_AND_INIT) {
  318                 delay(10);
  319                 timeout--;
  320         }
  321         if (timeout <= 0) {
  322                 DPRINTF(("ad1848: Auto calibration timed out(1.5).\n"));
  323         }
  324 
  325         if (!(ad_read(sc, SP_TEST_AND_INIT) & AUTO_CAL_IN_PROG)) {
  326                 if (sc->mode > 1) {
  327                         /* A new chip, just delay a little. */
  328                         delay(100);     /* XXX what should it be? */
  329                 } else {
  330                         timeout = 10000;
  331                         while (timeout > 0 &&
  332                                !(ad_read(sc, SP_TEST_AND_INIT) &
  333                                  AUTO_CAL_IN_PROG)) {
  334                                 delay(10);
  335                                 timeout--;
  336                         }
  337                         if (timeout <= 0) {
  338                                 DPRINTF(("ad1848: Auto calibration timed out(2).\n"));
  339                         }
  340                 }
  341         }
  342 
  343         timeout = 10000;
  344         while (timeout > 0 &&
  345                ad_read(sc, SP_TEST_AND_INIT) & AUTO_CAL_IN_PROG) {
  346                 delay(10);
  347                 timeout--;
  348         }
  349         if (timeout <= 0) {
  350                 DPRINTF(("ad1848: Auto calibration timed out(3).\n"));
  351         }
  352 }
  353 
  354 #ifdef AUDIO_DEBUG
  355 void
  356 ad1848_dump_regs(struct ad1848_softc *sc)
  357 {
  358         int i;
  359         u_char r;
  360 
  361         printf("ad1848 status=%02x", ADREAD(sc, AD1848_STATUS));
  362         printf(" regs: ");
  363         for (i = 0; i < 16; i++) {
  364                 r = ad_read(sc, i);
  365                 printf("%02x ", r);
  366         }
  367         if (sc->mode >= 2) {
  368                 for (i = 16; i < 32; i++) {
  369                         r = ad_read(sc, i);
  370                         printf("%02x ", r);
  371                 }
  372         }
  373         printf("\n");
  374 }
  375 #endif /* AUDIO_DEBUG */
  376 
  377 
  378 /*
  379  * Attach hardware to driver, attach hardware driver to audio
  380  * pseudo-device driver .
  381  */
  382 void
  383 ad1848_attach(struct ad1848_softc *sc)
  384 {
  385         static struct ad1848_volume vol_mid = {220, 220};
  386         static struct ad1848_volume vol_0   = {0, 0};
  387         int i;
  388         int timeout;
  389 
  390         /* Initialize the ad1848... */
  391         for (i = 0; i < 0x10; i++) {
  392                 ad_write(sc, i, ad1848_init_values[i]);
  393                 timeout = 100000;
  394                 while (timeout > 0 && ADREAD(sc, AD1848_IADDR) & SP_IN_INIT)
  395                         timeout--;
  396         }
  397         /* ...and additional CS4231 stuff too */
  398         if (sc->mode >= 2) {
  399                 ad_write(sc, SP_INTERFACE_CONFIG, 0); /* disable SINGLE_DMA */
  400                 for (i = 0x10; i < 0x20; i++)
  401                         if (ad1848_init_values[i] != 0) {
  402                                 ad_write(sc, i, ad1848_init_values[i]);
  403                                 timeout = 100000;
  404                                 while (timeout > 0 &&
  405                                        ADREAD(sc, AD1848_IADDR) & SP_IN_INIT)
  406                                         timeout--;
  407                         }
  408         }
  409         ad1848_reset(sc);
  410 
  411         /* Set default gains */
  412         ad1848_set_rec_gain(sc, &vol_mid);
  413         ad1848_set_channel_gain(sc, AD1848_DAC_CHANNEL, &vol_mid);
  414         ad1848_set_channel_gain(sc, AD1848_MONITOR_CHANNEL, &vol_0);
  415         ad1848_set_channel_gain(sc, AD1848_AUX1_CHANNEL, &vol_mid);     /* CD volume */
  416         sc->mute[AD1848_MONITOR_CHANNEL] = MUTE_ALL;
  417         if (sc->mode >= 2
  418 #if AD1845_HACK
  419             && sc->is_ad1845 == 0
  420 #endif
  421                 ) {
  422                 ad1848_set_channel_gain(sc, AD1848_AUX2_CHANNEL, &vol_mid); /* CD volume */
  423                 ad1848_set_channel_gain(sc, AD1848_LINE_CHANNEL, &vol_mid);
  424                 ad1848_set_channel_gain(sc, AD1848_MONO_CHANNEL, &vol_0);
  425                 sc->mute[AD1848_MONO_CHANNEL] = MUTE_ALL;
  426         } else
  427                 ad1848_set_channel_gain(sc, AD1848_AUX2_CHANNEL, &vol_0);
  428 
  429         /* Set default port */
  430         ad1848_set_rec_port(sc, MIC_IN_PORT);
  431 
  432         printf(": %s", sc->chip_name);
  433 }
  434 
  435 /*
  436  * Various routines to interface to higher level audio driver
  437  */
  438 static const struct ad1848_mixerinfo {
  439         int  left_reg;
  440         int  right_reg;
  441         int  atten_bits;
  442         int  atten_mask;
  443 } mixer_channel_info[] =
  444 {
  445   { SP_LEFT_AUX2_CONTROL, SP_RIGHT_AUX2_CONTROL, AUX_INPUT_ATTEN_BITS,
  446     AUX_INPUT_ATTEN_MASK },
  447   { SP_LEFT_AUX1_CONTROL, SP_RIGHT_AUX1_CONTROL, AUX_INPUT_ATTEN_BITS,
  448     AUX_INPUT_ATTEN_MASK },
  449   { SP_LEFT_OUTPUT_CONTROL, SP_RIGHT_OUTPUT_CONTROL,
  450     OUTPUT_ATTEN_BITS, OUTPUT_ATTEN_MASK },
  451   { CS_LEFT_LINE_CONTROL, CS_RIGHT_LINE_CONTROL, LINE_INPUT_ATTEN_BITS,
  452     LINE_INPUT_ATTEN_MASK },
  453   { CS_MONO_IO_CONTROL, 0, MONO_INPUT_ATTEN_BITS, MONO_INPUT_ATTEN_MASK },
  454   { CS_MONO_IO_CONTROL, 0, 0, 0 },
  455   { SP_DIGITAL_MIX, 0, OUTPUT_ATTEN_BITS, MIX_ATTEN_MASK }
  456 };
  457 
  458 /*
  459  *  This function doesn't set the mute flags but does use them.
  460  *  The mute flags reflect the mutes that have been applied by the user.
  461  *  However, the driver occasionally wants to mute devices (e.g. when chaing
  462  *  sampling rate). These operations should not affect the mute flags.
  463  */
  464 
  465 void
  466 ad1848_mute_channel(struct ad1848_softc *sc, int device, int mute)
  467 {
  468         u_char reg;
  469 
  470         reg = ad_read(sc, mixer_channel_info[device].left_reg);
  471 
  472         if (mute & MUTE_LEFT) {
  473                 if (device == AD1848_MONITOR_CHANNEL) {
  474                         if (sc->open_mode & FREAD)
  475                                 ad1848_mute_wave_output(sc, WAVE_UNMUTE1, 0);
  476                         ad_write(sc, mixer_channel_info[device].left_reg,
  477                                  reg & ~DIGITAL_MIX1_ENABLE);
  478                 } else if (device == AD1848_OUT_CHANNEL)
  479                         ad_write(sc, mixer_channel_info[device].left_reg,
  480                                  reg | MONO_OUTPUT_MUTE);
  481                 else
  482                         ad_write(sc, mixer_channel_info[device].left_reg,
  483                                  reg | 0x80);
  484         } else if (!(sc->mute[device] & MUTE_LEFT)) {
  485                 if (device == AD1848_MONITOR_CHANNEL) {
  486                         ad_write(sc, mixer_channel_info[device].left_reg,
  487                                  reg | DIGITAL_MIX1_ENABLE);
  488                         if (sc->open_mode & FREAD)
  489                                 ad1848_mute_wave_output(sc, WAVE_UNMUTE1, 1);
  490                 } else if (device == AD1848_OUT_CHANNEL)
  491                         ad_write(sc, mixer_channel_info[device].left_reg,
  492                                  reg & ~MONO_OUTPUT_MUTE);
  493                 else
  494                         ad_write(sc, mixer_channel_info[device].left_reg,
  495                                  reg & ~0x80);
  496         }
  497 
  498         if (!mixer_channel_info[device].right_reg)
  499                 return;
  500 
  501         reg = ad_read(sc, mixer_channel_info[device].right_reg);
  502 
  503         if (mute & MUTE_RIGHT) {
  504                 ad_write(sc, mixer_channel_info[device].right_reg, reg | 0x80);
  505         } else if (!(sc->mute[device] & MUTE_RIGHT)) {
  506                 ad_write(sc, mixer_channel_info[device].right_reg, reg &~0x80);
  507         }
  508 }
  509 
  510 int
  511 ad1848_set_channel_gain(struct ad1848_softc *sc, int device,
  512     struct ad1848_volume *gp)
  513 {
  514         const struct ad1848_mixerinfo *info;
  515         u_char reg;
  516         u_int atten;
  517 
  518         info = &mixer_channel_info[device];
  519         sc->gains[device] = *gp;
  520 
  521         atten = (AUDIO_MAX_GAIN - gp->left) * (info->atten_bits + 1) /
  522                 (AUDIO_MAX_GAIN + 1);
  523 
  524         reg = ad_read(sc, info->left_reg) & (info->atten_mask);
  525         if (device == AD1848_MONITOR_CHANNEL)
  526                 reg |= ((atten & info->atten_bits) << 2);
  527         else
  528                 reg |= ((atten & info->atten_bits));
  529 
  530         ad_write(sc, info->left_reg, reg);
  531 
  532         if (!info->right_reg)
  533                 return 0;
  534 
  535         atten = (AUDIO_MAX_GAIN - gp->right) * (info->atten_bits + 1) /
  536                 (AUDIO_MAX_GAIN + 1);
  537         reg = ad_read(sc, info->right_reg);
  538         reg &= info->atten_mask;
  539         ad_write(sc, info->right_reg, (atten & info->atten_bits) | reg);
  540 
  541         return 0;
  542 }
  543 
  544 int
  545 ad1848_get_device_gain(struct ad1848_softc *sc, int device,
  546     struct ad1848_volume *gp)
  547 {
  548 
  549         *gp = sc->gains[device];
  550         return 0;
  551 }
  552 
  553 int
  554 ad1848_get_rec_gain(struct ad1848_softc *sc, struct ad1848_volume *gp)
  555 {
  556 
  557         *gp = sc->rec_gain;
  558         return 0;
  559 }
  560 
  561 int
  562 ad1848_set_rec_gain(struct ad1848_softc *sc, struct ad1848_volume *gp)
  563 {
  564         u_char reg, gain;
  565 
  566         DPRINTF(("ad1848_set_rec_gain: %d:%d\n", gp->left, gp->right));
  567 
  568         sc->rec_gain = *gp;
  569 
  570         gain = (gp->left * (GAIN_22_5 + 1)) / (AUDIO_MAX_GAIN + 1);
  571         reg = ad_read(sc, SP_LEFT_INPUT_CONTROL);
  572         reg &= INPUT_GAIN_MASK;
  573         ad_write(sc, SP_LEFT_INPUT_CONTROL, (gain & 0x0f) | reg);
  574 
  575         gain = (gp->right * (GAIN_22_5 + 1)) / (AUDIO_MAX_GAIN + 1);
  576         reg = ad_read(sc, SP_RIGHT_INPUT_CONTROL);
  577         reg &= INPUT_GAIN_MASK;
  578         ad_write(sc, SP_RIGHT_INPUT_CONTROL, (gain & 0x0f) | reg);
  579 
  580         return 0;
  581 }
  582 
  583 void
  584 ad1848_mute_wave_output(struct ad1848_softc *sc, int mute, int set)
  585 {
  586         int m;
  587 
  588         DPRINTF(("ad1848_mute_wave_output: %d, %d\n", mute, set));
  589 
  590         if (mute == WAVE_MUTE2_INIT) {
  591                 sc->wave_mute_status = 0;
  592                 mute = WAVE_MUTE2;
  593         }
  594         if (set)
  595                 m = sc->wave_mute_status |= mute;
  596         else
  597                 m = sc->wave_mute_status &= ~mute;
  598 
  599         if (m & WAVE_MUTE0 || ((m & WAVE_UNMUTE1) == 0 && m & WAVE_MUTE2))
  600                 ad1848_mute_channel(sc, AD1848_DAC_CHANNEL, MUTE_ALL);
  601         else
  602                 ad1848_mute_channel(sc, AD1848_DAC_CHANNEL,
  603                                             sc->mute[AD1848_DAC_CHANNEL]);
  604 }
  605 
  606 int
  607 ad1848_set_mic_gain(struct ad1848_softc *sc, struct ad1848_volume *gp)
  608 {
  609         u_char reg;
  610 
  611         DPRINTF(("cs4231_set_mic_gain: %d\n", gp->left));
  612 
  613         if (gp->left > AUDIO_MAX_GAIN/2) {
  614                 sc->mic_gain_on = 1;
  615                 reg = ad_read(sc, SP_LEFT_INPUT_CONTROL);
  616                 ad_write(sc, SP_LEFT_INPUT_CONTROL,
  617                          reg | INPUT_MIC_GAIN_ENABLE);
  618         } else {
  619                 sc->mic_gain_on = 0;
  620                 reg = ad_read(sc, SP_LEFT_INPUT_CONTROL);
  621                 ad_write(sc, SP_LEFT_INPUT_CONTROL,
  622                          reg & ~INPUT_MIC_GAIN_ENABLE);
  623         }
  624 
  625         return 0;
  626 }
  627 
  628 int
  629 ad1848_get_mic_gain(struct ad1848_softc *sc, struct ad1848_volume *gp)
  630 {
  631         if (sc->mic_gain_on)
  632                 gp->left = gp->right = AUDIO_MAX_GAIN;
  633         else
  634                 gp->left = gp->right = AUDIO_MIN_GAIN;
  635         return 0;
  636 }
  637 
  638 static const ad1848_devmap_t *
  639 ad1848_mixer_find_dev(const ad1848_devmap_t *map, int cnt, mixer_ctrl_t *cp)
  640 {
  641         int i;
  642 
  643         for (i = 0; i < cnt; i++) {
  644                 if (map[i].id == cp->dev) {
  645                         return (&map[i]);
  646                 }
  647         }
  648         return 0;
  649 }
  650 
  651 int
  652 ad1848_mixer_get_port(struct ad1848_softc *ac, const struct ad1848_devmap *map,
  653     int cnt, mixer_ctrl_t *cp)
  654 {
  655         const ad1848_devmap_t *entry;
  656         struct ad1848_volume vol;
  657         int error;
  658         int dev;
  659 
  660         error = EINVAL;
  661         if (!(entry = ad1848_mixer_find_dev(map, cnt, cp)))
  662                 return ENXIO;
  663 
  664         dev = entry->dev;
  665 
  666         switch (entry->kind) {
  667         case AD1848_KIND_LVL:
  668                 if (cp->type != AUDIO_MIXER_VALUE)
  669                         break;
  670 
  671                 if (dev < AD1848_AUX2_CHANNEL ||
  672                     dev > AD1848_MONITOR_CHANNEL)
  673                         break;
  674 
  675                 if (cp->un.value.num_channels != 1 &&
  676                     mixer_channel_info[dev].right_reg == 0)
  677                         break;
  678 
  679                 error = ad1848_get_device_gain(ac, dev, &vol);
  680                 if (!error)
  681                         ad1848_from_vol(cp, &vol);
  682 
  683                 break;
  684 
  685         case AD1848_KIND_MUTE:
  686                 if (cp->type != AUDIO_MIXER_ENUM) break;
  687 
  688                 cp->un.ord = ac->mute[dev] ? 1 : 0;
  689                 error = 0;
  690                 break;
  691 
  692         case AD1848_KIND_RECORDGAIN:
  693                 if (cp->type != AUDIO_MIXER_VALUE) break;
  694 
  695                 error = ad1848_get_rec_gain(ac, &vol);
  696                 if (!error)
  697                         ad1848_from_vol(cp, &vol);
  698 
  699                 break;
  700 
  701         case AD1848_KIND_MICGAIN:
  702                 if (cp->type != AUDIO_MIXER_VALUE) break;
  703 
  704                 error = ad1848_get_mic_gain(ac, &vol);
  705                 if (!error)
  706                         ad1848_from_vol(cp, &vol);
  707 
  708                 break;
  709 
  710         case AD1848_KIND_RECORDSOURCE:
  711                 if (cp->type != AUDIO_MIXER_ENUM) break;
  712                 cp->un.ord = ad1848_get_rec_port(ac);
  713                 error = 0;
  714                 break;
  715 
  716         default:
  717                 printf ("Invalid kind\n");
  718                 break;
  719         }
  720 
  721         return error;
  722 }
  723 
  724 int
  725 ad1848_mixer_set_port(struct ad1848_softc *ac, const struct ad1848_devmap *map,
  726     int cnt, mixer_ctrl_t *cp)
  727 {
  728         const ad1848_devmap_t *entry;
  729         struct ad1848_volume vol;
  730         int error;
  731         int dev;
  732 
  733         error = EINVAL;
  734         if (!(entry = ad1848_mixer_find_dev(map, cnt, cp)))
  735                 return ENXIO;
  736 
  737         dev = entry->dev;
  738 
  739         switch (entry->kind) {
  740         case AD1848_KIND_LVL:
  741                 if (cp->type != AUDIO_MIXER_VALUE)
  742                         break;
  743 
  744                 if (dev < AD1848_AUX2_CHANNEL ||
  745                     dev > AD1848_MONITOR_CHANNEL)
  746                         break;
  747 
  748                 if (cp->un.value.num_channels != 1 &&
  749                     mixer_channel_info[dev].right_reg == 0)
  750                         break;
  751 
  752                 ad1848_to_vol(cp, &vol);
  753                 error = ad1848_set_channel_gain(ac, dev, &vol);
  754                 break;
  755 
  756         case AD1848_KIND_MUTE:
  757                 if (cp->type != AUDIO_MIXER_ENUM) break;
  758 
  759                 ac->mute[dev] = (cp->un.ord ? MUTE_ALL : 0);
  760                 ad1848_mute_channel(ac, dev, ac->mute[dev]);
  761                 error = 0;
  762                 break;
  763 
  764         case AD1848_KIND_RECORDGAIN:
  765                 if (cp->type != AUDIO_MIXER_VALUE) break;
  766 
  767                 ad1848_to_vol(cp, &vol);
  768                 error = ad1848_set_rec_gain(ac, &vol);
  769                 break;
  770 
  771         case AD1848_KIND_MICGAIN:
  772                 if (cp->type != AUDIO_MIXER_VALUE) break;
  773 
  774                 ad1848_to_vol(cp, &vol);
  775                 error = ad1848_set_mic_gain(ac, &vol);
  776                 break;
  777 
  778         case AD1848_KIND_RECORDSOURCE:
  779                 if (cp->type != AUDIO_MIXER_ENUM) break;
  780 
  781                 error = ad1848_set_rec_port(ac,  cp->un.ord);
  782                 break;
  783 
  784         default:
  785                 printf ("Invalid kind\n");
  786                 break;
  787         }
  788 
  789         return error;
  790 }
  791 
  792 int
  793 ad1848_query_format(void *addr, audio_format_query_t *afp)
  794 {
  795 
  796         return audio_query_format(ad1848_formats, AD1848_NFORMATS, afp);
  797 }
  798 
  799 int
  800 ad1848_set_format(void *addr, int setmode,
  801     const audio_params_t *p, const audio_params_t *r,
  802     audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
  803 {
  804         struct ad1848_softc *sc;
  805         int rate;
  806         int error;
  807 
  808         /* *p and *r are the identical because !AUDIO_PROP_INDEPENDENT. */
  809         DPRINTF(("%s: %u %u %u %u\n", __func__,
  810             p->encoding, p->precision, p->channels, p->sample_rate));
  811 
  812         sc = addr;
  813 
  814         rate = p->sample_rate;
  815         error = ad1848_set_speed(sc, &rate);
  816         if (error)
  817                 return error;
  818 
  819         sc->format_bits = FMT_TWOS_COMP >> 5;
  820         sc->channels = p->channels;
  821         sc->precision = p->precision;
  822         sc->need_commit = 1;
  823 
  824         DPRINTF(("%s succeeded\n", __func__));
  825         return 0;
  826 }
  827 
  828 int
  829 ad1848_set_rec_port(struct ad1848_softc *sc, int port)
  830 {
  831         u_char inp, reg;
  832 
  833         DPRINTF(("ad1848_set_rec_port: 0x%x\n", port));
  834 
  835         if (port == MIC_IN_PORT)
  836                 inp = MIC_INPUT;
  837         else if (port == LINE_IN_PORT)
  838                 inp = LINE_INPUT;
  839         else if (port == DAC_IN_PORT)
  840                 inp = MIXED_DAC_INPUT;
  841         else if (sc->mode >= 2 && port == AUX1_IN_PORT)
  842                 inp = AUX_INPUT;
  843         else
  844                 return EINVAL;
  845 
  846         reg = ad_read(sc, SP_LEFT_INPUT_CONTROL);
  847         reg &= INPUT_SOURCE_MASK;
  848         ad_write(sc, SP_LEFT_INPUT_CONTROL, (inp|reg));
  849 
  850         reg = ad_read(sc, SP_RIGHT_INPUT_CONTROL);
  851         reg &= INPUT_SOURCE_MASK;
  852         ad_write(sc, SP_RIGHT_INPUT_CONTROL, (inp|reg));
  853 
  854         sc->rec_port = port;
  855 
  856         return 0;
  857 }
  858 
  859 int
  860 ad1848_get_rec_port(struct ad1848_softc *sc)
  861 {
  862         return sc->rec_port;
  863 }
  864 
  865 int
  866 ad1848_open(void *addr, int flags)
  867 {
  868         struct ad1848_softc *sc;
  869         u_char reg;
  870 
  871         sc = addr;
  872         DPRINTF(("ad1848_open: sc=%p\n", sc));
  873 
  874         sc->open_mode = flags;
  875 
  876         /* Enable interrupts */
  877         DPRINTF(("ad1848_open: enable intrs\n"));
  878         reg = ad_read(sc, SP_PIN_CONTROL);
  879         ad_write(sc, SP_PIN_CONTROL, reg | INTERRUPT_ENABLE);
  880 
  881         /* If recording && monitoring, the playback part is also used. */
  882         if (flags & FREAD && sc->mute[AD1848_MONITOR_CHANNEL] == 0)
  883                 ad1848_mute_wave_output(sc, WAVE_UNMUTE1, 1);
  884 
  885 #ifdef AUDIO_DEBUG
  886         if (ad1848debug)
  887                 ad1848_dump_regs(sc);
  888 #endif
  889 
  890         return 0;
  891 }
  892 
  893 void
  894 ad1848_close(void *addr)
  895 {
  896         struct ad1848_softc *sc;
  897         u_char reg;
  898 
  899         sc = addr;
  900         sc->open_mode = 0;
  901 
  902         ad1848_mute_wave_output(sc, WAVE_UNMUTE1, 0);
  903 
  904         /* Disable interrupts */
  905         DPRINTF(("ad1848_close: disable intrs\n"));
  906         reg = ad_read(sc, SP_PIN_CONTROL);
  907         ad_write(sc, SP_PIN_CONTROL, reg & ~INTERRUPT_ENABLE);
  908 
  909 #ifdef AUDIO_DEBUG
  910         if (ad1848debug)
  911                 ad1848_dump_regs(sc);
  912 #endif
  913 }
  914 
  915 /*
  916  * Lower-level routines
  917  */
  918 int
  919 ad1848_commit_settings(void *addr)
  920 {
  921         struct ad1848_softc *sc;
  922         int timeout;
  923         u_char fs;
  924 
  925         sc = addr;
  926         if (!sc->need_commit)
  927                 return 0;
  928 
  929         mutex_spin_enter(&sc->sc_intr_lock);
  930 
  931         ad1848_mute_wave_output(sc, WAVE_MUTE0, 1);
  932 
  933         ad_set_MCE(sc, 1);      /* Enables changes to the format select reg */
  934 
  935         fs = sc->speed_bits | (sc->format_bits << 5);
  936 
  937         if (sc->channels == 2)
  938                 fs |= FMT_STEREO;
  939 
  940         /*
  941          * OPL3-SA2 (YMF711) is sometimes busy here.
  942          * Wait until it becomes ready.
  943          */
  944         for (timeout = 0;
  945             timeout < 1000 && ADREAD(sc, AD1848_IADDR) & SP_IN_INIT; timeout++)
  946                 delay(10);
  947 
  948         ad_write(sc, SP_CLOCK_DATA_FORMAT, fs);
  949 
  950         /*
  951          * If mode >= 2 (CS4231), set I28 also.
  952          * It's the capture format register.
  953          */
  954         if (sc->mode >= 2) {
  955                 /*
  956                  * Gravis Ultrasound MAX SDK sources says something about
  957                  * errata sheets, with the implication that these inb()s
  958                  * are necessary.
  959                  */
  960                 (void)ADREAD(sc, AD1848_IDATA);
  961                 (void)ADREAD(sc, AD1848_IDATA);
  962                 /* Write to I8 starts resynchronization. Wait for completion. */
  963                 timeout = 100000;
  964                 while (timeout > 0 && ADREAD(sc, AD1848_IADDR) == SP_IN_INIT)
  965                         timeout--;
  966 
  967                 ad_write(sc, CS_REC_FORMAT, fs);
  968                 (void)ADREAD(sc, AD1848_IDATA);
  969                 (void)ADREAD(sc, AD1848_IDATA);
  970                 /* Now wait for resync for capture side of the house */
  971         }
  972         /*
  973          * Write to I8 starts resynchronization. Wait until it completes.
  974          */
  975         timeout = 100000;
  976         while (timeout > 0 && ADREAD(sc, AD1848_IADDR) == SP_IN_INIT) {
  977                 delay(10);
  978                 timeout--;
  979         }
  980 
  981         if (ADREAD(sc, AD1848_IADDR) == SP_IN_INIT)
  982                 printf("ad1848_commit: Auto calibration timed out\n");
  983 
  984         /*
  985          * Starts the calibration process and
  986          * enters playback mode after it.
  987          */
  988         ad_set_MCE(sc, 0);
  989         wait_for_calibration(sc);
  990 
  991         ad1848_mute_wave_output(sc, WAVE_MUTE0, 0);
  992 
  993         mutex_spin_exit(&sc->sc_intr_lock);
  994 
  995         sc->need_commit = 0;
  996 
  997         return 0;
  998 }
  999 
 1000 void
 1001 ad1848_reset(struct ad1848_softc *sc)
 1002 {
 1003         u_char r;
 1004 
 1005         DPRINTF(("ad1848_reset\n"));
 1006 
 1007         /* Clear the PEN and CEN bits */
 1008         r = ad_read(sc, SP_INTERFACE_CONFIG);
 1009         r &= ~(CAPTURE_ENABLE | PLAYBACK_ENABLE);
 1010         ad_write(sc, SP_INTERFACE_CONFIG, r);
 1011 
 1012         if (sc->mode >= 2) {
 1013                 ADWRITE(sc, AD1848_IADDR, CS_IRQ_STATUS);
 1014                 ADWRITE(sc, AD1848_IDATA, 0);
 1015         }
 1016         /* Clear interrupt status */
 1017         ADWRITE(sc, AD1848_STATUS, 0);
 1018 #ifdef AUDIO_DEBUG
 1019         if (ad1848debug)
 1020                 ad1848_dump_regs(sc);
 1021 #endif
 1022 }
 1023 
 1024 int
 1025 ad1848_set_speed(struct ad1848_softc *sc, u_int *argp)
 1026 {
 1027         /*
 1028          * The sampling speed is encoded in the least significant nible of I8.
 1029          * The LSB selects the clock source (0=24.576 MHz, 1=16.9344 MHz) and
 1030          * other three bits select the divisor (indirectly):
 1031          *
 1032          * The available speeds are in the following table. Keep the speeds in
 1033          * the increasing order.
 1034          */
 1035         typedef struct {
 1036                 int     speed;
 1037                 u_char  bits;
 1038         } speed_struct;
 1039         u_long arg;
 1040 
 1041         static const speed_struct speed_table[] =  {
 1042                 {5510, (0 << 1) | 1},
 1043                 {5510, (0 << 1) | 1},
 1044                 {6620, (7 << 1) | 1},
 1045                 {8000, (0 << 1) | 0},
 1046                 {9600, (7 << 1) | 0},
 1047                 {11025, (1 << 1) | 1},
 1048                 {16000, (1 << 1) | 0},
 1049                 {18900, (2 << 1) | 1},
 1050                 {22050, (3 << 1) | 1},
 1051                 {27420, (2 << 1) | 0},
 1052                 {32000, (3 << 1) | 0},
 1053                 {33075, (6 << 1) | 1},
 1054                 {37800, (4 << 1) | 1},
 1055                 {44100, (5 << 1) | 1},
 1056                 {48000, (6 << 1) | 0}
 1057         };
 1058 
 1059         int i, n, selected;
 1060 
 1061         arg = *argp;
 1062         selected = -1;
 1063         n = sizeof(speed_table) / sizeof(speed_struct);
 1064 
 1065         if (arg < speed_table[0].speed)
 1066                 selected = 0;
 1067         if (arg > speed_table[n - 1].speed)
 1068                 selected = n - 1;
 1069 
 1070         for (i = 1 /*really*/ ; selected == -1 && i < n; i++)
 1071                 if (speed_table[i].speed == arg)
 1072                         selected = i;
 1073                 else if (speed_table[i].speed > arg) {
 1074                         int diff1, diff2;
 1075 
 1076                         diff1 = arg - speed_table[i - 1].speed;
 1077                         diff2 = speed_table[i].speed - arg;
 1078 
 1079                         if (diff1 < diff2)
 1080                                 selected = i - 1;
 1081                         else
 1082                                 selected = i;
 1083                 }
 1084 
 1085         if (selected == -1) {
 1086                 printf("ad1848: Can't find speed???\n");
 1087                 selected = 3;
 1088         }
 1089 
 1090         sc->speed_bits = speed_table[selected].bits;
 1091         sc->need_commit = 1;
 1092         *argp = speed_table[selected].speed;
 1093 
 1094         return 0;
 1095 }
 1096 
 1097 /*
 1098  * Halt I/O
 1099  */
 1100 int
 1101 ad1848_halt_output(void *addr)
 1102 {
 1103         struct ad1848_softc *sc;
 1104         u_char reg;
 1105 
 1106         DPRINTF(("ad1848: ad1848_halt_output\n"));
 1107         sc = addr;
 1108         reg = ad_read(sc, SP_INTERFACE_CONFIG);
 1109         ad_write(sc, SP_INTERFACE_CONFIG, reg & ~PLAYBACK_ENABLE);
 1110 
 1111         return 0;
 1112 }
 1113 
 1114 int
 1115 ad1848_halt_input(void *addr)
 1116 {
 1117         struct ad1848_softc *sc;
 1118         u_char reg;
 1119 
 1120         DPRINTF(("ad1848: ad1848_halt_input\n"));
 1121         sc = addr;
 1122         reg = ad_read(sc, SP_INTERFACE_CONFIG);
 1123         ad_write(sc, SP_INTERFACE_CONFIG, reg & ~CAPTURE_ENABLE);
 1124 
 1125         return 0;
 1126 }
 1127 
 1128 void
 1129 ad1848_get_locks(void *addr, kmutex_t **intr, kmutex_t **thread)
 1130 {
 1131         struct ad1848_softc *sc;
 1132 
 1133         sc = addr;
 1134         *intr = &sc->sc_intr_lock;
 1135         *thread = &sc->sc_lock;
 1136 }
 1137 
 1138 void
 1139 ad1848_init_locks(struct ad1848_softc *sc, int ipl)
 1140 {
 1141 
 1142         mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
 1143         mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, ipl);
 1144 }
 1145 
 1146 void
 1147 ad1848_destroy_locks(struct ad1848_softc *sc)
 1148 {
 1149 
 1150         mutex_destroy(&sc->sc_lock);
 1151         mutex_destroy(&sc->sc_intr_lock);
 1152 }

Cache object: 28be580e31ae6d5911260b9b39432dd9


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