1d5688b6aSAriff Abdullah /*- 2d5688b6aSAriff Abdullah * Copyright (c) 2005 Ariff Abdullah <ariff@FreeBSD.org> 3d5688b6aSAriff Abdullah * All rights reserved. 4d5688b6aSAriff Abdullah * 5d5688b6aSAriff Abdullah * Redistribution and use in source and binary forms, with or without 6d5688b6aSAriff Abdullah * modification, are permitted provided that the following conditions 7d5688b6aSAriff Abdullah * are met: 8d5688b6aSAriff Abdullah * 1. Redistributions of source code must retain the above copyright 9d5688b6aSAriff Abdullah * notice, this list of conditions and the following disclaimer. 10d5688b6aSAriff Abdullah * 2. Redistributions in binary form must reproduce the above copyright 11d5688b6aSAriff Abdullah * notice, this list of conditions and the following disclaimer in the 12d5688b6aSAriff Abdullah * documentation and/or other materials provided with the distribution. 13d5688b6aSAriff Abdullah * 14d5688b6aSAriff Abdullah * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15d5688b6aSAriff Abdullah * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16d5688b6aSAriff Abdullah * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17d5688b6aSAriff Abdullah * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18d5688b6aSAriff Abdullah * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19d5688b6aSAriff Abdullah * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20d5688b6aSAriff Abdullah * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21d5688b6aSAriff Abdullah * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT 22d5688b6aSAriff Abdullah * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23d5688b6aSAriff Abdullah * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF 24d5688b6aSAriff Abdullah * SUCH DAMAGE. 25d5688b6aSAriff Abdullah */ 26d5688b6aSAriff Abdullah 27d5688b6aSAriff Abdullah /* 28d5688b6aSAriff Abdullah * FreeBSD pcm driver for ATI IXP 150/200/250/300 AC97 controllers 29d5688b6aSAriff Abdullah * 30d5688b6aSAriff Abdullah * Features 31d5688b6aSAriff Abdullah * * 16bit playback / recording 32d5688b6aSAriff Abdullah * * 32bit native playback - yay! 3305051995SAriff Abdullah * * 32bit native recording (seems broken on few hardwares) 34d5688b6aSAriff Abdullah * 35d5688b6aSAriff Abdullah * Issues / TODO: 36d5688b6aSAriff Abdullah * * SPDIF 37d5688b6aSAriff Abdullah * * Support for more than 2 channels. 38d5688b6aSAriff Abdullah * * VRA ? VRM ? DRA ? 3905051995SAriff Abdullah * * 32bit native recording seems broken on few hardwares, most 4005051995SAriff Abdullah * probably because of incomplete VRA/DRA cleanup. 41d5688b6aSAriff Abdullah * 42d5688b6aSAriff Abdullah * 43d5688b6aSAriff Abdullah * Thanks goes to: 44d5688b6aSAriff Abdullah * 45d5688b6aSAriff Abdullah * Shaharil @ SCAN Associates whom relentlessly providing me the 46d5688b6aSAriff Abdullah * mind blowing Acer Ferrari 4002 WLMi with this ATI IXP hardware. 47d5688b6aSAriff Abdullah * 48d5688b6aSAriff Abdullah * Reinoud Zandijk <reinoud@NetBSD.org> (auixp), which this driver is 49d5688b6aSAriff Abdullah * largely based upon although large part of it has been reworked. His 50d5688b6aSAriff Abdullah * driver is the primary reference and pretty much well documented. 51d5688b6aSAriff Abdullah * 52d5688b6aSAriff Abdullah * Takashi Iwai (ALSA snd-atiixp), for register definitions and some 53d5688b6aSAriff Abdullah * random ninja hackery. 54d5688b6aSAriff Abdullah */ 55d5688b6aSAriff Abdullah 56d5688b6aSAriff Abdullah #include <dev/sound/pcm/sound.h> 57d5688b6aSAriff Abdullah #include <dev/sound/pcm/ac97.h> 58d5688b6aSAriff Abdullah 59d5688b6aSAriff Abdullah #include <dev/pci/pcireg.h> 60d5688b6aSAriff Abdullah #include <dev/pci/pcivar.h> 61d5688b6aSAriff Abdullah #include <sys/sysctl.h> 62d5688b6aSAriff Abdullah #include <sys/endian.h> 63d5688b6aSAriff Abdullah 64d5688b6aSAriff Abdullah #include <dev/sound/pci/atiixp.h> 65d5688b6aSAriff Abdullah 66d5688b6aSAriff Abdullah SND_DECLARE_FILE("$FreeBSD$"); 67d5688b6aSAriff Abdullah 689f52a325SAriff Abdullah #define ATI_IXP_DMA_RETRY_MAX 100 699f52a325SAriff Abdullah 709f52a325SAriff Abdullah #define ATI_IXP_BUFSZ_MIN 4096 719f52a325SAriff Abdullah #define ATI_IXP_BUFSZ_MAX 65536 729f52a325SAriff Abdullah #define ATI_IXP_BUFSZ_DEFAULT 16384 739f52a325SAriff Abdullah 741042342aSAriff Abdullah #define ATI_IXP_BLK_MIN 32 751042342aSAriff Abdullah #define ATI_IXP_BLK_ALIGN (~(ATI_IXP_BLK_MIN - 1)) 761042342aSAriff Abdullah 77d5688b6aSAriff Abdullah struct atiixp_dma_op { 7805051995SAriff Abdullah volatile uint32_t addr; 7905051995SAriff Abdullah volatile uint16_t status; 8005051995SAriff Abdullah volatile uint16_t size; 8105051995SAriff Abdullah volatile uint32_t next; 82d5688b6aSAriff Abdullah }; 83d5688b6aSAriff Abdullah 84d5688b6aSAriff Abdullah struct atiixp_info; 85d5688b6aSAriff Abdullah 86d5688b6aSAriff Abdullah struct atiixp_chinfo { 87d5688b6aSAriff Abdullah struct snd_dbuf *buffer; 88d5688b6aSAriff Abdullah struct pcm_channel *channel; 89d5688b6aSAriff Abdullah struct atiixp_info *parent; 90d5688b6aSAriff Abdullah struct atiixp_dma_op *sgd_table; 91d5688b6aSAriff Abdullah bus_addr_t sgd_addr; 92a580b31aSAriff Abdullah uint32_t enable_bit, flush_bit, linkptr_bit, dt_cur_bit; 93a580b31aSAriff Abdullah uint32_t blksz, blkcnt; 94a580b31aSAriff Abdullah uint32_t ptr, prevptr; 9588a50509SAriff Abdullah uint32_t fmt; 9688a50509SAriff Abdullah int caps_32bit, dir, active; 97d5688b6aSAriff Abdullah }; 98d5688b6aSAriff Abdullah 99d5688b6aSAriff Abdullah struct atiixp_info { 100d5688b6aSAriff Abdullah device_t dev; 101d5688b6aSAriff Abdullah 102d5688b6aSAriff Abdullah bus_space_tag_t st; 103d5688b6aSAriff Abdullah bus_space_handle_t sh; 104d5688b6aSAriff Abdullah bus_dma_tag_t parent_dmat; 105d5688b6aSAriff Abdullah bus_dma_tag_t sgd_dmat; 106d5688b6aSAriff Abdullah bus_dmamap_t sgd_dmamap; 107d5688b6aSAriff Abdullah bus_addr_t sgd_addr; 108d5688b6aSAriff Abdullah 109d5688b6aSAriff Abdullah struct resource *reg, *irq; 110d5688b6aSAriff Abdullah int regtype, regid, irqid; 111d5688b6aSAriff Abdullah void *ih; 112d5688b6aSAriff Abdullah struct ac97_info *codec; 113d5688b6aSAriff Abdullah 114d5688b6aSAriff Abdullah struct atiixp_chinfo pch; 115d5688b6aSAriff Abdullah struct atiixp_chinfo rch; 116d5688b6aSAriff Abdullah struct atiixp_dma_op *sgd_table; 117d5688b6aSAriff Abdullah struct intr_config_hook delayed_attach; 118d5688b6aSAriff Abdullah 119d5688b6aSAriff Abdullah uint32_t bufsz; 120d5688b6aSAriff Abdullah uint32_t codec_not_ready_bits, codec_idx, codec_found; 121a580b31aSAriff Abdullah uint32_t blkcnt; 122d5688b6aSAriff Abdullah int registered_channels; 123d5688b6aSAriff Abdullah 124d5688b6aSAriff Abdullah struct mtx *lock; 125a580b31aSAriff Abdullah struct callout poll_timer; 126a580b31aSAriff Abdullah int poll_ticks, polling; 127d5688b6aSAriff Abdullah }; 128d5688b6aSAriff Abdullah 129d5688b6aSAriff Abdullah #define atiixp_rd(_sc, _reg) \ 130d5688b6aSAriff Abdullah bus_space_read_4((_sc)->st, (_sc)->sh, _reg) 131d5688b6aSAriff Abdullah #define atiixp_wr(_sc, _reg, _val) \ 132d5688b6aSAriff Abdullah bus_space_write_4((_sc)->st, (_sc)->sh, _reg, _val) 133d5688b6aSAriff Abdullah 134d5688b6aSAriff Abdullah #define atiixp_lock(_sc) snd_mtxlock((_sc)->lock) 135d5688b6aSAriff Abdullah #define atiixp_unlock(_sc) snd_mtxunlock((_sc)->lock) 136d5688b6aSAriff Abdullah #define atiixp_assert(_sc) snd_mtxassert((_sc)->lock) 137d5688b6aSAriff Abdullah 138d5688b6aSAriff Abdullah static uint32_t atiixp_fmt_32bit[] = { 139d5688b6aSAriff Abdullah AFMT_STEREO | AFMT_S16_LE, 140d5688b6aSAriff Abdullah AFMT_STEREO | AFMT_S32_LE, 141d5688b6aSAriff Abdullah 0 142d5688b6aSAriff Abdullah }; 143d5688b6aSAriff Abdullah 144d5688b6aSAriff Abdullah static uint32_t atiixp_fmt[] = { 145d5688b6aSAriff Abdullah AFMT_STEREO | AFMT_S16_LE, 146d5688b6aSAriff Abdullah 0 147d5688b6aSAriff Abdullah }; 148d5688b6aSAriff Abdullah 149d5688b6aSAriff Abdullah static struct pcmchan_caps atiixp_caps_32bit = { 150d5688b6aSAriff Abdullah ATI_IXP_BASE_RATE, 151d5688b6aSAriff Abdullah ATI_IXP_BASE_RATE, 152d5688b6aSAriff Abdullah atiixp_fmt_32bit, 0 153d5688b6aSAriff Abdullah }; 154d5688b6aSAriff Abdullah 155d5688b6aSAriff Abdullah static struct pcmchan_caps atiixp_caps = { 156d5688b6aSAriff Abdullah ATI_IXP_BASE_RATE, 157d5688b6aSAriff Abdullah ATI_IXP_BASE_RATE, 158d5688b6aSAriff Abdullah atiixp_fmt, 0 159d5688b6aSAriff Abdullah }; 160d5688b6aSAriff Abdullah 161d5688b6aSAriff Abdullah static const struct { 162d5688b6aSAriff Abdullah uint16_t vendor; 163d5688b6aSAriff Abdullah uint16_t devid; 164d5688b6aSAriff Abdullah char *desc; 165d5688b6aSAriff Abdullah } atiixp_hw[] = { 166d5688b6aSAriff Abdullah { ATI_VENDOR_ID, ATI_IXP_200_ID, "ATI IXP 200" }, 167d5688b6aSAriff Abdullah { ATI_VENDOR_ID, ATI_IXP_300_ID, "ATI IXP 300" }, 168d5688b6aSAriff Abdullah { ATI_VENDOR_ID, ATI_IXP_400_ID, "ATI IXP 400" }, 169d5688b6aSAriff Abdullah }; 170d5688b6aSAriff Abdullah 171d5688b6aSAriff Abdullah static void atiixp_enable_interrupts(struct atiixp_info *); 172d5688b6aSAriff Abdullah static void atiixp_disable_interrupts(struct atiixp_info *); 173d5688b6aSAriff Abdullah static void atiixp_reset_aclink(struct atiixp_info *); 1749f52a325SAriff Abdullah static void atiixp_flush_dma(struct atiixp_chinfo *); 1759f52a325SAriff Abdullah static void atiixp_enable_dma(struct atiixp_chinfo *); 1769f52a325SAriff Abdullah static void atiixp_disable_dma(struct atiixp_chinfo *); 177d5688b6aSAriff Abdullah 178d5688b6aSAriff Abdullah static int atiixp_waitready_codec(struct atiixp_info *); 179d5688b6aSAriff Abdullah static int atiixp_rdcd(kobj_t, void *, int); 180d5688b6aSAriff Abdullah static int atiixp_wrcd(kobj_t, void *, int, uint32_t); 181d5688b6aSAriff Abdullah 182d5688b6aSAriff Abdullah static void *atiixp_chan_init(kobj_t, void *, struct snd_dbuf *, 183d5688b6aSAriff Abdullah struct pcm_channel *, int); 184d5688b6aSAriff Abdullah static int atiixp_chan_setformat(kobj_t, void *, uint32_t); 185d5688b6aSAriff Abdullah static int atiixp_chan_setspeed(kobj_t, void *, uint32_t); 1861042342aSAriff Abdullah static int atiixp_chan_setfragments(kobj_t, void *, uint32_t, uint32_t); 187d5688b6aSAriff Abdullah static int atiixp_chan_setblocksize(kobj_t, void *, uint32_t); 188d5688b6aSAriff Abdullah static void atiixp_buildsgdt(struct atiixp_chinfo *); 189d5688b6aSAriff Abdullah static int atiixp_chan_trigger(kobj_t, void *, int); 1909f52a325SAriff Abdullah static __inline uint32_t atiixp_dmapos(struct atiixp_chinfo *); 191d5688b6aSAriff Abdullah static int atiixp_chan_getptr(kobj_t, void *); 192d5688b6aSAriff Abdullah static struct pcmchan_caps *atiixp_chan_getcaps(kobj_t, void *); 193d5688b6aSAriff Abdullah 194d5688b6aSAriff Abdullah static void atiixp_intr(void *); 195d5688b6aSAriff Abdullah static void atiixp_dma_cb(void *, bus_dma_segment_t *, int, int); 196d5688b6aSAriff Abdullah static void atiixp_chip_pre_init(struct atiixp_info *); 197d5688b6aSAriff Abdullah static void atiixp_chip_post_init(void *); 198f2a1d71aSAriff Abdullah static void atiixp_release_resource(struct atiixp_info *); 199d5688b6aSAriff Abdullah static int atiixp_pci_probe(device_t); 200d5688b6aSAriff Abdullah static int atiixp_pci_attach(device_t); 201d5688b6aSAriff Abdullah static int atiixp_pci_detach(device_t); 20288a50509SAriff Abdullah static int atiixp_pci_suspend(device_t); 20388a50509SAriff Abdullah static int atiixp_pci_resume(device_t); 204d5688b6aSAriff Abdullah 205d5688b6aSAriff Abdullah /* 206d5688b6aSAriff Abdullah * ATI IXP helper functions 207d5688b6aSAriff Abdullah */ 208d5688b6aSAriff Abdullah static void 209d5688b6aSAriff Abdullah atiixp_enable_interrupts(struct atiixp_info *sc) 210d5688b6aSAriff Abdullah { 211d5688b6aSAriff Abdullah uint32_t value; 212d5688b6aSAriff Abdullah 213d5688b6aSAriff Abdullah /* clear all pending */ 214d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_ISR, 0xffffffff); 215d5688b6aSAriff Abdullah 216d5688b6aSAriff Abdullah /* enable all relevant interrupt sources we can handle */ 217d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_IER); 218d5688b6aSAriff Abdullah 219d5688b6aSAriff Abdullah value |= ATI_REG_IER_IO_STATUS_EN; 220d5688b6aSAriff Abdullah 221d5688b6aSAriff Abdullah /* 222d5688b6aSAriff Abdullah * Disable / ignore internal xrun/spdf interrupt flags 223d5688b6aSAriff Abdullah * since it doesn't interest us (for now). 224d5688b6aSAriff Abdullah */ 2259f52a325SAriff Abdullah #if 1 2269f52a325SAriff Abdullah value &= ~(ATI_REG_IER_IN_XRUN_EN | ATI_REG_IER_OUT_XRUN_EN | 2279f52a325SAriff Abdullah ATI_REG_IER_SPDF_XRUN_EN | ATI_REG_IER_SPDF_STATUS_EN); 2289f52a325SAriff Abdullah #else 229d5688b6aSAriff Abdullah value |= ATI_REG_IER_IN_XRUN_EN; 230d5688b6aSAriff Abdullah value |= ATI_REG_IER_OUT_XRUN_EN; 231d5688b6aSAriff Abdullah 232d5688b6aSAriff Abdullah value |= ATI_REG_IER_SPDF_XRUN_EN; 233d5688b6aSAriff Abdullah value |= ATI_REG_IER_SPDF_STATUS_EN; 234d5688b6aSAriff Abdullah #endif 235d5688b6aSAriff Abdullah 236d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_IER, value); 237d5688b6aSAriff Abdullah } 238d5688b6aSAriff Abdullah 239d5688b6aSAriff Abdullah static void 240d5688b6aSAriff Abdullah atiixp_disable_interrupts(struct atiixp_info *sc) 241d5688b6aSAriff Abdullah { 242d5688b6aSAriff Abdullah /* disable all interrupt sources */ 243d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_IER, 0); 244d5688b6aSAriff Abdullah 245d5688b6aSAriff Abdullah /* clear all pending */ 246d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_ISR, 0xffffffff); 247d5688b6aSAriff Abdullah } 248d5688b6aSAriff Abdullah 249d5688b6aSAriff Abdullah static void 250d5688b6aSAriff Abdullah atiixp_reset_aclink(struct atiixp_info *sc) 251d5688b6aSAriff Abdullah { 252d5688b6aSAriff Abdullah uint32_t value, timeout; 253d5688b6aSAriff Abdullah 254d5688b6aSAriff Abdullah /* if power is down, power it up */ 255d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_CMD); 256d5688b6aSAriff Abdullah if (value & ATI_REG_CMD_POWERDOWN) { 257d5688b6aSAriff Abdullah /* explicitly enable power */ 258d5688b6aSAriff Abdullah value &= ~ATI_REG_CMD_POWERDOWN; 259d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_CMD, value); 260d5688b6aSAriff Abdullah 261d5688b6aSAriff Abdullah /* have to wait at least 10 usec for it to initialise */ 262d5688b6aSAriff Abdullah DELAY(20); 2639f52a325SAriff Abdullah } 264d5688b6aSAriff Abdullah 265d5688b6aSAriff Abdullah /* perform a soft reset */ 266d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_CMD); 267d5688b6aSAriff Abdullah value |= ATI_REG_CMD_AC_SOFT_RESET; 268d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_CMD, value); 269d5688b6aSAriff Abdullah 270d5688b6aSAriff Abdullah /* need to read the CMD reg and wait aprox. 10 usec to init */ 271d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_CMD); 272d5688b6aSAriff Abdullah DELAY(20); 273d5688b6aSAriff Abdullah 274d5688b6aSAriff Abdullah /* clear soft reset flag again */ 275d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_CMD); 276d5688b6aSAriff Abdullah value &= ~ATI_REG_CMD_AC_SOFT_RESET; 277d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_CMD, value); 278d5688b6aSAriff Abdullah 279d5688b6aSAriff Abdullah /* check if the ac-link is working; reset device otherwise */ 280d5688b6aSAriff Abdullah timeout = 10; 281d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_CMD); 282a580b31aSAriff Abdullah while (!(value & ATI_REG_CMD_ACLINK_ACTIVE) && --timeout) { 28388a50509SAriff Abdullah #if 0 284d5688b6aSAriff Abdullah device_printf(sc->dev, "not up; resetting aclink hardware\n"); 28588a50509SAriff Abdullah #endif 286d5688b6aSAriff Abdullah 287d5688b6aSAriff Abdullah /* dip aclink reset but keep the acsync */ 288d5688b6aSAriff Abdullah value &= ~ATI_REG_CMD_AC_RESET; 289d5688b6aSAriff Abdullah value |= ATI_REG_CMD_AC_SYNC; 290d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_CMD, value); 291d5688b6aSAriff Abdullah 292d5688b6aSAriff Abdullah /* need to read CMD again and wait again (clocking in issue?) */ 293d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_CMD); 294d5688b6aSAriff Abdullah DELAY(20); 295d5688b6aSAriff Abdullah 296d5688b6aSAriff Abdullah /* assert aclink reset again */ 297d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_CMD); 298d5688b6aSAriff Abdullah value |= ATI_REG_CMD_AC_RESET; 299d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_CMD, value); 300d5688b6aSAriff Abdullah 301d5688b6aSAriff Abdullah /* check if its active now */ 302d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_CMD); 3039f52a325SAriff Abdullah } 304d5688b6aSAriff Abdullah 305d5688b6aSAriff Abdullah if (timeout == 0) 306d5688b6aSAriff Abdullah device_printf(sc->dev, "giving up aclink reset\n"); 30788a50509SAriff Abdullah #if 0 308d5688b6aSAriff Abdullah if (timeout != 10) 309d5688b6aSAriff Abdullah device_printf(sc->dev, "aclink hardware reset successful\n"); 31088a50509SAriff Abdullah #endif 311d5688b6aSAriff Abdullah 312d5688b6aSAriff Abdullah /* assert reset and sync for safety */ 313d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_CMD); 314d5688b6aSAriff Abdullah value |= ATI_REG_CMD_AC_SYNC | ATI_REG_CMD_AC_RESET; 315d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_CMD, value); 316d5688b6aSAriff Abdullah } 317d5688b6aSAriff Abdullah 318d5688b6aSAriff Abdullah static void 3199f52a325SAriff Abdullah atiixp_flush_dma(struct atiixp_chinfo *ch) 320d5688b6aSAriff Abdullah { 3219f52a325SAriff Abdullah atiixp_wr(ch->parent, ATI_REG_FIFO_FLUSH, ch->flush_bit); 322d5688b6aSAriff Abdullah } 323d5688b6aSAriff Abdullah 324d5688b6aSAriff Abdullah static void 3259f52a325SAriff Abdullah atiixp_enable_dma(struct atiixp_chinfo *ch) 326d5688b6aSAriff Abdullah { 327d5688b6aSAriff Abdullah uint32_t value; 328d5688b6aSAriff Abdullah 3299f52a325SAriff Abdullah value = atiixp_rd(ch->parent, ATI_REG_CMD); 330d5688b6aSAriff Abdullah if (!(value & ch->enable_bit)) { 331d5688b6aSAriff Abdullah value |= ch->enable_bit; 3329f52a325SAriff Abdullah atiixp_wr(ch->parent, ATI_REG_CMD, value); 333d5688b6aSAriff Abdullah } 334d5688b6aSAriff Abdullah } 335d5688b6aSAriff Abdullah 336d5688b6aSAriff Abdullah static void 3379f52a325SAriff Abdullah atiixp_disable_dma(struct atiixp_chinfo *ch) 338d5688b6aSAriff Abdullah { 339d5688b6aSAriff Abdullah uint32_t value; 340d5688b6aSAriff Abdullah 3419f52a325SAriff Abdullah value = atiixp_rd(ch->parent, ATI_REG_CMD); 342d5688b6aSAriff Abdullah if (value & ch->enable_bit) { 343d5688b6aSAriff Abdullah value &= ~ch->enable_bit; 3449f52a325SAriff Abdullah atiixp_wr(ch->parent, ATI_REG_CMD, value); 345d5688b6aSAriff Abdullah } 346d5688b6aSAriff Abdullah } 347d5688b6aSAriff Abdullah 348d5688b6aSAriff Abdullah /* 349d5688b6aSAriff Abdullah * AC97 interface 350d5688b6aSAriff Abdullah */ 351d5688b6aSAriff Abdullah static int 352d5688b6aSAriff Abdullah atiixp_waitready_codec(struct atiixp_info *sc) 353d5688b6aSAriff Abdullah { 354d5688b6aSAriff Abdullah int timeout = 500; 355d5688b6aSAriff Abdullah 356d5688b6aSAriff Abdullah do { 357d5688b6aSAriff Abdullah if ((atiixp_rd(sc, ATI_REG_PHYS_OUT_ADDR) & 358d5688b6aSAriff Abdullah ATI_REG_PHYS_OUT_ADDR_EN) == 0) 3599f52a325SAriff Abdullah return (0); 360d5688b6aSAriff Abdullah DELAY(1); 3619f52a325SAriff Abdullah } while (--timeout); 362d5688b6aSAriff Abdullah 3639f52a325SAriff Abdullah return (-1); 364d5688b6aSAriff Abdullah } 365d5688b6aSAriff Abdullah 366d5688b6aSAriff Abdullah static int 367d5688b6aSAriff Abdullah atiixp_rdcd(kobj_t obj, void *devinfo, int reg) 368d5688b6aSAriff Abdullah { 369d5688b6aSAriff Abdullah struct atiixp_info *sc = devinfo; 370d5688b6aSAriff Abdullah uint32_t data; 371d5688b6aSAriff Abdullah int timeout; 372d5688b6aSAriff Abdullah 373d5688b6aSAriff Abdullah if (atiixp_waitready_codec(sc)) 3749f52a325SAriff Abdullah return (-1); 375d5688b6aSAriff Abdullah 376d5688b6aSAriff Abdullah data = (reg << ATI_REG_PHYS_OUT_ADDR_SHIFT) | 377a580b31aSAriff Abdullah ATI_REG_PHYS_OUT_ADDR_EN | ATI_REG_PHYS_OUT_RW | sc->codec_idx; 378d5688b6aSAriff Abdullah 379d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_PHYS_OUT_ADDR, data); 380d5688b6aSAriff Abdullah 381d5688b6aSAriff Abdullah if (atiixp_waitready_codec(sc)) 3829f52a325SAriff Abdullah return (-1); 383d5688b6aSAriff Abdullah 384d5688b6aSAriff Abdullah timeout = 500; 385d5688b6aSAriff Abdullah do { 386d5688b6aSAriff Abdullah data = atiixp_rd(sc, ATI_REG_PHYS_IN_ADDR); 387d5688b6aSAriff Abdullah if (data & ATI_REG_PHYS_IN_READ_FLAG) 3889f52a325SAriff Abdullah return (data >> ATI_REG_PHYS_IN_DATA_SHIFT); 389d5688b6aSAriff Abdullah DELAY(1); 3909f52a325SAriff Abdullah } while (--timeout); 391d5688b6aSAriff Abdullah 392d5688b6aSAriff Abdullah if (reg < 0x7c) 393d5688b6aSAriff Abdullah device_printf(sc->dev, "codec read timeout! (reg 0x%x)\n", reg); 394d5688b6aSAriff Abdullah 3959f52a325SAriff Abdullah return (-1); 396d5688b6aSAriff Abdullah } 397d5688b6aSAriff Abdullah 398d5688b6aSAriff Abdullah static int 399d5688b6aSAriff Abdullah atiixp_wrcd(kobj_t obj, void *devinfo, int reg, uint32_t data) 400d5688b6aSAriff Abdullah { 401d5688b6aSAriff Abdullah struct atiixp_info *sc = devinfo; 402d5688b6aSAriff Abdullah 403d5688b6aSAriff Abdullah if (atiixp_waitready_codec(sc)) 4049f52a325SAriff Abdullah return (-1); 405d5688b6aSAriff Abdullah 406d5688b6aSAriff Abdullah data = (data << ATI_REG_PHYS_OUT_DATA_SHIFT) | 407d5688b6aSAriff Abdullah (((uint32_t)reg) << ATI_REG_PHYS_OUT_ADDR_SHIFT) | 408d5688b6aSAriff Abdullah ATI_REG_PHYS_OUT_ADDR_EN | sc->codec_idx; 409d5688b6aSAriff Abdullah 410d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_PHYS_OUT_ADDR, data); 411d5688b6aSAriff Abdullah 4129f52a325SAriff Abdullah return (0); 413d5688b6aSAriff Abdullah } 414d5688b6aSAriff Abdullah 415d5688b6aSAriff Abdullah static kobj_method_t atiixp_ac97_methods[] = { 416d5688b6aSAriff Abdullah KOBJMETHOD(ac97_read, atiixp_rdcd), 417d5688b6aSAriff Abdullah KOBJMETHOD(ac97_write, atiixp_wrcd), 418d5688b6aSAriff Abdullah { 0, 0 } 419d5688b6aSAriff Abdullah }; 420d5688b6aSAriff Abdullah AC97_DECLARE(atiixp_ac97); 421d5688b6aSAriff Abdullah 422d5688b6aSAriff Abdullah /* 423d5688b6aSAriff Abdullah * Playback / Record channel interface 424d5688b6aSAriff Abdullah */ 425d5688b6aSAriff Abdullah static void * 426d5688b6aSAriff Abdullah atiixp_chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, 427d5688b6aSAriff Abdullah struct pcm_channel *c, int dir) 428d5688b6aSAriff Abdullah { 429d5688b6aSAriff Abdullah struct atiixp_info *sc = devinfo; 430d5688b6aSAriff Abdullah struct atiixp_chinfo *ch; 431d5688b6aSAriff Abdullah int num; 432d5688b6aSAriff Abdullah 433d5688b6aSAriff Abdullah atiixp_lock(sc); 434d5688b6aSAriff Abdullah 435d5688b6aSAriff Abdullah if (dir == PCMDIR_PLAY) { 436d5688b6aSAriff Abdullah ch = &sc->pch; 437d5688b6aSAriff Abdullah ch->linkptr_bit = ATI_REG_OUT_DMA_LINKPTR; 438d5688b6aSAriff Abdullah ch->enable_bit = ATI_REG_CMD_OUT_DMA_EN | ATI_REG_CMD_SEND_EN; 439d5688b6aSAriff Abdullah ch->flush_bit = ATI_REG_FIFO_OUT_FLUSH; 440a580b31aSAriff Abdullah ch->dt_cur_bit = ATI_REG_OUT_DMA_DT_CUR; 441d5688b6aSAriff Abdullah /* Native 32bit playback working properly */ 442d5688b6aSAriff Abdullah ch->caps_32bit = 1; 443d5688b6aSAriff Abdullah } else { 444d5688b6aSAriff Abdullah ch = &sc->rch; 445d5688b6aSAriff Abdullah ch->linkptr_bit = ATI_REG_IN_DMA_LINKPTR; 446d5688b6aSAriff Abdullah ch->enable_bit = ATI_REG_CMD_IN_DMA_EN | ATI_REG_CMD_RECEIVE_EN; 447d5688b6aSAriff Abdullah ch->flush_bit = ATI_REG_FIFO_IN_FLUSH; 448a580b31aSAriff Abdullah ch->dt_cur_bit = ATI_REG_IN_DMA_DT_CUR; 449d5688b6aSAriff Abdullah /* XXX Native 32bit recording appear to be broken */ 4508815a869SAriff Abdullah ch->caps_32bit = 1; 451d5688b6aSAriff Abdullah } 452d5688b6aSAriff Abdullah 453d5688b6aSAriff Abdullah ch->buffer = b; 454d5688b6aSAriff Abdullah ch->parent = sc; 455d5688b6aSAriff Abdullah ch->channel = c; 456d5688b6aSAriff Abdullah ch->dir = dir; 457a580b31aSAriff Abdullah ch->blkcnt = sc->blkcnt; 458a580b31aSAriff Abdullah ch->blksz = sc->bufsz / ch->blkcnt; 459d5688b6aSAriff Abdullah 460d5688b6aSAriff Abdullah atiixp_unlock(sc); 461d5688b6aSAriff Abdullah 462d5688b6aSAriff Abdullah if (sndbuf_alloc(ch->buffer, sc->parent_dmat, sc->bufsz) == -1) 4639f52a325SAriff Abdullah return (NULL); 464d5688b6aSAriff Abdullah 465d5688b6aSAriff Abdullah atiixp_lock(sc); 466d5688b6aSAriff Abdullah num = sc->registered_channels++; 4671042342aSAriff Abdullah ch->sgd_table = &sc->sgd_table[num * ATI_IXP_DMA_CHSEGS_MAX]; 4681042342aSAriff Abdullah ch->sgd_addr = sc->sgd_addr + (num * ATI_IXP_DMA_CHSEGS_MAX * 469a580b31aSAriff Abdullah sizeof(struct atiixp_dma_op)); 4709f52a325SAriff Abdullah atiixp_disable_dma(ch); 471d5688b6aSAriff Abdullah atiixp_unlock(sc); 472d5688b6aSAriff Abdullah 4739f52a325SAriff Abdullah return (ch); 474d5688b6aSAriff Abdullah } 475d5688b6aSAriff Abdullah 476d5688b6aSAriff Abdullah static int 477d5688b6aSAriff Abdullah atiixp_chan_setformat(kobj_t obj, void *data, uint32_t format) 478d5688b6aSAriff Abdullah { 479d5688b6aSAriff Abdullah struct atiixp_chinfo *ch = data; 480d5688b6aSAriff Abdullah struct atiixp_info *sc = ch->parent; 481d5688b6aSAriff Abdullah uint32_t value; 482d5688b6aSAriff Abdullah 483d5688b6aSAriff Abdullah atiixp_lock(sc); 484d5688b6aSAriff Abdullah if (ch->dir == PCMDIR_REC) { 485d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_CMD); 486d5688b6aSAriff Abdullah value &= ~ATI_REG_CMD_INTERLEAVE_IN; 48705051995SAriff Abdullah if ((format & AFMT_32BIT) == 0) 488d5688b6aSAriff Abdullah value |= ATI_REG_CMD_INTERLEAVE_IN; 489d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_CMD, value); 490d5688b6aSAriff Abdullah } else { 491d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_OUT_DMA_SLOT); 492d5688b6aSAriff Abdullah value &= ~ATI_REG_OUT_DMA_SLOT_MASK; 493d5688b6aSAriff Abdullah /* We do not have support for more than 2 channels, _yet_. */ 494d5688b6aSAriff Abdullah value |= ATI_REG_OUT_DMA_SLOT_BIT(3) | 495d5688b6aSAriff Abdullah ATI_REG_OUT_DMA_SLOT_BIT(4); 496d5688b6aSAriff Abdullah value |= 0x04 << ATI_REG_OUT_DMA_THRESHOLD_SHIFT; 497d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_OUT_DMA_SLOT, value); 498d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_CMD); 499d5688b6aSAriff Abdullah value &= ~ATI_REG_CMD_INTERLEAVE_OUT; 50005051995SAriff Abdullah if ((format & AFMT_32BIT) == 0) 501d5688b6aSAriff Abdullah value |= ATI_REG_CMD_INTERLEAVE_OUT; 502d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_CMD, value); 503d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_6CH_REORDER); 504d5688b6aSAriff Abdullah value &= ~ATI_REG_6CH_REORDER_EN; 505d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_6CH_REORDER, value); 506d5688b6aSAriff Abdullah } 50788a50509SAriff Abdullah ch->fmt = format; 508d5688b6aSAriff Abdullah atiixp_unlock(sc); 509d5688b6aSAriff Abdullah 5109f52a325SAriff Abdullah return (0); 511d5688b6aSAriff Abdullah } 512d5688b6aSAriff Abdullah 513d5688b6aSAriff Abdullah static int 514d5688b6aSAriff Abdullah atiixp_chan_setspeed(kobj_t obj, void *data, uint32_t spd) 515d5688b6aSAriff Abdullah { 516d5688b6aSAriff Abdullah /* XXX We're supposed to do VRA/DRA processing right here */ 5179f52a325SAriff Abdullah return (ATI_IXP_BASE_RATE); 518d5688b6aSAriff Abdullah } 519d5688b6aSAriff Abdullah 520d5688b6aSAriff Abdullah static int 5211042342aSAriff Abdullah atiixp_chan_setfragments(kobj_t obj, void *data, 5221042342aSAriff Abdullah uint32_t blksz, uint32_t blkcnt) 5231042342aSAriff Abdullah { 5241042342aSAriff Abdullah struct atiixp_chinfo *ch = data; 5251042342aSAriff Abdullah struct atiixp_info *sc = ch->parent; 5261042342aSAriff Abdullah 5271042342aSAriff Abdullah blksz &= ATI_IXP_BLK_ALIGN; 5281042342aSAriff Abdullah 5291042342aSAriff Abdullah if (blksz > (sndbuf_getmaxsize(ch->buffer) / ATI_IXP_DMA_CHSEGS_MIN)) 5301042342aSAriff Abdullah blksz = sndbuf_getmaxsize(ch->buffer) / ATI_IXP_DMA_CHSEGS_MIN; 5311042342aSAriff Abdullah if (blksz < ATI_IXP_BLK_MIN) 5321042342aSAriff Abdullah blksz = ATI_IXP_BLK_MIN; 5331042342aSAriff Abdullah if (blkcnt > ATI_IXP_DMA_CHSEGS_MAX) 5341042342aSAriff Abdullah blkcnt = ATI_IXP_DMA_CHSEGS_MAX; 5351042342aSAriff Abdullah if (blkcnt < ATI_IXP_DMA_CHSEGS_MIN) 5361042342aSAriff Abdullah blkcnt = ATI_IXP_DMA_CHSEGS_MIN; 5371042342aSAriff Abdullah 5381042342aSAriff Abdullah while ((blksz * blkcnt) > sndbuf_getmaxsize(ch->buffer)) { 5391042342aSAriff Abdullah if ((blkcnt >> 1) >= ATI_IXP_DMA_CHSEGS_MIN) 5401042342aSAriff Abdullah blkcnt >>= 1; 5411042342aSAriff Abdullah else if ((blksz >> 1) >= ATI_IXP_BLK_MIN) 5421042342aSAriff Abdullah blksz >>= 1; 5431042342aSAriff Abdullah else 5441042342aSAriff Abdullah break; 5451042342aSAriff Abdullah } 5461042342aSAriff Abdullah 5471042342aSAriff Abdullah if ((sndbuf_getblksz(ch->buffer) != blksz || 5481042342aSAriff Abdullah sndbuf_getblkcnt(ch->buffer) != blkcnt) && 5491042342aSAriff Abdullah sndbuf_resize(ch->buffer, blkcnt, blksz) != 0) 5501042342aSAriff Abdullah device_printf(sc->dev, "%s: failed blksz=%u blkcnt=%u\n", 5511042342aSAriff Abdullah __func__, blksz, blkcnt); 5521042342aSAriff Abdullah 5531042342aSAriff Abdullah ch->blksz = sndbuf_getblksz(ch->buffer); 5541042342aSAriff Abdullah ch->blkcnt = sndbuf_getblkcnt(ch->buffer); 5551042342aSAriff Abdullah 5561042342aSAriff Abdullah return (1); 5571042342aSAriff Abdullah } 5581042342aSAriff Abdullah 5591042342aSAriff Abdullah static int 560d5688b6aSAriff Abdullah atiixp_chan_setblocksize(kobj_t obj, void *data, uint32_t blksz) 561d5688b6aSAriff Abdullah { 562d5688b6aSAriff Abdullah struct atiixp_chinfo *ch = data; 563d5688b6aSAriff Abdullah struct atiixp_info *sc = ch->parent; 564d5688b6aSAriff Abdullah 5651042342aSAriff Abdullah atiixp_chan_setfragments(obj, data, blksz, sc->blkcnt); 566a580b31aSAriff Abdullah 567a580b31aSAriff Abdullah return (ch->blksz); 568d5688b6aSAriff Abdullah } 569d5688b6aSAriff Abdullah 570d5688b6aSAriff Abdullah static void 571d5688b6aSAriff Abdullah atiixp_buildsgdt(struct atiixp_chinfo *ch) 572d5688b6aSAriff Abdullah { 573a580b31aSAriff Abdullah struct atiixp_info *sc = ch->parent; 574a580b31aSAriff Abdullah uint32_t addr, blksz, blkcnt; 575d5688b6aSAriff Abdullah int i; 576d5688b6aSAriff Abdullah 577d5688b6aSAriff Abdullah addr = sndbuf_getbufaddr(ch->buffer); 578d5688b6aSAriff Abdullah 579a580b31aSAriff Abdullah if (sc->polling != 0) { 580a580b31aSAriff Abdullah blksz = ch->blksz * ch->blkcnt; 581a580b31aSAriff Abdullah blkcnt = 1; 582a580b31aSAriff Abdullah } else { 583a580b31aSAriff Abdullah blksz = ch->blksz; 584a580b31aSAriff Abdullah blkcnt = ch->blkcnt; 585d5688b6aSAriff Abdullah } 5869f52a325SAriff Abdullah 587a580b31aSAriff Abdullah for (i = 0; i < blkcnt; i++) { 588a580b31aSAriff Abdullah ch->sgd_table[i].addr = htole32(addr + (i * blksz)); 589a580b31aSAriff Abdullah ch->sgd_table[i].status = htole16(0); 590a580b31aSAriff Abdullah ch->sgd_table[i].size = htole16(blksz >> 2); 591a580b31aSAriff Abdullah ch->sgd_table[i].next = htole32((uint32_t)ch->sgd_addr + 592a580b31aSAriff Abdullah (((i + 1) % blkcnt) * sizeof(struct atiixp_dma_op))); 593a580b31aSAriff Abdullah } 594a580b31aSAriff Abdullah } 595a580b31aSAriff Abdullah 596a580b31aSAriff Abdullah static __inline uint32_t 597a580b31aSAriff Abdullah atiixp_dmapos(struct atiixp_chinfo *ch) 598a580b31aSAriff Abdullah { 599a580b31aSAriff Abdullah struct atiixp_info *sc = ch->parent; 600a580b31aSAriff Abdullah uint32_t reg, addr, sz, retry; 601a580b31aSAriff Abdullah volatile uint32_t ptr; 602a580b31aSAriff Abdullah 603a580b31aSAriff Abdullah reg = ch->dt_cur_bit; 604a580b31aSAriff Abdullah addr = sndbuf_getbufaddr(ch->buffer); 605a580b31aSAriff Abdullah sz = ch->blkcnt * ch->blksz; 606a580b31aSAriff Abdullah retry = ATI_IXP_DMA_RETRY_MAX; 607a580b31aSAriff Abdullah 608a580b31aSAriff Abdullah do { 609a580b31aSAriff Abdullah ptr = atiixp_rd(sc, reg); 610a580b31aSAriff Abdullah if (ptr < addr) 611a580b31aSAriff Abdullah continue; 612a580b31aSAriff Abdullah ptr -= addr; 613a580b31aSAriff Abdullah if (ptr < sz) { 614a580b31aSAriff Abdullah #if 0 6159f52a325SAriff Abdullah #ifdef ATI_IXP_DEBUG 616a580b31aSAriff Abdullah if ((ptr & ~(ch->blksz - 1)) != ch->ptr) { 617a580b31aSAriff Abdullah uint32_t delta; 618a580b31aSAriff Abdullah 619a580b31aSAriff Abdullah delta = (sz + ptr - ch->prevptr) % sz; 620a580b31aSAriff Abdullah #ifndef ATI_IXP_DEBUG_VERBOSE 621a580b31aSAriff Abdullah if (delta < ch->blksz) 6229f52a325SAriff Abdullah #endif 623a580b31aSAriff Abdullah device_printf(sc->dev, 624a580b31aSAriff Abdullah "PCMDIR_%s: incoherent DMA " 625a580b31aSAriff Abdullah "prevptr=%u ptr=%u " 626a580b31aSAriff Abdullah "ptr=%u blkcnt=%u " 627a580b31aSAriff Abdullah "[delta=%u != blksz=%u] " 628a580b31aSAriff Abdullah "(%s)\n", 629a580b31aSAriff Abdullah (ch->dir == PCMDIR_PLAY) ? 630a580b31aSAriff Abdullah "PLAY" : "REC", 631a580b31aSAriff Abdullah ch->prevptr, ptr, 632a580b31aSAriff Abdullah ch->ptr, ch->blkcnt, 633a580b31aSAriff Abdullah delta, ch->blksz, 634a580b31aSAriff Abdullah (delta < ch->blksz) ? 635a580b31aSAriff Abdullah "OVERLAPPED!" : "Ok"); 636a580b31aSAriff Abdullah ch->ptr = ptr & ~(ch->blksz - 1); 637a580b31aSAriff Abdullah } 638a580b31aSAriff Abdullah ch->prevptr = ptr; 639a580b31aSAriff Abdullah #endif 640a580b31aSAriff Abdullah #endif 641a580b31aSAriff Abdullah return (ptr); 642a580b31aSAriff Abdullah } 643a580b31aSAriff Abdullah } while (--retry); 644a580b31aSAriff Abdullah 645a580b31aSAriff Abdullah device_printf(sc->dev, "PCMDIR_%s: invalid DMA pointer ptr=%u\n", 646a580b31aSAriff Abdullah (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC", ptr); 647a580b31aSAriff Abdullah 648a580b31aSAriff Abdullah return (0); 649a580b31aSAriff Abdullah } 650a580b31aSAriff Abdullah 651a580b31aSAriff Abdullah static __inline int 652a580b31aSAriff Abdullah atiixp_poll_channel(struct atiixp_chinfo *ch) 653a580b31aSAriff Abdullah { 654a580b31aSAriff Abdullah uint32_t sz, delta; 655a580b31aSAriff Abdullah volatile uint32_t ptr; 656a580b31aSAriff Abdullah 657a580b31aSAriff Abdullah if (ch->active == 0) 658a580b31aSAriff Abdullah return (0); 659a580b31aSAriff Abdullah 660a580b31aSAriff Abdullah sz = ch->blksz * ch->blkcnt; 661a580b31aSAriff Abdullah ptr = atiixp_dmapos(ch); 662a580b31aSAriff Abdullah ch->ptr = ptr; 663a580b31aSAriff Abdullah ptr %= sz; 664a580b31aSAriff Abdullah ptr &= ~(ch->blksz - 1); 665a580b31aSAriff Abdullah delta = (sz + ptr - ch->prevptr) % sz; 666a580b31aSAriff Abdullah 667a580b31aSAriff Abdullah if (delta < ch->blksz) 668a580b31aSAriff Abdullah return (0); 669a580b31aSAriff Abdullah 670a580b31aSAriff Abdullah ch->prevptr = ptr; 671a580b31aSAriff Abdullah 672a580b31aSAriff Abdullah return (1); 673a580b31aSAriff Abdullah } 674a580b31aSAriff Abdullah 675a580b31aSAriff Abdullah #define atiixp_chan_active(sc) ((sc)->pch.active + (sc)->rch.active) 676a580b31aSAriff Abdullah 677a580b31aSAriff Abdullah static void 678a580b31aSAriff Abdullah atiixp_poll_callback(void *arg) 679a580b31aSAriff Abdullah { 680a580b31aSAriff Abdullah struct atiixp_info *sc = arg; 681a580b31aSAriff Abdullah uint32_t trigger = 0; 682a580b31aSAriff Abdullah 683a580b31aSAriff Abdullah if (sc == NULL) 684a580b31aSAriff Abdullah return; 685a580b31aSAriff Abdullah 686a580b31aSAriff Abdullah atiixp_lock(sc); 687a580b31aSAriff Abdullah if (sc->polling == 0 || atiixp_chan_active(sc) == 0) { 688a580b31aSAriff Abdullah atiixp_unlock(sc); 689a580b31aSAriff Abdullah return; 690a580b31aSAriff Abdullah } 691a580b31aSAriff Abdullah 692a580b31aSAriff Abdullah trigger |= (atiixp_poll_channel(&sc->pch) != 0) ? 1 : 0; 693a580b31aSAriff Abdullah trigger |= (atiixp_poll_channel(&sc->rch) != 0) ? 2 : 0; 694a580b31aSAriff Abdullah 695a580b31aSAriff Abdullah /* XXX */ 696a580b31aSAriff Abdullah callout_reset(&sc->poll_timer, 1/*sc->poll_ticks*/, 697a580b31aSAriff Abdullah atiixp_poll_callback, sc); 698a580b31aSAriff Abdullah 699a580b31aSAriff Abdullah atiixp_unlock(sc); 700a580b31aSAriff Abdullah 701a580b31aSAriff Abdullah if (trigger & 1) 702a580b31aSAriff Abdullah chn_intr(sc->pch.channel); 703a580b31aSAriff Abdullah if (trigger & 2) 704a580b31aSAriff Abdullah chn_intr(sc->rch.channel); 705d5688b6aSAriff Abdullah } 706d5688b6aSAriff Abdullah 707d5688b6aSAriff Abdullah static int 708d5688b6aSAriff Abdullah atiixp_chan_trigger(kobj_t obj, void *data, int go) 709d5688b6aSAriff Abdullah { 710d5688b6aSAriff Abdullah struct atiixp_chinfo *ch = data; 711d5688b6aSAriff Abdullah struct atiixp_info *sc = ch->parent; 712d5688b6aSAriff Abdullah uint32_t value; 713a580b31aSAriff Abdullah int pollticks; 714d5688b6aSAriff Abdullah 715d5688b6aSAriff Abdullah atiixp_lock(sc); 716d5688b6aSAriff Abdullah 717d5688b6aSAriff Abdullah switch (go) { 718d5688b6aSAriff Abdullah case PCMTRIG_START: 7199f52a325SAriff Abdullah atiixp_flush_dma(ch); 720d5688b6aSAriff Abdullah atiixp_buildsgdt(ch); 721d5688b6aSAriff Abdullah atiixp_wr(sc, ch->linkptr_bit, 0); 7229f52a325SAriff Abdullah atiixp_enable_dma(ch); 723d5688b6aSAriff Abdullah atiixp_wr(sc, ch->linkptr_bit, 724d5688b6aSAriff Abdullah (uint32_t)ch->sgd_addr | ATI_REG_LINKPTR_EN); 725a580b31aSAriff Abdullah if (sc->polling != 0) { 726a580b31aSAriff Abdullah ch->ptr = 0; 727a580b31aSAriff Abdullah ch->prevptr = 0; 728a580b31aSAriff Abdullah pollticks = ((uint64_t)hz * ch->blksz) / 729a580b31aSAriff Abdullah ((uint64_t)sndbuf_getbps(ch->buffer) * 730a580b31aSAriff Abdullah sndbuf_getspd(ch->buffer)); 731a580b31aSAriff Abdullah pollticks >>= 2; 732a580b31aSAriff Abdullah if (pollticks > hz) 733a580b31aSAriff Abdullah pollticks = hz; 734a580b31aSAriff Abdullah if (pollticks < 1) 735a580b31aSAriff Abdullah pollticks = 1; 736a580b31aSAriff Abdullah if (atiixp_chan_active(sc) == 0 || 737a580b31aSAriff Abdullah pollticks < sc->poll_ticks) { 738a580b31aSAriff Abdullah if (bootverbose) { 739a580b31aSAriff Abdullah if (atiixp_chan_active(sc) == 0) 740a580b31aSAriff Abdullah device_printf(sc->dev, 741a580b31aSAriff Abdullah "%s: pollticks=%d\n", 742a580b31aSAriff Abdullah __func__, pollticks); 743a580b31aSAriff Abdullah else 744a580b31aSAriff Abdullah device_printf(sc->dev, 745a580b31aSAriff Abdullah "%s: pollticks %d -> %d\n", 746a580b31aSAriff Abdullah __func__, sc->poll_ticks, 747a580b31aSAriff Abdullah pollticks); 748a580b31aSAriff Abdullah } 749a580b31aSAriff Abdullah sc->poll_ticks = pollticks; 750a580b31aSAriff Abdullah callout_reset(&sc->poll_timer, 1, 751a580b31aSAriff Abdullah atiixp_poll_callback, sc); 752a580b31aSAriff Abdullah } 753a580b31aSAriff Abdullah } 754a580b31aSAriff Abdullah ch->active = 1; 755d5688b6aSAriff Abdullah break; 756d5688b6aSAriff Abdullah case PCMTRIG_STOP: 757d5688b6aSAriff Abdullah case PCMTRIG_ABORT: 7589f52a325SAriff Abdullah atiixp_disable_dma(ch); 7599f52a325SAriff Abdullah atiixp_flush_dma(ch); 760a580b31aSAriff Abdullah ch->active = 0; 761a580b31aSAriff Abdullah if (sc->polling != 0) { 762a580b31aSAriff Abdullah if (atiixp_chan_active(sc) == 0) { 763a580b31aSAriff Abdullah callout_stop(&sc->poll_timer); 764a580b31aSAriff Abdullah sc->poll_ticks = 1; 765a580b31aSAriff Abdullah } else { 766a580b31aSAriff Abdullah if (sc->pch.active != 0) 767a580b31aSAriff Abdullah ch = &sc->pch; 768a580b31aSAriff Abdullah else 769a580b31aSAriff Abdullah ch = &sc->rch; 770a580b31aSAriff Abdullah pollticks = ((uint64_t)hz * ch->blksz) / 771a580b31aSAriff Abdullah ((uint64_t)sndbuf_getbps(ch->buffer) * 772a580b31aSAriff Abdullah sndbuf_getspd(ch->buffer)); 773a580b31aSAriff Abdullah pollticks >>= 2; 774a580b31aSAriff Abdullah if (pollticks > hz) 775a580b31aSAriff Abdullah pollticks = hz; 776a580b31aSAriff Abdullah if (pollticks < 1) 777a580b31aSAriff Abdullah pollticks = 1; 778a580b31aSAriff Abdullah if (pollticks > sc->poll_ticks) { 779a580b31aSAriff Abdullah if (bootverbose) 780a580b31aSAriff Abdullah device_printf(sc->dev, 781a580b31aSAriff Abdullah "%s: pollticks %d -> %d\n", 782a580b31aSAriff Abdullah __func__, sc->poll_ticks, 783a580b31aSAriff Abdullah pollticks); 784a580b31aSAriff Abdullah sc->poll_ticks = pollticks; 785a580b31aSAriff Abdullah callout_reset(&sc->poll_timer, 786a580b31aSAriff Abdullah 1, atiixp_poll_callback, 787a580b31aSAriff Abdullah sc); 788a580b31aSAriff Abdullah } 789a580b31aSAriff Abdullah } 790a580b31aSAriff Abdullah } 791d5688b6aSAriff Abdullah break; 792d5688b6aSAriff Abdullah default: 793d5688b6aSAriff Abdullah atiixp_unlock(sc); 7949f52a325SAriff Abdullah return (0); 795d5688b6aSAriff Abdullah break; 796d5688b6aSAriff Abdullah } 797d5688b6aSAriff Abdullah 798d5688b6aSAriff Abdullah /* Update bus busy status */ 799d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_IER); 800a580b31aSAriff Abdullah if (atiixp_rd(sc, ATI_REG_CMD) & (ATI_REG_CMD_SEND_EN | 801a580b31aSAriff Abdullah ATI_REG_CMD_RECEIVE_EN | ATI_REG_CMD_SPDF_OUT_EN)) 802d5688b6aSAriff Abdullah value |= ATI_REG_IER_SET_BUS_BUSY; 803d5688b6aSAriff Abdullah else 804d5688b6aSAriff Abdullah value &= ~ATI_REG_IER_SET_BUS_BUSY; 805d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_IER, value); 806d5688b6aSAriff Abdullah 807d5688b6aSAriff Abdullah atiixp_unlock(sc); 808d5688b6aSAriff Abdullah 8099f52a325SAriff Abdullah return (0); 8109f52a325SAriff Abdullah } 8119f52a325SAriff Abdullah 812d5688b6aSAriff Abdullah static int 813d5688b6aSAriff Abdullah atiixp_chan_getptr(kobj_t obj, void *data) 814d5688b6aSAriff Abdullah { 815d5688b6aSAriff Abdullah struct atiixp_chinfo *ch = data; 816d5688b6aSAriff Abdullah struct atiixp_info *sc = ch->parent; 8179f52a325SAriff Abdullah uint32_t ptr; 818d5688b6aSAriff Abdullah 819d5688b6aSAriff Abdullah atiixp_lock(sc); 820a580b31aSAriff Abdullah if (sc->polling != 0) 821a580b31aSAriff Abdullah ptr = ch->ptr; 822a580b31aSAriff Abdullah else 8239f52a325SAriff Abdullah ptr = atiixp_dmapos(ch); 824d5688b6aSAriff Abdullah atiixp_unlock(sc); 825d5688b6aSAriff Abdullah 8269f52a325SAriff Abdullah return (ptr); 827d5688b6aSAriff Abdullah } 828d5688b6aSAriff Abdullah 829d5688b6aSAriff Abdullah static struct pcmchan_caps * 830d5688b6aSAriff Abdullah atiixp_chan_getcaps(kobj_t obj, void *data) 831d5688b6aSAriff Abdullah { 832d5688b6aSAriff Abdullah struct atiixp_chinfo *ch = data; 833d5688b6aSAriff Abdullah 834d5688b6aSAriff Abdullah if (ch->caps_32bit) 8359f52a325SAriff Abdullah return (&atiixp_caps_32bit); 8369f52a325SAriff Abdullah return (&atiixp_caps); 837d5688b6aSAriff Abdullah } 838d5688b6aSAriff Abdullah 839d5688b6aSAriff Abdullah static kobj_method_t atiixp_chan_methods[] = { 840d5688b6aSAriff Abdullah KOBJMETHOD(channel_init, atiixp_chan_init), 841d5688b6aSAriff Abdullah KOBJMETHOD(channel_setformat, atiixp_chan_setformat), 842d5688b6aSAriff Abdullah KOBJMETHOD(channel_setspeed, atiixp_chan_setspeed), 843d5688b6aSAriff Abdullah KOBJMETHOD(channel_setblocksize, atiixp_chan_setblocksize), 8441042342aSAriff Abdullah KOBJMETHOD(channel_setfragments, atiixp_chan_setfragments), 845d5688b6aSAriff Abdullah KOBJMETHOD(channel_trigger, atiixp_chan_trigger), 846d5688b6aSAriff Abdullah KOBJMETHOD(channel_getptr, atiixp_chan_getptr), 847d5688b6aSAriff Abdullah KOBJMETHOD(channel_getcaps, atiixp_chan_getcaps), 848d5688b6aSAriff Abdullah { 0, 0 } 849d5688b6aSAriff Abdullah }; 850d5688b6aSAriff Abdullah CHANNEL_DECLARE(atiixp_chan); 851d5688b6aSAriff Abdullah 852d5688b6aSAriff Abdullah /* 853d5688b6aSAriff Abdullah * PCI driver interface 854d5688b6aSAriff Abdullah */ 855d5688b6aSAriff Abdullah static void 856d5688b6aSAriff Abdullah atiixp_intr(void *p) 857d5688b6aSAriff Abdullah { 858d5688b6aSAriff Abdullah struct atiixp_info *sc = p; 859d5688b6aSAriff Abdullah uint32_t status, enable, detected_codecs; 860a580b31aSAriff Abdullah uint32_t trigger = 0; 861d5688b6aSAriff Abdullah 862d5688b6aSAriff Abdullah atiixp_lock(sc); 863a580b31aSAriff Abdullah if (sc->polling != 0) { 864a580b31aSAriff Abdullah atiixp_unlock(sc); 865a580b31aSAriff Abdullah return; 866a580b31aSAriff Abdullah } 867d5688b6aSAriff Abdullah status = atiixp_rd(sc, ATI_REG_ISR); 868d5688b6aSAriff Abdullah 869d5688b6aSAriff Abdullah if (status == 0) { 870d5688b6aSAriff Abdullah atiixp_unlock(sc); 871d5688b6aSAriff Abdullah return; 872d5688b6aSAriff Abdullah } 873d5688b6aSAriff Abdullah 874a580b31aSAriff Abdullah if ((status & ATI_REG_ISR_OUT_STATUS) && sc->pch.active != 0) 875a580b31aSAriff Abdullah trigger |= 1; 876a580b31aSAriff Abdullah if ((status & ATI_REG_ISR_IN_STATUS) && sc->rch.active != 0) 877a580b31aSAriff Abdullah trigger |= 2; 878d5688b6aSAriff Abdullah 879d5688b6aSAriff Abdullah #if 0 880d5688b6aSAriff Abdullah if (status & ATI_REG_ISR_IN_XRUN) { 881d5688b6aSAriff Abdullah device_printf(sc->dev, 882d5688b6aSAriff Abdullah "Recieve IN XRUN interrupt\n"); 883d5688b6aSAriff Abdullah } 884d5688b6aSAriff Abdullah if (status & ATI_REG_ISR_OUT_XRUN) { 885d5688b6aSAriff Abdullah device_printf(sc->dev, 886d5688b6aSAriff Abdullah "Recieve OUT XRUN interrupt\n"); 887d5688b6aSAriff Abdullah } 888d5688b6aSAriff Abdullah #endif 889d5688b6aSAriff Abdullah 890d5688b6aSAriff Abdullah if (status & CODEC_CHECK_BITS) { 891d5688b6aSAriff Abdullah /* mark missing codecs as not ready */ 892d5688b6aSAriff Abdullah detected_codecs = status & CODEC_CHECK_BITS; 893d5688b6aSAriff Abdullah sc->codec_not_ready_bits |= detected_codecs; 894d5688b6aSAriff Abdullah 895d5688b6aSAriff Abdullah /* disable detected interupt sources */ 896d5688b6aSAriff Abdullah enable = atiixp_rd(sc, ATI_REG_IER); 897d5688b6aSAriff Abdullah enable &= ~detected_codecs; 898d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_IER, enable); 899d5688b6aSAriff Abdullah } 900d5688b6aSAriff Abdullah 901d5688b6aSAriff Abdullah /* acknowledge */ 902d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_ISR, status); 903d5688b6aSAriff Abdullah atiixp_unlock(sc); 904a580b31aSAriff Abdullah 905a580b31aSAriff Abdullah if (trigger & 1) 906a580b31aSAriff Abdullah chn_intr(sc->pch.channel); 907a580b31aSAriff Abdullah if (trigger & 2) 908a580b31aSAriff Abdullah chn_intr(sc->rch.channel); 909d5688b6aSAriff Abdullah } 910d5688b6aSAriff Abdullah 911d5688b6aSAriff Abdullah static void 912d5688b6aSAriff Abdullah atiixp_dma_cb(void *p, bus_dma_segment_t *bds, int a, int b) 913d5688b6aSAriff Abdullah { 914d5688b6aSAriff Abdullah struct atiixp_info *sc = (struct atiixp_info *)p; 915d5688b6aSAriff Abdullah sc->sgd_addr = bds->ds_addr; 916d5688b6aSAriff Abdullah } 917d5688b6aSAriff Abdullah 918d5688b6aSAriff Abdullah static void 919d5688b6aSAriff Abdullah atiixp_chip_pre_init(struct atiixp_info *sc) 920d5688b6aSAriff Abdullah { 921d5688b6aSAriff Abdullah uint32_t value; 922d5688b6aSAriff Abdullah 923d5688b6aSAriff Abdullah atiixp_lock(sc); 924d5688b6aSAriff Abdullah 925d5688b6aSAriff Abdullah /* disable interrupts */ 926d5688b6aSAriff Abdullah atiixp_disable_interrupts(sc); 927d5688b6aSAriff Abdullah 928d5688b6aSAriff Abdullah /* clear all DMA enables (preserving rest of settings) */ 929d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_CMD); 930d5688b6aSAriff Abdullah value &= ~(ATI_REG_CMD_IN_DMA_EN | ATI_REG_CMD_OUT_DMA_EN | 931d5688b6aSAriff Abdullah ATI_REG_CMD_SPDF_OUT_EN ); 932d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_CMD, value); 933d5688b6aSAriff Abdullah 934d5688b6aSAriff Abdullah /* reset aclink */ 935d5688b6aSAriff Abdullah atiixp_reset_aclink(sc); 936d5688b6aSAriff Abdullah 937d5688b6aSAriff Abdullah sc->codec_not_ready_bits = 0; 938d5688b6aSAriff Abdullah 939d5688b6aSAriff Abdullah /* enable all codecs to interrupt as well as the new frame interrupt */ 940d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_IER, CODEC_CHECK_BITS); 941d5688b6aSAriff Abdullah 942d5688b6aSAriff Abdullah atiixp_unlock(sc); 943d5688b6aSAriff Abdullah } 944d5688b6aSAriff Abdullah 945a580b31aSAriff Abdullah #ifdef SND_DYNSYSCTL 946a580b31aSAriff Abdullah static int 947a580b31aSAriff Abdullah sysctl_atiixp_polling(SYSCTL_HANDLER_ARGS) 948a580b31aSAriff Abdullah { 949a580b31aSAriff Abdullah struct atiixp_info *sc; 950a580b31aSAriff Abdullah device_t dev; 951a580b31aSAriff Abdullah int err, val; 952a580b31aSAriff Abdullah 953a580b31aSAriff Abdullah dev = oidp->oid_arg1; 954a580b31aSAriff Abdullah sc = pcm_getdevinfo(dev); 955a580b31aSAriff Abdullah if (sc == NULL) 956a580b31aSAriff Abdullah return (EINVAL); 957a580b31aSAriff Abdullah atiixp_lock(sc); 958a580b31aSAriff Abdullah val = sc->polling; 959a580b31aSAriff Abdullah atiixp_unlock(sc); 960a580b31aSAriff Abdullah err = sysctl_handle_int(oidp, &val, sizeof(val), req); 961a580b31aSAriff Abdullah 962a580b31aSAriff Abdullah if (err || req->newptr == NULL) 963a580b31aSAriff Abdullah return (err); 964a580b31aSAriff Abdullah if (val < 0 || val > 1) 965a580b31aSAriff Abdullah return (EINVAL); 966a580b31aSAriff Abdullah 967a580b31aSAriff Abdullah atiixp_lock(sc); 968a580b31aSAriff Abdullah if (val != sc->polling) { 969a580b31aSAriff Abdullah if (atiixp_chan_active(sc) != 0) 970a580b31aSAriff Abdullah err = EBUSY; 971a580b31aSAriff Abdullah else if (val == 0) { 972a580b31aSAriff Abdullah atiixp_enable_interrupts(sc); 973a580b31aSAriff Abdullah sc->polling = 0; 974a580b31aSAriff Abdullah DELAY(1000); 975a580b31aSAriff Abdullah } else { 976a580b31aSAriff Abdullah atiixp_disable_interrupts(sc); 977a580b31aSAriff Abdullah sc->polling = 1; 978a580b31aSAriff Abdullah DELAY(1000); 979a580b31aSAriff Abdullah } 980a580b31aSAriff Abdullah } 981a580b31aSAriff Abdullah atiixp_unlock(sc); 982a580b31aSAriff Abdullah 983a580b31aSAriff Abdullah return (err); 984a580b31aSAriff Abdullah } 985a580b31aSAriff Abdullah #endif 986a580b31aSAriff Abdullah 987d5688b6aSAriff Abdullah static void 988d5688b6aSAriff Abdullah atiixp_chip_post_init(void *arg) 989d5688b6aSAriff Abdullah { 990d5688b6aSAriff Abdullah struct atiixp_info *sc = (struct atiixp_info *)arg; 99105051995SAriff Abdullah uint32_t subdev; 992a580b31aSAriff Abdullah int i, timeout, found, polling; 993d5688b6aSAriff Abdullah char status[SND_STATUSLEN]; 994d5688b6aSAriff Abdullah 995d5688b6aSAriff Abdullah atiixp_lock(sc); 996d5688b6aSAriff Abdullah 997d5688b6aSAriff Abdullah if (sc->delayed_attach.ich_func) { 998d5688b6aSAriff Abdullah config_intrhook_disestablish(&sc->delayed_attach); 999d5688b6aSAriff Abdullah sc->delayed_attach.ich_func = NULL; 1000d5688b6aSAriff Abdullah } 1001d5688b6aSAriff Abdullah 1002a580b31aSAriff Abdullah polling = sc->polling; 1003a580b31aSAriff Abdullah sc->polling = 0; 1004a580b31aSAriff Abdullah 1005d5688b6aSAriff Abdullah /* wait for the interrupts to happen */ 1006f2a1d71aSAriff Abdullah timeout = 100; 10079f52a325SAriff Abdullah do { 1008f2a1d71aSAriff Abdullah msleep(sc, sc->lock, PWAIT, "ixpslp", 1); 1009d5688b6aSAriff Abdullah if (sc->codec_not_ready_bits) 1010d5688b6aSAriff Abdullah break; 10119f52a325SAriff Abdullah } while (--timeout); 1012d5688b6aSAriff Abdullah 1013a580b31aSAriff Abdullah sc->polling = polling; 1014d5688b6aSAriff Abdullah atiixp_disable_interrupts(sc); 1015d5688b6aSAriff Abdullah 1016d5688b6aSAriff Abdullah if (timeout == 0) { 1017d5688b6aSAriff Abdullah device_printf(sc->dev, 1018d5688b6aSAriff Abdullah "WARNING: timeout during codec detection; " 1019d5688b6aSAriff Abdullah "codecs might be present but haven't interrupted\n"); 1020d5688b6aSAriff Abdullah atiixp_unlock(sc); 1021f2a1d71aSAriff Abdullah goto postinitbad; 1022d5688b6aSAriff Abdullah } 1023d5688b6aSAriff Abdullah 1024d5688b6aSAriff Abdullah found = 0; 1025d5688b6aSAriff Abdullah 1026d5688b6aSAriff Abdullah /* 1027d5688b6aSAriff Abdullah * ATI IXP can have upto 3 codecs, but single codec should be 1028d5688b6aSAriff Abdullah * suffice for now. 1029d5688b6aSAriff Abdullah */ 1030a580b31aSAriff Abdullah if (!(sc->codec_not_ready_bits & ATI_REG_ISR_CODEC0_NOT_READY)) { 1031d5688b6aSAriff Abdullah /* codec 0 present */ 1032d5688b6aSAriff Abdullah sc->codec_found++; 1033d5688b6aSAriff Abdullah sc->codec_idx = 0; 1034d5688b6aSAriff Abdullah found++; 1035d5688b6aSAriff Abdullah } 1036d5688b6aSAriff Abdullah 1037a580b31aSAriff Abdullah if (!(sc->codec_not_ready_bits & ATI_REG_ISR_CODEC1_NOT_READY)) { 1038d5688b6aSAriff Abdullah /* codec 1 present */ 1039d5688b6aSAriff Abdullah sc->codec_found++; 1040d5688b6aSAriff Abdullah } 1041d5688b6aSAriff Abdullah 1042a580b31aSAriff Abdullah if (!(sc->codec_not_ready_bits & ATI_REG_ISR_CODEC2_NOT_READY)) { 1043d5688b6aSAriff Abdullah /* codec 2 present */ 1044d5688b6aSAriff Abdullah sc->codec_found++; 1045d5688b6aSAriff Abdullah } 1046d5688b6aSAriff Abdullah 1047d5688b6aSAriff Abdullah atiixp_unlock(sc); 1048d5688b6aSAriff Abdullah 1049d5688b6aSAriff Abdullah if (found == 0) 1050f2a1d71aSAriff Abdullah goto postinitbad; 1051d5688b6aSAriff Abdullah 1052d5688b6aSAriff Abdullah /* create/init mixer */ 1053d5688b6aSAriff Abdullah sc->codec = AC97_CREATE(sc->dev, sc, atiixp_ac97); 1054d5688b6aSAriff Abdullah if (sc->codec == NULL) 1055d5688b6aSAriff Abdullah goto postinitbad; 1056d5688b6aSAriff Abdullah 1057a580b31aSAriff Abdullah subdev = (pci_get_subdevice(sc->dev) << 16) | 1058a580b31aSAriff Abdullah pci_get_subvendor(sc->dev); 105905051995SAriff Abdullah switch (subdev) { 10600585c315SAriff Abdullah case 0x11831043: /* ASUS A6R */ 106105051995SAriff Abdullah case 0x2043161f: /* Maxselect x710s - http://maxselect.ru/ */ 1062a580b31aSAriff Abdullah ac97_setflags(sc->codec, ac97_getflags(sc->codec) | 1063a580b31aSAriff Abdullah AC97_F_EAPD_INV); 106405051995SAriff Abdullah break; 106505051995SAriff Abdullah default: 106605051995SAriff Abdullah break; 106705051995SAriff Abdullah } 106805051995SAriff Abdullah 1069d5688b6aSAriff Abdullah mixer_init(sc->dev, ac97_getmixerclass(), sc->codec); 1070d5688b6aSAriff Abdullah 1071d5688b6aSAriff Abdullah if (pcm_register(sc->dev, sc, ATI_IXP_NPCHAN, ATI_IXP_NRCHAN)) 1072d5688b6aSAriff Abdullah goto postinitbad; 1073d5688b6aSAriff Abdullah 1074d5688b6aSAriff Abdullah for (i = 0; i < ATI_IXP_NPCHAN; i++) 1075d5688b6aSAriff Abdullah pcm_addchan(sc->dev, PCMDIR_PLAY, &atiixp_chan_class, sc); 1076d5688b6aSAriff Abdullah for (i = 0; i < ATI_IXP_NRCHAN; i++) 1077d5688b6aSAriff Abdullah pcm_addchan(sc->dev, PCMDIR_REC, &atiixp_chan_class, sc); 1078d5688b6aSAriff Abdullah 1079a580b31aSAriff Abdullah #ifdef SND_DYNSYSCTL 1080a580b31aSAriff Abdullah SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev), 1081a580b31aSAriff Abdullah SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO, 1082a580b31aSAriff Abdullah "polling", CTLTYPE_INT | CTLFLAG_RW, sc->dev, sizeof(sc->dev), 1083a580b31aSAriff Abdullah sysctl_atiixp_polling, "I", "Enable polling mode"); 1084a580b31aSAriff Abdullah #endif 1085a580b31aSAriff Abdullah 1086d5688b6aSAriff Abdullah snprintf(status, SND_STATUSLEN, "at memory 0x%lx irq %ld %s", 1087d5688b6aSAriff Abdullah rman_get_start(sc->reg), rman_get_start(sc->irq), 1088d5688b6aSAriff Abdullah PCM_KLDSTRING(snd_atiixp)); 1089d5688b6aSAriff Abdullah 1090d5688b6aSAriff Abdullah pcm_setstatus(sc->dev, status); 1091d5688b6aSAriff Abdullah 1092d5688b6aSAriff Abdullah atiixp_lock(sc); 1093a580b31aSAriff Abdullah if (sc->polling == 0) 1094d5688b6aSAriff Abdullah atiixp_enable_interrupts(sc); 1095d5688b6aSAriff Abdullah atiixp_unlock(sc); 1096d5688b6aSAriff Abdullah 1097d5688b6aSAriff Abdullah return; 1098d5688b6aSAriff Abdullah 1099d5688b6aSAriff Abdullah postinitbad: 1100f2a1d71aSAriff Abdullah atiixp_release_resource(sc); 1101f2a1d71aSAriff Abdullah } 1102f2a1d71aSAriff Abdullah 1103f2a1d71aSAriff Abdullah static void 1104f2a1d71aSAriff Abdullah atiixp_release_resource(struct atiixp_info *sc) 1105f2a1d71aSAriff Abdullah { 1106f2a1d71aSAriff Abdullah if (sc == NULL) 1107f2a1d71aSAriff Abdullah return; 1108f2a1d71aSAriff Abdullah if (sc->codec) { 1109d5688b6aSAriff Abdullah ac97_destroy(sc->codec); 1110f2a1d71aSAriff Abdullah sc->codec = NULL; 1111f2a1d71aSAriff Abdullah } 1112f2a1d71aSAriff Abdullah if (sc->ih) { 1113d5688b6aSAriff Abdullah bus_teardown_intr(sc->dev, sc->irq, sc->ih); 1114703c934aSAriff Abdullah sc->ih = NULL; 1115f2a1d71aSAriff Abdullah } 1116f2a1d71aSAriff Abdullah if (sc->reg) { 1117d5688b6aSAriff Abdullah bus_release_resource(sc->dev, sc->regtype, sc->regid, sc->reg); 1118703c934aSAriff Abdullah sc->reg = NULL; 1119f2a1d71aSAriff Abdullah } 1120f2a1d71aSAriff Abdullah if (sc->irq) { 1121d5688b6aSAriff Abdullah bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irqid, sc->irq); 1122703c934aSAriff Abdullah sc->irq = NULL; 1123f2a1d71aSAriff Abdullah } 1124f2a1d71aSAriff Abdullah if (sc->parent_dmat) { 1125d5688b6aSAriff Abdullah bus_dma_tag_destroy(sc->parent_dmat); 1126703c934aSAriff Abdullah sc->parent_dmat = NULL; 1127f2a1d71aSAriff Abdullah } 1128703c934aSAriff Abdullah if (sc->sgd_dmamap) 1129d5688b6aSAriff Abdullah bus_dmamap_unload(sc->sgd_dmat, sc->sgd_dmamap); 1130703c934aSAriff Abdullah if (sc->sgd_table) { 1131703c934aSAriff Abdullah bus_dmamem_free(sc->sgd_dmat, sc->sgd_table, sc->sgd_dmamap); 1132703c934aSAriff Abdullah sc->sgd_table = NULL; 1133f2a1d71aSAriff Abdullah } 1134703c934aSAriff Abdullah sc->sgd_dmamap = NULL; 1135f2a1d71aSAriff Abdullah if (sc->sgd_dmat) { 1136d5688b6aSAriff Abdullah bus_dma_tag_destroy(sc->sgd_dmat); 1137703c934aSAriff Abdullah sc->sgd_dmat = NULL; 1138f2a1d71aSAriff Abdullah } 1139f2a1d71aSAriff Abdullah if (sc->lock) { 1140d5688b6aSAriff Abdullah snd_mtxfree(sc->lock); 1141f2a1d71aSAriff Abdullah sc->lock = NULL; 1142f2a1d71aSAriff Abdullah } 1143d5688b6aSAriff Abdullah } 1144d5688b6aSAriff Abdullah 1145d5688b6aSAriff Abdullah static int 1146d5688b6aSAriff Abdullah atiixp_pci_probe(device_t dev) 1147d5688b6aSAriff Abdullah { 1148d5688b6aSAriff Abdullah int i; 1149d5688b6aSAriff Abdullah uint16_t devid, vendor; 1150d5688b6aSAriff Abdullah 1151d5688b6aSAriff Abdullah vendor = pci_get_vendor(dev); 1152d5688b6aSAriff Abdullah devid = pci_get_device(dev); 1153d5688b6aSAriff Abdullah for (i = 0; i < sizeof(atiixp_hw) / sizeof(atiixp_hw[0]); i++) { 1154d5688b6aSAriff Abdullah if (vendor == atiixp_hw[i].vendor && 1155d5688b6aSAriff Abdullah devid == atiixp_hw[i].devid) { 1156d5688b6aSAriff Abdullah device_set_desc(dev, atiixp_hw[i].desc); 11579f52a325SAriff Abdullah return (BUS_PROBE_DEFAULT); 1158d5688b6aSAriff Abdullah } 1159d5688b6aSAriff Abdullah } 1160d5688b6aSAriff Abdullah 11619f52a325SAriff Abdullah return (ENXIO); 1162d5688b6aSAriff Abdullah } 1163d5688b6aSAriff Abdullah 1164d5688b6aSAriff Abdullah static int 1165d5688b6aSAriff Abdullah atiixp_pci_attach(device_t dev) 1166d5688b6aSAriff Abdullah { 1167d5688b6aSAriff Abdullah struct atiixp_info *sc; 1168d5688b6aSAriff Abdullah int i; 1169d5688b6aSAriff Abdullah 1170d5688b6aSAriff Abdullah if ((sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) { 1171d5688b6aSAriff Abdullah device_printf(dev, "cannot allocate softc\n"); 11729f52a325SAriff Abdullah return (ENXIO); 1173d5688b6aSAriff Abdullah } 1174d5688b6aSAriff Abdullah 11754582b3a1SAriff Abdullah sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_atiixp softc"); 1176d5688b6aSAriff Abdullah sc->dev = dev; 1177a580b31aSAriff Abdullah 1178a580b31aSAriff Abdullah callout_init(&sc->poll_timer, CALLOUT_MPSAFE); 1179a580b31aSAriff Abdullah sc->poll_ticks = 1; 1180a580b31aSAriff Abdullah 1181a580b31aSAriff Abdullah if (resource_int_value(device_get_name(sc->dev), 1182a580b31aSAriff Abdullah device_get_unit(sc->dev), "polling", &i) == 0 && i != 0) 1183a580b31aSAriff Abdullah sc->polling = 1; 1184a580b31aSAriff Abdullah else 1185a580b31aSAriff Abdullah sc->polling = 0; 1186d5688b6aSAriff Abdullah 1187d5688b6aSAriff Abdullah pci_set_powerstate(dev, PCI_POWERSTATE_D0); 1188d5688b6aSAriff Abdullah pci_enable_busmaster(dev); 1189d5688b6aSAriff Abdullah 1190d5688b6aSAriff Abdullah sc->regid = PCIR_BAR(0); 1191d5688b6aSAriff Abdullah sc->regtype = SYS_RES_MEMORY; 1192a580b31aSAriff Abdullah sc->reg = bus_alloc_resource_any(dev, sc->regtype, 1193a580b31aSAriff Abdullah &sc->regid, RF_ACTIVE); 1194d5688b6aSAriff Abdullah 1195d5688b6aSAriff Abdullah if (!sc->reg) { 1196d5688b6aSAriff Abdullah device_printf(dev, "unable to allocate register space\n"); 1197d5688b6aSAriff Abdullah goto bad; 1198d5688b6aSAriff Abdullah } 1199d5688b6aSAriff Abdullah 1200d5688b6aSAriff Abdullah sc->st = rman_get_bustag(sc->reg); 1201d5688b6aSAriff Abdullah sc->sh = rman_get_bushandle(sc->reg); 1202d5688b6aSAriff Abdullah 12039f52a325SAriff Abdullah sc->bufsz = pcm_getbuffersize(dev, ATI_IXP_BUFSZ_MIN, 12049f52a325SAriff Abdullah ATI_IXP_BUFSZ_DEFAULT, ATI_IXP_BUFSZ_MAX); 1205d5688b6aSAriff Abdullah 1206d5688b6aSAriff Abdullah sc->irqid = 0; 1207d5688b6aSAriff Abdullah sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid, 1208d5688b6aSAriff Abdullah RF_ACTIVE | RF_SHAREABLE); 1209a580b31aSAriff Abdullah if (!sc->irq || snd_setup_intr(dev, sc->irq, INTR_MPSAFE, 1210d5688b6aSAriff Abdullah atiixp_intr, sc, &sc->ih)) { 1211d5688b6aSAriff Abdullah device_printf(dev, "unable to map interrupt\n"); 1212d5688b6aSAriff Abdullah goto bad; 1213d5688b6aSAriff Abdullah } 1214d5688b6aSAriff Abdullah 1215d5688b6aSAriff Abdullah /* 1216d5688b6aSAriff Abdullah * Let the user choose the best DMA segments. 1217d5688b6aSAriff Abdullah */ 1218d5688b6aSAriff Abdullah if (resource_int_value(device_get_name(dev), 1219a580b31aSAriff Abdullah device_get_unit(dev), "blocksize", &i) == 0 && i > 0) { 12201042342aSAriff Abdullah i &= ATI_IXP_BLK_ALIGN; 12211042342aSAriff Abdullah if (i < ATI_IXP_BLK_MIN) 12221042342aSAriff Abdullah i = ATI_IXP_BLK_MIN; 1223a580b31aSAriff Abdullah sc->blkcnt = sc->bufsz / i; 122405051995SAriff Abdullah i = 0; 1225a580b31aSAriff Abdullah while (sc->blkcnt >> i) 122605051995SAriff Abdullah i++; 1227a580b31aSAriff Abdullah sc->blkcnt = 1 << (i - 1); 1228a580b31aSAriff Abdullah if (sc->blkcnt < ATI_IXP_DMA_CHSEGS_MIN) 1229a580b31aSAriff Abdullah sc->blkcnt = ATI_IXP_DMA_CHSEGS_MIN; 1230a580b31aSAriff Abdullah else if (sc->blkcnt > ATI_IXP_DMA_CHSEGS_MAX) 1231a580b31aSAriff Abdullah sc->blkcnt = ATI_IXP_DMA_CHSEGS_MAX; 1232a580b31aSAriff Abdullah 1233a580b31aSAriff Abdullah } else 1234a580b31aSAriff Abdullah sc->blkcnt = ATI_IXP_DMA_CHSEGS; 123505051995SAriff Abdullah 123605051995SAriff Abdullah /* 1237d5688b6aSAriff Abdullah * DMA tag for scatter-gather buffers and link pointers 1238d5688b6aSAriff Abdullah */ 12390b989078SAlexander Leidinger if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2, 12400b989078SAlexander Leidinger /*boundary*/0, 1241d5688b6aSAriff Abdullah /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 1242d5688b6aSAriff Abdullah /*highaddr*/BUS_SPACE_MAXADDR, 1243d5688b6aSAriff Abdullah /*filter*/NULL, /*filterarg*/NULL, 1244d5688b6aSAriff Abdullah /*maxsize*/sc->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff, 1245d5688b6aSAriff Abdullah /*flags*/0, /*lockfunc*/NULL, 1246d5688b6aSAriff Abdullah /*lockarg*/NULL, &sc->parent_dmat) != 0) { 1247d5688b6aSAriff Abdullah device_printf(dev, "unable to create dma tag\n"); 1248d5688b6aSAriff Abdullah goto bad; 1249d5688b6aSAriff Abdullah } 1250d5688b6aSAriff Abdullah 12510b989078SAlexander Leidinger if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2, 12520b989078SAlexander Leidinger /*boundary*/0, 1253d5688b6aSAriff Abdullah /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 1254d5688b6aSAriff Abdullah /*highaddr*/BUS_SPACE_MAXADDR, 1255d5688b6aSAriff Abdullah /*filter*/NULL, /*filterarg*/NULL, 12561042342aSAriff Abdullah /*maxsize*/ATI_IXP_DMA_CHSEGS_MAX * ATI_IXP_NCHANS * 1257d5688b6aSAriff Abdullah sizeof(struct atiixp_dma_op), 1258d5688b6aSAriff Abdullah /*nsegments*/1, /*maxsegz*/0x3ffff, 1259d5688b6aSAriff Abdullah /*flags*/0, /*lockfunc*/NULL, 1260d5688b6aSAriff Abdullah /*lockarg*/NULL, &sc->sgd_dmat) != 0) { 1261d5688b6aSAriff Abdullah device_printf(dev, "unable to create dma tag\n"); 1262d5688b6aSAriff Abdullah goto bad; 1263d5688b6aSAriff Abdullah } 1264d5688b6aSAriff Abdullah 1265d5688b6aSAriff Abdullah if (bus_dmamem_alloc(sc->sgd_dmat, (void **)&sc->sgd_table, 1266d5688b6aSAriff Abdullah BUS_DMA_NOWAIT, &sc->sgd_dmamap) == -1) 1267d5688b6aSAriff Abdullah goto bad; 1268d5688b6aSAriff Abdullah 1269d5688b6aSAriff Abdullah if (bus_dmamap_load(sc->sgd_dmat, sc->sgd_dmamap, sc->sgd_table, 12701042342aSAriff Abdullah ATI_IXP_DMA_CHSEGS_MAX * ATI_IXP_NCHANS * 12711042342aSAriff Abdullah sizeof(struct atiixp_dma_op), atiixp_dma_cb, sc, 0)) 1272d5688b6aSAriff Abdullah goto bad; 1273d5688b6aSAriff Abdullah 1274d5688b6aSAriff Abdullah 1275d5688b6aSAriff Abdullah atiixp_chip_pre_init(sc); 1276d5688b6aSAriff Abdullah 1277d5688b6aSAriff Abdullah sc->delayed_attach.ich_func = atiixp_chip_post_init; 1278d5688b6aSAriff Abdullah sc->delayed_attach.ich_arg = sc; 1279d5688b6aSAriff Abdullah if (cold == 0 || 1280d5688b6aSAriff Abdullah config_intrhook_establish(&sc->delayed_attach) != 0) { 1281d5688b6aSAriff Abdullah sc->delayed_attach.ich_func = NULL; 1282d5688b6aSAriff Abdullah atiixp_chip_post_init(sc); 1283d5688b6aSAriff Abdullah } 1284d5688b6aSAriff Abdullah 12859f52a325SAriff Abdullah return (0); 1286d5688b6aSAriff Abdullah 1287d5688b6aSAriff Abdullah bad: 1288f2a1d71aSAriff Abdullah atiixp_release_resource(sc); 12899f52a325SAriff Abdullah return (ENXIO); 1290d5688b6aSAriff Abdullah } 1291d5688b6aSAriff Abdullah 1292d5688b6aSAriff Abdullah static int 1293d5688b6aSAriff Abdullah atiixp_pci_detach(device_t dev) 1294d5688b6aSAriff Abdullah { 1295d5688b6aSAriff Abdullah int r; 1296d5688b6aSAriff Abdullah struct atiixp_info *sc; 1297d5688b6aSAriff Abdullah 1298f2a1d71aSAriff Abdullah sc = pcm_getdevinfo(dev); 1299f2a1d71aSAriff Abdullah if (sc != NULL) { 1300f2a1d71aSAriff Abdullah if (sc->codec != NULL) { 1301d5688b6aSAriff Abdullah r = pcm_unregister(dev); 1302d5688b6aSAriff Abdullah if (r) 13039f52a325SAriff Abdullah return (r); 1304f2a1d71aSAriff Abdullah } 1305f2a1d71aSAriff Abdullah sc->codec = NULL; 13069f52a325SAriff Abdullah if (sc->st != 0 && sc->sh != 0) 1307d5688b6aSAriff Abdullah atiixp_disable_interrupts(sc); 1308f2a1d71aSAriff Abdullah atiixp_release_resource(sc); 1309d5688b6aSAriff Abdullah free(sc, M_DEVBUF); 1310f2a1d71aSAriff Abdullah } 13119f52a325SAriff Abdullah return (0); 1312d5688b6aSAriff Abdullah } 1313d5688b6aSAriff Abdullah 131488a50509SAriff Abdullah static int 131588a50509SAriff Abdullah atiixp_pci_suspend(device_t dev) 131688a50509SAriff Abdullah { 131788a50509SAriff Abdullah struct atiixp_info *sc = pcm_getdevinfo(dev); 131888a50509SAriff Abdullah uint32_t value; 131988a50509SAriff Abdullah 132088a50509SAriff Abdullah /* quickly disable interrupts and save channels active state */ 132188a50509SAriff Abdullah atiixp_lock(sc); 132288a50509SAriff Abdullah atiixp_disable_interrupts(sc); 132388a50509SAriff Abdullah atiixp_unlock(sc); 132488a50509SAriff Abdullah 132588a50509SAriff Abdullah /* stop everything */ 1326a580b31aSAriff Abdullah if (sc->pch.active != 0) 132788a50509SAriff Abdullah atiixp_chan_trigger(NULL, &sc->pch, PCMTRIG_STOP); 1328a580b31aSAriff Abdullah if (sc->rch.active != 0) 132988a50509SAriff Abdullah atiixp_chan_trigger(NULL, &sc->rch, PCMTRIG_STOP); 133088a50509SAriff Abdullah 133188a50509SAriff Abdullah /* power down aclink and pci bus */ 133288a50509SAriff Abdullah atiixp_lock(sc); 133388a50509SAriff Abdullah value = atiixp_rd(sc, ATI_REG_CMD); 133488a50509SAriff Abdullah value |= ATI_REG_CMD_POWERDOWN | ATI_REG_CMD_AC_RESET; 133588a50509SAriff Abdullah atiixp_wr(sc, ATI_REG_CMD, ATI_REG_CMD_POWERDOWN); 133688a50509SAriff Abdullah pci_set_powerstate(dev, PCI_POWERSTATE_D3); 133788a50509SAriff Abdullah atiixp_unlock(sc); 133888a50509SAriff Abdullah 13399f52a325SAriff Abdullah return (0); 134088a50509SAriff Abdullah } 134188a50509SAriff Abdullah 134288a50509SAriff Abdullah static int 134388a50509SAriff Abdullah atiixp_pci_resume(device_t dev) 134488a50509SAriff Abdullah { 134588a50509SAriff Abdullah struct atiixp_info *sc = pcm_getdevinfo(dev); 134688a50509SAriff Abdullah 134788a50509SAriff Abdullah atiixp_lock(sc); 134888a50509SAriff Abdullah /* power up pci bus */ 134988a50509SAriff Abdullah pci_set_powerstate(dev, PCI_POWERSTATE_D0); 135088a50509SAriff Abdullah pci_enable_io(dev, SYS_RES_MEMORY); 135188a50509SAriff Abdullah pci_enable_busmaster(dev); 135288a50509SAriff Abdullah /* reset / power up aclink */ 135388a50509SAriff Abdullah atiixp_reset_aclink(sc); 135488a50509SAriff Abdullah atiixp_unlock(sc); 135588a50509SAriff Abdullah 135688a50509SAriff Abdullah if (mixer_reinit(dev) == -1) { 135788a50509SAriff Abdullah device_printf(dev, "unable to reinitialize the mixer\n"); 13589f52a325SAriff Abdullah return (ENXIO); 135988a50509SAriff Abdullah } 136088a50509SAriff Abdullah 136188a50509SAriff Abdullah /* 136288a50509SAriff Abdullah * Resume channel activities. Reset channel format regardless 136388a50509SAriff Abdullah * of its previous state. 136488a50509SAriff Abdullah */ 1365a580b31aSAriff Abdullah if (sc->pch.channel != NULL) { 1366a580b31aSAriff Abdullah if (sc->pch.fmt != 0) 136788a50509SAriff Abdullah atiixp_chan_setformat(NULL, &sc->pch, sc->pch.fmt); 1368a580b31aSAriff Abdullah if (sc->pch.active != 0) 136988a50509SAriff Abdullah atiixp_chan_trigger(NULL, &sc->pch, PCMTRIG_START); 137088a50509SAriff Abdullah } 1371a580b31aSAriff Abdullah if (sc->rch.channel != NULL) { 1372a580b31aSAriff Abdullah if (sc->rch.fmt != 0) 137388a50509SAriff Abdullah atiixp_chan_setformat(NULL, &sc->rch, sc->rch.fmt); 1374a580b31aSAriff Abdullah if (sc->rch.active != 0) 137588a50509SAriff Abdullah atiixp_chan_trigger(NULL, &sc->rch, PCMTRIG_START); 137688a50509SAriff Abdullah } 137788a50509SAriff Abdullah 137888a50509SAriff Abdullah /* enable interrupts */ 137988a50509SAriff Abdullah atiixp_lock(sc); 1380a580b31aSAriff Abdullah if (sc->polling == 0) 138188a50509SAriff Abdullah atiixp_enable_interrupts(sc); 138288a50509SAriff Abdullah atiixp_unlock(sc); 138388a50509SAriff Abdullah 13849f52a325SAriff Abdullah return (0); 138588a50509SAriff Abdullah } 138688a50509SAriff Abdullah 1387d5688b6aSAriff Abdullah static device_method_t atiixp_methods[] = { 1388d5688b6aSAriff Abdullah DEVMETHOD(device_probe, atiixp_pci_probe), 1389d5688b6aSAriff Abdullah DEVMETHOD(device_attach, atiixp_pci_attach), 1390d5688b6aSAriff Abdullah DEVMETHOD(device_detach, atiixp_pci_detach), 139188a50509SAriff Abdullah DEVMETHOD(device_suspend, atiixp_pci_suspend), 139288a50509SAriff Abdullah DEVMETHOD(device_resume, atiixp_pci_resume), 1393d5688b6aSAriff Abdullah { 0, 0 } 1394d5688b6aSAriff Abdullah }; 1395d5688b6aSAriff Abdullah 1396d5688b6aSAriff Abdullah static driver_t atiixp_driver = { 1397d5688b6aSAriff Abdullah "pcm", 1398d5688b6aSAriff Abdullah atiixp_methods, 1399d5688b6aSAriff Abdullah PCM_SOFTC_SIZE, 1400d5688b6aSAriff Abdullah }; 1401d5688b6aSAriff Abdullah 1402d5688b6aSAriff Abdullah DRIVER_MODULE(snd_atiixp, pci, atiixp_driver, pcm_devclass, 0, 0); 1403d5688b6aSAriff Abdullah MODULE_DEPEND(snd_atiixp, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 1404d5688b6aSAriff Abdullah MODULE_VERSION(snd_atiixp, 1); 1405