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

          Line data    Source code
       1             : /* $OpenBSD: auixp.c,v 1.40 2018/09/03 05:37:32 miko Exp $ */
       2             : /* $NetBSD: auixp.c,v 1.9 2005/06/27 21:13:09 thorpej Exp $ */
       3             : 
       4             : /*
       5             :  * Copyright (c) 2004, 2005 Reinoud Zandijk <reinoud@netbsd.org>
       6             :  * All rights reserved.
       7             :  *
       8             :  * Redistribution and use in source and binary forms, with or without
       9             :  * modification, are permitted provided that the following conditions
      10             :  * are met:
      11             :  * 1. Redistributions of source code must retain the above copyright
      12             :  *    notice, this list of conditions and the following disclaimer.
      13             :  * 2. The name of the author may not be used to endorse or promote products
      14             :  *    derived from this software without specific prior written permission.
      15             :  * 3. All advertising materials mentioning features or use of this software
      16             :  *    must display the following acknowledgement:
      17             :  *      This product includes software developed by the NetBSD
      18             :  *      Foundation, Inc. and its contributors.
      19             :  * 4. Neither the name of The NetBSD Foundation nor the names of its
      20             :  *    contributors may be used to endorse or promote products derived
      21             :  *    from this software without specific prior written permission.
      22             :  *
      23             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
      24             :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      25             :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      26             :  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
      27             :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
      28             :  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
      29             :  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
      30             :  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
      31             :  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      32             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      33             :  * SUCH DAMAGE.
      34             :  */
      35             : /*
      36             :  * Audio driver for ATI IXP-{150,200,...} audio driver hardware.
      37             :  *
      38             :  * Recording and playback has been tested OK on various sample rates and
      39             :  * encodings.
      40             :  *
      41             :  * Known problems and issues :
      42             :  * - SPDIF is untested and needs some work still (LED stays off)
      43             :  * - 32 bit audio playback failed last time i tried but that might an AC'97
      44             :  *   codec support problem.
      45             :  * - 32 bit recording works but can't try out playing: see above.
      46             :  * - no suspend/resume support yet.
      47             :  * - multiple codecs are `supported' but not tested; the implemetation needs
      48             :  *   some cleaning up.
      49             :  */
      50             : 
      51             : /*#define DEBUG_AUIXP*/
      52             : 
      53             : #include <sys/param.h>
      54             : #include <sys/errno.h>
      55             : #include <sys/systm.h>
      56             : #include <sys/malloc.h>
      57             : #include <sys/device.h>
      58             : #include <sys/conf.h>
      59             : #include <sys/exec.h>
      60             : #include <sys/selinfo.h>
      61             : #include <sys/audioio.h>
      62             : #include <sys/queue.h>
      63             : 
      64             : #include <machine/bus.h>
      65             : 
      66             : #include <dev/pci/pcidevs.h>
      67             : #include <dev/pci/pcivar.h>
      68             : 
      69             : #include <dev/audio_if.h>
      70             : #include <dev/ic/ac97.h>
      71             : 
      72             : #include <dev/pci/auixpreg.h>
      73             : #include <dev/pci/auixpvar.h>
      74             : 
      75             : /* codec detection constant indicating the interrupt flags */
      76             : #define ALL_CODECS_NOT_READY \
      77             :     (ATI_REG_ISR_CODEC0_NOT_READY | ATI_REG_ISR_CODEC1_NOT_READY |\
      78             :      ATI_REG_ISR_CODEC2_NOT_READY)
      79             : #define CODEC_CHECK_BITS (ALL_CODECS_NOT_READY|ATI_REG_ISR_NEW_FRAME)
      80             : 
      81             : /* why isn't this base address register not in the headerfile? */
      82             : #define PCI_CBIO 0x10
      83             : 
      84             : /* macro's used */
      85             : #define KERNADDR(p)     ((void *)((p)->addr))
      86             : #define DMAADDR(p)      ((p)->map->dm_segs[0].ds_addr)
      87             : 
      88             : const struct pci_matchid auixp_pci_devices[] = {
      89             :         { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB200_AUDIO },
      90             :         { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB300_AUDIO },
      91             :         { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB400_AUDIO },
      92             :         { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB600_AUDIO }
      93             : };
      94             : 
      95             : struct cfdriver auixp_cd = {
      96             :         NULL, "auixp", DV_DULL
      97             : };
      98             : 
      99             : int     auixp_match( struct device *, void *, void *);
     100             : void    auixp_attach(struct device *, struct device *, void *);
     101             : int     auixp_detach(struct device *, int);
     102             : 
     103             : int     auixp_activate(struct device *, int);
     104             : 
     105             : struct cfattach auixp_ca = {
     106             :         sizeof(struct auixp_softc), auixp_match, auixp_attach,
     107             :         NULL, auixp_activate
     108             : };
     109             : 
     110             : int     auixp_open(void *v, int flags);
     111             : void    auixp_close(void *v);
     112             : int     auixp_set_params(void *, int, int, struct audio_params *,
     113             :     struct audio_params *);
     114             : int     auixp_commit_settings(void *);
     115             : int     auixp_round_blocksize(void *, int);
     116             : int     auixp_trigger_output(void *, void *, void *, int,
     117             :     void (*)(void *), void *, struct audio_params *);
     118             : int     auixp_trigger_input(void *, void *, void *, int,
     119             :     void (*)(void *), void *, struct audio_params *);
     120             : int     auixp_halt_output(void *);
     121             : int     auixp_halt_input(void *);
     122             : int     auixp_set_port(void *, mixer_ctrl_t *);
     123             : int     auixp_get_port(void *, mixer_ctrl_t *);
     124             : int     auixp_query_devinfo(void *, mixer_devinfo_t *);
     125             : void *  auixp_malloc(void *, int, size_t, int, int);
     126             : void    auixp_free(void *, void *, int);
     127             : int     auixp_get_props(void *);
     128             : int     auixp_intr(void *);
     129             : int     auixp_allocmem(struct auixp_softc *, size_t, size_t,
     130             :     struct auixp_dma *);
     131             : int     auixp_freemem(struct auixp_softc *, struct auixp_dma *);
     132             : 
     133             : /* Supporting subroutines */
     134             : int     auixp_init(struct auixp_softc *);
     135             : void    auixp_autodetect_codecs(struct auixp_softc *);
     136             : void    auixp_post_config(struct device *);
     137             : 
     138             : void    auixp_reset_aclink(struct auixp_softc *);
     139             : int     auixp_attach_codec(void *, struct ac97_codec_if *);
     140             : int     auixp_read_codec(void *, u_int8_t, u_int16_t *);
     141             : int     auixp_write_codec(void *, u_int8_t, u_int16_t);
     142             : int     auixp_wait_for_codecs(struct auixp_softc *, const char *);
     143             : void    auixp_reset_codec(void *);
     144             : enum ac97_host_flags    auixp_flags_codec(void *);
     145             : 
     146             : void    auixp_enable_dma(struct auixp_softc *, struct auixp_dma *);
     147             : void    auixp_disable_dma(struct auixp_softc *, struct auixp_dma *);
     148             : void    auixp_enable_interrupts(struct auixp_softc *);
     149             : void    auixp_disable_interrupts(struct auixp_softc *);
     150             : 
     151             : void    auixp_link_daisychain(struct auixp_softc *,
     152             :     struct auixp_dma *, struct auixp_dma *, int, int);
     153             : int     auixp_allocate_dma_chain(struct auixp_softc *, struct auixp_dma **);
     154             : void    auixp_program_dma_chain(struct auixp_softc *, struct auixp_dma *);
     155             : void    auixp_dma_update(struct auixp_softc *, struct auixp_dma *);
     156             : void    auixp_update_busbusy(struct auixp_softc *);
     157             : 
     158             : #ifdef DEBUG_AUIXP
     159             : #define DPRINTF(x)      printf x;
     160             : #else
     161             : #define DPRINTF(x)
     162             : #endif
     163             : 
     164             : struct audio_hw_if auixp_hw_if = {
     165             :         auixp_open,
     166             :         auixp_close,
     167             :         auixp_set_params,
     168             :         auixp_round_blocksize,
     169             :         auixp_commit_settings,
     170             :         NULL,                   /* init_output  */
     171             :         NULL,                   /* init_input   */
     172             :         NULL,                   /* start_output */
     173             :         NULL,                   /* start_input  */
     174             :         auixp_halt_output,
     175             :         auixp_halt_input,
     176             :         NULL,                   /* speaker_ctl */
     177             :         NULL,                   /* getfd */
     178             :         auixp_set_port,
     179             :         auixp_get_port,
     180             :         auixp_query_devinfo,
     181             :         auixp_malloc,
     182             :         auixp_free,
     183             :         NULL,                   /* round_buffersize */
     184             :         auixp_get_props,
     185             :         auixp_trigger_output,
     186             :         auixp_trigger_input
     187             : };
     188             : 
     189             : int
     190           0 : auixp_open(void *v, int flags)
     191             : {
     192             : 
     193           0 :         return 0;
     194             : }
     195             : 
     196             : void
     197           0 : auixp_close(void *v)
     198             : {
     199           0 : }
     200             : 
     201             : /* commit setting and program ATI IXP chip */
     202             : int
     203           0 : auixp_commit_settings(void *hdl)
     204             : {
     205             :         struct auixp_codec *co;
     206             :         struct auixp_softc *sc;
     207             :         bus_space_tag_t    iot;
     208             :         bus_space_handle_t ioh;
     209             :         struct audio_params *params;
     210             :         u_int32_t value;
     211             : 
     212             :         /* XXX would it be better to stop interrupts first? XXX */
     213           0 :         co = (struct auixp_codec *) hdl;
     214           0 :         sc = co->sc;
     215           0 :         iot = sc->sc_iot;
     216           0 :         ioh = sc->sc_ioh;
     217             : 
     218             :         /* process input settings */
     219           0 :         params = &sc->sc_play_params;
     220             : 
     221             :         /* set input interleaving (precision) */
     222           0 :         value  =  bus_space_read_4(iot, ioh, ATI_REG_CMD);
     223           0 :         value &= ~ATI_REG_CMD_INTERLEAVE_IN;
     224           0 :         if (params->precision <= 16)
     225           0 :                 value |= ATI_REG_CMD_INTERLEAVE_IN;
     226           0 :         bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
     227             : 
     228             :         /* process output settings */
     229             :         params = &sc->sc_play_params;
     230             : 
     231           0 :         value  =  bus_space_read_4(iot, ioh, ATI_REG_OUT_DMA_SLOT);
     232           0 :         value &= ~ATI_REG_OUT_DMA_SLOT_MASK;
     233             : 
     234             :         /* TODO SPDIF case for 8 channels */
     235           0 :         switch (params->channels) {
     236             :         case 6:
     237           0 :                 value |= ATI_REG_OUT_DMA_SLOT_BIT(7) |
     238             :                          ATI_REG_OUT_DMA_SLOT_BIT(8);
     239             :                 /* FALLTHROUGH */
     240             :         case 4:
     241           0 :                 value |= ATI_REG_OUT_DMA_SLOT_BIT(6) |
     242             :                          ATI_REG_OUT_DMA_SLOT_BIT(9);
     243             :                 /* FALLTHROUGH */
     244             :         default:
     245           0 :                 value |= ATI_REG_OUT_DMA_SLOT_BIT(3) |
     246             :                          ATI_REG_OUT_DMA_SLOT_BIT(4);
     247             :                 break;
     248             :         }
     249             :         /* set output threshold */
     250           0 :         value |= 0x04 << ATI_REG_OUT_DMA_THRESHOLD_SHIFT;
     251           0 :         bus_space_write_4(iot, ioh, ATI_REG_OUT_DMA_SLOT, value);
     252             : 
     253             :         /* set output interleaving (precision) */
     254           0 :         value  =  bus_space_read_4(iot, ioh, ATI_REG_CMD);
     255           0 :         value &= ~ATI_REG_CMD_INTERLEAVE_OUT;
     256           0 :         if (params->precision <= 16)
     257           0 :                 value |= ATI_REG_CMD_INTERLEAVE_OUT;
     258           0 :         bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
     259             : 
     260             :         /* enable 6 channel reordering */
     261           0 :         value  =  bus_space_read_4(iot, ioh, ATI_REG_6CH_REORDER);
     262           0 :         value &= ~ATI_REG_6CH_REORDER_EN;
     263           0 :         if (params->channels == 6)
     264           0 :                 value |= ATI_REG_6CH_REORDER_EN;
     265           0 :         bus_space_write_4(iot, ioh, ATI_REG_6CH_REORDER, value);
     266             : 
     267           0 :         if (sc->has_spdif) {
     268             :                 /* set SPDIF (if present) */
     269           0 :                 value  =  bus_space_read_4(iot, ioh, ATI_REG_CMD);
     270           0 :                 value &= ~ATI_REG_CMD_SPDF_CONFIG_MASK;
     271           0 :                 value |=  ATI_REG_CMD_SPDF_CONFIG_34; /* NetBSD AC'97 default */
     272             : 
     273             :                 /* XXX this is probably not necessary unless splitted XXX */
     274           0 :                 value &= ~ATI_REG_CMD_INTERLEAVE_SPDF;
     275           0 :                 if (params->precision <= 16)
     276           0 :                         value |= ATI_REG_CMD_INTERLEAVE_SPDF;
     277           0 :                 bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
     278           0 :         }
     279             : 
     280           0 :         return 0;
     281             : }
     282             : 
     283             : 
     284             : /* set audio properties in desired setting */
     285             : int
     286           0 : auixp_set_params(void *hdl, int setmode, int usemode,
     287             :     struct audio_params *play, struct audio_params *rec)
     288             : {
     289             :         struct auixp_codec *co;
     290             :         int error;
     291             :         u_int temprate;
     292             : 
     293           0 :         co = (struct auixp_codec *) hdl;
     294           0 :         if (setmode & AUMODE_PLAY) {
     295           0 :                 play->channels = 2;
     296           0 :                 play->precision = 16;
     297           0 :                 switch(play->encoding) {
     298             :                 case AUDIO_ENCODING_SLINEAR_LE:
     299             :                         break;
     300             :                 default:
     301           0 :                         return (EINVAL);
     302             :                 }
     303           0 :                 play->bps = AUDIO_BPS(play->precision);
     304           0 :                 play->msb = 1;
     305             : 
     306           0 :                 temprate = play->sample_rate;
     307           0 :                 error = ac97_set_rate(co->codec_if,
     308             :                     AC97_REG_PCM_LFE_DAC_RATE, &play->sample_rate);
     309           0 :                 if (error)
     310           0 :                         return (error);
     311             : 
     312           0 :                 play->sample_rate = temprate;
     313           0 :                 error = ac97_set_rate(co->codec_if,
     314             :                     AC97_REG_PCM_SURR_DAC_RATE, &play->sample_rate);
     315           0 :                 if (error)
     316           0 :                         return (error);
     317             : 
     318           0 :                 play->sample_rate = temprate;
     319           0 :                 error = ac97_set_rate(co->codec_if,
     320             :                     AC97_REG_PCM_FRONT_DAC_RATE, &play->sample_rate);
     321           0 :                 if (error)
     322           0 :                         return (error);
     323             : 
     324             :         }
     325             : 
     326           0 :         if (setmode & AUMODE_RECORD) {              
     327           0 :                 rec->channels = 2;
     328           0 :                 rec->precision = 16;
     329           0 :                 switch(rec->encoding) {
     330             :                 case AUDIO_ENCODING_SLINEAR_LE:
     331             :                         break;
     332             :                 default:
     333           0 :                         return (EINVAL);
     334             :                 }
     335           0 :                 rec->bps = AUDIO_BPS(rec->precision);
     336           0 :                 rec->msb = 1;
     337             : 
     338           0 :                 error = ac97_set_rate(co->codec_if, AC97_REG_PCM_LR_ADC_RATE,
     339           0 :                     &rec->sample_rate);
     340           0 :                 if (error)
     341           0 :                         return (error);
     342             :         }
     343             : 
     344           0 :         return (0);
     345           0 : }
     346             : 
     347             : 
     348             : /* called to translate a requested blocksize to a hw-possible one */
     349             : int
     350           0 : auixp_round_blocksize(void *v, int blk)
     351             : {
     352             : 
     353           0 :         blk = (blk + 0x1f) & ~0x1f;
     354             :         /* Be conservative; align to 32 bytes and maximise it to 64 kb */
     355           0 :         if (blk > 0x10000)
     356             :                 blk = 0x10000;
     357             : 
     358           0 :         return blk;
     359             : }
     360             : 
     361             : 
     362             : /*
     363             :  * allocate dma capable memory and record its information for later retrieval
     364             :  * when we program the dma chain itself. The trigger routines passes on the
     365             :  * kernel virtual address we return here as a reference to the mapping.
     366             :  */
     367             : void *
     368           0 : auixp_malloc(void *hdl, int direction, size_t size, int pool, int flags)
     369             : {
     370             :         struct auixp_codec *co;
     371             :         struct auixp_softc *sc;
     372             :         struct auixp_dma *dma;
     373             :         int error;
     374             : 
     375           0 :         co = (struct auixp_codec *) hdl;
     376           0 :         sc = co->sc;
     377             :         /* get us a auixp_dma structure */
     378           0 :         dma = malloc(sizeof(*dma), pool, flags);
     379           0 :         if (!dma)
     380           0 :                 return NULL;
     381             : 
     382             :         /* get us a dma buffer itself */
     383           0 :         error = auixp_allocmem(sc, size, 16, dma);
     384           0 :         if (error) {
     385           0 :                 free(dma, pool, 0);
     386           0 :                 printf("%s: auixp_malloc: not enough memory\n",
     387           0 :                     sc->sc_dev.dv_xname);
     388           0 :                 return NULL;
     389             :         }
     390           0 :         SLIST_INSERT_HEAD(&sc->sc_dma_list, dma, dma_chain);
     391             : 
     392             :         DPRINTF(("auixp_malloc: returning kern %p,   hw 0x%08x for %d bytes "
     393             :             "in %d segs\n", KERNADDR(dma), (u_int32_t) DMAADDR(dma), dma->size,
     394             :             dma->nsegs)
     395             :         );
     396             : 
     397           0 :         return KERNADDR(dma);
     398           0 : }
     399             : 
     400             : /*
     401             :  * free and release dma capable memory we allocated before and remove its
     402             :  * recording
     403             :  */
     404             : void
     405           0 : auixp_free(void *hdl, void *addr, int pool)
     406             : {
     407             :         struct auixp_codec *co;
     408             :         struct auixp_softc *sc;
     409             :         struct auixp_dma *dma;
     410             : 
     411           0 :         co = (struct auixp_codec *) hdl;
     412           0 :         sc = co->sc;
     413           0 :         SLIST_FOREACH(dma, &sc->sc_dma_list, dma_chain) {
     414           0 :                 if (KERNADDR(dma) == addr) {
     415           0 :                         SLIST_REMOVE(&sc->sc_dma_list, dma, auixp_dma,
     416             :                             dma_chain);
     417           0 :                         auixp_freemem(sc, dma);
     418           0 :                         free(dma, pool, 0);
     419           0 :                         return;
     420             :                 }
     421             :         }
     422           0 : }
     423             : 
     424             : /* pass request to AC'97 codec code */
     425             : int
     426           0 : auixp_set_port(void *hdl, mixer_ctrl_t *mc)
     427             : {
     428             :         struct auixp_codec *co;
     429             : 
     430           0 :         co = (struct auixp_codec *) hdl;
     431           0 :         return co->codec_if->vtbl->mixer_set_port(co->codec_if, mc);
     432             : }
     433             : 
     434             : 
     435             : /* pass request to AC'97 codec code */
     436             : int
     437           0 : auixp_get_port(void *hdl, mixer_ctrl_t *mc)
     438             : {
     439             :         struct auixp_codec *co;
     440             : 
     441           0 :         co = (struct auixp_codec *) hdl;
     442           0 :         return co->codec_if->vtbl->mixer_get_port(co->codec_if, mc);
     443             : }
     444             : 
     445             : /* pass request to AC'97 codec code */
     446             : int
     447           0 : auixp_query_devinfo(void *hdl, mixer_devinfo_t *di)
     448             : {
     449             :         struct auixp_codec *co;
     450             : 
     451           0 :         co = (struct auixp_codec *) hdl;
     452           0 :         return co->codec_if->vtbl->query_devinfo(co->codec_if, di);
     453             : }
     454             : 
     455             : int
     456           0 : auixp_get_props(void *hdl)
     457             : {
     458             : 
     459           0 :         return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX;
     460             : }
     461             : 
     462             : 
     463             : /*
     464             :  * A dma descriptor has dma->nsegs segments defined in dma->segs set up when
     465             :  * we claimed the memory.
     466             :  *
     467             :  * Due to our demand for one contiguous DMA area, we only have one segment. A
     468             :  * c_dma structure is about 3 kb for the 256 entries we maximally program
     469             :  * -arbitrary limit AFAIK- so all is most likely to be in one segment/page
     470             :  * anyway.
     471             :  *
     472             :  * XXX ought to implement fragmented dma area XXX
     473             :  *
     474             :  * Note that _v variables depict kernel virtual addresses, _p variables depict
     475             :  * physical addresses.
     476             :  */
     477             : void
     478           0 : auixp_link_daisychain(struct auixp_softc *sc,
     479             :                 struct auixp_dma *c_dma, struct auixp_dma *s_dma,
     480             :                 int blksize, int blocks)
     481             : {
     482             :         atiixp_dma_desc_t *caddr_v, *next_caddr_v;
     483             :         u_int32_t caddr_p, next_caddr_p, saddr_p;
     484             :         int i;
     485             : 
     486             :         /* just make sure we are not changing when its running */
     487           0 :         auixp_disable_dma(sc, c_dma);
     488             : 
     489             :         /* setup dma chain start addresses */
     490           0 :         caddr_v = KERNADDR(c_dma);
     491           0 :         caddr_p = DMAADDR(c_dma);
     492           0 :         saddr_p = DMAADDR(s_dma);
     493             : 
     494             :         /* program the requested number of blocks */
     495           0 :         for (i = 0; i < blocks; i++) {
     496             :                 /* clear the block just in case */
     497           0 :                 bzero(caddr_v, sizeof(atiixp_dma_desc_t));
     498             : 
     499             :                 /* round robin the chain dma addresses for its successor */
     500           0 :                 next_caddr_v = caddr_v + 1;
     501           0 :                 next_caddr_p = caddr_p + sizeof(atiixp_dma_desc_t);
     502             : 
     503           0 :                 if (i == blocks-1) {
     504           0 :                         next_caddr_v = KERNADDR(c_dma);
     505           0 :                         next_caddr_p = DMAADDR(c_dma);
     506           0 :                 }
     507             : 
     508             :                 /* fill in the hardware dma chain descriptor in little-endian */
     509           0 :                 caddr_v->addr   = htole32(saddr_p);
     510           0 :                 caddr_v->status = htole16(0);
     511           0 :                 caddr_v->size   = htole16((blksize >> 2)); /* in dwords (!!!) */
     512           0 :                 caddr_v->next   = htole32(next_caddr_p);
     513             : 
     514             :                 /* advance slot */
     515           0 :                 saddr_p += blksize;     /* XXX assuming contiguous XXX */
     516             :                 caddr_v  = next_caddr_v;
     517             :                 caddr_p  = next_caddr_p;
     518             :         }
     519           0 : }
     520             : 
     521             : 
     522             : int
     523           0 : auixp_allocate_dma_chain(struct auixp_softc *sc, struct auixp_dma **dmap)
     524             : {
     525             :         struct auixp_dma *dma;
     526             :         int error;
     527             : 
     528             :         /* allocate keeper of dma area */
     529           0 :         *dmap = NULL;
     530           0 :         dma = malloc(sizeof(*dma), M_DEVBUF, M_NOWAIT | M_ZERO);
     531           0 :         if (!dma)
     532           0 :                 return ENOMEM;
     533             : 
     534             :         /* allocate for daisychain of IXP hardware-dma descriptors */
     535           0 :         error = auixp_allocmem(sc, DMA_DESC_CHAIN * sizeof(atiixp_dma_desc_t),
     536             :             16, dma);
     537           0 :         if (error) {
     538           0 :                 printf("%s: can't malloc dma descriptor chain\n",
     539           0 :                     sc->sc_dev.dv_xname);
     540           0 :                 free(dma, M_DEVBUF, 0);
     541           0 :                 return ENOMEM;
     542             :         }
     543             : 
     544             :         /* return info and initialise structure */
     545           0 :         dma->intr    = NULL;
     546           0 :         dma->intrarg = NULL;
     547             : 
     548           0 :         *dmap = dma;
     549           0 :         return 0;
     550           0 : }
     551             : 
     552             : 
     553             : /* program dma chain in its link address descriptor */
     554             : void
     555           0 : auixp_program_dma_chain(struct auixp_softc *sc, struct auixp_dma *dma)
     556             : {
     557             :         bus_space_tag_t    iot;
     558             :         bus_space_handle_t ioh;
     559             :         u_int32_t value;
     560             : 
     561           0 :         iot = sc->sc_iot;
     562           0 :         ioh = sc->sc_ioh;
     563             :         /* get hardware start address of DMA chain and set valid-flag in it */
     564             :         /* XXX always at start? XXX */
     565           0 :         value = DMAADDR(dma);
     566           0 :         value = value | ATI_REG_LINKPTR_EN;
     567             : 
     568             :         /* reset linkpointer */
     569           0 :         bus_space_write_4(iot, ioh, dma->linkptr, 0);
     570             : 
     571             :         /* reset this DMA engine */
     572           0 :         auixp_disable_dma(sc, dma);
     573           0 :         auixp_enable_dma(sc, dma);
     574             : 
     575             :         /* program new DMA linkpointer */
     576           0 :         bus_space_write_4(iot, ioh, dma->linkptr, value);
     577           0 : }
     578             : 
     579             : 
     580             : /* called from interrupt code to signal end of one dma-slot */
     581             : void
     582           0 : auixp_dma_update(struct auixp_softc *sc, struct auixp_dma *dma)
     583             : {
     584             : 
     585             :         /* be very paranoid */
     586           0 :         if (!dma)
     587           0 :                 panic("auixp: update: dma = NULL");
     588           0 :         if (!dma->intr)
     589           0 :                 panic("auixp: update: dma->intr = NULL");
     590             : 
     591             :         /* request more input from upper layer */
     592           0 :         (*dma->intr)(dma->intrarg);
     593           0 : }
     594             : 
     595             : 
     596             : /*
     597             :  * The magic `busbusy' bit that needs to be set when dma is active; allowing
     598             :  * busmastering?
     599             :  */
     600             : void
     601           0 : auixp_update_busbusy(struct auixp_softc *sc)
     602             : {
     603             :         bus_space_tag_t    iot;
     604             :         bus_space_handle_t ioh;
     605             :         u_int32_t value;
     606             :         int running;
     607             : 
     608           0 :         iot = sc->sc_iot;
     609           0 :         ioh = sc->sc_ioh;
     610             :         /* set bus-busy flag when either recording or playing is performed */
     611           0 :         value  = bus_space_read_4(iot, ioh, ATI_REG_IER);
     612           0 :         value &= ~ATI_REG_IER_SET_BUS_BUSY;
     613             : 
     614           0 :         running = ((sc->sc_output_dma->running) || (sc->sc_input_dma->running));
     615           0 :         if (running)
     616           0 :                 value |= ATI_REG_IER_SET_BUS_BUSY;
     617             : 
     618           0 :         bus_space_write_4(iot, ioh, ATI_REG_IER, value);
     619             : 
     620           0 : }
     621             : 
     622             : 
     623             : /*
     624             :  * Called from upper audio layer to request playing audio, only called once;
     625             :  * audio is refilled by calling the intr() function when space is available
     626             :  * again.
     627             :  */
     628             : /* XXX almost literally a copy of trigger-input; could be factorised XXX */
     629             : int
     630           0 : auixp_trigger_output(void *hdl, void *start, void *end, int blksize,
     631             :     void (*intr)(void *), void *intrarg, struct audio_params *param)
     632             : {
     633             :         struct auixp_codec *co;
     634             :         struct auixp_softc *sc;
     635             :         struct auixp_dma   *chain_dma;
     636             :         struct auixp_dma   *sound_dma;
     637             :         u_int32_t blocks;
     638             : 
     639           0 :         co = (struct auixp_codec *) hdl;
     640           0 :         sc = co->sc;
     641           0 :         chain_dma = sc->sc_output_dma;
     642             :         /* add functions to call back */
     643           0 :         chain_dma->intr    = intr;
     644           0 :         chain_dma->intrarg = intrarg;
     645             : 
     646             :         /*
     647             :          * Program output DMA chain with blocks from [start...end] with
     648             :          * blksize fragments.
     649             :          *
     650             :          * NOTE, we can assume its in one block since we asked for it to be in
     651             :          * one contiguous blob; XXX change this? XXX
     652             :          */
     653           0 :         blocks = (size_t) (((caddr_t) end) - ((caddr_t) start)) / blksize;
     654             : 
     655             :         /* lookup `start' address in our list of DMA area's */
     656           0 :         SLIST_FOREACH(sound_dma, &sc->sc_dma_list, dma_chain) {
     657           0 :                 if (KERNADDR(sound_dma) == start)
     658             :                         break;
     659             :         }
     660             : 
     661             :         /* not ours ? then bail out */
     662           0 :         if (!sound_dma) {
     663           0 :                 printf("%s: auixp_trigger_output: bad sound addr %p\n",
     664           0 :                     sc->sc_dev.dv_xname, start);
     665           0 :                 return EINVAL;
     666             :         }
     667             : 
     668             :         /* link round-robin daisychain and program hardware */
     669           0 :         auixp_link_daisychain(sc, chain_dma, sound_dma, blksize, blocks);
     670           0 :         auixp_program_dma_chain(sc, chain_dma);
     671             : 
     672             :         /* mark we are now able to run now */
     673           0 :         mtx_enter(&audio_lock);
     674           0 :         chain_dma->running = 1;
     675             : 
     676             :         /* update bus-flags; XXX programs more flags XXX */
     677           0 :         auixp_update_busbusy(sc);
     678           0 :         mtx_leave(&audio_lock);
     679             : 
     680             :         /* callbacks happen in interrupt routine */
     681           0 :         return 0;
     682           0 : }
     683             : 
     684             : 
     685             : /* halt output of audio, just disable its dma and update bus state */
     686             : int
     687           0 : auixp_halt_output(void *hdl)
     688             : {
     689             :         struct auixp_codec *co;
     690             :         struct auixp_softc *sc;
     691             :         struct auixp_dma   *dma;
     692             : 
     693           0 :         mtx_enter(&audio_lock);
     694           0 :         co  = (struct auixp_codec *) hdl;
     695           0 :         sc  = co->sc;
     696           0 :         dma = sc->sc_output_dma;
     697           0 :         auixp_disable_dma(sc, dma);
     698             : 
     699           0 :         dma->running = 0;
     700           0 :         auixp_update_busbusy(sc);
     701           0 :         mtx_leave(&audio_lock);
     702           0 :         return 0;
     703             : }
     704             : 
     705             : 
     706             : /* XXX almost literally a copy of trigger-output; could be factorised XXX */
     707             : int
     708           0 : auixp_trigger_input(void *hdl, void *start, void *end, int blksize,
     709             :     void (*intr)(void *), void *intrarg, struct audio_params *param)
     710             : {
     711             :         struct auixp_codec *co;
     712             :         struct auixp_softc *sc;
     713             :         struct auixp_dma   *chain_dma;
     714             :         struct auixp_dma   *sound_dma;
     715             :         u_int32_t blocks;
     716             : 
     717           0 :         co = (struct auixp_codec *) hdl;
     718           0 :         sc = co->sc;
     719           0 :         chain_dma = sc->sc_input_dma;
     720             :         /* add functions to call back */
     721           0 :         chain_dma->intr    = intr;
     722           0 :         chain_dma->intrarg = intrarg;
     723             : 
     724             :         /*
     725             :          * Program output DMA chain with blocks from [start...end] with
     726             :          * blksize fragments.
     727             :          *
     728             :          * NOTE, we can assume its in one block since we asked for it to be in
     729             :          * one contiguous blob; XXX change this? XXX
     730             :          */
     731           0 :         blocks = (size_t) (((caddr_t) end) - ((caddr_t) start)) / blksize;
     732             : 
     733             :         /* lookup `start' address in our list of DMA area's */
     734           0 :         SLIST_FOREACH(sound_dma, &sc->sc_dma_list, dma_chain) {
     735           0 :                 if (KERNADDR(sound_dma) == start)
     736             :                         break;
     737             :         }
     738             : 
     739             :         /* not ours ? then bail out */
     740           0 :         if (!sound_dma) {
     741           0 :                 printf("%s: auixp_trigger_input: bad sound addr %p\n",
     742           0 :                     sc->sc_dev.dv_xname, start);
     743           0 :                 return EINVAL;
     744             :         }
     745             : 
     746             :         /* link round-robin daisychain and program hardware */
     747           0 :         auixp_link_daisychain(sc, chain_dma, sound_dma, blksize, blocks);
     748           0 :         auixp_program_dma_chain(sc, chain_dma);
     749             : 
     750             :         /* mark we are now able to run now */
     751           0 :         mtx_enter(&audio_lock);
     752           0 :         chain_dma->running = 1;
     753             : 
     754             :         /* update bus-flags; XXX programs more flags XXX */
     755           0 :         auixp_update_busbusy(sc);
     756           0 :         mtx_leave(&audio_lock);
     757             : 
     758             :         /* callbacks happen in interrupt routine */
     759           0 :         return 0;
     760           0 : }
     761             : 
     762             : 
     763             : /* halt sampling audio, just disable its dma and update bus state */
     764             : int
     765           0 : auixp_halt_input(void *hdl)
     766             : {
     767             :         struct auixp_codec *co;
     768             :         struct auixp_softc *sc;
     769             :         struct auixp_dma   *dma;
     770             : 
     771           0 :         mtx_enter(&audio_lock);
     772           0 :         co = (struct auixp_codec *) hdl;
     773           0 :         sc = co->sc;
     774           0 :         dma = sc->sc_input_dma;
     775           0 :         auixp_disable_dma(sc, dma);
     776             : 
     777           0 :         dma->running = 0;
     778           0 :         auixp_update_busbusy(sc);
     779             : 
     780           0 :         mtx_leave(&audio_lock);
     781           0 :         return 0;
     782             : }
     783             : 
     784             : 
     785             : /*
     786             :  * IXP audio interrupt handler
     787             :  *
     788             :  * note that we return the number of bits handled; the return value is not
     789             :  * documented but I saw it implemented in other drivers. Probably returning a
     790             :  * value > 0 means "I've dealt with it"
     791             :  *
     792             :  */
     793             : int
     794           0 : auixp_intr(void *softc)
     795             : {
     796             :         struct auixp_softc *sc;
     797             :         bus_space_tag_t    iot;
     798             :         bus_space_handle_t ioh;
     799             :         u_int32_t status, enable, detected_codecs;
     800             :         int ret;
     801             : 
     802           0 :         mtx_enter(&audio_lock);
     803           0 :         sc = softc;
     804           0 :         iot = sc->sc_iot;
     805           0 :         ioh = sc->sc_ioh;
     806             :         ret = 0;
     807             :         /* get status from the interrupt status register */
     808           0 :         status = bus_space_read_4(iot, ioh, ATI_REG_ISR);
     809             : 
     810           0 :         if (status == 0) {
     811           0 :                 mtx_leave(&audio_lock);
     812           0 :                 return 0;
     813             :         }
     814             : 
     815             :         DPRINTF(("%s: (status = %x)\n", sc->sc_dev.dv_xname, status));
     816             : 
     817             :         /* check DMA UPDATE flags for input & output */
     818           0 :         if (status & ATI_REG_ISR_IN_STATUS) {
     819             :                 ret++; DPRINTF(("IN_STATUS\n"));
     820           0 :                 auixp_dma_update(sc, sc->sc_input_dma);
     821           0 :         }
     822           0 :         if (status & ATI_REG_ISR_OUT_STATUS) {
     823           0 :                 ret++; DPRINTF(("OUT_STATUS\n"));
     824           0 :                 auixp_dma_update(sc, sc->sc_output_dma);
     825           0 :         }
     826             : 
     827             :         /* XXX XRUN flags not used/needed yet; should i implement it? XXX */
     828             :         /* acknowledge the interrupts nevertheless */
     829           0 :         if (status & ATI_REG_ISR_IN_XRUN) {
     830           0 :                 ret++; DPRINTF(("IN_XRUN\n"));
     831             :                 /* auixp_dma_xrun(sc, sc->sc_input_dma);  */
     832           0 :         }
     833           0 :         if (status & ATI_REG_ISR_OUT_XRUN) {
     834           0 :                 ret++; DPRINTF(("OUT_XRUN\n"));
     835             :                 /* auixp_dma_xrun(sc, sc->sc_output_dma); */
     836           0 :         }
     837             : 
     838             :         /* check if we are looking for codec detection */
     839           0 :         if (status & CODEC_CHECK_BITS) {
     840           0 :                 ret++;
     841             :                 /* mark missing codecs as not ready */
     842             :                 detected_codecs = status & CODEC_CHECK_BITS;
     843           0 :                 sc->sc_codec_not_ready_bits |= detected_codecs;
     844             : 
     845             :                 /* disable detected interrupt sources */
     846           0 :                 enable  = bus_space_read_4(iot, ioh, ATI_REG_IER);
     847           0 :                 enable &= ~detected_codecs;
     848           0 :                 bus_space_write_4(iot, ioh, ATI_REG_IER, enable);
     849           0 :         }
     850             : 
     851             :         /* acknowledge interrupt sources */
     852           0 :         bus_space_write_4(iot, ioh, ATI_REG_ISR, status);
     853           0 :         mtx_leave(&audio_lock);
     854           0 :         return ret;
     855           0 : }
     856             : 
     857             : 
     858             : /* allocate memory for dma purposes; on failure of any of the steps, roll back */
     859             : int
     860           0 : auixp_allocmem(struct auixp_softc *sc, size_t size,
     861             :                size_t align, struct auixp_dma *dma)
     862             : {
     863             :         int error;
     864             : 
     865             :         /* remember size */
     866           0 :         dma->size = size;
     867             : 
     868             :         /* allocate DMA safe memory but in just one segment for now :( */
     869           0 :         error = bus_dmamem_alloc(sc->sc_dmat, dma->size, align, 0,
     870             :             dma->segs, sizeof(dma->segs) / sizeof(dma->segs[0]), &dma->nsegs,
     871             :             BUS_DMA_NOWAIT);
     872           0 :         if (error)
     873           0 :                 return error;
     874             : 
     875             :         /*
     876             :          * map allocated memory into kernel virtual address space and keep it
     877             :          * coherent with the CPU.
     878             :          */
     879           0 :         error = bus_dmamem_map(sc->sc_dmat, dma->segs, dma->nsegs, dma->size,
     880             :                                 &dma->addr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
     881           0 :         if (error)
     882             :                 goto free;
     883             : 
     884             :         /* allocate associated dma handle and initialize it. */
     885           0 :         error = bus_dmamap_create(sc->sc_dmat, dma->size, 1, dma->size, 0,
     886             :                                   BUS_DMA_NOWAIT, &dma->map);
     887           0 :         if (error)
     888             :                 goto unmap;
     889             : 
     890             :         /*
     891             :          * load the dma handle with mappings for a dma transfer; all pages
     892             :          * need to be wired.
     893             :          */
     894           0 :         error = bus_dmamap_load(sc->sc_dmat, dma->map, dma->addr, dma->size, NULL,
     895             :                                 BUS_DMA_NOWAIT);
     896           0 :         if (error)
     897             :                 goto destroy;
     898             : 
     899           0 :         return 0;
     900             : 
     901             : destroy:
     902           0 :         bus_dmamap_destroy(sc->sc_dmat, dma->map);
     903             : unmap:
     904           0 :         bus_dmamem_unmap(sc->sc_dmat, dma->addr, dma->size);
     905             : free:
     906           0 :         bus_dmamem_free(sc->sc_dmat, dma->segs, dma->nsegs);
     907             : 
     908           0 :         return error;
     909           0 : }
     910             : 
     911             : 
     912             : /* undo dma mapping and release memory allocated */
     913             : int
     914           0 : auixp_freemem(struct auixp_softc *sc, struct auixp_dma *p)
     915             : {
     916             : 
     917           0 :         bus_dmamap_unload(sc->sc_dmat, p->map);
     918           0 :         bus_dmamap_destroy(sc->sc_dmat, p->map);
     919           0 :         bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size);
     920           0 :         bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs);
     921             : 
     922           0 :         return 0;
     923             : }
     924             : 
     925             : int
     926           0 : auixp_match(struct device *dev, void *match, void *aux)
     927             : {
     928           0 :         return (pci_matchbyid((struct pci_attach_args *)aux, auixp_pci_devices,
     929             :             sizeof(auixp_pci_devices)/sizeof(auixp_pci_devices[0])));
     930             : }
     931             : 
     932             : int
     933           0 : auixp_activate(struct device *self, int act)
     934             : {
     935           0 :         struct auixp_softc *sc = (struct auixp_softc *)self;
     936             :         int rv = 0;
     937             : 
     938           0 :         switch (act) {
     939             :         case DVACT_SUSPEND:
     940           0 :                 auixp_disable_interrupts(sc);
     941           0 :                 break;
     942             :         case DVACT_RESUME:
     943           0 :                 auixp_init(sc);
     944           0 :                 ac97_resume(&sc->sc_codec.host_if, sc->sc_codec.codec_if);
     945           0 :                 rv = config_activate_children(self, act);
     946           0 :                 break;
     947             :         default:
     948           0 :                 rv = config_activate_children(self, act);
     949           0 :                 break;
     950             :         }
     951           0 :         return (rv);
     952             : }
     953             : 
     954             : void
     955           0 : auixp_attach(struct device *parent, struct device *self, void *aux)
     956             : {
     957             :         struct auixp_softc *sc;
     958             :         struct pci_attach_args *pa;
     959             :         pcitag_t tag;
     960             :         pci_chipset_tag_t pc;
     961           0 :         pci_intr_handle_t ih;
     962             :         const char *intrstr;
     963             : 
     964           0 :         sc = (struct auixp_softc *)self;
     965           0 :         pa = (struct pci_attach_args *)aux;
     966           0 :         tag = pa->pa_tag;
     967           0 :         pc = pa->pa_pc;
     968             : 
     969             :         /* map memory; its not sized -> what is the size? max PCI slot size? */
     970           0 :         if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_MEM, 0,
     971           0 :             &sc->sc_iot, &sc->sc_ioh, &sc->sc_iob, &sc->sc_ios, 0)) {
     972           0 :                 printf(": can't map mem space\n");
     973           0 :                 return;
     974             :         }
     975             : 
     976             :         /* Initialize softc */
     977           0 :         sc->sc_tag = tag;
     978           0 :         sc->sc_pct = pc;
     979           0 :         sc->sc_dmat = pa->pa_dmat;
     980           0 :         SLIST_INIT(&sc->sc_dma_list);
     981             : 
     982             :         /* get us the auixp_dma structures */
     983           0 :         auixp_allocate_dma_chain(sc, &sc->sc_output_dma);
     984           0 :         auixp_allocate_dma_chain(sc, &sc->sc_input_dma);
     985             : 
     986             :         /* when that fails we are dead in the water */
     987           0 :         if (!sc->sc_output_dma || !sc->sc_input_dma)
     988           0 :                 return;
     989             : 
     990             : #if 0
     991             :         /* could preliminary program DMA chain */
     992             :         auixp_program_dma_chain(sc, sc->sc_output_dma);
     993             :         auixp_program_dma_chain(sc, sc->sc_input_dma);
     994             : #endif
     995             : 
     996           0 :         if (pci_intr_map(pa, &ih)) {
     997           0 :                 printf(": can't map interrupt\n");
     998           0 :                 return;
     999             :         }
    1000           0 :         intrstr = pci_intr_string(pc, ih);
    1001           0 :         sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO | IPL_MPSAFE,
    1002           0 :             auixp_intr, sc, sc->sc_dev.dv_xname);
    1003           0 :         if (sc->sc_ih == NULL) {
    1004           0 :                 printf(": can't establish interrupt");
    1005           0 :                 if (intrstr != NULL)
    1006           0 :                         printf(" at %s", intrstr);
    1007           0 :                 printf("\n");
    1008           0 :                 return;
    1009             :         }
    1010           0 :         printf(": %s\n", intrstr);
    1011             : 
    1012             :         /* power up chip */
    1013           0 :         pci_set_powerstate(pc, tag, PCI_PMCSR_STATE_D0);
    1014             : 
    1015             :         /* init chip */
    1016           0 :         if (auixp_init(sc) == -1) {
    1017           0 :                 printf("%s: auixp_attach: unable to initialize the card\n",
    1018             :                     sc->sc_dev.dv_xname);
    1019           0 :                 return;
    1020             :         }
    1021             : 
    1022             :         /*
    1023             :          * delay further configuration of codecs and audio after interrupts
    1024             :          * are enabled.
    1025             :          */
    1026           0 :         config_mountroot(self, auixp_post_config);
    1027           0 : }
    1028             : 
    1029             : /* called from autoconfigure system when interrupts are enabled */
    1030             : void
    1031           0 : auixp_post_config(struct device *self)
    1032             : {
    1033           0 :         struct auixp_softc *sc = (struct auixp_softc *)self;
    1034             : 
    1035             :         /* detect the AC97 codecs */
    1036           0 :         auixp_autodetect_codecs(sc);
    1037             : 
    1038             :         /* Bail if no codecs attached. */
    1039           0 :         if (!sc->sc_codec.present) {
    1040           0 :                 printf("%s: no codecs detected or initialised\n",
    1041           0 :                     sc->sc_dev.dv_xname);
    1042           0 :                 return;
    1043             :         }
    1044             : 
    1045           0 :         audio_attach_mi(&auixp_hw_if, &sc->sc_codec, &sc->sc_dev);
    1046             : 
    1047             : #if notyet
    1048             :         /* copy formats and invalidate entries not suitable for codec0 */
    1049             :         sc->has_4ch   = AC97_IS_4CH(sc->sc_codec.codec_if);
    1050             :         sc->has_6ch   = AC97_IS_6CH(sc->sc_codec.codec_if);
    1051             :         sc->is_fixed  = AC97_IS_FIXED_RATE(sc->sc_codec.codec_if);
    1052             :         sc->has_spdif = AC97_HAS_SPDIF(sc->sc_codec.codec_if);
    1053             : #endif
    1054             : 
    1055           0 :         if (sc->has_spdif)
    1056           0 :                 sc->has_spdif = 0;
    1057             : 
    1058             :         /* fill in the missing details about the dma channels. */
    1059             :         /* for output */
    1060           0 :         sc->sc_output_dma->linkptr        = ATI_REG_OUT_DMA_LINKPTR;
    1061           0 :         sc->sc_output_dma->dma_enable_bit = ATI_REG_CMD_OUT_DMA_EN |
    1062             :                                             ATI_REG_CMD_SEND_EN;
    1063             :         /* have spdif? then this too! XXX not seeing LED yet! XXX */
    1064           0 :         if (sc->has_spdif)
    1065           0 :                 sc->sc_output_dma->dma_enable_bit |= ATI_REG_CMD_SPDF_OUT_EN;
    1066             : 
    1067             :         /* and for input */
    1068           0 :         sc->sc_input_dma->linkptr         = ATI_REG_IN_DMA_LINKPTR;
    1069           0 :         sc->sc_input_dma->dma_enable_bit  = ATI_REG_CMD_IN_DMA_EN  |
    1070             :                                             ATI_REG_CMD_RECEIVE_EN;
    1071             : 
    1072             :         /* done! now enable all interrupts we can service */
    1073           0 :         auixp_enable_interrupts(sc);
    1074           0 : }
    1075             : 
    1076             : void
    1077           0 : auixp_enable_interrupts(struct auixp_softc *sc)
    1078             : {
    1079             :         bus_space_tag_t     iot;
    1080             :         bus_space_handle_t  ioh;
    1081             :         u_int32_t value;
    1082             : 
    1083           0 :         iot = sc->sc_iot;
    1084           0 :         ioh = sc->sc_ioh;
    1085             :         /* clear all pending */
    1086           0 :         bus_space_write_4(iot, ioh, ATI_REG_ISR, 0xffffffff);
    1087             : 
    1088             :         /* enable all relevant interrupt sources we can handle */
    1089           0 :         value = bus_space_read_4(iot, ioh, ATI_REG_IER);
    1090             : 
    1091           0 :         value |= ATI_REG_IER_IO_STATUS_EN;
    1092             : #ifdef notyet
    1093             :         value |= ATI_REG_IER_IN_XRUN_EN;
    1094             :         value |= ATI_REG_IER_OUT_XRUN_EN;
    1095             : 
    1096             :         value |= ATI_REG_IER_SPDIF_XRUN_EN;
    1097             :         value |= ATI_REG_IER_SPDF_STATUS_EN;
    1098             : #endif
    1099             : 
    1100           0 :         bus_space_write_4(iot, ioh, ATI_REG_IER, value);
    1101           0 : }
    1102             : 
    1103             : void
    1104           0 : auixp_disable_interrupts(struct auixp_softc *sc)
    1105             : {
    1106             :         bus_space_tag_t     iot;
    1107             :         bus_space_handle_t  ioh;
    1108             : 
    1109           0 :         iot = sc->sc_iot;
    1110           0 :         ioh = sc->sc_ioh;
    1111             :         /* disable all interrupt sources */
    1112           0 :         bus_space_write_4(iot, ioh, ATI_REG_IER, 0);
    1113             : 
    1114             :         /* clear all pending */
    1115           0 :         bus_space_write_4(iot, ioh, ATI_REG_ISR, 0xffffffff);
    1116           0 : }
    1117             : 
    1118             : /* dismantle what we've set up by undoing setup */
    1119             : int
    1120           0 : auixp_detach(struct device *self, int flags)
    1121             : {
    1122             :         struct auixp_softc *sc;
    1123             : 
    1124           0 :         sc = (struct auixp_softc *)self;
    1125             :         /* XXX shouldn't we just reset the chip? XXX */
    1126             :         /*
    1127             :          * should we explicitly disable interrupt generation and acknowledge
    1128             :          * what's left on? better be safe than sorry.
    1129             :          */
    1130           0 :         auixp_disable_interrupts(sc);
    1131             : 
    1132             :         /* tear down .... */
    1133           0 :         config_detach(&sc->sc_dev, flags);       /* XXX OK? XXX */
    1134             : 
    1135           0 :         if (sc->sc_ih != NULL)
    1136           0 :                 pci_intr_disestablish(sc->sc_pct, sc->sc_ih);
    1137           0 :         if (sc->sc_ios)
    1138           0 :                 bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
    1139           0 :         return 0;
    1140             : }
    1141             : 
    1142             : 
    1143             : /*
    1144             :  * codec handling
    1145             :  *
    1146             :  * IXP audio support can have upto 3 codecs! are they chained ? or
    1147             :  * alternative outlets with the same audio feed i.e. with different mixer
    1148             :  * settings? XXX does NetBSD support more than one audio codec? XXX
    1149             :  */
    1150             : 
    1151             : 
    1152             : int
    1153           0 : auixp_attach_codec(void *aux, struct ac97_codec_if *codec_if)
    1154             : {
    1155             :         struct auixp_codec *ixp_codec;
    1156             : 
    1157           0 :         ixp_codec = aux;
    1158           0 :         ixp_codec->codec_if = codec_if;
    1159             : 
    1160           0 :         return 0;
    1161             : }
    1162             : 
    1163             : int
    1164           0 : auixp_read_codec(void *aux, u_int8_t reg, u_int16_t *result)
    1165             : {
    1166             :         struct auixp_codec *co;
    1167             :         struct auixp_softc *sc;
    1168             :         bus_space_tag_t     iot;
    1169             :         bus_space_handle_t  ioh;
    1170             :         u_int32_t data;
    1171             :         int timeout;
    1172             : 
    1173           0 :         co  = aux;
    1174           0 :         sc  = co->sc;
    1175           0 :         iot = sc->sc_iot;
    1176           0 :         ioh = sc->sc_ioh;
    1177           0 :         if (auixp_wait_for_codecs(sc, "read_codec"))
    1178           0 :                 return 0xffff;
    1179             : 
    1180             :         /* build up command for reading codec register */
    1181           0 :         data = (reg << ATI_REG_PHYS_OUT_ADDR_SHIFT) |
    1182           0 :                 ATI_REG_PHYS_OUT_ADDR_EN |
    1183           0 :                 ATI_REG_PHYS_OUT_RW |
    1184           0 :                 co->codec_nr;
    1185             : 
    1186           0 :         bus_space_write_4(iot, ioh, ATI_REG_PHYS_OUT_ADDR, data);
    1187             : 
    1188           0 :         if (auixp_wait_for_codecs(sc, "read_codec"))
    1189           0 :                 return 0xffff;
    1190             : 
    1191             :         /* wait until codec info is clocked in */
    1192             :         timeout = 500;          /* 500*2 usec -> 0.001 sec */
    1193           0 :         do {
    1194           0 :                 data = bus_space_read_4(iot, ioh, ATI_REG_PHYS_IN_ADDR);
    1195           0 :                 if (data & ATI_REG_PHYS_IN_READ_FLAG) {
    1196             :                         DPRINTF(("read ac'97 codec reg 0x%x = 0x%08x\n",
    1197             :                                 reg, data >> ATI_REG_PHYS_IN_DATA_SHIFT));
    1198           0 :                         *result = data >> ATI_REG_PHYS_IN_DATA_SHIFT;
    1199           0 :                         return 0;
    1200             :                 }
    1201           0 :                 DELAY(2);
    1202           0 :                 timeout--;
    1203           0 :         } while (timeout > 0);
    1204             : 
    1205           0 :         if (reg < 0x7c)
    1206           0 :                 printf("%s: codec read timeout! (reg %x)\n",
    1207           0 :                     sc->sc_dev.dv_xname, reg);
    1208             : 
    1209           0 :         return 0xffff;
    1210           0 : }
    1211             : 
    1212             : int
    1213           0 : auixp_write_codec(void *aux, u_int8_t reg, u_int16_t data)
    1214             : {
    1215             :         struct auixp_codec *co;
    1216             :         struct auixp_softc *sc;
    1217             :         bus_space_tag_t     iot;
    1218             :         bus_space_handle_t  ioh;
    1219             :         u_int32_t value;
    1220             : 
    1221             :         DPRINTF(("write ac'97 codec reg 0x%x = 0x%08x\n", reg, data));
    1222           0 :         co  = aux;
    1223           0 :         sc  = co->sc;
    1224           0 :         iot = sc->sc_iot;
    1225           0 :         ioh = sc->sc_ioh;
    1226           0 :         if (auixp_wait_for_codecs(sc, "write_codec"))
    1227           0 :                 return -1;
    1228             : 
    1229             :         /* build up command for writing codec register */
    1230           0 :         value = (((u_int32_t) data) << ATI_REG_PHYS_OUT_DATA_SHIFT) |
    1231           0 :                 (((u_int32_t)  reg) << ATI_REG_PHYS_OUT_ADDR_SHIFT) |
    1232           0 :                 ATI_REG_PHYS_OUT_ADDR_EN |
    1233           0 :                 co->codec_nr;
    1234             : 
    1235           0 :         bus_space_write_4(iot, ioh, ATI_REG_PHYS_OUT_ADDR, value);
    1236             : 
    1237           0 :         return 0;
    1238           0 : }
    1239             : 
    1240             : void
    1241           0 : auixp_reset_codec(void *aux)
    1242             : {
    1243             : 
    1244             :         /* nothing to be done? */
    1245           0 : }
    1246             : 
    1247             : enum ac97_host_flags
    1248           0 : auixp_flags_codec(void *aux)
    1249             : {
    1250             :         struct auixp_codec *ixp_codec;
    1251             : 
    1252           0 :         ixp_codec = aux;
    1253           0 :         return ixp_codec->codec_flags;
    1254             : }
    1255             : 
    1256             : int
    1257           0 : auixp_wait_for_codecs(struct auixp_softc *sc, const char *func)
    1258             : {
    1259             :         bus_space_tag_t      iot;
    1260             :         bus_space_handle_t   ioh;
    1261             :         u_int32_t value;
    1262             :         int timeout;
    1263             : 
    1264           0 :         iot = sc->sc_iot;
    1265           0 :         ioh = sc->sc_ioh;
    1266             :         /* wait until all codec transfers are done */
    1267             :         timeout = 500;          /* 500*2 usec -> 0.001 sec */
    1268           0 :         do {
    1269           0 :                 value = bus_space_read_4(iot, ioh, ATI_REG_PHYS_OUT_ADDR);
    1270           0 :                 if ((value & ATI_REG_PHYS_OUT_ADDR_EN) == 0)
    1271           0 :                         return 0;
    1272             : 
    1273           0 :                 DELAY(2);
    1274           0 :                 timeout--;
    1275           0 :         } while (timeout > 0);
    1276             : 
    1277           0 :         printf("%s: %s: timed out\n", func, sc->sc_dev.dv_xname);
    1278           0 :         return -1;
    1279           0 : }
    1280             : 
    1281             : void
    1282           0 : auixp_autodetect_codecs(struct auixp_softc *sc)
    1283             : {
    1284             :         bus_space_tag_t      iot;
    1285             :         bus_space_handle_t   ioh;
    1286             :         pcireg_t subdev;
    1287             :         struct auixp_codec  *codec;
    1288             :         int timeout;
    1289             : 
    1290           0 :         iot = sc->sc_iot;
    1291           0 :         ioh = sc->sc_ioh;
    1292           0 :         subdev = pci_conf_read(sc->sc_pct, sc->sc_tag, PCI_SUBSYS_ID_REG);
    1293             : 
    1294             :         /* ATI IXP can have upto 3 codecs; mark all codecs as not existing */
    1295           0 :         sc->sc_codec_not_ready_bits = 0;
    1296             : 
    1297             :         /* enable all codecs to interrupt as well as the new frame interrupt */
    1298           0 :         bus_space_write_4(iot, ioh, ATI_REG_IER, CODEC_CHECK_BITS);
    1299             : 
    1300             :         /* wait for the interrupts to happen */
    1301             :         timeout = 100;          /* 100.000 usec -> 0.1 sec */
    1302             : 
    1303           0 :         while (timeout > 0) {
    1304           0 :                 DELAY(1000);
    1305           0 :                 if (sc->sc_codec_not_ready_bits)
    1306             :                         break;
    1307           0 :                 timeout--;
    1308             :         }
    1309             : 
    1310           0 :         if (timeout == 0)
    1311           0 :                 printf("%s: WARNING: timeout during codec detection; "
    1312             :                         "codecs might be present but haven't interrupted\n",
    1313           0 :                         sc->sc_dev.dv_xname);
    1314             : 
    1315             :         /* disable all interrupts for now */
    1316           0 :         auixp_disable_interrupts(sc);
    1317             : 
    1318             :         /* Attach AC97 host interfaces */
    1319           0 :         codec = &sc->sc_codec;
    1320           0 :         bzero(codec, sizeof(struct auixp_codec));
    1321             : 
    1322           0 :         codec->sc       = sc;
    1323             : 
    1324           0 :         codec->host_if.arg    = codec;
    1325           0 :         codec->host_if.attach = auixp_attach_codec;
    1326           0 :         codec->host_if.read   = auixp_read_codec;
    1327           0 :         codec->host_if.write  = auixp_write_codec;
    1328           0 :         codec->host_if.reset  = auixp_reset_codec;
    1329           0 :         codec->host_if.flags  = auixp_flags_codec;
    1330           0 :         switch (subdev) {
    1331             :         case 0x1311462: /* MSI S270 */
    1332             :         case 0x1611462: /* LG K1 Express */
    1333             :         case 0x3511462: /* MSI L725 */
    1334             :         case 0x4711462: /* MSI L720 */
    1335             :         case 0x0611462: /* MSI S250 */
    1336           0 :                 codec->codec_flags = AC97_HOST_ALC650_PIN47_IS_EAPD;
    1337           0 :                 break;
    1338             :         }
    1339             : 
    1340           0 :         if (!(sc->sc_codec_not_ready_bits & ATI_REG_ISR_CODEC0_NOT_READY)) {
    1341             :                 /* codec 0 present */
    1342             :                 DPRINTF(("auixp : YAY! codec 0 present!\n"));
    1343           0 :                 if (ac97_attach(&sc->sc_codec.host_if) == 0) {
    1344           0 :                         sc->sc_codec.codec_nr = 0;
    1345           0 :                         sc->sc_codec.present = 1;
    1346           0 :                         return;
    1347             :                 }
    1348             :         }
    1349             : 
    1350           0 :         if (!(sc->sc_codec_not_ready_bits & ATI_REG_ISR_CODEC1_NOT_READY)) {
    1351             :                 /* codec 1 present */
    1352             :                 DPRINTF(("auixp : YAY! codec 1 present!\n"));
    1353           0 :                 if (ac97_attach(&sc->sc_codec.host_if) == 0) {
    1354           0 :                         sc->sc_codec.codec_nr = 1;
    1355           0 :                         sc->sc_codec.present = 1;
    1356           0 :                         return;
    1357             :                 }
    1358             :         }
    1359             : 
    1360           0 :         if (!(sc->sc_codec_not_ready_bits & ATI_REG_ISR_CODEC2_NOT_READY)) {
    1361             :                 /* codec 2 present */
    1362             :                 DPRINTF(("auixp : YAY! codec 2 present!\n"));
    1363           0 :                 if (ac97_attach(&sc->sc_codec.host_if) == 0) {
    1364           0 :                         sc->sc_codec.codec_nr = 2;
    1365           0 :                         sc->sc_codec.present = 1;
    1366           0 :                         return;
    1367             :                 }
    1368             :         }
    1369           0 : }
    1370             : 
    1371             : void
    1372           0 : auixp_disable_dma(struct auixp_softc *sc, struct auixp_dma *dma)
    1373             : {
    1374             :         bus_space_tag_t      iot;
    1375             :         bus_space_handle_t   ioh;
    1376             :         u_int32_t value;
    1377             : 
    1378           0 :         iot = sc->sc_iot;
    1379           0 :         ioh = sc->sc_ioh;
    1380             :         /* lets not stress the DMA engine more than necessary */
    1381           0 :         value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
    1382           0 :         if (value & dma->dma_enable_bit) {
    1383           0 :                 value &= ~dma->dma_enable_bit;
    1384           0 :                 bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
    1385           0 :         }
    1386           0 : }
    1387             : 
    1388             : void
    1389           0 : auixp_enable_dma(struct auixp_softc *sc, struct auixp_dma *dma)
    1390             : {
    1391             :         bus_space_tag_t      iot;
    1392             :         bus_space_handle_t   ioh;
    1393             :         u_int32_t value;
    1394             : 
    1395           0 :         iot = sc->sc_iot;
    1396           0 :         ioh = sc->sc_ioh;
    1397             :         /* lets not stress the DMA engine more than necesssary */
    1398           0 :         value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
    1399           0 :         if (!(value & dma->dma_enable_bit)) {
    1400           0 :                 value |= dma->dma_enable_bit;
    1401           0 :                 bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
    1402           0 :         }
    1403           0 : }
    1404             : 
    1405             : void
    1406           0 : auixp_reset_aclink(struct auixp_softc *sc)
    1407             : {
    1408             :         bus_space_tag_t      iot;
    1409             :         bus_space_handle_t   ioh;
    1410             :         u_int32_t value, timeout;
    1411             : 
    1412           0 :         iot = sc->sc_iot;
    1413           0 :         ioh = sc->sc_ioh;
    1414             : 
    1415             :         /* if power is down, power it up */
    1416           0 :         value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
    1417           0 :         if (value & ATI_REG_CMD_POWERDOWN) {
    1418           0 :                 printf("%s: powering up\n", sc->sc_dev.dv_xname);
    1419             : 
    1420             :                 /* explicitly enable power */
    1421           0 :                 value &= ~ATI_REG_CMD_POWERDOWN;
    1422           0 :                 bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
    1423             : 
    1424             :                 /* have to wait at least 10 usec for it to initialise */
    1425           0 :                 DELAY(20);
    1426           0 :         };
    1427             : 
    1428           0 :         printf("%s: soft resetting aclink\n", sc->sc_dev.dv_xname);
    1429             : 
    1430             :         /* perform a soft reset */
    1431           0 :         value  = bus_space_read_4(iot, ioh, ATI_REG_CMD);
    1432           0 :         value |= ATI_REG_CMD_AC_SOFT_RESET;
    1433           0 :         bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
    1434             : 
    1435             :         /* need to read the CMD reg and wait aprox. 10 usec to init */
    1436           0 :         value  = bus_space_read_4(iot, ioh, ATI_REG_CMD);
    1437           0 :         DELAY(20);
    1438             : 
    1439             :         /* clear soft reset flag again */
    1440           0 :         value  = bus_space_read_4(iot, ioh, ATI_REG_CMD);
    1441           0 :         value &= ~ATI_REG_CMD_AC_SOFT_RESET;
    1442           0 :         bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
    1443             : 
    1444             :         /* check if the ac-link is working; reset device otherwise */
    1445             :         timeout = 10;
    1446           0 :         value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
    1447           0 :         while (!(value & ATI_REG_CMD_ACLINK_ACTIVE)) {
    1448           0 :                 printf("%s: not up; resetting aclink hardware\n",
    1449             :                                 sc->sc_dev.dv_xname);
    1450             : 
    1451             :                 /* dip aclink reset but keep the acsync */
    1452           0 :                 value &= ~ATI_REG_CMD_AC_RESET;
    1453           0 :                 value |=  ATI_REG_CMD_AC_SYNC;
    1454           0 :                 bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
    1455             : 
    1456             :                 /* need to read CMD again and wait again (clocking in issue?) */
    1457           0 :                 value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
    1458           0 :                 DELAY(20);
    1459             : 
    1460             :                 /* assert aclink reset again */
    1461           0 :                 value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
    1462           0 :                 value |=  ATI_REG_CMD_AC_RESET;
    1463           0 :                 bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
    1464             : 
    1465             :                 /* check if its active now */
    1466           0 :                 value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
    1467             : 
    1468           0 :                 timeout--;
    1469           0 :                 if (timeout == 0) break;
    1470             :         };
    1471             : 
    1472           0 :         if (timeout == 0) {
    1473           0 :                 printf("%s: giving up aclink reset\n", sc->sc_dev.dv_xname);
    1474           0 :         };
    1475           0 :         if (timeout != 10) {
    1476           0 :                 printf("%s: aclink hardware reset successful\n",
    1477             :                         sc->sc_dev.dv_xname);
    1478           0 :         };
    1479             : 
    1480             :         /* assert reset and sync for safety */
    1481           0 :         value  = bus_space_read_4(iot, ioh, ATI_REG_CMD);
    1482           0 :         value |= ATI_REG_CMD_AC_SYNC | ATI_REG_CMD_AC_RESET;
    1483           0 :         bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
    1484           0 : }
    1485             : 
    1486             : /* chip hard init */
    1487             : int
    1488           0 : auixp_init(struct auixp_softc *sc)
    1489             : {
    1490             :         bus_space_tag_t      iot;
    1491             :         bus_space_handle_t   ioh;
    1492             :         u_int32_t value;
    1493             : 
    1494           0 :         iot = sc->sc_iot;
    1495           0 :         ioh = sc->sc_ioh;
    1496             :         /* disable all interrupts and clear all sources */
    1497           0 :         auixp_disable_interrupts(sc);
    1498             : 
    1499             :         /* clear all DMA enables (preserving rest of settings) */
    1500           0 :         value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
    1501           0 :         value &= ~( ATI_REG_CMD_IN_DMA_EN  |
    1502             :                     ATI_REG_CMD_OUT_DMA_EN |
    1503             :                     ATI_REG_CMD_SPDF_OUT_EN );
    1504           0 :         bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
    1505             : 
    1506             :         /* Reset AC-link */
    1507           0 :         auixp_reset_aclink(sc);
    1508             : 
    1509             :         /*
    1510             :          * codecs get auto-detected later
    1511             :          *
    1512             :          * note: we are NOT enabling interrupts yet, no codecs have been
    1513             :          * detected yet nor is anything else set up
    1514             :          */
    1515             : 
    1516           0 :         return 0;
    1517             : }

Generated by: LCOV version 1.13