LCOV - code coverage report
Current view: top level - dev/pci - envy.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 1116 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 92 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: envy.c,v 1.73 2018/09/03 05:37:32 miko Exp $  */
       2             : /*
       3             :  * Copyright (c) 2007 Alexandre Ratchov <alex@caoua.org>
       4             :  *
       5             :  * Permission to use, copy, modify, and distribute this software for any
       6             :  * purpose with or without fee is hereby granted, provided that the above
       7             :  * copyright notice and this permission notice appear in all copies.
       8             :  *
       9             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      10             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      11             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      12             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      13             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      14             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      15             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      16             :  */
      17             : 
      18             : /*
      19             :  * TODO:
      20             :  *
      21             :  * - add nspdin, nspdout, to struct envy_card
      22             :  *
      23             :  * - use eeprom version rather isht flag
      24             :  *
      25             :  * - implement HT mixer, midi uart, spdif, init ADC/DACs for >48kHz modes
      26             :  *
      27             :  */
      28             : 
      29             : #include "midi.h"
      30             : #include <sys/param.h>
      31             : #include <sys/systm.h>
      32             : #include <sys/device.h>
      33             : #include <sys/audioio.h>
      34             : #include <sys/malloc.h>
      35             : #include <sys/kernel.h>
      36             : #include <dev/audio_if.h>
      37             : #include <dev/midi_if.h>
      38             : #include <dev/ic/ac97.h>
      39             : #include <dev/pci/pcivar.h>
      40             : #include <dev/pci/pcidevs.h>
      41             : #include <dev/pci/envyvar.h>
      42             : #include <dev/pci/envyreg.h>
      43             : #include <machine/bus.h>
      44             : #include <uvm/uvm.h>
      45             : 
      46             : #ifdef ENVY_DEBUG
      47             : #define DPRINTF(...) do { if (envydebug) printf(__VA_ARGS__); } while(0)
      48             : #define DPRINTFN(n, ...) do { if (envydebug > (n)) printf(__VA_ARGS__); } while(0)
      49             : int envydebug = 1;
      50             : #else
      51             : #define DPRINTF(...) do {} while(0)
      52             : #define DPRINTFN(n, ...) do {} while(0)
      53             : #endif
      54             : #define DEVNAME(sc) ((sc)->dev.dv_xname)
      55             : 
      56             : int  envymatch(struct device *, void *, void *);
      57             : void envyattach(struct device *, struct device *, void *);
      58             : int  envydetach(struct device *, int);
      59             : int  envyactivate(struct device *, int);
      60             : 
      61             : int  envy_ccs_read(struct envy_softc *, int);
      62             : void envy_ccs_write(struct envy_softc *, int, int);
      63             : int  envy_mt_read_1(struct envy_softc *, int);
      64             : void envy_mt_write_1(struct envy_softc *, int, int);
      65             : int  envy_mt_read_2(struct envy_softc *, int);
      66             : void envy_mt_write_2(struct envy_softc *, int, int);
      67             : int  envy_mt_read_4(struct envy_softc *, int);
      68             : void envy_mt_write_4(struct envy_softc *, int, int);
      69             : int  envy_cci_read(struct envy_softc *, int);
      70             : void envy_cci_write(struct envy_softc *, int, int);
      71             : void envy_i2c_wait(struct envy_softc *);
      72             : int  envy_i2c_read(struct envy_softc *, int, int);
      73             : void envy_i2c_write(struct envy_softc *, int, int, int);
      74             : int  envy_gpio_getstate(struct envy_softc *);
      75             : void envy_gpio_setstate(struct envy_softc *, int);
      76             : int  envy_gpio_getmask(struct envy_softc *);
      77             : void envy_gpio_setmask(struct envy_softc *, int);
      78             : int  envy_gpio_getdir(struct envy_softc *);
      79             : void envy_gpio_setdir(struct envy_softc *, int);
      80             : void envy_gpio_i2c_start_bit(struct envy_softc *, int, int);
      81             : void envy_gpio_i2c_stop_bit(struct envy_softc *, int, int);
      82             : void envy_gpio_i2c_byte_out(struct envy_softc *, int, int, int);
      83             : int  envy_eeprom_gpioxxx(struct envy_softc *, int);
      84             : void envy_midi_wait(struct envy_softc *);
      85             : void envy_reset(struct envy_softc *);
      86             : int  envy_codec_read(struct envy_softc *, int, int);
      87             : void envy_codec_write(struct envy_softc *, int, int, int);
      88             : void envy_pintr(struct envy_softc *);
      89             : int  envy_intr(void *);
      90             : 
      91             : int envy_lineout_getsrc(struct envy_softc *, int);
      92             : void envy_lineout_setsrc(struct envy_softc *, int, int);
      93             : int envy_spdout_getsrc(struct envy_softc *, int);
      94             : void envy_spdout_setsrc(struct envy_softc *, int, int);
      95             : void envy_mon_getvol(struct envy_softc *, int, int, int *);
      96             : void envy_mon_setvol(struct envy_softc *, int, int, int);
      97             : 
      98             : int envy_open(void *, int);
      99             : void envy_close(void *);
     100             : void *envy_allocm(void *, int, size_t, int, int);
     101             : void envy_freem(void *, void *, int);
     102             : int envy_set_params(void *, int, int, struct audio_params *,
     103             :     struct audio_params *);
     104             : int envy_round_blocksize(void *, int);
     105             : int envy_trigger_output(void *, void *, void *, int,
     106             :     void (*)(void *), void *, struct audio_params *);
     107             : int envy_trigger_input(void *, void *, void *, int,
     108             :     void (*)(void *), void *, struct audio_params *);
     109             : int envy_halt_output(void *);
     110             : int envy_halt_input(void *);
     111             : int envy_query_devinfo(void *, struct mixer_devinfo *);
     112             : int envy_get_port(void *, struct mixer_ctrl *);
     113             : int envy_set_port(void *, struct mixer_ctrl *);
     114             : int envy_get_props(void *);
     115             : #if NMIDI > 0
     116             : int envy_midi_open(void *, int, void (*)(void *, int),
     117             :     void (*)(void *), void *);
     118             : void envy_midi_close(void *);
     119             : int envy_midi_output(void *, int);
     120             : void envy_midi_getinfo(void *, struct midi_info *);
     121             : #endif
     122             : 
     123             : int  envy_ac97_wait(struct envy_softc *);
     124             : int  envy_ac97_attach_codec(void *, struct ac97_codec_if *);
     125             : int  envy_ac97_read_codec(void *, u_int8_t, u_int16_t *);
     126             : int  envy_ac97_write_codec(void *, u_int8_t, u_int16_t);
     127             : void envy_ac97_reset_codec(void *);
     128             : enum ac97_host_flags envy_ac97_flags_codec(void *);
     129             : 
     130             : void delta_init(struct envy_softc *);
     131             : void delta_codec_write(struct envy_softc *, int, int, int);
     132             : 
     133             : void ap192k_init(struct envy_softc *);
     134             : void ap192k_codec_write(struct envy_softc *, int, int, int);
     135             : 
     136             : void ewx_codec_write(struct envy_softc *, int, int, int);
     137             : 
     138             : void revo51_init(struct envy_softc *);
     139             : void revo51_codec_write(struct envy_softc *, int, int, int);
     140             : 
     141             : void envy_ac97_init(struct envy_softc *);
     142             : void dynex_sc51_init(struct envy_softc *);
     143             : 
     144             : void julia_init(struct envy_softc *);
     145             : void julia_codec_write(struct envy_softc *, int, int, int);
     146             : 
     147             : void unkenvy_init(struct envy_softc *);
     148             : void unkenvy_codec_write(struct envy_softc *, int, int, int);
     149             : int unkenvy_codec_ndev(struct envy_softc *);
     150             : 
     151             : int ak4524_dac_ndev(struct envy_softc *);
     152             : void ak4524_dac_devinfo(struct envy_softc *, struct mixer_devinfo *, int);
     153             : void ak4524_dac_get(struct envy_softc *, struct mixer_ctrl *, int);
     154             : int ak4524_dac_set(struct envy_softc *, struct mixer_ctrl *, int);
     155             : int ak4524_adc_ndev(struct envy_softc *);
     156             : void ak4524_adc_devinfo(struct envy_softc *, struct mixer_devinfo *, int);
     157             : void ak4524_adc_get(struct envy_softc *, struct mixer_ctrl *, int);
     158             : int ak4524_adc_set(struct envy_softc *, struct mixer_ctrl *, int);
     159             : 
     160             : int ak4358_dac_ndev(struct envy_softc *);
     161             : void ak4358_dac_devinfo(struct envy_softc *, struct mixer_devinfo *, int);
     162             : void ak4358_dac_get(struct envy_softc *, struct mixer_ctrl *, int);
     163             : int ak4358_dac_set(struct envy_softc *, struct mixer_ctrl *, int);
     164             : 
     165             : int ak5365_adc_ndev(struct envy_softc *);
     166             : void ak5365_adc_devinfo(struct envy_softc *, struct mixer_devinfo *, int);
     167             : void ak5365_adc_get(struct envy_softc *, struct mixer_ctrl *, int);
     168             : int ak5365_adc_set(struct envy_softc *, struct mixer_ctrl *, int);
     169             : 
     170             : struct cfattach envy_ca = {
     171             :         sizeof(struct envy_softc), envymatch, envyattach, envydetach,
     172             :         envyactivate
     173             : };
     174             : 
     175             : struct cfdriver envy_cd = {
     176             :         NULL, "envy", DV_DULL
     177             : };
     178             : 
     179             : struct audio_hw_if envy_hw_if = {
     180             :         envy_open,              /* open */
     181             :         envy_close,             /* close */
     182             :         envy_set_params,        /* set_params */
     183             :         envy_round_blocksize,   /* round_blocksize */
     184             :         NULL,                   /* commit_settings */
     185             :         NULL,                   /* init_output */
     186             :         NULL,                   /* init_input */
     187             :         NULL,                   /* start_output */
     188             :         NULL,                   /* start_input */
     189             :         envy_halt_output,       /* halt_output */
     190             :         envy_halt_input,        /* halt_input */
     191             :         NULL,                   /* speaker_ctl */
     192             :         NULL,                   /* setfd */
     193             :         envy_set_port,          /* set_port */
     194             :         envy_get_port,          /* get_port */
     195             :         envy_query_devinfo,     /* query_devinfo */
     196             :         envy_allocm,            /* malloc */
     197             :         envy_freem,             /* free */
     198             :         NULL,                   /* round_buffersize */
     199             :         envy_get_props,         /* get_props */
     200             :         envy_trigger_output,    /* trigger_output */
     201             :         envy_trigger_input      /* trigger_input */
     202             : };
     203             : 
     204             : #if NMIDI > 0
     205             : struct midi_hw_if envy_midi_hw_if = {
     206             :         envy_midi_open,
     207             :         envy_midi_close,
     208             :         envy_midi_output,
     209             :         NULL,                           /* flush */
     210             :         envy_midi_getinfo,
     211             :         NULL                            /* ioctl */
     212             : };
     213             : #endif
     214             : 
     215             : struct pci_matchid envy_matchids[] = {
     216             :         { PCI_VENDOR_ICENSEMBLE, PCI_PRODUCT_ICENSEMBLE_ICE1712 },
     217             :         { PCI_VENDOR_ICENSEMBLE, PCI_PRODUCT_ICENSEMBLE_VT172x }
     218             : };
     219             : 
     220             : /*
     221             :  * correspondence between rates (in frames per second)
     222             :  * and values of rate register
     223             :  */
     224             : struct {
     225             :         int rate, reg;
     226             : } envy_rates[] = {
     227             :         { 8000, 0x6}, { 9600, 0x3}, {11025, 0xa}, {12000, 2}, {16000, 5},
     228             :         {22050, 0x9}, {24000, 0x1}, {32000, 0x4}, {44100, 8}, {48000, 0},
     229             :         {64000, 0xf}, {88200, 0xb}, {96000, 0x7}, {-1, -1}
     230             : };
     231             : 
     232             : /*
     233             :  * ESI Julia cards don't have EEPROM, use this copy
     234             :  */
     235             : static unsigned char julia_eeprom[ENVY_EEPROM_MAXSZ] = {
     236             :         /* gpio mask/dir/state is from linux */
     237             :         0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     238             :         0x20, 0x80, 0xf8, 0xc3,
     239             :         0x9f, 0xff, 0x7f,
     240             :         0x90, 0xff, 0x7f,
     241             :         0x66, 0x00, 0x00
     242             : };
     243             : 
     244             : struct envy_codec ak4524_dac = {
     245             :         "ak4524 dac", ak4524_dac_ndev, ak4524_dac_devinfo, ak4524_dac_get, ak4524_dac_set
     246             : }, ak4524_adc = {
     247             :         "ak4524 adc", ak4524_adc_ndev, ak4524_adc_devinfo, ak4524_adc_get, ak4524_adc_set
     248             : }, ak4358_dac = {
     249             :         "ak4358 dac", ak4358_dac_ndev, ak4358_dac_devinfo, ak4358_dac_get, ak4358_dac_set
     250             : }, ak5365_adc = {
     251             :         "ak5365 adc", ak5365_adc_ndev, ak5365_adc_devinfo, ak5365_adc_get, ak5365_adc_set
     252             : }, unkenvy_codec = {
     253             :         "unknown codec", unkenvy_codec_ndev, NULL, NULL, NULL
     254             : };
     255             : 
     256             : /*
     257             :  * array with vendor/product sub-IDs to card info
     258             :  */
     259             : struct envy_card envy_cards[] = {
     260             :         {
     261             :                 PCI_ID_CODE(0x1412, 0xd630),
     262             :                 "M-Audio Delta 1010",
     263             :                 8, &ak4524_adc, 8, &ak4524_dac, 1,
     264             :                 delta_init,
     265             :                 delta_codec_write,
     266             :                 NULL
     267             :         }, {
     268             :                 PCI_ID_CODE(0x1412, 0xd632),
     269             :                 "M-Audio Delta 66",
     270             :                 4, &ak4524_adc, 4, &ak4524_dac, 0,
     271             :                 delta_init,
     272             :                 delta_codec_write,
     273             :                 NULL
     274             :         }, {
     275             : #define ENVY_SUBID_DELTA44      (PCI_ID_CODE(0x1412, 0xd633))
     276             :                 PCI_ID_CODE(0x1412, 0xd633),
     277             :                 "M-Audio Delta 44",
     278             :                 4, &ak4524_adc, 4, &ak4524_dac, 0,
     279             :                 delta_init,
     280             :                 delta_codec_write,
     281             :                 NULL
     282             :         }, {
     283             :                 PCI_ID_CODE(0x1412, 0xd63b),
     284             :                 "M-Audio Delta 1010LT",
     285             :                 8, &ak4524_adc, 8, &ak4524_dac, 1,
     286             :                 delta_init,
     287             :                 delta_codec_write,
     288             :                 NULL
     289             :         }, {
     290             :                 PCI_ID_CODE(0x1412, 0xd634),
     291             :                 "M-Audio Audiophile 2496",
     292             :                 2, &ak4524_adc, 2, &ak4524_dac, 1,
     293             :                 delta_init,
     294             :                 delta_codec_write,
     295             :                 NULL
     296             :         }, {
     297             :                 PCI_ID_CODE(0x153b, 0x1130),
     298             :                 "Terratec EWX 24/96",
     299             :                 2, &ak4524_adc, 2, &ak4524_dac, 1,
     300             :                 delta_init,
     301             :                 ewx_codec_write,
     302             :                 NULL
     303             :         }, {
     304             :                 0,
     305             :                 "unknown 1712-based card",
     306             :                 8, &unkenvy_codec, 8, &unkenvy_codec, 1,
     307             :                 unkenvy_init,
     308             :                 unkenvy_codec_write
     309             :         }
     310             : }, envy_cards_ht[] = {
     311             :         {
     312             :                 PCI_ID_CODE(0x3031, 0x4553),
     313             :                 "ESI Julia",
     314             :                 2, &unkenvy_codec, 2, &ak4358_dac, 1,
     315             :                 julia_init,
     316             :                 julia_codec_write,
     317             :                 julia_eeprom
     318             :         }, {
     319             :                 PCI_ID_CODE(0x1412, 0x3632),
     320             :                 "M-Audio Audiophile 192k",
     321             :                 2, &unkenvy_codec, 2, &ak4358_dac, 1,
     322             :                 ap192k_init,
     323             :                 ap192k_codec_write
     324             :         }, {
     325             :                 PCI_ID_CODE(0x1412, 0x3631),
     326             :                 "M-Audio Revolution 5.1",
     327             :                 2, &ak5365_adc, 6, &ak4358_dac, 1,
     328             :                 revo51_init,
     329             :                 revo51_codec_write
     330             :         }, {
     331             :                 PCI_ID_CODE(0x1412, 0x2403),
     332             :                 "VIA Tremor 5.1",
     333             :                 2, &unkenvy_codec, 6, &unkenvy_codec, 1,
     334             :                 envy_ac97_init,
     335             :                 unkenvy_codec_write
     336             :         }, {
     337             :                 PCI_ID_CODE(0x14c3, 0x1705),
     338             :                 "Dynex DX-SC51",
     339             :                 2, &unkenvy_codec, 6, &unkenvy_codec, 0,
     340             :                 dynex_sc51_init,
     341             :                 unkenvy_codec_write
     342             :         }, {
     343             :                 0,
     344             :                 "unknown 1724-based card",
     345             :                 2, &unkenvy_codec, 8, &unkenvy_codec, 1,
     346             :                 unkenvy_init,
     347             :                 unkenvy_codec_write
     348             :         }
     349             : };
     350             : 
     351             : 
     352             : /*
     353             :  * M-Audio Delta specific code
     354             :  */
     355             : 
     356             : void
     357           0 : delta_init(struct envy_softc *sc)
     358             : {
     359             :         int dev;
     360             : 
     361           0 :         for (dev = 0; dev < sc->card->noch / 2; dev++) {
     362           0 :                 envy_codec_write(sc, dev, AK4524_RST, 0x0);
     363           0 :                 delay(300);
     364           0 :                 envy_codec_write(sc, dev, AK4524_RST,
     365             :                     AK4524_RST_AD | AK4524_RST_DA);
     366           0 :                 envy_codec_write(sc, dev, AK4524_FMT,
     367             :                     AK4524_FMT_IIS24);
     368           0 :                 sc->shadow[dev][AK4524_DEEMVOL] = AK4524_DEEM_OFF;
     369           0 :                 sc->shadow[dev][AK4524_ADC_GAIN0] = 0x7f;
     370           0 :                 sc->shadow[dev][AK4524_ADC_GAIN1] = 0x7f;
     371           0 :                 sc->shadow[dev][AK4524_DAC_GAIN0] = 0x7f;
     372           0 :                 sc->shadow[dev][AK4524_DAC_GAIN1] = 0x7f;
     373             :         }
     374           0 : }
     375             : 
     376             : void
     377           0 : delta_codec_write(struct envy_softc *sc, int dev, int addr, int data)
     378             : {
     379             :         int bits, i, reg;
     380             :         int clk, dout, csmask, cs;
     381             : 
     382             :         /*
     383             :          * GPIO pin numbers
     384             :          */
     385           0 :         if (sc->card->subid == ENVY_SUBID_DELTA44) {
     386             :                 clk = 0x20;
     387             :                 dout = 0x10;
     388             :                 csmask = 0xc0;
     389           0 :                 cs = dev ? 0x40 : 0x80;
     390           0 :         } else {
     391             :                 clk = 0x2;
     392             :                 dout = 0x8;
     393             :                 csmask = 0x70;
     394           0 :                 cs = dev << 4;
     395             :         }
     396             : 
     397           0 :         reg = envy_gpio_getstate(sc);
     398           0 :         reg &= ~csmask;
     399           0 :         reg |= cs;
     400           0 :         envy_gpio_setstate(sc, reg);
     401           0 :         delay(1);
     402             : 
     403           0 :         bits  = 0xa000 | (addr << 8) | data;
     404           0 :         for (i = 0; i < 16; i++) {
     405           0 :                 reg &= ~(clk | dout);
     406           0 :                 reg |= (bits & 0x8000) ? dout : 0;
     407           0 :                 envy_gpio_setstate(sc, reg);
     408           0 :                 delay(1);
     409             : 
     410           0 :                 reg |= clk;
     411           0 :                 envy_gpio_setstate(sc, reg);
     412           0 :                 delay(1);
     413           0 :                 bits <<= 1;
     414             :         }
     415             : 
     416           0 :         reg |= csmask;
     417           0 :         envy_gpio_setstate(sc, reg);
     418           0 :         delay(1);
     419           0 : }
     420             : 
     421             : /*
     422             :  * M-Audio Audiophile 192 specific code
     423             :  */
     424             : 
     425             : /*
     426             :  * GPIO pin numbers
     427             :  */
     428             : #define AP192K_GPIO_CLK         0x2
     429             : #define AP192K_GPIO_DOUT        0x8
     430             : #define AP192K_GPIO_CSMASK      0x30
     431             : #define AP192K_GPIO_CS(dev)     ((dev) << 4)
     432             : #define AP192K_GPIO_ADC_PWR     0x800
     433             : #define AP192K_GPIO_ADC_DFSMASK (3 << 9)
     434             : #define AP192K_GPIO_ADC_DFS(v)  ((v) << 9)
     435             : #define AP192K_GPIO_MUTE        0x400000
     436             : 
     437             : void
     438           0 : ap192k_init(struct envy_softc *sc)
     439             : {
     440             :         int i, reg;
     441             : 
     442             :         /* AK4358 */
     443           0 :         envy_codec_write(sc, 0, 0, 0);  /* reset */
     444           0 :         delay(300);
     445           0 :         envy_codec_write(sc, 0, 0, 0x87);       /* i2s mode */
     446           0 :         delay(1);
     447           0 :         for (i = 0; i < sc->card->noch; i++) {
     448           0 :                 sc->shadow[0][AK4358_ATT(i)] = 0xff;
     449             :         }
     450             : 
     451             :         /* AK5385 */
     452           0 :         delay(1);
     453           0 :         reg = envy_gpio_getstate(sc);
     454           0 :         reg &= ~(AP192K_GPIO_ADC_PWR | AP192K_GPIO_ADC_DFSMASK);
     455             :         reg |= AP192K_GPIO_ADC_DFS(0);
     456           0 :         envy_gpio_setstate(sc, reg);
     457           0 :         reg |= AP192K_GPIO_ADC_PWR;
     458           0 :         envy_gpio_setstate(sc, reg);
     459           0 : }
     460             : 
     461             : void
     462           0 : ap192k_codec_write(struct envy_softc *sc, int dev, int addr, int data)
     463             : {
     464             :         int bits, i, reg;
     465             : 
     466           0 :         reg = envy_gpio_getstate(sc);
     467           0 :         reg &= ~AP192K_GPIO_CSMASK;
     468           0 :         reg |=  AP192K_GPIO_CS(dev);
     469           0 :         envy_gpio_setstate(sc, reg);
     470           0 :         delay(1);
     471             : 
     472           0 :         bits  = 0xa000 | (addr << 8) | data;
     473           0 :         for (i = 0; i < 16; i++) {
     474           0 :                 reg &= ~(AP192K_GPIO_CLK | AP192K_GPIO_DOUT);
     475           0 :                 reg |= (bits & 0x8000) ? AP192K_GPIO_DOUT : 0;
     476           0 :                 envy_gpio_setstate(sc, reg);
     477           0 :                 delay(1);
     478             : 
     479           0 :                 reg |= AP192K_GPIO_CLK;
     480           0 :                 envy_gpio_setstate(sc, reg);
     481           0 :                 delay(1);
     482           0 :                 bits <<= 1;
     483             :         }
     484             : 
     485           0 :         reg |= AP192K_GPIO_CSMASK;
     486           0 :         envy_gpio_setstate(sc, reg);
     487           0 :         delay(1);
     488           0 : }
     489             : 
     490             : /*
     491             :  * Terratec EWX specific code
     492             :  */
     493             : 
     494             : /*
     495             :  * GPIO pin numbers
     496             :  */
     497             : #define EWX_GPIO_CSMASK         0x01
     498             : #define EWX_GPIO_DOUT           0x10
     499             : #define EWX_GPIO_CLK            0x20
     500             : 
     501             : void
     502           0 : ewx_codec_write(struct envy_softc *sc, int dev, int addr, int data)
     503             : {
     504             :         int bits, i, reg;
     505             : 
     506           0 :         reg = envy_gpio_getstate(sc);
     507           0 :         reg |= (EWX_GPIO_CSMASK | EWX_GPIO_CLK);
     508           0 :         envy_gpio_setstate(sc, reg);
     509           0 :         delay(1);
     510             : 
     511           0 :         bits = 0xa000 | (addr << 8) | data;
     512           0 :         for (i = 0; i < 16; i++) {
     513           0 :                 reg &= ~(EWX_GPIO_CLK | EWX_GPIO_DOUT);
     514           0 :                 reg |= (bits & 0x8000) ? EWX_GPIO_DOUT : 0;
     515           0 :                 envy_gpio_setstate(sc, reg);
     516           0 :                 delay(1);
     517             : 
     518           0 :                 reg |= EWX_GPIO_CLK;
     519           0 :                 envy_gpio_setstate(sc, reg);
     520           0 :                 delay(1);
     521           0 :                 bits <<= 1;
     522             :         }
     523             : 
     524           0 :         reg &= ~EWX_GPIO_CSMASK;
     525           0 :         envy_gpio_setstate(sc, reg);
     526           0 :         delay(1);
     527             : 
     528           0 :         reg |= EWX_GPIO_CSMASK;
     529           0 :         envy_gpio_setstate(sc, reg);
     530           0 :         delay(1);
     531           0 : }
     532             : 
     533             : 
     534             : /*
     535             :  * M-Audio Revolution 5.1 specific code
     536             :  */
     537             : 
     538             : #define REVO51_GPIO_CLK         0x2
     539             : #define REVO51_GPIO_DOUT        0x8
     540             : #define REVO51_GPIO_CSMASK      0x30
     541             : #define REVO51_GPIO_CS(dev)     ((dev) ? 0x10 : 0x20)
     542             : #define REVO51_MUTE             0x400000
     543             : #define REVO51_PT2258S_SDA      0x40
     544             : #define REVO51_PT2258S_SCL      0x80
     545             : #define REVO51_PT2258S_ADDR     0x80
     546             : #define REVO51_PT2258S_MUTE     6
     547             : 
     548             : void
     549           0 : revo51_init(struct envy_softc *sc)
     550             : {
     551             :         int i, reg;
     552             : 
     553             :         /* AK4358 */
     554           0 :         envy_codec_write(sc, 0, 0, 0);  /* reset */
     555           0 :         delay(300);
     556           0 :         envy_codec_write(sc, 0, 0, 0x87);       /* i2s mode */
     557           0 :         for (i = 0; i < sc->card->noch; i++) {
     558           0 :                 sc->shadow[0][AK4358_ATT(i)] = 0xff;
     559             :         }
     560             : 
     561             :         /* AK5365 */
     562           0 :         envy_codec_write(sc, 1, AK5365_RST, 0); /* reset */
     563           0 :         delay(300);
     564           0 :         envy_codec_write(sc, 1, AK5365_CTRL, AK5365_CTRL_I2S);  /* i2s mode */
     565           0 :         envy_codec_write(sc, 1, AK5365_RST , AK5365_RST_NORM);
     566           0 :         sc->shadow[1][AK5365_ATT(0)] = 0x7f;
     567           0 :         sc->shadow[1][AK5365_ATT(1)] = 0x7f;
     568             : 
     569             :         /* PT2258S */
     570           0 :         envy_codec_write(sc, 2, REVO51_PT2258S_MUTE, 0xc0);     /* reset */
     571           0 :         envy_codec_write(sc, 2, REVO51_PT2258S_MUTE, 0xf9);     /* mute */
     572             : 
     573           0 :         reg = envy_gpio_getstate(sc);
     574           0 :         reg |= REVO51_MUTE;
     575           0 :         envy_gpio_setstate(sc, reg);
     576           0 : }
     577             : 
     578             : void
     579           0 : revo51_codec_write(struct envy_softc *sc, int dev, int addr, int data)
     580             : {
     581             :         int attn, bits, mask, reg;
     582           0 :         int xlat[6] = {0x90, 0x50, 0x10, 0x30, 0x70, 0xb0};
     583             : 
     584             :         /* AK4358 & AK5365 */
     585           0 :         if (dev < 2) {
     586           0 :                 reg = envy_gpio_getstate(sc);
     587           0 :                 reg &= ~REVO51_GPIO_CSMASK;
     588           0 :                 reg |=  REVO51_GPIO_CS(dev);
     589           0 :                 envy_gpio_setstate(sc, reg);
     590           0 :                 delay(1);
     591             : 
     592           0 :                 bits  = 0xa000 | (addr << 8) | data;
     593           0 :                 for (mask = 0x8000; mask != 0; mask >>= 1) {
     594           0 :                         reg &= ~(REVO51_GPIO_CLK | REVO51_GPIO_DOUT);
     595           0 :                         reg |= (bits & mask) ? REVO51_GPIO_DOUT : 0;
     596           0 :                         envy_gpio_setstate(sc, reg);
     597           0 :                         delay(1);
     598             : 
     599           0 :                         reg |= REVO51_GPIO_CLK;
     600           0 :                         envy_gpio_setstate(sc, reg);
     601           0 :                         delay(1);
     602             :                 }
     603             : 
     604           0 :                 reg |= REVO51_GPIO_CSMASK;
     605           0 :                 envy_gpio_setstate(sc, reg);
     606           0 :                 delay(1);
     607           0 :                 return;
     608             :         }
     609             : 
     610             :         /* PT2258S */
     611           0 :         envy_gpio_i2c_start_bit(sc, REVO51_PT2258S_SDA, REVO51_PT2258S_SCL);
     612           0 :         envy_gpio_i2c_byte_out(sc, REVO51_PT2258S_SDA, REVO51_PT2258S_SCL,
     613             :             REVO51_PT2258S_ADDR);
     614             : 
     615           0 :         if (addr == REVO51_PT2258S_MUTE) {
     616           0 :                 envy_gpio_i2c_byte_out(sc, REVO51_PT2258S_SDA,
     617             :                     REVO51_PT2258S_SCL, data);
     618           0 :         } else {
     619             :                 /* 1's digit */
     620           0 :                 attn = data % 10;
     621           0 :                 attn += xlat[addr];
     622           0 :                 envy_gpio_i2c_byte_out(sc, REVO51_PT2258S_SDA,
     623             :                     REVO51_PT2258S_SCL, attn);
     624             : 
     625             :                 /* 10's digit */
     626           0 :                 attn = data / 10;
     627           0 :                 attn += xlat[addr] - 0x10;
     628           0 :                 envy_gpio_i2c_byte_out(sc, REVO51_PT2258S_SDA,
     629             :                     REVO51_PT2258S_SCL, attn);
     630             :         }
     631             : 
     632           0 :         envy_gpio_i2c_stop_bit(sc, REVO51_PT2258S_SDA, REVO51_PT2258S_SCL);
     633           0 : }
     634             : 
     635             : /*
     636             :  * Generic AC'97 initialization
     637             :  */
     638             : 
     639             : void
     640           0 : envy_ac97_init(struct envy_softc *sc)
     641             : {
     642           0 :         sc->isac97 = 1;
     643           0 :         sc->host_if.arg = sc;
     644           0 :         sc->host_if.attach = envy_ac97_attach_codec;
     645           0 :         sc->host_if.read = envy_ac97_read_codec;
     646           0 :         sc->host_if.write = envy_ac97_write_codec;
     647           0 :         sc->host_if.reset = envy_ac97_reset_codec;
     648           0 :         sc->host_if.flags = envy_ac97_flags_codec;
     649             : 
     650           0 :         if (ac97_attach(&sc->host_if) != 0)
     651           0 :                 printf("%s: can't attach ac97\n", DEVNAME(sc));
     652           0 : }
     653             : 
     654             : /*
     655             :  * Dynex
     656             :  */
     657             : 
     658             : void
     659           0 : dynex_sc51_init(struct envy_softc *sc)
     660             : {
     661           0 :         sc->codec_flags |= AC97_HOST_VT1616_DYNEX;
     662           0 :         envy_ac97_init(sc);
     663           0 : }
     664             : 
     665             : /*
     666             :  * ESI Julia specific code
     667             :  */
     668             : 
     669             : void
     670           0 : julia_init(struct envy_softc *sc)
     671             : {
     672             :         int i;
     673             : 
     674           0 :         envy_codec_write(sc, 0, 0, 0);  /* reset */
     675           0 :         delay(300);
     676           0 :         envy_codec_write(sc, 0, 0, 0x87);       /* i2s mode */
     677           0 :         for (i = 0; i < sc->card->noch; i++) {
     678           0 :                 sc->shadow[0][AK4358_ATT(i)] = 0xff;
     679             :         }
     680           0 : }
     681             : 
     682             : void
     683           0 : julia_codec_write(struct envy_softc *sc, int dev, int addr, int data)
     684             : {
     685             : #define JULIA_AK4358_ADDR       0x11
     686           0 :         envy_i2c_write(sc, JULIA_AK4358_ADDR, addr, data);
     687           0 : }
     688             : 
     689             : /*
     690             :  * unknown card, ignore codecs setup and hope it works with the power on
     691             :  * settings
     692             :  */
     693             : 
     694             : void
     695           0 : unkenvy_init(struct envy_softc *sc)
     696             : {
     697           0 : }
     698             : 
     699             : void
     700           0 : unkenvy_codec_write(struct envy_softc *sc, int dev, int addr, int data)
     701             : {
     702           0 : }
     703             : 
     704             : int
     705           0 : unkenvy_codec_ndev(struct envy_softc *sc)
     706             : {
     707           0 :         return 0;
     708             : }
     709             : 
     710             : /*
     711             :  * AK 4358 DAC specific code
     712             :  */
     713             : int
     714           0 : ak4358_dac_ndev(struct envy_softc *sc)
     715             : {
     716             :         /* 1 volume knob per channel */
     717           0 :         return sc->card->noch;
     718             : }
     719             : 
     720             : void
     721           0 : ak4358_dac_devinfo(struct envy_softc *sc, struct mixer_devinfo *dev, int idx)
     722             : {
     723           0 :         dev->type = AUDIO_MIXER_VALUE;
     724           0 :         dev->mixer_class = ENVY_MIX_CLASSOUT;
     725           0 :         dev->un.v.delta = 2;
     726           0 :         dev->un.v.num_channels = 1;
     727           0 :         snprintf(dev->label.name, MAX_AUDIO_DEV_LEN,
     728             :             AudioNline "-%d", idx);
     729           0 :         strlcpy(dev->un.v.units.name, AudioNvolume,
     730             :             MAX_AUDIO_DEV_LEN);
     731           0 : }
     732             : 
     733             : void
     734           0 : ak4358_dac_get(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
     735             : {
     736             :         int val;
     737             : 
     738           0 :         val = envy_codec_read(sc, 0, AK4358_ATT(idx)) & ~AK4358_ATT_EN;
     739           0 :         ctl->un.value.num_channels = 1;
     740           0 :         ctl->un.value.level[0] = 2 * val;
     741           0 : }
     742             : 
     743             : int
     744           0 : ak4358_dac_set(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
     745             : {
     746             :         int val;
     747             : 
     748           0 :         if (ctl->un.value.num_channels != 1)
     749           0 :                 return EINVAL;
     750           0 :         val = ctl->un.value.level[0] / 2;
     751           0 :         envy_codec_write(sc, 0, AK4358_ATT(idx), val | AK4358_ATT_EN);
     752           0 :         return 0;
     753           0 : }
     754             : 
     755             : /*
     756             :  * AK 4524 DAC specific code
     757             :  */
     758             : int
     759           0 : ak4524_dac_ndev(struct envy_softc *sc)
     760             : {
     761             :         /* 1 mute + 2 volume knobs per channel pair */
     762           0 :         return 3 * (sc->card->noch / 2);
     763             : }
     764             : 
     765             : void
     766           0 : ak4524_dac_devinfo(struct envy_softc *sc, struct mixer_devinfo *dev, int idx)
     767             : {
     768             :         int ndev;
     769             : 
     770           0 :         ndev = sc->card->noch;
     771           0 :         if (idx < ndev) {
     772           0 :                 dev->type = AUDIO_MIXER_VALUE;
     773           0 :                 dev->mixer_class = ENVY_MIX_CLASSOUT;
     774           0 :                 dev->un.v.delta = 2;
     775           0 :                 dev->un.v.num_channels = 1;
     776           0 :                 snprintf(dev->label.name, MAX_AUDIO_DEV_LEN,
     777             :                     AudioNline "-%d", idx);
     778           0 :                 strlcpy(dev->un.v.units.name, AudioNvolume,
     779             :                     MAX_AUDIO_DEV_LEN);
     780           0 :         } else {
     781           0 :                 idx -= ndev;
     782           0 :                 dev->type = AUDIO_MIXER_ENUM;
     783           0 :                 dev->mixer_class = ENVY_MIX_CLASSOUT;
     784           0 :                 dev->un.e.member[0].ord = 0;
     785           0 :                 strlcpy(dev->un.e.member[0].label.name, AudioNoff,
     786             :                     MAX_AUDIO_DEV_LEN);
     787           0 :                 dev->un.e.member[1].ord = 1;
     788           0 :                 strlcpy(dev->un.e.member[1].label.name, AudioNon,
     789             :                    MAX_AUDIO_DEV_LEN);
     790           0 :                 dev->un.e.num_mem = 2;
     791           0 :                 snprintf(dev->label.name, MAX_AUDIO_DEV_LEN,
     792           0 :                     AudioNline "-%d:%d_" AudioNmute, 2 * idx, 2 * idx + 1);
     793             :         }
     794           0 : }
     795             : 
     796             : void
     797           0 : ak4524_dac_get(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
     798             : {
     799             :         int val, ndev;
     800             : 
     801           0 :         ndev = sc->card->noch;
     802           0 :         if (idx < ndev) {
     803           0 :                 val = envy_codec_read(sc, idx / 2,
     804           0 :                     (idx % 2) + AK4524_DAC_GAIN0);
     805           0 :                 ctl->un.value.num_channels = 1;
     806           0 :                 ctl->un.value.level[0] = 2 * val;
     807           0 :         } else {
     808           0 :                 idx -= ndev;
     809           0 :                 val = envy_codec_read(sc, idx, AK4524_DEEMVOL);
     810           0 :                 ctl->un.ord = (val & AK4524_MUTE) ? 1 : 0;
     811             :         }
     812           0 : }
     813             : 
     814             : int
     815           0 : ak4524_dac_set(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
     816             : {
     817             :         int val, ndev;
     818             : 
     819           0 :         ndev = sc->card->noch;
     820           0 :         if (idx < ndev) {
     821           0 :                 if (ctl->un.value.num_channels != 1)
     822           0 :                         return EINVAL;
     823           0 :                 val = ctl->un.value.level[0] / 2;
     824           0 :                 envy_codec_write(sc, idx / 2,
     825           0 :                     (idx % 2) + AK4524_DAC_GAIN0, val);
     826           0 :         } else {
     827           0 :                 idx -= ndev;
     828           0 :                 if (ctl->un.ord >= 2)
     829           0 :                         return EINVAL;
     830           0 :                 val = AK4524_DEEM_OFF | (ctl->un.ord ? AK4524_MUTE : 0);
     831           0 :                 envy_codec_write(sc, idx, AK4524_DEEMVOL, val);
     832             :         }
     833           0 :         return 0;
     834           0 : }
     835             : 
     836             : /*
     837             :  * AK 4524 ADC specific code
     838             :  */
     839             : int
     840           0 : ak4524_adc_ndev(struct envy_softc *sc)
     841             : {
     842             :         /* one volume per channel */
     843           0 :         return sc->card->nich;
     844             : }
     845             : 
     846             : void
     847           0 : ak4524_adc_devinfo(struct envy_softc *sc, struct mixer_devinfo *dev, int idx)
     848             : {
     849           0 :         dev->type = AUDIO_MIXER_VALUE;
     850           0 :         dev->mixer_class = ENVY_MIX_CLASSIN;
     851           0 :         dev->un.v.delta = 2;
     852           0 :         dev->un.v.num_channels = 1;
     853           0 :         snprintf(dev->label.name, MAX_AUDIO_DEV_LEN, AudioNline "-%d", idx);
     854           0 :         strlcpy(dev->un.v.units.name, AudioNvolume, MAX_AUDIO_DEV_LEN);
     855           0 : }
     856             : 
     857             : void
     858           0 : ak4524_adc_get(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
     859             : {
     860             :         int val;
     861             : 
     862           0 :         val = envy_codec_read(sc, idx / 2, (idx % 2) + AK4524_ADC_GAIN0);
     863           0 :         ctl->un.value.num_channels = 1;
     864           0 :         ctl->un.value.level[0] = 2 * val;
     865           0 : }
     866             : 
     867             : int
     868           0 : ak4524_adc_set(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
     869             : {
     870             :         int val;
     871             : 
     872           0 :         if (ctl->un.value.num_channels != 1)
     873           0 :                 return EINVAL;
     874           0 :         val = ctl->un.value.level[0] / 2;
     875           0 :         envy_codec_write(sc, idx / 2, (idx % 2) + AK4524_ADC_GAIN0, val);
     876           0 :         return 0;
     877           0 : }
     878             : 
     879             : /*
     880             :  * AK 5365 ADC specific code
     881             :  */
     882             : int
     883           0 : ak5365_adc_ndev(struct envy_softc *sc)
     884             : {
     885             :         /* 1 source + 2 volume knobs per channel pair */
     886           0 :         return (sc->card->nich + 1);
     887             : }
     888             : 
     889             : void
     890           0 : ak5365_adc_devinfo(struct envy_softc *sc, struct mixer_devinfo *dev, int idx)
     891             : {
     892             :         int ndev, i;
     893             : 
     894           0 :         ndev = sc->card->nich;
     895           0 :         if (idx < ndev) {
     896           0 :                 dev->type = AUDIO_MIXER_VALUE;
     897           0 :                 dev->mixer_class = ENVY_MIX_CLASSIN;
     898           0 :                 dev->un.v.delta = 2;
     899           0 :                 dev->un.v.num_channels = 1;
     900           0 :                 snprintf(dev->label.name, MAX_AUDIO_DEV_LEN,
     901             :                     AudioNline "-%d", idx);
     902           0 :                 strlcpy(dev->un.v.units.name, AudioNvolume,
     903             :                     MAX_AUDIO_DEV_LEN);
     904           0 :         } else {
     905           0 :                 dev->type = AUDIO_MIXER_ENUM;
     906           0 :                 dev->mixer_class = ENVY_MIX_CLASSIN;
     907           0 :                 for (i = 0; i < 5; i++) {
     908           0 :                         dev->un.e.member[i].ord = i;
     909           0 :                         snprintf(dev->un.e.member[i].label.name,
     910             :                             MAX_AUDIO_DEV_LEN, AudioNline "-%d", i);
     911             :                 }
     912           0 :                 dev->un.e.num_mem = 5;
     913           0 :                 strlcpy(dev->label.name, AudioNsource,
     914             :                     MAX_AUDIO_DEV_LEN);
     915             :         }
     916           0 : }
     917             : 
     918             : void
     919           0 : ak5365_adc_get(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
     920             : {
     921             :         int val, ndev;
     922             : 
     923           0 :         ndev = sc->card->nich;
     924           0 :         if (idx < ndev) {
     925           0 :                 val = envy_codec_read(sc, 1, AK5365_ATT(idx));
     926           0 :                 ctl->un.value.num_channels = 1;
     927           0 :                 ctl->un.value.level[0] = 2 * val;
     928           0 :         } else {
     929           0 :                 ctl->un.ord = envy_codec_read(sc, 1, AK5365_SRC);
     930             :         }
     931           0 : }
     932             : 
     933             : int
     934           0 : ak5365_adc_set(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
     935             : {
     936             :         int val, ndev;
     937             : 
     938           0 :         ndev = sc->card->nich;
     939           0 :         if (idx < ndev) {
     940           0 :                 if (ctl->un.value.num_channels != 1)
     941           0 :                         return EINVAL;
     942           0 :                 val = ctl->un.value.level[0] / 2;
     943           0 :                 envy_codec_write(sc, 1, AK5365_ATT(idx), val);
     944           0 :         } else {
     945           0 :                 if (ctl->un.ord >= 5)
     946           0 :                         return EINVAL;
     947           0 :                 val = ctl->un.ord & AK5365_SRC_MASK;
     948           0 :                 envy_codec_write(sc, 1, AK5365_SRC, val);
     949             :         }
     950           0 :         return 0;
     951           0 : }
     952             : 
     953             : /*
     954             :  * generic Envy24 and Envy24HT code, common to all cards
     955             :  */
     956             : 
     957             : int
     958           0 : envy_ccs_read(struct envy_softc *sc, int reg)
     959             : {
     960             :         int val;
     961             : 
     962           0 :         val = bus_space_read_1(sc->ccs_iot, sc->ccs_ioh, reg);
     963           0 :         bus_space_barrier(sc->ccs_iot, sc->ccs_ioh, 0, sc->ccs_iosz,
     964             :             BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
     965           0 :         return val;
     966             : }
     967             : 
     968             : void
     969           0 : envy_ccs_write(struct envy_softc *sc, int reg, int val)
     970             : {
     971           0 :         bus_space_write_1(sc->ccs_iot, sc->ccs_ioh, reg, val);
     972           0 :         bus_space_barrier(sc->ccs_iot, sc->ccs_ioh, 0, sc->ccs_iosz,
     973             :             BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
     974           0 : }
     975             : 
     976             : int
     977           0 : envy_mt_read_1(struct envy_softc *sc, int reg)
     978             : {
     979             :         int val;
     980             : 
     981           0 :         val = bus_space_read_1(sc->mt_iot, sc->mt_ioh, reg);
     982           0 :         bus_space_barrier(sc->mt_iot, sc->mt_ioh, 0, sc->mt_iosz,
     983             :             BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
     984           0 :         return val;
     985             : }
     986             : 
     987             : void
     988           0 : envy_mt_write_1(struct envy_softc *sc, int reg, int val)
     989             : {
     990           0 :         bus_space_write_1(sc->mt_iot, sc->mt_ioh, reg, val);
     991           0 :         bus_space_barrier(sc->mt_iot, sc->mt_ioh, 0, sc->mt_iosz,
     992             :             BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
     993           0 : }
     994             : 
     995             : int
     996           0 : envy_mt_read_2(struct envy_softc *sc, int reg)
     997             : {
     998             :         int val;
     999             : 
    1000           0 :         val = bus_space_read_2(sc->mt_iot, sc->mt_ioh, reg);
    1001           0 :         bus_space_barrier(sc->mt_iot, sc->mt_ioh, 0, sc->mt_iosz,
    1002             :             BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
    1003           0 :         return val;
    1004             : }
    1005             : 
    1006             : void
    1007           0 : envy_mt_write_2(struct envy_softc *sc, int reg, int val)
    1008             : {
    1009           0 :         bus_space_write_2(sc->mt_iot, sc->mt_ioh, reg, val);
    1010           0 :         bus_space_barrier(sc->mt_iot, sc->mt_ioh, 0, sc->mt_iosz,
    1011             :             BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
    1012           0 : }
    1013             : 
    1014             : int
    1015           0 : envy_mt_read_4(struct envy_softc *sc, int reg)
    1016             : {
    1017             :         int val;
    1018             : 
    1019           0 :         val = bus_space_read_4(sc->mt_iot, sc->mt_ioh, reg);
    1020           0 :         bus_space_barrier(sc->mt_iot, sc->mt_ioh, 0, sc->mt_iosz,
    1021             :             BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
    1022           0 :         return val;
    1023             : }
    1024             : 
    1025             : void
    1026           0 : envy_mt_write_4(struct envy_softc *sc, int reg, int val)
    1027             : {
    1028           0 :         bus_space_write_4(sc->mt_iot, sc->mt_ioh, reg, val);
    1029           0 :         bus_space_barrier(sc->mt_iot, sc->mt_ioh, 0, sc->mt_iosz,
    1030             :             BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
    1031           0 : }
    1032             : 
    1033             : int
    1034           0 : envy_cci_read(struct envy_softc *sc, int index)
    1035             : {
    1036           0 :         envy_ccs_write(sc, ENVY_CCI_INDEX, index);
    1037           0 :         return (envy_ccs_read(sc, ENVY_CCI_DATA));
    1038             : }
    1039             : 
    1040             : void
    1041           0 : envy_cci_write(struct envy_softc *sc, int index, int data)
    1042             : {
    1043           0 :         envy_ccs_write(sc, ENVY_CCI_INDEX, index);
    1044           0 :         envy_ccs_write(sc, ENVY_CCI_DATA, data);
    1045           0 : }
    1046             : 
    1047             : int
    1048           0 : envy_gpio_getstate(struct envy_softc *sc)
    1049             : {
    1050           0 :         if (sc->isht) {
    1051           0 :                 return envy_ccs_read(sc, ENVY_CCS_GPIODATA0) |
    1052           0 :                     (envy_ccs_read(sc, ENVY_CCS_GPIODATA1) << 8) |
    1053           0 :                     (envy_ccs_read(sc, ENVY_CCS_GPIODATA2) << 16);
    1054             :         } else
    1055           0 :                 return envy_cci_read(sc, ENVY_CCI_GPIODATA);
    1056           0 : }
    1057             : 
    1058             : void
    1059           0 : envy_gpio_setstate(struct envy_softc *sc, int reg)
    1060             : {
    1061           0 :         if (sc->isht) {
    1062           0 :                 envy_ccs_write(sc, ENVY_CCS_GPIODATA0, reg & 0xff);
    1063           0 :                 envy_ccs_write(sc, ENVY_CCS_GPIODATA1, (reg >> 8) & 0xff);
    1064           0 :                 envy_ccs_write(sc, ENVY_CCS_GPIODATA2, (reg >> 16) & 0xff);
    1065           0 :         } else
    1066           0 :                 envy_cci_write(sc, ENVY_CCI_GPIODATA, reg);
    1067           0 : }
    1068             : 
    1069             : int
    1070           0 : envy_gpio_getmask(struct envy_softc *sc)
    1071             : {
    1072           0 :         if (sc->isht) {
    1073           0 :                 return envy_ccs_read(sc, ENVY_CCS_GPIOMASK0) |
    1074           0 :                     (envy_ccs_read(sc, ENVY_CCS_GPIOMASK1) << 8) |
    1075           0 :                     (envy_ccs_read(sc, ENVY_CCS_GPIOMASK2) << 16);
    1076             :         } else
    1077           0 :                 return envy_cci_read(sc, ENVY_CCI_GPIOMASK);
    1078           0 : }
    1079             : 
    1080             : void
    1081           0 : envy_gpio_setmask(struct envy_softc *sc, int mask)
    1082             : {
    1083           0 :         if (sc->isht) {
    1084           0 :                 envy_ccs_write(sc, ENVY_CCS_GPIOMASK0, mask & 0xff);
    1085           0 :                 envy_ccs_write(sc, ENVY_CCS_GPIOMASK1, (mask >> 8) & 0xff);
    1086           0 :                 envy_ccs_write(sc, ENVY_CCS_GPIOMASK2, (mask >> 16) & 0xff);
    1087           0 :         } else
    1088           0 :                 envy_cci_write(sc, ENVY_CCI_GPIOMASK, mask);
    1089           0 : }
    1090             : 
    1091             : int
    1092           0 : envy_gpio_getdir(struct envy_softc *sc)
    1093             : {
    1094           0 :         if (sc->isht) {
    1095           0 :                 return envy_ccs_read(sc, ENVY_CCS_GPIODIR0) |
    1096           0 :                     (envy_ccs_read(sc, ENVY_CCS_GPIODIR1) << 8) |
    1097           0 :                     (envy_ccs_read(sc, ENVY_CCS_GPIODIR2) << 16);
    1098             :         } else
    1099           0 :                 return envy_cci_read(sc, ENVY_CCI_GPIODIR);
    1100           0 : }
    1101             : 
    1102             : void
    1103           0 : envy_gpio_setdir(struct envy_softc *sc, int dir)
    1104             : {
    1105           0 :         if (sc->isht) {
    1106           0 :                 envy_ccs_write(sc, ENVY_CCS_GPIODIR0, dir & 0xff);
    1107           0 :                 envy_ccs_write(sc, ENVY_CCS_GPIODIR1, (dir >> 8) & 0xff);
    1108           0 :                 envy_ccs_write(sc, ENVY_CCS_GPIODIR2, (dir >> 16) & 0xff);
    1109           0 :         } else
    1110           0 :                 envy_cci_write(sc, ENVY_CCI_GPIODIR, dir);
    1111           0 : }
    1112             : 
    1113             : void
    1114           0 : envy_gpio_i2c_start_bit(struct envy_softc *sc, int sda, int scl)
    1115             : {
    1116             :         int reg;
    1117             : 
    1118           0 :         reg = envy_gpio_getstate(sc);
    1119           0 :         reg |= (sda | scl);
    1120           0 :         envy_gpio_setstate(sc, reg);
    1121           0 :         delay(5);
    1122           0 :         reg &= ~sda;
    1123           0 :         envy_gpio_setstate(sc, reg);
    1124           0 :         delay(4);
    1125           0 :         reg &= ~scl;
    1126           0 :         envy_gpio_setstate(sc, reg);
    1127           0 :         delay(5);
    1128           0 : }
    1129             : 
    1130             : void
    1131           0 : envy_gpio_i2c_stop_bit(struct envy_softc *sc, int sda, int scl)
    1132             : {
    1133             :         int reg;
    1134             : 
    1135           0 :         reg = envy_gpio_getstate(sc);
    1136           0 :         reg &= ~sda;
    1137           0 :         reg |= scl;
    1138           0 :         envy_gpio_setstate(sc, reg);
    1139           0 :         delay(4);
    1140           0 :         reg |= sda;
    1141           0 :         envy_gpio_setstate(sc, reg);
    1142           0 : }
    1143             : 
    1144             : void
    1145           0 : envy_gpio_i2c_byte_out(struct envy_softc *sc, int sda, int scl, int val)
    1146             : {
    1147             :         int mask, reg;
    1148             : 
    1149           0 :         reg = envy_gpio_getstate(sc);
    1150             : 
    1151           0 :         for (mask = 0x80; mask != 0; mask >>= 1) {
    1152           0 :                 reg &= ~sda;
    1153           0 :                 reg |= (val & mask) ? sda : 0;
    1154           0 :                 envy_gpio_setstate(sc, reg);
    1155           0 :                 delay(1);
    1156           0 :                 reg |= scl;
    1157           0 :                 envy_gpio_setstate(sc, reg);
    1158           0 :                 delay(4);
    1159           0 :                 reg &= ~scl;
    1160           0 :                 envy_gpio_setstate(sc, reg);
    1161           0 :                 delay(5);
    1162             :         }
    1163             : 
    1164           0 :         reg |= scl;
    1165           0 :         envy_gpio_setstate(sc, reg);
    1166           0 :         delay(4);
    1167           0 :         reg &= ~scl;
    1168           0 :         envy_gpio_setstate(sc, reg);
    1169           0 :         delay(5);
    1170           0 : }
    1171             : 
    1172             : void
    1173           0 : envy_i2c_wait(struct envy_softc *sc)
    1174             : {
    1175             :         int timeout = 50, st;
    1176             : 
    1177           0 :         for (;;) {
    1178           0 :                 st = envy_ccs_read(sc, ENVY_I2C_CTL);
    1179           0 :                 if (!(st & ENVY_I2C_CTL_BUSY))
    1180             :                         break;
    1181           0 :                 if (timeout == 0) {
    1182           0 :                         printf("%s: i2c busy timeout\n", DEVNAME(sc));
    1183           0 :                         break;
    1184             :                 }
    1185           0 :                 delay(50);
    1186           0 :                 timeout--;
    1187             :         }
    1188           0 : }
    1189             : 
    1190             : int
    1191           0 : envy_i2c_read(struct envy_softc *sc, int dev, int addr)
    1192             : {
    1193           0 :         envy_i2c_wait(sc);
    1194           0 :         envy_ccs_write(sc, ENVY_I2C_ADDR, addr);
    1195           0 :         envy_i2c_wait(sc);
    1196           0 :         envy_ccs_write(sc, ENVY_I2C_DEV, dev << 1);
    1197           0 :         envy_i2c_wait(sc);
    1198           0 :         return envy_ccs_read(sc, ENVY_I2C_DATA);
    1199             : }
    1200             : 
    1201             : void
    1202           0 : envy_i2c_write(struct envy_softc *sc, int dev, int addr, int data)
    1203             : {
    1204           0 :         if (dev == 0x50) {
    1205           0 :                 printf("%s: writing on eeprom is evil...\n", DEVNAME(sc));
    1206           0 :                 return;
    1207             :         }
    1208           0 :         envy_i2c_wait(sc);
    1209           0 :         envy_ccs_write(sc, ENVY_I2C_ADDR, addr);
    1210           0 :         envy_i2c_wait(sc);
    1211           0 :         envy_ccs_write(sc, ENVY_I2C_DATA, data);
    1212           0 :         envy_i2c_wait(sc);
    1213           0 :         envy_ccs_write(sc, ENVY_I2C_DEV, (dev << 1) | 1);
    1214           0 : }
    1215             : 
    1216             : int
    1217           0 : envy_codec_read(struct envy_softc *sc, int dev, int addr) {
    1218           0 :         return sc->shadow[dev][addr];
    1219             : }
    1220             : 
    1221             : void
    1222           0 : envy_codec_write(struct envy_softc *sc, int dev, int addr, int data)
    1223             : {
    1224             :         DPRINTFN(2, "envy_codec_write: %d, %d, 0x%x\n", dev, addr, data);
    1225           0 :         sc->shadow[dev][addr] = data;
    1226           0 :         sc->card->codec_write(sc, dev, addr, data);
    1227           0 : }
    1228             : 
    1229             : int
    1230           0 : envy_eeprom_gpioxxx(struct envy_softc *sc, int addr)
    1231             : {
    1232             :         int val;
    1233             : 
    1234           0 :         val = sc->eeprom[addr];
    1235           0 :         if (sc->isht) {
    1236           0 :                 val |= sc->eeprom[++addr] << 8;
    1237           0 :                 val |= sc->eeprom[++addr] << 16;
    1238           0 :         }
    1239           0 :         return val;
    1240             : }
    1241             : 
    1242             : int
    1243           0 : envy_ac97_wait(struct envy_softc *sc)
    1244             : {
    1245             :         int timeout = 50, st;
    1246             : 
    1247           0 :         for (;;) {
    1248           0 :                 st = envy_mt_read_1(sc, ENVY_MT_AC97_CMD);
    1249           0 :                 if ((st & ENVY_MT_AC97_READY) && !(st & ENVY_MT_AC97_CMD_MASK)) {
    1250             :                         st = 0;
    1251           0 :                         break;
    1252             :                 }
    1253           0 :                 if (timeout == 0) {
    1254             :                         st = -1;
    1255           0 :                         break;
    1256             :                 }
    1257           0 :                 delay(50);
    1258           0 :                 timeout--;
    1259             :         }
    1260             : 
    1261           0 :         return (st);
    1262             : }
    1263             : 
    1264             : int
    1265           0 : envy_ac97_attach_codec(void *hdl, struct ac97_codec_if *codec_if)
    1266             : {
    1267           0 :         struct envy_softc *sc = hdl;
    1268             : 
    1269           0 :         sc->codec_if = codec_if;
    1270             : 
    1271           0 :         return (0);
    1272             : }
    1273             : 
    1274             : int
    1275           0 : envy_ac97_read_codec(void *hdl, u_int8_t reg, u_int16_t *result)
    1276             : {
    1277           0 :         struct envy_softc *sc = hdl;
    1278             : 
    1279           0 :         if (envy_ac97_wait(sc)) {
    1280           0 :                 printf("%s: envy_ac97_read_codec: timed out\n", DEVNAME(sc));
    1281           0 :                 return (-1);
    1282             :         }
    1283             : 
    1284           0 :         envy_mt_write_1(sc, ENVY_MT_AC97_IDX, reg & 0x7f);
    1285           0 :         envy_mt_write_1(sc, ENVY_MT_AC97_CMD,
    1286             :             ENVY_MT_AC97_CMD_RD);
    1287           0 :         delay(50);
    1288             : 
    1289           0 :         if (envy_ac97_wait(sc)) {
    1290           0 :                 printf("%s: envy_ac97_read_codec: timed out\n", DEVNAME(sc));
    1291           0 :                 return (-1);
    1292             :         }
    1293             : 
    1294           0 :         *result = envy_mt_read_2(sc, ENVY_MT_AC97_DATA);
    1295             : 
    1296           0 :         return (0);
    1297           0 : }
    1298             : 
    1299             : int
    1300           0 : envy_ac97_write_codec(void *hdl, u_int8_t reg, u_int16_t data)
    1301             : {
    1302           0 :         struct envy_softc *sc = hdl;
    1303             : 
    1304           0 :         if (envy_ac97_wait(sc)) {
    1305           0 :                 printf("%s: envy_ac97_write_codec: timed out\n", DEVNAME(sc));
    1306           0 :                 return (-1);
    1307             :         }
    1308             : 
    1309           0 :         envy_mt_write_1(sc, ENVY_MT_AC97_IDX, reg & 0x7f);
    1310           0 :         envy_mt_write_2(sc, ENVY_MT_AC97_DATA, data);
    1311           0 :         envy_mt_write_1(sc, ENVY_MT_AC97_CMD,
    1312             :             ENVY_MT_AC97_CMD_WR);
    1313           0 :         delay(50);
    1314             : 
    1315           0 :         return (0);
    1316           0 : }
    1317             : 
    1318             : void
    1319           0 : envy_ac97_reset_codec(void *hdl)
    1320             : {
    1321           0 :         struct envy_softc *sc = hdl;
    1322             : 
    1323           0 :         envy_mt_write_1(sc, ENVY_MT_AC97_CMD, ENVY_MT_AC97_CMD_RST);
    1324           0 :         delay(50);
    1325           0 :         envy_mt_write_1(sc, ENVY_MT_AC97_CMD, 0);
    1326           0 :         delay(50);
    1327             : 
    1328           0 :         if (envy_ac97_wait(sc)) {
    1329           0 :                 printf("%s: envy_ac97_reset_codec: timed out\n", DEVNAME(sc));
    1330           0 :         }
    1331             : 
    1332             :         return;
    1333           0 : }
    1334             : 
    1335             : enum ac97_host_flags
    1336           0 : envy_ac97_flags_codec(void *hdl)
    1337             : {
    1338           0 :         struct envy_softc *sc = hdl;
    1339             : 
    1340           0 :         return (sc->codec_flags);
    1341             : }
    1342             : 
    1343             : void
    1344           0 : envy_midi_wait(struct envy_softc *sc)
    1345             : {
    1346             :         int i, st;
    1347             :         
    1348           0 :         for (i = 100;; i--) {
    1349           0 :                 st = envy_ccs_read(sc, ENVY_CCS_MIDISTAT0);
    1350           0 :                 if (!(st & ENVY_MIDISTAT_OBUSY(sc)))
    1351             :                         break;
    1352           0 :                 if (i == 0) {
    1353           0 :                         printf("%s: midi wait timeout\n", DEVNAME(sc));
    1354           0 :                         break;
    1355             :                 }
    1356           0 :                 delay(10);
    1357             :         }
    1358           0 : }
    1359             : 
    1360             : void
    1361           0 : envy_reset(struct envy_softc *sc)
    1362             : {
    1363             :         int i, reg;
    1364             : 
    1365             :         /*
    1366             :          * full reset
    1367             :          */
    1368           0 :         envy_ccs_write(sc, ENVY_CTL, ENVY_CTL_RESET | ENVY_CTL_NATIVE);
    1369           0 :         delay(200);
    1370           0 :         envy_ccs_write(sc, ENVY_CTL, ENVY_CTL_NATIVE);
    1371           0 :         delay(200);
    1372             : 
    1373             :         /*
    1374             :          * read EEPROM using i2c device or from a static array
    1375             :          */
    1376           0 :         if (sc->card->eeprom == NULL) {
    1377           0 :                 for (i = 0; i < ENVY_EEPROM_MAXSZ; i++) {
    1378           0 :                         sc->eeprom[i] = envy_i2c_read(sc, ENVY_I2C_DEV_EEPROM, i);
    1379             :                 }
    1380             : #ifdef ENVY_DEBUG
    1381             :                 printf("%s: eeprom: ", DEVNAME(sc));
    1382             :                 for (i = 0; i < ENVY_EEPROM_MAXSZ; i++) {
    1383             :                         printf(" %02x", (unsigned)sc->eeprom[i]);
    1384             :                 }
    1385             :                 printf("\n");
    1386             : #endif
    1387             :         } else
    1388           0 :                 memcpy(sc->eeprom, sc->card->eeprom, ENVY_EEPROM_MAXSZ);
    1389             : 
    1390             :         /*
    1391             :          * write EEPROM values to corresponding registers
    1392             :          */
    1393           0 :         if (sc->isht) {
    1394           0 :                 envy_ccs_write(sc, ENVY_CCS_CONF,
    1395           0 :                     sc->eeprom[ENVY_EEPROM_CONF]);
    1396           0 :                 envy_ccs_write(sc, ENVY_CCS_ACLINK,
    1397           0 :                     sc->eeprom[ENVY_EEPROM_ACLINK]);
    1398           0 :                 envy_ccs_write(sc, ENVY_CCS_I2S,
    1399           0 :                     sc->eeprom[ENVY_EEPROM_I2S]);
    1400           0 :                 envy_ccs_write(sc, ENVY_CCS_SPDIF,
    1401           0 :                     sc->eeprom[ENVY_EEPROM_SPDIF]);
    1402           0 :         } else {
    1403           0 :                 pci_conf_write(sc->pci_pc, sc->pci_tag, ENVY_CONF,
    1404           0 :                     sc->eeprom[ENVY_EEPROM_CONF] |
    1405           0 :                     (sc->eeprom[ENVY_EEPROM_ACLINK] << 8) |
    1406           0 :                     (sc->eeprom[ENVY_EEPROM_I2S] << 16) |
    1407           0 :                     (sc->eeprom[ENVY_EEPROM_SPDIF] << 24));
    1408             :         }
    1409             : 
    1410           0 :         envy_gpio_setmask(sc, envy_eeprom_gpioxxx(sc, ENVY_EEPROM_GPIOMASK(sc)));
    1411           0 :         envy_gpio_setdir(sc, envy_eeprom_gpioxxx(sc, ENVY_EEPROM_GPIODIR(sc)));
    1412           0 :         envy_gpio_setstate(sc, envy_eeprom_gpioxxx(sc, ENVY_EEPROM_GPIOST(sc)));
    1413             : 
    1414             :         DPRINTF("%s: gpio_mask = %02x\n", DEVNAME(sc),
    1415             :                 envy_gpio_getmask(sc));
    1416             :         DPRINTF("%s: gpio_dir = %02x\n", DEVNAME(sc),
    1417             :                 envy_gpio_getdir(sc));
    1418             :         DPRINTF("%s: gpio_state = %02x\n", DEVNAME(sc),
    1419             :                 envy_gpio_getstate(sc));
    1420             : 
    1421           0 :         if (sc->isht) {
    1422             :                 /*
    1423             :                  * set water marks so we get an interrupt for each byte
    1424             :                  */
    1425           0 :                 envy_ccs_write(sc, ENVY_CCS_MIDIWAT, 1);
    1426           0 :                 envy_ccs_write(sc, ENVY_CCS_MIDIWAT, 1 | ENVY_CCS_MIDIWAT_RX);
    1427           0 :         }
    1428             : 
    1429             :         /*
    1430             :          * switch to UART mode
    1431             :          */
    1432           0 :         envy_ccs_write(sc, ENVY_CCS_MIDISTAT0, 0xff);
    1433           0 :         envy_midi_wait(sc);
    1434           0 :         envy_ccs_write(sc, ENVY_CCS_MIDISTAT0, ENVY_MIDISTAT_UART);
    1435           0 :         envy_midi_wait(sc);
    1436           0 :         if (!sc->isht)
    1437           0 :                 (void)envy_ccs_read(sc, ENVY_CCS_MIDIDATA0);
    1438             : 
    1439             :         /*
    1440             :          * clear all interrupts and unmask used ones
    1441             :          */
    1442           0 :         envy_ccs_write(sc, ENVY_CCS_INTSTAT, 0xff);
    1443             :         reg = ~ENVY_CCS_INT_MT;
    1444           0 :         if (sc->midi_isopen)
    1445           0 :                 reg &= ~ENVY_CCS_INT_MIDI0;
    1446           0 :         envy_ccs_write(sc, ENVY_CCS_INTMASK, ~ENVY_CCS_INT_MT);
    1447           0 :         if (sc->isht) {
    1448           0 :                 envy_mt_write_1(sc, ENVY_MT_NSTREAM, 4 - sc->card->noch / 2);
    1449           0 :                 envy_mt_write_1(sc, ENVY_MT_IMASK, ~(ENVY_MT_IMASK_PDMA0 |
    1450             :                     ENVY_MT_IMASK_RDMA0 | ENVY_MT_IMASK_ERR));
    1451           0 :         }
    1452           0 :         sc->iactive = 0;
    1453           0 :         sc->oactive = 0;
    1454           0 :         sc->card->init(sc);
    1455           0 : }
    1456             : 
    1457             : int
    1458           0 : envy_lineout_getsrc(struct envy_softc *sc, int out)
    1459             : {
    1460             :         int reg, shift, src;
    1461             : 
    1462           0 :         if (sc->isht) {
    1463           0 :                 reg = envy_mt_read_4(sc, ENVY_MT_HTSRC);
    1464             :                 DPRINTF("%s: outsrc=%x\n", DEVNAME(sc), reg);
    1465           0 :                 shift = 3 * (out / 2) + ((out & 1) ? 20 : 8);
    1466           0 :                 src = (reg >> shift) & ENVY_MT_HTSRC_MASK;
    1467           0 :                 if (src == ENVY_MT_HTSRC_DMA) {
    1468           0 :                         return ENVY_MIX_OUTSRC_DMA;
    1469             :                 } else {
    1470           0 :                         src -= ENVY_MT_HTSRC_LINE;
    1471           0 :                         return ENVY_MIX_OUTSRC_LINEIN + src;
    1472             :                 }
    1473             :         }
    1474             : 
    1475           0 :         reg = envy_mt_read_2(sc, ENVY_MT_OUTSRC);
    1476             :         DPRINTF("%s: outsrc=%x\n", DEVNAME(sc), reg);
    1477           0 :         shift = (out  & 1) ? (out & ~1) + 8 : out;
    1478           0 :         src = (reg >> shift) & 3;
    1479           0 :         if (src == ENVY_MT_OUTSRC_DMA) {
    1480           0 :                 return ENVY_MIX_OUTSRC_DMA;
    1481           0 :         } else if (src == ENVY_MT_OUTSRC_MON) {
    1482           0 :                 return ENVY_MIX_OUTSRC_MON;
    1483             :         }
    1484           0 :         reg = envy_mt_read_4(sc, ENVY_MT_INSEL);
    1485             :         DPRINTF("%s: insel=%x\n", DEVNAME(sc), reg);
    1486           0 :         reg = (reg >> (out * 4)) & 0xf;
    1487           0 :         if (src == ENVY_MT_OUTSRC_LINE)
    1488           0 :                 return ENVY_MIX_OUTSRC_LINEIN + (reg & 7);
    1489             :         else
    1490           0 :                 return ENVY_MIX_OUTSRC_SPDIN + (reg >> 3);
    1491           0 : }
    1492             : 
    1493             : void
    1494           0 : envy_lineout_setsrc(struct envy_softc *sc, int out, int src)
    1495             : {
    1496             :         int reg, shift, mask, sel;
    1497             : 
    1498           0 :         if (sc->isht) {
    1499           0 :                 if (src < ENVY_MIX_OUTSRC_SPDIN) {
    1500             :                         sel = ENVY_MT_HTSRC_LINE;
    1501           0 :                         sel += src;
    1502           0 :                 } else if (src < ENVY_MIX_OUTSRC_DMA) {
    1503             :                         sel = ENVY_MT_HTSRC_SPD;
    1504           0 :                         sel += src - ENVY_MIX_OUTSRC_SPDIN;
    1505           0 :                 } else {
    1506             :                         sel = ENVY_MT_HTSRC_DMA;
    1507             :                 }
    1508           0 :                 shift = 3 * (out / 2) + ((out & 1) ? 20 : 8);
    1509           0 :                 mask = ENVY_MT_HTSRC_MASK << shift;
    1510           0 :                 reg = envy_mt_read_4(sc, ENVY_MT_HTSRC);
    1511           0 :                 reg = (reg & ~mask) | (sel << shift);
    1512           0 :                 envy_mt_write_4(sc, ENVY_MT_HTSRC, reg);
    1513             :                 DPRINTF("%s: outsrc <- %x\n", DEVNAME(sc), reg);
    1514           0 :                 return;
    1515             :         }
    1516             : 
    1517           0 :         if (src < ENVY_MIX_OUTSRC_DMA) {
    1518             :                 /*
    1519             :                  * linein and spdin are used as output source so we
    1520             :                  * must select the input source channel number
    1521             :                  */
    1522           0 :                 if (src < ENVY_MIX_OUTSRC_SPDIN)
    1523           0 :                         sel = src - ENVY_MIX_OUTSRC_LINEIN;
    1524             :                 else
    1525           0 :                         sel = (src - ENVY_MIX_OUTSRC_SPDIN) << 3;
    1526             : 
    1527           0 :                 shift = out * ENVY_MT_INSEL_BITS;
    1528           0 :                 mask = ENVY_MT_INSEL_MASK << shift;
    1529           0 :                 reg = envy_mt_read_4(sc, ENVY_MT_INSEL);
    1530           0 :                 reg = (reg & ~mask) | (sel << shift);
    1531           0 :                 envy_mt_write_4(sc, ENVY_MT_INSEL, reg);
    1532             :                 DPRINTF("%s: insel <- %x\n", DEVNAME(sc), reg);
    1533           0 :         }
    1534             : 
    1535             :         /*
    1536             :          * set the lineout route register
    1537             :          */
    1538           0 :         if (src < ENVY_MIX_OUTSRC_SPDIN) {
    1539             :                 sel = ENVY_MT_OUTSRC_LINE;
    1540           0 :         } else if (src < ENVY_MIX_OUTSRC_DMA) {
    1541             :                 sel = ENVY_MT_OUTSRC_SPD;
    1542           0 :         } else if (src == ENVY_MIX_OUTSRC_DMA) {
    1543             :                 sel = ENVY_MT_OUTSRC_DMA;
    1544           0 :         } else {
    1545             :                 sel = ENVY_MT_OUTSRC_MON;
    1546             :         }
    1547           0 :         shift = (out  & 1) ? (out & ~1) + 8 : out;
    1548           0 :         mask = ENVY_MT_OUTSRC_MASK << shift;
    1549           0 :         reg = envy_mt_read_2(sc, ENVY_MT_OUTSRC);
    1550           0 :         reg = (reg & ~mask) | (sel << shift);
    1551           0 :         envy_mt_write_2(sc, ENVY_MT_OUTSRC, reg);
    1552             :         DPRINTF("%s: outsrc <- %x\n", DEVNAME(sc), reg);
    1553           0 : }
    1554             : 
    1555             : 
    1556             : int
    1557           0 : envy_spdout_getsrc(struct envy_softc *sc, int out)
    1558             : {
    1559             :         int reg, src, sel;
    1560             : 
    1561           0 :         reg = envy_mt_read_2(sc, ENVY_MT_SPDROUTE);
    1562             :         DPRINTF("%s: spdroute=%x\n", DEVNAME(sc), reg);
    1563           0 :         src = (out == 0) ? reg : reg >> 2;
    1564           0 :         src &= ENVY_MT_SPDSRC_MASK;
    1565           0 :         if (src == ENVY_MT_SPDSRC_DMA) {
    1566           0 :                 return ENVY_MIX_OUTSRC_DMA;
    1567           0 :         } else if (src == ENVY_MT_SPDSRC_MON) {
    1568           0 :                 return ENVY_MIX_OUTSRC_MON;
    1569             :         }
    1570             : 
    1571           0 :         sel = (out == 0) ? reg >> 8 : reg >> 12;
    1572           0 :         sel &= ENVY_MT_SPDSEL_MASK;
    1573           0 :         if (src == ENVY_MT_SPDSRC_LINE)
    1574           0 :                 return ENVY_MIX_OUTSRC_LINEIN + (sel & 7);
    1575             :         else
    1576           0 :                 return ENVY_MIX_OUTSRC_SPDIN + (sel >> 3);
    1577           0 : }
    1578             : 
    1579             : void
    1580           0 : envy_spdout_setsrc(struct envy_softc *sc, int out, int src)
    1581             : {
    1582             :         int reg, shift, mask, sel;
    1583             : 
    1584           0 :         reg = envy_mt_read_2(sc, ENVY_MT_SPDROUTE);
    1585           0 :         if (src < ENVY_MIX_OUTSRC_DMA) {
    1586             :                 /*
    1587             :                  * linein and spdin are used as output source so we
    1588             :                  * must select the input source channel number
    1589             :                  */
    1590           0 :                 if (src < ENVY_MIX_OUTSRC_SPDIN)
    1591           0 :                         sel = src - ENVY_MIX_OUTSRC_LINEIN;
    1592             :                 else
    1593           0 :                         sel = (src - ENVY_MIX_OUTSRC_SPDIN) << 3;
    1594             : 
    1595           0 :                 shift = 8 + out * ENVY_MT_SPDSEL_BITS;
    1596           0 :                 mask = ENVY_MT_SPDSEL_MASK << shift;
    1597           0 :                 reg = (reg & ~mask) | (sel << shift);
    1598           0 :         }
    1599             : 
    1600             :         /*
    1601             :          * set the lineout route register
    1602             :          */
    1603           0 :         if (src < ENVY_MIX_OUTSRC_SPDIN) {
    1604             :                 sel = ENVY_MT_OUTSRC_LINE;
    1605           0 :         } else if (src < ENVY_MIX_OUTSRC_DMA) {
    1606             :                 sel = ENVY_MT_OUTSRC_SPD;
    1607           0 :         } else if (src == ENVY_MIX_OUTSRC_DMA) {
    1608             :                 sel = ENVY_MT_OUTSRC_DMA;
    1609           0 :         } else {
    1610             :                 sel = ENVY_MT_OUTSRC_MON;
    1611             :         }
    1612           0 :         shift = out * 2;
    1613           0 :         mask = ENVY_MT_SPDSRC_MASK << shift;
    1614           0 :         reg = (reg & ~mask) | (sel << shift);
    1615           0 :         envy_mt_write_2(sc, ENVY_MT_SPDROUTE, reg);
    1616             :         DPRINTF("%s: spdroute <- %x\n", DEVNAME(sc), reg);
    1617           0 : }
    1618             : 
    1619             : void
    1620           0 : envy_mon_getvol(struct envy_softc *sc, int idx, int ch, int *val)
    1621             : {
    1622             :         int reg;
    1623             : 
    1624           0 :         envy_mt_write_2(sc, ENVY_MT_MONIDX, idx);
    1625           0 :         reg = envy_mt_read_1(sc, ENVY_MT_MONDATA + ch);
    1626           0 :         *val = 0x7f - (reg & 0x7f);
    1627           0 : }
    1628             : 
    1629             : void
    1630           0 : envy_mon_setvol(struct envy_softc *sc, int idx, int ch, int val)
    1631             : {
    1632             :         int reg;
    1633             : 
    1634           0 :         envy_mt_write_2(sc, ENVY_MT_MONIDX, idx);
    1635           0 :         reg = 0x7f - val;
    1636             :         DPRINTF("%s: mon=%d/%d <- %d\n", DEVNAME(sc), reg, ch, val);
    1637           0 :         envy_mt_write_1(sc, ENVY_MT_MONDATA + ch, reg);
    1638           0 : }
    1639             : 
    1640             : int
    1641           0 : envymatch(struct device *parent, void *match, void *aux)
    1642             : {
    1643           0 :         return pci_matchbyid((struct pci_attach_args *)aux, envy_matchids,
    1644             :             sizeof(envy_matchids) / sizeof(envy_matchids[0]));
    1645             : }
    1646             : 
    1647             : void
    1648           0 : envyattach(struct device *parent, struct device *self, void *aux)
    1649             : {
    1650           0 :         struct envy_softc *sc = (struct envy_softc *)self;
    1651           0 :         struct pci_attach_args *pa = (struct pci_attach_args *)aux;
    1652           0 :         pci_intr_handle_t ih;
    1653             :         const char *intrstr;
    1654             :         int subid;
    1655             : 
    1656             : #if NMIDI > 0
    1657           0 :         sc->midi_isopen = 0;
    1658             : #endif
    1659           0 :         sc->pci_tag = pa->pa_tag;
    1660           0 :         sc->pci_pc = pa->pa_pc;
    1661           0 :         sc->pci_dmat = pa->pa_dmat;
    1662           0 :         sc->pci_ih = NULL;
    1663           0 :         sc->ibuf.addr = sc->obuf.addr = NULL;
    1664           0 :         sc->ccs_iosz = 0;
    1665           0 :         sc->mt_iosz = 0;
    1666           0 :         sc->isht = (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ICENSEMBLE_VT172x);
    1667             : 
    1668           0 :         if (pci_mapreg_map(pa, ENVY_CTL_BAR, PCI_MAPREG_TYPE_IO, 0,
    1669           0 :                 &sc->ccs_iot, &sc->ccs_ioh, NULL, &sc->ccs_iosz, 0)) {
    1670           0 :                 printf(": can't map ctl i/o space\n");
    1671           0 :                 sc->ccs_iosz = 0;
    1672           0 :                 return;
    1673             :         }
    1674           0 :         if (pci_mapreg_map(pa, ENVY_MT_BAR(sc->isht), PCI_MAPREG_TYPE_IO, 0,
    1675           0 :                 &sc->mt_iot, &sc->mt_ioh, NULL, &sc->mt_iosz, 0)) {
    1676           0 :                 printf(": can't map mt i/o space\n");
    1677           0 :                 sc->mt_iosz = 0;
    1678           0 :                 return;
    1679             :         }
    1680           0 :         if (pci_intr_map(pa, &ih)) {
    1681           0 :                 printf(": can't map interrupt\n");
    1682           0 :         }
    1683           0 :         intrstr = pci_intr_string(sc->pci_pc, ih);
    1684           0 :         sc->pci_ih = pci_intr_establish(sc->pci_pc, ih, IPL_AUDIO | IPL_MPSAFE,
    1685           0 :             envy_intr, sc, sc->dev.dv_xname);
    1686           0 :         if (sc->pci_ih == NULL) {
    1687           0 :                 printf(": can't establish interrupt");
    1688           0 :                 if (intrstr)
    1689           0 :                         printf(" at %s", intrstr);
    1690           0 :                 printf("\n");
    1691           0 :                 return;
    1692             :         }
    1693           0 :         printf(": %s\n", intrstr);
    1694           0 :         subid = pci_conf_read(sc->pci_pc, sc->pci_tag, PCI_SUBVEND_0);
    1695           0 :         sc->card = sc->isht ? envy_cards_ht : envy_cards;
    1696           0 :         while (sc->card->subid != subid) {
    1697           0 :                 if (sc->card->subid == 0)
    1698             :                         break;
    1699           0 :                 sc->card++;
    1700             :         }
    1701           0 :         printf("%s: %s, %u inputs, %u outputs\n", DEVNAME(sc),
    1702           0 :             sc->card->name, sc->card->nich, sc->card->noch);
    1703           0 :         envy_reset(sc);
    1704           0 :         sc->audio = audio_attach_mi(&envy_hw_if, sc, &sc->dev);
    1705             : #if NMIDI > 0
    1706           0 :         if (sc->card->nmidi > 0 && (!sc->isht ||
    1707           0 :                 sc->eeprom[ENVY_EEPROM_CONF] & ENVY_CONF_MIDI)) {
    1708           0 :                 sc->midi = midi_attach_mi(&envy_midi_hw_if, sc, &sc->dev);
    1709           0 :         }
    1710             : #endif
    1711           0 : }
    1712             : 
    1713             : int
    1714           0 : envydetach(struct device *self, int flags)
    1715             : {
    1716           0 :         struct envy_softc *sc = (struct envy_softc *)self;
    1717             : 
    1718           0 :         if (sc->pci_ih != NULL) {
    1719           0 :                 pci_intr_disestablish(sc->pci_pc, sc->pci_ih);
    1720           0 :                 sc->pci_ih = NULL;
    1721           0 :         }
    1722           0 :         if (sc->ccs_iosz) {
    1723           0 :                 bus_space_unmap(sc->ccs_iot, sc->ccs_ioh, sc->ccs_iosz);
    1724           0 :         }
    1725           0 :         if (sc->mt_iosz) {
    1726           0 :                 bus_space_unmap(sc->mt_iot, sc->mt_ioh, sc->mt_iosz);
    1727           0 :         }
    1728           0 :         return 0;
    1729             : }
    1730             : 
    1731             : int
    1732           0 : envyactivate(struct device *self, int act)
    1733             : {
    1734           0 :         struct envy_softc *sc = (struct envy_softc *)self;
    1735             : 
    1736           0 :         if (act == DVACT_RESUME) {
    1737             :                 /*
    1738             :                  * The audio(4) layer will restore parameters and, if
    1739             :                  * needed, start DMA. So we only need to reach the
    1740             :                  * same device state as after the audio_attach() call.
    1741             :                  */
    1742           0 :                 envy_reset(sc);
    1743           0 :         }
    1744           0 :         return config_activate_children(self, act);
    1745             : }
    1746             : 
    1747             : int
    1748           0 : envy_open(void *self, int flags)
    1749             : {
    1750           0 :         return 0;
    1751             : }
    1752             : 
    1753             : void
    1754           0 : envy_close(void *self)
    1755             : {
    1756           0 : }
    1757             : 
    1758             : void *
    1759           0 : envy_allocm(void *self, int dir, size_t size, int type, int flags)
    1760             : {
    1761           0 :         struct envy_softc *sc = (struct envy_softc *)self;
    1762             :         int err, wait;
    1763             :         struct envy_buf *buf;
    1764             :         bus_addr_t dma_addr;
    1765             : 
    1766           0 :         buf = (dir == AUMODE_RECORD) ? &sc->ibuf : &sc->obuf;
    1767           0 :         if (buf->addr != NULL) {
    1768             :                 DPRINTF("%s: multiple alloc, dir = %d\n", DEVNAME(sc), dir);
    1769           0 :                 return NULL;
    1770             :         }
    1771           0 :         buf->size = size;
    1772           0 :         wait = (flags & M_NOWAIT) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK;
    1773             : 
    1774             : #define ENVY_ALIGN      4
    1775             : #define ENVY_MAXADDR    ((1 << 28) - 1)
    1776             : 
    1777           0 :         buf->addr = (caddr_t)uvm_km_kmemalloc_pla(kernel_map,
    1778           0 :             uvm.kernel_object, buf->size, 0, UVM_KMF_NOWAIT, 0,
    1779             :             (paddr_t)ENVY_MAXADDR, 0, 0, 1);
    1780           0 :         if (buf->addr == NULL) {
    1781             :                 DPRINTF("%s: unable to alloc dma segment\n", DEVNAME(sc));
    1782             :                 goto err_ret;
    1783             :         }
    1784           0 :         err = bus_dmamap_create(sc->pci_dmat, buf->size, 1, buf->size, 0,
    1785             :             wait, &buf->map);
    1786           0 :         if (err) {
    1787             :                 DPRINTF("%s: dmamap_create: failed %d\n", DEVNAME(sc), err);
    1788             :                 goto err_unmap;
    1789             :         }
    1790           0 :         err = bus_dmamap_load(sc->pci_dmat, buf->map, buf->addr,
    1791             :             buf->size, NULL, wait);
    1792           0 :         if (err) {
    1793             :                 DPRINTF("%s: dmamap_load: failed %d\n", DEVNAME(sc), err);
    1794             :                 goto err_destroy;
    1795             :         }
    1796           0 :         dma_addr = buf->map->dm_segs[0].ds_addr;
    1797             :         DPRINTF("%s: allocated %zd bytes dir=%d, ka=%p, da=%lx\n", DEVNAME(sc),
    1798             :             buf->size, dir, buf->addr, dma_addr);
    1799           0 :         if (!sc->isht && (dma_addr & ~ENVY_MAXADDR)) {
    1800           0 :                 printf("%s: DMA address beyond 0x10000000\n", DEVNAME(sc));
    1801             :                 goto err_unload;
    1802             :         }
    1803           0 :         return buf->addr;
    1804             :  err_unload:
    1805           0 :         bus_dmamap_unload(sc->pci_dmat, buf->map);
    1806             :  err_destroy:
    1807           0 :         bus_dmamap_destroy(sc->pci_dmat, buf->map);
    1808             :  err_unmap:
    1809           0 :         uvm_km_free(kernel_map, (vaddr_t)buf->addr, buf->size);
    1810             :  err_ret:
    1811           0 :         return NULL;
    1812           0 : }
    1813             : 
    1814             : void
    1815           0 : envy_freem(void *self, void *addr, int type)
    1816             : {
    1817             :         struct envy_buf *buf;
    1818           0 :         struct envy_softc *sc = (struct envy_softc *)self;
    1819             :         int dir;
    1820             : 
    1821           0 :         if (sc->ibuf.addr == addr) {
    1822             :                 buf = &sc->ibuf;
    1823             :                 dir = AUMODE_RECORD;
    1824           0 :         } else if (sc->obuf.addr == addr) {
    1825             :                 buf = &sc->obuf;
    1826             :                 dir = AUMODE_PLAY;
    1827             :         } else {
    1828             :                 DPRINTF("%s: no buf to free\n", DEVNAME(sc));
    1829           0 :                 return;
    1830             :         }
    1831           0 :         bus_dmamap_unload(sc->pci_dmat, buf->map);
    1832           0 :         bus_dmamap_destroy(sc->pci_dmat, buf->map);
    1833           0 :         uvm_km_free(kernel_map, (vaddr_t)&buf->addr, buf->size);
    1834           0 :         buf->addr = NULL;
    1835             :         DPRINTF("%s: freed buffer (mode=%d)\n", DEVNAME(sc), dir);
    1836           0 : }
    1837             : 
    1838             : int
    1839           0 : envy_set_params(void *self, int setmode, int usemode,
    1840             :     struct audio_params *p, struct audio_params *r)
    1841             : {
    1842           0 :         struct envy_softc *sc = (struct envy_softc *)self;
    1843             :         int i, rate, reg;
    1844             : 
    1845           0 :         if (setmode == 0)
    1846           0 :                 return 0;
    1847           0 :         if (setmode == (AUMODE_PLAY | AUMODE_RECORD) &&
    1848           0 :             p->sample_rate != r->sample_rate) {
    1849             :                 DPRINTF("%s: play/rec rates mismatch\n", DEVNAME(sc));
    1850           0 :                 r->sample_rate = p->sample_rate;
    1851           0 :         }
    1852           0 :         rate = (setmode & AUMODE_PLAY) ? p->sample_rate : r->sample_rate;
    1853           0 :         for (i = 0; envy_rates[i].rate < rate; i++) {
    1854           0 :                 if (envy_rates[i].rate == -1) {
    1855           0 :                         i--;
    1856             :                         DPRINTF("%s: rate: %d -> %d\n", DEVNAME(sc), rate, i);
    1857           0 :                         break;
    1858             :                 }
    1859             :         }
    1860           0 :         reg = envy_mt_read_1(sc, ENVY_MT_RATE);
    1861           0 :         reg &= ~ENVY_MT_RATEMASK;
    1862           0 :         reg |= envy_rates[i].reg;
    1863           0 :         envy_mt_write_1(sc, ENVY_MT_RATE, reg);
    1864           0 :         if (setmode & AUMODE_PLAY) {
    1865           0 :                 p->sample_rate = envy_rates[i].rate;
    1866           0 :                 p->encoding = AUDIO_ENCODING_SLINEAR_LE;
    1867           0 :                 p->precision = 24;
    1868           0 :                 p->bps = 4;
    1869           0 :                 p->msb = 1;
    1870           0 :                 p->channels = sc->isht ? sc->card->noch : ENVY_PCHANS;
    1871           0 :         }
    1872           0 :         if (setmode & AUMODE_RECORD) {
    1873           0 :                 r->sample_rate = envy_rates[i].rate;
    1874           0 :                 r->encoding = AUDIO_ENCODING_SLINEAR_LE;
    1875           0 :                 r->precision = 24;
    1876           0 :                 r->bps = 4;
    1877           0 :                 r->msb = 1;
    1878           0 :                 r->channels = sc->isht ? sc->card->nich : ENVY_RCHANS;
    1879           0 :         }
    1880           0 :         return 0;
    1881           0 : }
    1882             : 
    1883             : int
    1884           0 : envy_round_blocksize(void *self, int blksz)
    1885             : {
    1886           0 :         return (blksz + 0x1f) & ~0x1f;
    1887             : }
    1888             : 
    1889             : #ifdef ENVY_DEBUG
    1890             : void
    1891             : envy_pintr(struct envy_softc *sc)
    1892             : {
    1893             :         int i;
    1894             : 
    1895             :         if (sc->spurious > 0 || envydebug >= 2) {
    1896             :                 printf("%s: spurious = %u, start = %lld.%ld\n", 
    1897             :                         DEVNAME(sc), sc->spurious,
    1898             :                         (long long)sc->start_ts.tv_sec, sc->start_ts.tv_nsec);
    1899             :                 for (i = 0; i < sc->nintr; i++) {
    1900             :                         printf("%lld.%09ld: "
    1901             :                             "active=%d/%d pos=%d/%d st=%x/%x, ctl=%x\n",
    1902             :                             (long long)sc->intrs[i].ts.tv_sec,
    1903             :                             sc->intrs[i].ts.tv_nsec,
    1904             :                             sc->intrs[i].iactive,
    1905             :                             sc->intrs[i].oactive,
    1906             :                             sc->intrs[i].ipos,
    1907             :                             sc->intrs[i].opos,
    1908             :                             sc->intrs[i].st,
    1909             :                             sc->intrs[i].mask,
    1910             :                             sc->intrs[i].ctl);
    1911             :                 }
    1912             :         }
    1913             : }
    1914             : #endif
    1915             : 
    1916             : int
    1917           0 : envy_intr(void *self)
    1918             : {
    1919           0 :         struct envy_softc *sc = (struct envy_softc *)self;
    1920             :         unsigned int reg, hwpos, cnt;
    1921             :         int mintr, mstat, mdata;
    1922             :         int st, err, ctl;
    1923             :         int max;
    1924             : 
    1925           0 :         mtx_enter(&audio_lock);
    1926           0 :         st = envy_mt_read_1(sc, ENVY_MT_INTR);
    1927           0 :         mintr = envy_ccs_read(sc, ENVY_CCS_INTSTAT);
    1928           0 :         if (!(st & ENVY_MT_INTR_ALL) && !(mintr & ENVY_CCS_INT_MIDI0)) {
    1929           0 :                 mtx_leave(&audio_lock);
    1930           0 :                 return 0;
    1931             :         }
    1932           0 :         if (st & ENVY_MT_INTR_ERR) {
    1933           0 :                 err = envy_mt_read_1(sc, ENVY_MT_ERR);
    1934           0 :                 envy_mt_write_1(sc, ENVY_MT_ERR, err);
    1935           0 :         }
    1936           0 :         envy_mt_write_1(sc, ENVY_MT_INTR, st);
    1937           0 :         envy_ccs_write(sc, ENVY_CCS_INTSTAT, mintr);
    1938             : 
    1939             : #ifdef ENVY_DEBUG
    1940             :         if (sc->nintr < ENVY_NINTR) {
    1941             :                 sc->intrs[sc->nintr].iactive = sc->iactive;
    1942             :                 sc->intrs[sc->nintr].oactive = sc->oactive;
    1943             :                 sc->intrs[sc->nintr].st = st;
    1944             :                 sc->intrs[sc->nintr].ipos = envy_mt_read_2(sc, ENVY_MT_RBUFSZ);
    1945             :                 sc->intrs[sc->nintr].opos = envy_mt_read_2(sc, ENVY_MT_PBUFSZ);
    1946             :                 sc->intrs[sc->nintr].ctl = envy_mt_read_1(sc, ENVY_MT_CTL);
    1947             :                 sc->intrs[sc->nintr].mask = envy_mt_read_1(sc, ENVY_MT_IMASK);
    1948             :                 nanouptime(&sc->intrs[sc->nintr].ts);
    1949             :                 sc->nintr++;
    1950             :         }
    1951             : #endif
    1952           0 :         if (mintr & ENVY_CCS_INT_MIDI0) {
    1953           0 :                 for (max = 128; max > 0; max--) {
    1954           0 :                         mstat = envy_ccs_read(sc, ENVY_CCS_MIDISTAT0);
    1955           0 :                         if (mstat & ENVY_MIDISTAT_IEMPTY(sc))
    1956             :                                 break;
    1957           0 :                         mdata = envy_ccs_read(sc, ENVY_CCS_MIDIDATA0);
    1958             : #if NMIDI > 0
    1959           0 :                         if (sc->midi_in)
    1960           0 :                                 sc->midi_in(sc->midi_arg, mdata);
    1961             : #endif
    1962             :                 }
    1963             :         }
    1964           0 :         if (st & ENVY_MT_INTR_PACK) {
    1965           0 :                 if (sc->oactive) {
    1966           0 :                         reg = envy_mt_read_2(sc, ENVY_MT_PBUFSZ);
    1967           0 :                         hwpos = sc->obuf.bufsz - 4 * (reg + 1);
    1968           0 :                         if (hwpos >= sc->obuf.bufsz)
    1969           0 :                                 hwpos -= sc->obuf.bufsz;
    1970             :                         DPRINTFN(2, "%s: play: reg = %u, pos: %u -> %u\n",
    1971             :                             DEVNAME(sc), reg, sc->obuf.swpos, hwpos);
    1972             :                         cnt = 0;
    1973           0 :                         while (hwpos - sc->obuf.swpos >= sc->obuf.blksz) {
    1974           0 :                                 sc->ointr(sc->oarg);
    1975           0 :                                 sc->obuf.swpos += sc->obuf.blksz;
    1976           0 :                                 if (sc->obuf.swpos == sc->obuf.bufsz)
    1977           0 :                                         sc->obuf.swpos = 0;
    1978           0 :                                 cnt++;
    1979             :                         }
    1980             :                         if (cnt != 1) {
    1981             :                                 DPRINTFN(2, "%s: play: %u intrs\n",
    1982             :                                     DEVNAME(sc), cnt);
    1983             :                         }
    1984           0 :                 } else {
    1985           0 :                         ctl = envy_mt_read_1(sc, ENVY_MT_CTL);
    1986           0 :                         if (ctl & ENVY_MT_CTL_PSTART) {
    1987           0 :                                 envy_mt_write_1(sc,
    1988           0 :                                     ENVY_MT_CTL, ctl & ~ENVY_MT_CTL_PSTART);
    1989           0 :                                 st &= ~ENVY_MT_INTR_PACK;
    1990           0 :                                 sc->obusy = 0;
    1991           0 :                                 wakeup(&sc->obusy);
    1992           0 :                         }
    1993             : #ifdef ENVY_DEBUG
    1994             :                         else
    1995             :                                 sc->spurious++;
    1996             : #endif
    1997             :                 }
    1998             :         }
    1999           0 :         if (st & ENVY_MT_INTR_RACK) {
    2000           0 :                 if (sc->iactive) {
    2001           0 :                         reg = envy_mt_read_2(sc, ENVY_MT_RBUFSZ);
    2002           0 :                         hwpos = sc->ibuf.bufsz - 4 * (reg + 1);
    2003           0 :                         if (hwpos >= sc->ibuf.bufsz)
    2004           0 :                                 hwpos -= sc->ibuf.bufsz;
    2005             :                         DPRINTFN(2, "%s: rec: reg = %u, pos: %u -> %u\n",
    2006             :                             DEVNAME(sc), reg, sc->ibuf.swpos, hwpos);
    2007             :                         cnt = 0;
    2008           0 :                         while (hwpos - sc->ibuf.swpos >= sc->ibuf.blksz) {
    2009           0 :                                 sc->iintr(sc->iarg);
    2010           0 :                                 sc->ibuf.swpos += sc->ibuf.blksz;
    2011           0 :                                 if (sc->ibuf.swpos == sc->ibuf.bufsz)
    2012           0 :                                         sc->ibuf.swpos = 0;
    2013           0 :                                 cnt++;
    2014             :                         }
    2015             :                         if (cnt != 1) {
    2016             :                                 DPRINTFN(2, "%s: rec: %u intrs\n",
    2017             :                                     DEVNAME(sc), cnt);
    2018             :                         }
    2019           0 :                 } else {
    2020           0 :                         ctl = envy_mt_read_1(sc, ENVY_MT_CTL);
    2021           0 :                         if (ctl & ENVY_MT_CTL_RSTART(sc)) {
    2022           0 :                                 envy_mt_write_1(sc,
    2023           0 :                                     ENVY_MT_CTL, ctl & ~ENVY_MT_CTL_RSTART(sc));
    2024             :                                 st &= ~ENVY_MT_INTR_RACK;
    2025           0 :                                 sc->ibusy = 0;
    2026           0 :                                 wakeup(&sc->ibusy);
    2027           0 :                         }
    2028             : #ifdef ENVY_DEBUG
    2029             :                         else
    2030             :                                 sc->spurious++;
    2031             : #endif
    2032             :                 }
    2033             :         }
    2034           0 :         mtx_leave(&audio_lock);
    2035           0 :         return 1;
    2036           0 : }
    2037             : 
    2038             : int
    2039           0 : envy_trigger_output(void *self, void *start, void *end, int blksz,
    2040             :     void (*intr)(void *), void *arg, struct audio_params *param)
    2041             : {
    2042           0 :         struct envy_softc *sc = (struct envy_softc *)self;
    2043             :         size_t bufsz;
    2044             :         int st;
    2045             : 
    2046           0 :         bufsz = (char *)end - (char *)start;
    2047             : #ifdef ENVY_DEBUG
    2048             :         if (blksz % (sc->isht ? sc->card->noch * 4 : ENVY_PFRAME_SIZE) != 0) {
    2049             :                 printf("%s: %d: bad output blksz\n", DEVNAME(sc), blksz);
    2050             :                 return EINVAL;
    2051             :         }
    2052             :         if (bufsz % blksz) {
    2053             :                 printf("%s: %ld: bad output bufsz\n", DEVNAME(sc), bufsz);
    2054             :                 return EINVAL;
    2055             :         }
    2056             : #endif
    2057           0 :         mtx_enter(&audio_lock);
    2058           0 :         envy_mt_write_4(sc, ENVY_MT_PADDR, sc->obuf.map->dm_segs[0].ds_addr);
    2059           0 :         envy_mt_write_2(sc, ENVY_MT_PBUFSZ, bufsz / 4 - 1);
    2060           0 :         envy_mt_write_2(sc, ENVY_MT_PBLKSZ(sc), blksz / 4 - 1);
    2061             : 
    2062             : #ifdef ENVY_DEBUG
    2063             :         if (!sc->iactive) {
    2064             :                 sc->nintr = 0;
    2065             :                 sc->spurious = 0;
    2066             :                 nanouptime(&sc->start_ts);
    2067             :         }
    2068             : #endif
    2069           0 :         sc->obuf.bufsz = bufsz;
    2070           0 :         sc->obuf.blksz = blksz;
    2071           0 :         sc->obuf.swpos = 0;
    2072           0 :         sc->ointr = intr;
    2073           0 :         sc->oarg = arg;
    2074           0 :         sc->oactive = 1;
    2075           0 :         sc->obusy = 1;
    2076             :         st = ENVY_MT_INTR_PACK;
    2077           0 :         envy_mt_write_1(sc, ENVY_MT_INTR, st);
    2078           0 :         st = envy_mt_read_1(sc, ENVY_MT_CTL);
    2079           0 :         st |= ENVY_MT_CTL_PSTART;
    2080           0 :         envy_mt_write_1(sc, ENVY_MT_CTL, st);
    2081           0 :         mtx_leave(&audio_lock);
    2082           0 :         return 0;
    2083             : }
    2084             : 
    2085             : int
    2086           0 : envy_trigger_input(void *self, void *start, void *end, int blksz,
    2087             :     void (*intr)(void *), void *arg, struct audio_params *param)
    2088             : {
    2089           0 :         struct envy_softc *sc = (struct envy_softc *)self;
    2090             :         size_t bufsz;
    2091             :         int st;
    2092             : 
    2093           0 :         bufsz = (char *)end - (char *)start;
    2094             : #ifdef ENVY_DEBUG
    2095             :         if (blksz % (sc->isht ? sc->card->nich * 4 : ENVY_RFRAME_SIZE) != 0) {
    2096             :                 printf("%s: %d: bad input blksz\n", DEVNAME(sc), blksz);
    2097             :                 return EINVAL;
    2098             :         }
    2099             :         if (bufsz % blksz != 0) {
    2100             :                 printf("%s: %ld: bad input bufsz\n", DEVNAME(sc), bufsz);
    2101             :                 return EINVAL;
    2102             :         }
    2103             : #endif
    2104           0 :         mtx_enter(&audio_lock);
    2105           0 :         envy_mt_write_4(sc, ENVY_MT_RADDR, sc->ibuf.map->dm_segs[0].ds_addr);
    2106           0 :         envy_mt_write_2(sc, ENVY_MT_RBUFSZ, bufsz / 4 - 1);
    2107           0 :         envy_mt_write_2(sc, ENVY_MT_RBLKSZ, blksz / 4 - 1);
    2108             : 
    2109             : #ifdef ENVY_DEBUG
    2110             :         if (!sc->oactive) {
    2111             :                 sc->nintr = 0;
    2112             :                 sc->spurious = 0;
    2113             :                 nanouptime(&sc->start_ts);
    2114             :         }
    2115             : #endif
    2116           0 :         sc->ibuf.bufsz = bufsz;
    2117           0 :         sc->ibuf.blksz = blksz;
    2118           0 :         sc->ibuf.swpos = 0;
    2119           0 :         sc->iintr = intr;
    2120           0 :         sc->iarg = arg;
    2121           0 :         sc->iactive = 1;
    2122           0 :         sc->ibusy = 1;
    2123             :         st = ENVY_MT_INTR_RACK;
    2124           0 :         envy_mt_write_1(sc, ENVY_MT_INTR, st);
    2125           0 :         st = envy_mt_read_1(sc, ENVY_MT_CTL);
    2126           0 :         st |= ENVY_MT_CTL_RSTART(sc);
    2127           0 :         envy_mt_write_1(sc, ENVY_MT_CTL, st);
    2128           0 :         mtx_leave(&audio_lock);
    2129           0 :         return 0;
    2130             : }
    2131             : 
    2132             : int
    2133           0 : envy_halt_output(void *self)
    2134             : {
    2135           0 :         struct envy_softc *sc = (struct envy_softc *)self;
    2136             :         int err;
    2137             : 
    2138           0 :         mtx_enter(&audio_lock);
    2139           0 :         sc->oactive = 0;
    2140           0 :         if (sc->obusy) {
    2141           0 :                 err = msleep(&sc->obusy, &audio_lock, PWAIT, "envyobus", 4 * hz);
    2142           0 :                 if (err)
    2143           0 :                         printf("%s: output DMA halt timeout\n", DEVNAME(sc));
    2144             :         }
    2145             : #ifdef ENVY_DEBUG
    2146             :         if (!sc->iactive)
    2147             :                 envy_pintr(sc);
    2148             : #endif
    2149           0 :         mtx_leave(&audio_lock);
    2150           0 :         return 0;
    2151             : }
    2152             : 
    2153             : int
    2154           0 : envy_halt_input(void *self)
    2155             : {
    2156           0 :         struct envy_softc *sc = (struct envy_softc *)self;
    2157             :         int err;
    2158             : 
    2159           0 :         mtx_enter(&audio_lock);
    2160           0 :         sc->iactive = 0;
    2161           0 :         if (sc->ibusy) {
    2162           0 :                 err = msleep(&sc->ibusy, &audio_lock, PWAIT, "envyibus", 4 * hz); 
    2163           0 :                 if (err)
    2164           0 :                         printf("%s: input DMA halt timeout\n", DEVNAME(sc));
    2165             :         }
    2166             : #ifdef ENVY_DEBUG
    2167             :         if (!sc->oactive)
    2168             :                 envy_pintr(sc);
    2169             : #endif
    2170           0 :         mtx_leave(&audio_lock);
    2171           0 :         return 0;
    2172             : }
    2173             : 
    2174             : int
    2175           0 : envy_query_devinfo(void *self, struct mixer_devinfo *dev)
    2176             : {
    2177           0 :         struct envy_softc *sc = (struct envy_softc *)self;
    2178             :         int i, n, idx, ndev;
    2179           0 :         char *classes[] = {
    2180             :                 AudioCinputs, AudioCoutputs, AudioCmonitor
    2181             :         };
    2182             : 
    2183           0 :         if (sc->isac97)
    2184           0 :                 return (sc->codec_if->vtbl->query_devinfo(sc->codec_if, dev));
    2185             : 
    2186           0 :         if (dev->index < 0)
    2187           0 :                 return ENXIO;
    2188             : 
    2189             :         idx = dev->index;
    2190             :         ndev = ENVY_MIX_NCLASS;
    2191           0 :         dev->prev = dev->next = AUDIO_MIXER_LAST;
    2192             : 
    2193             :         /*
    2194             :          * classes
    2195             :          */
    2196           0 :         if (idx < ndev) {
    2197           0 :                 dev->type = AUDIO_MIXER_CLASS;
    2198           0 :                 dev->mixer_class = idx;
    2199           0 :                 strlcpy(dev->label.name, classes[idx], MAX_AUDIO_DEV_LEN);
    2200           0 :                 return 0;
    2201             :         }
    2202           0 :         idx -= ndev;
    2203             : 
    2204             :         /*
    2205             :          * output.lineX_source
    2206             :          */
    2207           0 :         ndev = sc->card->noch;
    2208           0 :         if (idx < ndev) {
    2209             :                 n = 0;
    2210           0 :                 dev->type = AUDIO_MIXER_ENUM;
    2211           0 :                 dev->mixer_class = ENVY_MIX_CLASSOUT;
    2212           0 :                 for (i = 0; i < sc->card->nich; i++) {
    2213             :                         dev->un.e.member[n].ord = n;
    2214           0 :                         snprintf(dev->un.e.member[n++].label.name,
    2215             :                             MAX_AUDIO_DEV_LEN, AudioNline "-%d", i);
    2216             :                 }
    2217             :                 dev->un.e.member[n].ord = n;
    2218           0 :                 snprintf(dev->un.e.member[n++].label.name,
    2219             :                          MAX_AUDIO_DEV_LEN, "play-%d", idx);
    2220           0 :                 if (!sc->isht && idx < 2) {
    2221           0 :                         dev->un.e.member[n].ord = n;
    2222           0 :                         snprintf(dev->un.e.member[n++].label.name,
    2223             :                             MAX_AUDIO_DEV_LEN, "mon-%d", idx);
    2224           0 :                 }
    2225           0 :                 snprintf(dev->label.name, MAX_AUDIO_DEV_LEN,
    2226             :                     AudioNline "-%d_" AudioNsource, idx);
    2227           0 :                 dev->un.s.num_mem = n;
    2228           0 :                 return 0;
    2229             :         }
    2230           0 :         idx -= ndev;
    2231             : 
    2232             :         /*
    2233             :          * envy monitor level
    2234             :          */
    2235           0 :         ndev = sc->isht ? 0 : ENVY_MIX_NMONITOR;
    2236           0 :         if (idx < ndev) {
    2237           0 :                 dev->type = AUDIO_MIXER_VALUE;
    2238           0 :                 dev->mixer_class = ENVY_MIX_CLASSMON;
    2239           0 :                 dev->un.v.delta = 2;
    2240           0 :                 dev->un.v.num_channels = 1;
    2241           0 :                 snprintf(dev->label.name, MAX_AUDIO_DEV_LEN,
    2242           0 :                          "%s-%d", idx < 10 ? "play" : "rec", idx % 10);
    2243           0 :                 strlcpy(dev->un.v.units.name, AudioNvolume, MAX_AUDIO_DEV_LEN);
    2244           0 :                 return 0;
    2245             :         }
    2246           0 :         idx -= ndev;
    2247             : 
    2248             :         /*
    2249             :          * inputs.xxx
    2250             :          */
    2251           0 :         ndev = sc->card->adc->ndev(sc);
    2252           0 :         if (idx < ndev) {
    2253           0 :                 sc->card->adc->devinfo(sc, dev, idx);
    2254           0 :                 return 0;
    2255             :         }
    2256           0 :         idx -= ndev;
    2257             : 
    2258             :         /*
    2259             :          * outputs.xxx
    2260             :          */
    2261           0 :         ndev = sc->card->dac->ndev(sc);
    2262           0 :         if (idx < ndev) {
    2263           0 :                 sc->card->dac->devinfo(sc, dev, idx);
    2264           0 :                 return 0;
    2265             :         }
    2266           0 :         return ENXIO;
    2267           0 : }
    2268             : 
    2269             : int
    2270           0 : envy_get_port(void *self, struct mixer_ctrl *ctl)
    2271             : {
    2272           0 :         struct envy_softc *sc = (struct envy_softc *)self;
    2273           0 :         int val, idx, ndev;
    2274             : 
    2275           0 :         if (sc->isac97)
    2276           0 :                 return (sc->codec_if->vtbl->mixer_get_port(sc->codec_if, ctl));
    2277             : 
    2278           0 :         if (ctl->dev < ENVY_MIX_NCLASS) {
    2279           0 :                 return EINVAL;
    2280             :         }
    2281             : 
    2282           0 :         idx = ctl->dev - ENVY_MIX_NCLASS;
    2283           0 :         ndev = sc->card->noch;
    2284           0 :         if (idx < ndev) {
    2285           0 :                 ctl->un.ord = envy_lineout_getsrc(sc, idx);
    2286           0 :                 if (ctl->un.ord >= ENVY_MIX_NOUTSRC)
    2287           0 :                         ctl->un.ord -= ENVY_MIX_NOUTSRC - sc->card->nich;
    2288           0 :                 return 0;
    2289             :         }
    2290           0 :         idx -= ndev;
    2291           0 :         ndev = sc->isht ? 0 : ENVY_MIX_NMONITOR;
    2292           0 :         if (idx < ndev) {
    2293           0 :                 envy_mon_getvol(sc, idx / 2, idx % 2, &val);
    2294           0 :                 ctl->un.value.num_channels = 1;
    2295           0 :                 ctl->un.value.level[0] = 2 * val;
    2296           0 :                 return 0;
    2297             :         }
    2298           0 :         idx -= ndev;
    2299           0 :         ndev = sc->card->adc->ndev(sc);
    2300           0 :         if (idx < ndev) {
    2301           0 :                 sc->card->adc->get(sc, ctl, idx);
    2302           0 :                 return 0;
    2303             :         }
    2304           0 :         idx -= ndev;
    2305           0 :         ndev = sc->card->dac->ndev(sc);
    2306           0 :         if (idx < ndev) {
    2307           0 :                 sc->card->dac->get(sc, ctl, idx);
    2308           0 :                 return 0;
    2309             :         }
    2310           0 :         return ENXIO;
    2311           0 : }
    2312             : 
    2313             : int
    2314           0 : envy_set_port(void *self, struct mixer_ctrl *ctl)
    2315             : {
    2316           0 :         struct envy_softc *sc = (struct envy_softc *)self;
    2317             :         int maxsrc, val, idx, ndev;
    2318             : 
    2319           0 :         if (sc->isac97)
    2320           0 :                 return (sc->codec_if->vtbl->mixer_set_port(sc->codec_if, ctl));
    2321             : 
    2322           0 :         if (ctl->dev < ENVY_MIX_NCLASS) {
    2323           0 :                 return EINVAL;
    2324             :         }
    2325             : 
    2326           0 :         idx = ctl->dev - ENVY_MIX_NCLASS;
    2327           0 :         ndev = sc->card->noch;
    2328           0 :         if (idx < ndev) {
    2329           0 :                 maxsrc = sc->card->nich + 1;
    2330           0 :                 if (idx < 2)
    2331           0 :                         maxsrc++;
    2332           0 :                 if (ctl->un.ord < 0 || ctl->un.ord >= maxsrc)
    2333           0 :                         return EINVAL;
    2334           0 :                 if (ctl->un.ord >= sc->card->nich)
    2335           0 :                         ctl->un.ord += ENVY_MIX_NOUTSRC - sc->card->nich;
    2336           0 :                 envy_lineout_setsrc(sc, idx, ctl->un.ord);
    2337           0 :                 return 0;
    2338             :         }
    2339           0 :         idx -= ndev;
    2340           0 :         ndev = sc->isht ? 0 : ENVY_MIX_NMONITOR;
    2341           0 :         if (idx < ndev) {
    2342           0 :                 if (ctl->un.value.num_channels != 1) {
    2343           0 :                         return EINVAL;
    2344             :                 }
    2345           0 :                 val = ctl->un.value.level[0] / 2;
    2346           0 :                 envy_mon_setvol(sc, idx / 2, idx % 2, val);
    2347           0 :                 return 0;
    2348             :         }
    2349           0 :         idx -= ndev;
    2350           0 :         ndev = sc->card->adc->ndev(sc);
    2351           0 :         if (idx < ndev)
    2352           0 :                 return sc->card->adc->set(sc, ctl, idx);
    2353           0 :         idx -= ndev;
    2354           0 :         ndev = sc->card->dac->ndev(sc);
    2355           0 :         if (idx < ndev)
    2356           0 :                 return sc->card->dac->set(sc, ctl, idx);
    2357           0 :         return ENXIO;
    2358           0 : }
    2359             : 
    2360             : int
    2361           0 : envy_get_props(void *self)
    2362             : {
    2363           0 :         return AUDIO_PROP_FULLDUPLEX | AUDIO_PROP_INDEPENDENT;
    2364             : }
    2365             : 
    2366             : #if NMIDI > 0
    2367             : int
    2368           0 : envy_midi_open(void *self, int flags,
    2369             :     void (*in)(void *, int),
    2370             :     void (*out)(void *),
    2371             :     void *arg)
    2372             : {
    2373           0 :         struct envy_softc *sc = (struct envy_softc *)self;
    2374             :         unsigned int i, reg;
    2375             : 
    2376             :         /* discard pending data */
    2377           0 :         for (i = 0; i < 128; i++) {
    2378           0 :                 reg = envy_ccs_read(sc, ENVY_CCS_MIDISTAT0);
    2379           0 :                 if (reg & ENVY_MIDISTAT_IEMPTY(sc))
    2380             :                         break;
    2381           0 :                 (void)envy_ccs_read(sc, ENVY_CCS_MIDIDATA0);
    2382             :         }
    2383             : #ifdef ENVY_DEBUG
    2384             :         if (i > 0)
    2385             :                 DPRINTF("%s: midi: discarded %u bytes\n", DEVNAME(sc), i);
    2386             : #endif
    2387             : 
    2388             :         /* clear pending midi interrupt */
    2389           0 :         envy_ccs_write(sc, ENVY_CCS_INTSTAT, ENVY_CCS_INT_MIDI0);
    2390             : 
    2391             :         /* interrupts are disabled, it safe to manipulate these */
    2392           0 :         sc->midi_in = in;
    2393           0 :         sc->midi_out = out;
    2394           0 :         sc->midi_arg = arg;
    2395           0 :         sc->midi_isopen = 1;
    2396             : 
    2397             :         /* enable interrupts */
    2398           0 :         reg = envy_ccs_read(sc, ENVY_CCS_INTMASK);
    2399           0 :         reg &= ~ENVY_CCS_INT_MIDI0;
    2400           0 :         envy_ccs_write(sc, ENVY_CCS_INTMASK, reg);
    2401           0 :         return 0;
    2402             : }
    2403             : 
    2404             : void
    2405           0 : envy_midi_close(void *self)
    2406             : {
    2407           0 :         struct envy_softc *sc = (struct envy_softc *)self;
    2408             :         unsigned int reg;
    2409             : 
    2410             :         /* wait for output fifo to drain */
    2411           0 :         tsleep(sc, PWAIT, "envymid", hz / 10);
    2412             : 
    2413             :         /* disable interrupts */
    2414           0 :         reg = envy_ccs_read(sc, ENVY_CCS_INTMASK);
    2415           0 :         reg |= ENVY_CCS_INT_MIDI0;
    2416           0 :         envy_ccs_write(sc, ENVY_CCS_INTMASK, reg);
    2417             : 
    2418             :         /* interrupts are disabled, it safe to manipulate these */
    2419           0 :         sc->midi_in = NULL;
    2420           0 :         sc->midi_out = NULL;
    2421           0 :         sc->midi_isopen = 0;
    2422           0 : }
    2423             : 
    2424             : int
    2425           0 : envy_midi_output(void *self, int data)
    2426             : {
    2427           0 :         struct envy_softc *sc = (struct envy_softc *)self;
    2428             :         int st;
    2429             :         
    2430           0 :         st = envy_ccs_read(sc, ENVY_CCS_MIDISTAT0);
    2431           0 :         if (st & ENVY_MIDISTAT_OBUSY(sc))
    2432           0 :                 return 0;
    2433           0 :         envy_ccs_write(sc, ENVY_CCS_MIDIDATA0, data);
    2434           0 :         return 1;
    2435           0 : }
    2436             : 
    2437             : void
    2438           0 : envy_midi_getinfo(void *self, struct midi_info *mi)
    2439             : {
    2440           0 :         mi->props = MIDI_PROP_CAN_INPUT;
    2441           0 :         mi->name = "Envy24 MIDI UART";
    2442           0 : }
    2443             : #endif

Generated by: LCOV version 1.13