1152851Sariff/*- 2152851Sariff * Copyright (c) 2005 Ariff Abdullah <ariff@FreeBSD.org> 3152851Sariff * All rights reserved. 4152851Sariff * 5152851Sariff * Redistribution and use in source and binary forms, with or without 6152851Sariff * modification, are permitted provided that the following conditions 7152851Sariff * are met: 8152851Sariff * 1. Redistributions of source code must retain the above copyright 9152851Sariff * notice, this list of conditions and the following disclaimer. 10152851Sariff * 2. Redistributions in binary form must reproduce the above copyright 11152851Sariff * notice, this list of conditions and the following disclaimer in the 12152851Sariff * documentation and/or other materials provided with the distribution. 13152851Sariff * 14152851Sariff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15152851Sariff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16152851Sariff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17152851Sariff * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18152851Sariff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19152851Sariff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20152851Sariff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21152851Sariff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT 22152851Sariff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23152851Sariff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF 24152851Sariff * SUCH DAMAGE. 25152851Sariff */ 26152851Sariff 27152851Sariff/* 28152851Sariff * FreeBSD pcm driver for ATI IXP 150/200/250/300 AC97 controllers 29152851Sariff * 30152851Sariff * Features 31152851Sariff * * 16bit playback / recording 32152851Sariff * * 32bit native playback - yay! 33155800Sariff * * 32bit native recording (seems broken on few hardwares) 34152851Sariff * 35152851Sariff * Issues / TODO: 36152851Sariff * * SPDIF 37152851Sariff * * Support for more than 2 channels. 38152851Sariff * * VRA ? VRM ? DRA ? 39155800Sariff * * 32bit native recording seems broken on few hardwares, most 40155800Sariff * probably because of incomplete VRA/DRA cleanup. 41152851Sariff * 42152851Sariff * 43152851Sariff * Thanks goes to: 44152851Sariff * 45152851Sariff * Shaharil @ SCAN Associates whom relentlessly providing me the 46152851Sariff * mind blowing Acer Ferrari 4002 WLMi with this ATI IXP hardware. 47152851Sariff * 48152851Sariff * Reinoud Zandijk <reinoud@NetBSD.org> (auixp), which this driver is 49152851Sariff * largely based upon although large part of it has been reworked. His 50152851Sariff * driver is the primary reference and pretty much well documented. 51152851Sariff * 52152851Sariff * Takashi Iwai (ALSA snd-atiixp), for register definitions and some 53152851Sariff * random ninja hackery. 54152851Sariff */ 55152851Sariff 56193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS 57193640Sariff#include "opt_snd.h" 58193640Sariff#endif 59193640Sariff 60152851Sariff#include <dev/sound/pcm/sound.h> 61152851Sariff#include <dev/sound/pcm/ac97.h> 62152851Sariff 63152851Sariff#include <dev/pci/pcireg.h> 64152851Sariff#include <dev/pci/pcivar.h> 65152851Sariff#include <sys/sysctl.h> 66152851Sariff#include <sys/endian.h> 67152851Sariff 68152851Sariff#include <dev/sound/pci/atiixp.h> 69152851Sariff 70152851SariffSND_DECLARE_FILE("$FreeBSD$"); 71152851Sariff 72167648Sariff#define ATI_IXP_DMA_RETRY_MAX 100 73162931Sariff 74167648Sariff#define ATI_IXP_BUFSZ_MIN 4096 75167648Sariff#define ATI_IXP_BUFSZ_MAX 65536 76167648Sariff#define ATI_IXP_BUFSZ_DEFAULT 16384 77162931Sariff 78167648Sariff#define ATI_IXP_BLK_MIN 32 79167648Sariff#define ATI_IXP_BLK_ALIGN (~(ATI_IXP_BLK_MIN - 1)) 80167648Sariff 81171329Sariff#define ATI_IXP_CHN_RUNNING 0x00000001 82171329Sariff#define ATI_IXP_CHN_SUSPEND 0x00000002 83171329Sariff 84152851Sariffstruct atiixp_dma_op { 85155800Sariff volatile uint32_t addr; 86155800Sariff volatile uint16_t status; 87155800Sariff volatile uint16_t size; 88155800Sariff volatile uint32_t next; 89152851Sariff}; 90152851Sariff 91152851Sariffstruct atiixp_info; 92152851Sariff 93152851Sariffstruct atiixp_chinfo { 94152851Sariff struct snd_dbuf *buffer; 95152851Sariff struct pcm_channel *channel; 96152851Sariff struct atiixp_info *parent; 97152851Sariff struct atiixp_dma_op *sgd_table; 98152851Sariff bus_addr_t sgd_addr; 99164614Sariff uint32_t enable_bit, flush_bit, linkptr_bit, dt_cur_bit; 100164614Sariff uint32_t blksz, blkcnt; 101164614Sariff uint32_t ptr, prevptr; 102153708Sariff uint32_t fmt; 103171329Sariff uint32_t flags; 104171329Sariff int caps_32bit, dir; 105152851Sariff}; 106152851Sariff 107152851Sariffstruct atiixp_info { 108152851Sariff device_t dev; 109152851Sariff 110152851Sariff bus_space_tag_t st; 111152851Sariff bus_space_handle_t sh; 112152851Sariff bus_dma_tag_t parent_dmat; 113152851Sariff bus_dma_tag_t sgd_dmat; 114152851Sariff bus_dmamap_t sgd_dmamap; 115152851Sariff bus_addr_t sgd_addr; 116152851Sariff 117152851Sariff struct resource *reg, *irq; 118152851Sariff int regtype, regid, irqid; 119152851Sariff void *ih; 120152851Sariff struct ac97_info *codec; 121152851Sariff 122152851Sariff struct atiixp_chinfo pch; 123152851Sariff struct atiixp_chinfo rch; 124152851Sariff struct atiixp_dma_op *sgd_table; 125152851Sariff struct intr_config_hook delayed_attach; 126152851Sariff 127152851Sariff uint32_t bufsz; 128152851Sariff uint32_t codec_not_ready_bits, codec_idx, codec_found; 129164614Sariff uint32_t blkcnt; 130152851Sariff int registered_channels; 131152851Sariff 132152851Sariff struct mtx *lock; 133164614Sariff struct callout poll_timer; 134164614Sariff int poll_ticks, polling; 135152851Sariff}; 136152851Sariff 137152851Sariff#define atiixp_rd(_sc, _reg) \ 138152851Sariff bus_space_read_4((_sc)->st, (_sc)->sh, _reg) 139152851Sariff#define atiixp_wr(_sc, _reg, _val) \ 140152851Sariff bus_space_write_4((_sc)->st, (_sc)->sh, _reg, _val) 141152851Sariff 142152851Sariff#define atiixp_lock(_sc) snd_mtxlock((_sc)->lock) 143152851Sariff#define atiixp_unlock(_sc) snd_mtxunlock((_sc)->lock) 144152851Sariff#define atiixp_assert(_sc) snd_mtxassert((_sc)->lock) 145152851Sariff 146152851Sariffstatic uint32_t atiixp_fmt_32bit[] = { 147193640Sariff SND_FORMAT(AFMT_S16_LE, 2, 0), 148193640Sariff SND_FORMAT(AFMT_S32_LE, 2, 0), 149152851Sariff 0 150152851Sariff}; 151152851Sariff 152152851Sariffstatic uint32_t atiixp_fmt[] = { 153193640Sariff SND_FORMAT(AFMT_S16_LE, 2, 0), 154152851Sariff 0 155152851Sariff}; 156152851Sariff 157152851Sariffstatic struct pcmchan_caps atiixp_caps_32bit = { 158152851Sariff ATI_IXP_BASE_RATE, 159152851Sariff ATI_IXP_BASE_RATE, 160152851Sariff atiixp_fmt_32bit, 0 161152851Sariff}; 162152851Sariff 163152851Sariffstatic struct pcmchan_caps atiixp_caps = { 164152851Sariff ATI_IXP_BASE_RATE, 165162931Sariff ATI_IXP_BASE_RATE, 166152851Sariff atiixp_fmt, 0 167152851Sariff}; 168152851Sariff 169152851Sariffstatic const struct { 170152851Sariff uint16_t vendor; 171152851Sariff uint16_t devid; 172152851Sariff char *desc; 173152851Sariff} atiixp_hw[] = { 174152851Sariff { ATI_VENDOR_ID, ATI_IXP_200_ID, "ATI IXP 200" }, 175152851Sariff { ATI_VENDOR_ID, ATI_IXP_300_ID, "ATI IXP 300" }, 176152851Sariff { ATI_VENDOR_ID, ATI_IXP_400_ID, "ATI IXP 400" }, 177173329Sariff { ATI_VENDOR_ID, ATI_IXP_SB600_ID, "ATI IXP SB600" }, 178152851Sariff}; 179152851Sariff 180152851Sariffstatic void atiixp_enable_interrupts(struct atiixp_info *); 181152851Sariffstatic void atiixp_disable_interrupts(struct atiixp_info *); 182152851Sariffstatic void atiixp_reset_aclink(struct atiixp_info *); 183162931Sariffstatic void atiixp_flush_dma(struct atiixp_chinfo *); 184162931Sariffstatic void atiixp_enable_dma(struct atiixp_chinfo *); 185162931Sariffstatic void atiixp_disable_dma(struct atiixp_chinfo *); 186152851Sariff 187152851Sariffstatic int atiixp_waitready_codec(struct atiixp_info *); 188152851Sariffstatic int atiixp_rdcd(kobj_t, void *, int); 189152851Sariffstatic int atiixp_wrcd(kobj_t, void *, int, uint32_t); 190152851Sariff 191152851Sariffstatic void *atiixp_chan_init(kobj_t, void *, struct snd_dbuf *, 192152851Sariff struct pcm_channel *, int); 193152851Sariffstatic int atiixp_chan_setformat(kobj_t, void *, uint32_t); 194193640Sariffstatic uint32_t atiixp_chan_setspeed(kobj_t, void *, uint32_t); 195193640Sariffstatic int atiixp_chan_setfragments(kobj_t, void *, uint32_t, uint32_t); 196193640Sariffstatic uint32_t atiixp_chan_setblocksize(kobj_t, void *, uint32_t); 197152851Sariffstatic void atiixp_buildsgdt(struct atiixp_chinfo *); 198152851Sariffstatic int atiixp_chan_trigger(kobj_t, void *, int); 199162931Sariffstatic __inline uint32_t atiixp_dmapos(struct atiixp_chinfo *); 200193640Sariffstatic uint32_t atiixp_chan_getptr(kobj_t, void *); 201152851Sariffstatic struct pcmchan_caps *atiixp_chan_getcaps(kobj_t, void *); 202152851Sariff 203152851Sariffstatic void atiixp_intr(void *); 204152851Sariffstatic void atiixp_dma_cb(void *, bus_dma_segment_t *, int, int); 205152851Sariffstatic void atiixp_chip_pre_init(struct atiixp_info *); 206152851Sariffstatic void atiixp_chip_post_init(void *); 207157026Sariffstatic void atiixp_release_resource(struct atiixp_info *); 208152851Sariffstatic int atiixp_pci_probe(device_t); 209152851Sariffstatic int atiixp_pci_attach(device_t); 210152851Sariffstatic int atiixp_pci_detach(device_t); 211153708Sariffstatic int atiixp_pci_suspend(device_t); 212153708Sariffstatic int atiixp_pci_resume(device_t); 213152851Sariff 214152851Sariff/* 215152851Sariff * ATI IXP helper functions 216152851Sariff */ 217152851Sariffstatic void 218152851Sariffatiixp_enable_interrupts(struct atiixp_info *sc) 219152851Sariff{ 220152851Sariff uint32_t value; 221152851Sariff 222152851Sariff /* clear all pending */ 223152851Sariff atiixp_wr(sc, ATI_REG_ISR, 0xffffffff); 224152851Sariff 225152851Sariff /* enable all relevant interrupt sources we can handle */ 226152851Sariff value = atiixp_rd(sc, ATI_REG_IER); 227152851Sariff 228152851Sariff value |= ATI_REG_IER_IO_STATUS_EN; 229152851Sariff 230152851Sariff /* 231152851Sariff * Disable / ignore internal xrun/spdf interrupt flags 232152851Sariff * since it doesn't interest us (for now). 233152851Sariff */ 234162931Sariff#if 1 235162931Sariff value &= ~(ATI_REG_IER_IN_XRUN_EN | ATI_REG_IER_OUT_XRUN_EN | 236164614Sariff ATI_REG_IER_SPDF_XRUN_EN | ATI_REG_IER_SPDF_STATUS_EN); 237162931Sariff#else 238152851Sariff value |= ATI_REG_IER_IN_XRUN_EN; 239152851Sariff value |= ATI_REG_IER_OUT_XRUN_EN; 240152851Sariff 241152851Sariff value |= ATI_REG_IER_SPDF_XRUN_EN; 242152851Sariff value |= ATI_REG_IER_SPDF_STATUS_EN; 243152851Sariff#endif 244152851Sariff 245152851Sariff atiixp_wr(sc, ATI_REG_IER, value); 246152851Sariff} 247152851Sariff 248152851Sariffstatic void 249152851Sariffatiixp_disable_interrupts(struct atiixp_info *sc) 250152851Sariff{ 251152851Sariff /* disable all interrupt sources */ 252152851Sariff atiixp_wr(sc, ATI_REG_IER, 0); 253152851Sariff 254152851Sariff /* clear all pending */ 255152851Sariff atiixp_wr(sc, ATI_REG_ISR, 0xffffffff); 256152851Sariff} 257152851Sariff 258152851Sariffstatic void 259152851Sariffatiixp_reset_aclink(struct atiixp_info *sc) 260152851Sariff{ 261152851Sariff uint32_t value, timeout; 262152851Sariff 263152851Sariff /* if power is down, power it up */ 264152851Sariff value = atiixp_rd(sc, ATI_REG_CMD); 265152851Sariff if (value & ATI_REG_CMD_POWERDOWN) { 266152851Sariff /* explicitly enable power */ 267152851Sariff value &= ~ATI_REG_CMD_POWERDOWN; 268152851Sariff atiixp_wr(sc, ATI_REG_CMD, value); 269152851Sariff 270152851Sariff /* have to wait at least 10 usec for it to initialise */ 271152851Sariff DELAY(20); 272162931Sariff } 273152851Sariff 274152851Sariff /* perform a soft reset */ 275152851Sariff value = atiixp_rd(sc, ATI_REG_CMD); 276152851Sariff value |= ATI_REG_CMD_AC_SOFT_RESET; 277152851Sariff atiixp_wr(sc, ATI_REG_CMD, value); 278152851Sariff 279152851Sariff /* need to read the CMD reg and wait aprox. 10 usec to init */ 280152851Sariff value = atiixp_rd(sc, ATI_REG_CMD); 281152851Sariff DELAY(20); 282152851Sariff 283152851Sariff /* clear soft reset flag again */ 284152851Sariff value = atiixp_rd(sc, ATI_REG_CMD); 285152851Sariff value &= ~ATI_REG_CMD_AC_SOFT_RESET; 286152851Sariff atiixp_wr(sc, ATI_REG_CMD, value); 287152851Sariff 288152851Sariff /* check if the ac-link is working; reset device otherwise */ 289152851Sariff timeout = 10; 290152851Sariff value = atiixp_rd(sc, ATI_REG_CMD); 291164614Sariff while (!(value & ATI_REG_CMD_ACLINK_ACTIVE) && --timeout) { 292153708Sariff#if 0 293152851Sariff device_printf(sc->dev, "not up; resetting aclink hardware\n"); 294153708Sariff#endif 295152851Sariff 296152851Sariff /* dip aclink reset but keep the acsync */ 297152851Sariff value &= ~ATI_REG_CMD_AC_RESET; 298152851Sariff value |= ATI_REG_CMD_AC_SYNC; 299152851Sariff atiixp_wr(sc, ATI_REG_CMD, value); 300152851Sariff 301152851Sariff /* need to read CMD again and wait again (clocking in issue?) */ 302152851Sariff value = atiixp_rd(sc, ATI_REG_CMD); 303152851Sariff DELAY(20); 304152851Sariff 305152851Sariff /* assert aclink reset again */ 306152851Sariff value = atiixp_rd(sc, ATI_REG_CMD); 307152851Sariff value |= ATI_REG_CMD_AC_RESET; 308152851Sariff atiixp_wr(sc, ATI_REG_CMD, value); 309152851Sariff 310152851Sariff /* check if its active now */ 311152851Sariff value = atiixp_rd(sc, ATI_REG_CMD); 312162931Sariff } 313152851Sariff 314152851Sariff if (timeout == 0) 315152851Sariff device_printf(sc->dev, "giving up aclink reset\n"); 316153708Sariff#if 0 317152851Sariff if (timeout != 10) 318152851Sariff device_printf(sc->dev, "aclink hardware reset successful\n"); 319153708Sariff#endif 320152851Sariff 321152851Sariff /* assert reset and sync for safety */ 322152851Sariff value = atiixp_rd(sc, ATI_REG_CMD); 323152851Sariff value |= ATI_REG_CMD_AC_SYNC | ATI_REG_CMD_AC_RESET; 324152851Sariff atiixp_wr(sc, ATI_REG_CMD, value); 325152851Sariff} 326152851Sariff 327152851Sariffstatic void 328162931Sariffatiixp_flush_dma(struct atiixp_chinfo *ch) 329152851Sariff{ 330162931Sariff atiixp_wr(ch->parent, ATI_REG_FIFO_FLUSH, ch->flush_bit); 331152851Sariff} 332152851Sariff 333152851Sariffstatic void 334162931Sariffatiixp_enable_dma(struct atiixp_chinfo *ch) 335152851Sariff{ 336152851Sariff uint32_t value; 337152851Sariff 338162931Sariff value = atiixp_rd(ch->parent, ATI_REG_CMD); 339152851Sariff if (!(value & ch->enable_bit)) { 340152851Sariff value |= ch->enable_bit; 341162931Sariff atiixp_wr(ch->parent, ATI_REG_CMD, value); 342152851Sariff } 343152851Sariff} 344152851Sariff 345162931Sariffstatic void 346162931Sariffatiixp_disable_dma(struct atiixp_chinfo *ch) 347152851Sariff{ 348152851Sariff uint32_t value; 349152851Sariff 350162931Sariff value = atiixp_rd(ch->parent, ATI_REG_CMD); 351152851Sariff if (value & ch->enable_bit) { 352152851Sariff value &= ~ch->enable_bit; 353162931Sariff atiixp_wr(ch->parent, ATI_REG_CMD, value); 354152851Sariff } 355152851Sariff} 356152851Sariff 357152851Sariff/* 358152851Sariff * AC97 interface 359152851Sariff */ 360152851Sariffstatic int 361152851Sariffatiixp_waitready_codec(struct atiixp_info *sc) 362152851Sariff{ 363152851Sariff int timeout = 500; 364152851Sariff 365152851Sariff do { 366152851Sariff if ((atiixp_rd(sc, ATI_REG_PHYS_OUT_ADDR) & 367164614Sariff ATI_REG_PHYS_OUT_ADDR_EN) == 0) 368162931Sariff return (0); 369152851Sariff DELAY(1); 370162931Sariff } while (--timeout); 371152851Sariff 372162931Sariff return (-1); 373152851Sariff} 374152851Sariff 375152851Sariffstatic int 376152851Sariffatiixp_rdcd(kobj_t obj, void *devinfo, int reg) 377152851Sariff{ 378152851Sariff struct atiixp_info *sc = devinfo; 379152851Sariff uint32_t data; 380152851Sariff int timeout; 381152851Sariff 382152851Sariff if (atiixp_waitready_codec(sc)) 383162931Sariff return (-1); 384152851Sariff 385152851Sariff data = (reg << ATI_REG_PHYS_OUT_ADDR_SHIFT) | 386164614Sariff ATI_REG_PHYS_OUT_ADDR_EN | ATI_REG_PHYS_OUT_RW | sc->codec_idx; 387152851Sariff 388152851Sariff atiixp_wr(sc, ATI_REG_PHYS_OUT_ADDR, data); 389152851Sariff 390152851Sariff if (atiixp_waitready_codec(sc)) 391162931Sariff return (-1); 392152851Sariff 393152851Sariff timeout = 500; 394152851Sariff do { 395152851Sariff data = atiixp_rd(sc, ATI_REG_PHYS_IN_ADDR); 396152851Sariff if (data & ATI_REG_PHYS_IN_READ_FLAG) 397162931Sariff return (data >> ATI_REG_PHYS_IN_DATA_SHIFT); 398152851Sariff DELAY(1); 399162931Sariff } while (--timeout); 400152851Sariff 401152851Sariff if (reg < 0x7c) 402152851Sariff device_printf(sc->dev, "codec read timeout! (reg 0x%x)\n", reg); 403152851Sariff 404162931Sariff return (-1); 405152851Sariff} 406152851Sariff 407152851Sariffstatic int 408152851Sariffatiixp_wrcd(kobj_t obj, void *devinfo, int reg, uint32_t data) 409152851Sariff{ 410152851Sariff struct atiixp_info *sc = devinfo; 411152851Sariff 412152851Sariff if (atiixp_waitready_codec(sc)) 413162931Sariff return (-1); 414152851Sariff 415152851Sariff data = (data << ATI_REG_PHYS_OUT_DATA_SHIFT) | 416164614Sariff (((uint32_t)reg) << ATI_REG_PHYS_OUT_ADDR_SHIFT) | 417164614Sariff ATI_REG_PHYS_OUT_ADDR_EN | sc->codec_idx; 418152851Sariff 419152851Sariff atiixp_wr(sc, ATI_REG_PHYS_OUT_ADDR, data); 420152851Sariff 421162931Sariff return (0); 422152851Sariff} 423152851Sariff 424152851Sariffstatic kobj_method_t atiixp_ac97_methods[] = { 425164614Sariff KOBJMETHOD(ac97_read, atiixp_rdcd), 426164614Sariff KOBJMETHOD(ac97_write, atiixp_wrcd), 427193640Sariff KOBJMETHOD_END 428152851Sariff}; 429152851SariffAC97_DECLARE(atiixp_ac97); 430152851Sariff 431152851Sariff/* 432152851Sariff * Playback / Record channel interface 433152851Sariff */ 434152851Sariffstatic void * 435152851Sariffatiixp_chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, 436152851Sariff struct pcm_channel *c, int dir) 437152851Sariff{ 438152851Sariff struct atiixp_info *sc = devinfo; 439152851Sariff struct atiixp_chinfo *ch; 440152851Sariff int num; 441152851Sariff 442152851Sariff atiixp_lock(sc); 443152851Sariff 444152851Sariff if (dir == PCMDIR_PLAY) { 445152851Sariff ch = &sc->pch; 446152851Sariff ch->linkptr_bit = ATI_REG_OUT_DMA_LINKPTR; 447152851Sariff ch->enable_bit = ATI_REG_CMD_OUT_DMA_EN | ATI_REG_CMD_SEND_EN; 448152851Sariff ch->flush_bit = ATI_REG_FIFO_OUT_FLUSH; 449164614Sariff ch->dt_cur_bit = ATI_REG_OUT_DMA_DT_CUR; 450152851Sariff /* Native 32bit playback working properly */ 451152851Sariff ch->caps_32bit = 1; 452152851Sariff } else { 453152851Sariff ch = &sc->rch; 454152851Sariff ch->linkptr_bit = ATI_REG_IN_DMA_LINKPTR; 455164614Sariff ch->enable_bit = ATI_REG_CMD_IN_DMA_EN | ATI_REG_CMD_RECEIVE_EN; 456152851Sariff ch->flush_bit = ATI_REG_FIFO_IN_FLUSH; 457164614Sariff ch->dt_cur_bit = ATI_REG_IN_DMA_DT_CUR; 458152851Sariff /* XXX Native 32bit recording appear to be broken */ 459154595Sariff ch->caps_32bit = 1; 460152851Sariff } 461152851Sariff 462152851Sariff ch->buffer = b; 463152851Sariff ch->parent = sc; 464152851Sariff ch->channel = c; 465152851Sariff ch->dir = dir; 466164614Sariff ch->blkcnt = sc->blkcnt; 467164614Sariff ch->blksz = sc->bufsz / ch->blkcnt; 468152851Sariff 469152851Sariff atiixp_unlock(sc); 470152851Sariff 471168847Sariff if (sndbuf_alloc(ch->buffer, sc->parent_dmat, 0, sc->bufsz) == -1) 472162931Sariff return (NULL); 473152851Sariff 474152851Sariff atiixp_lock(sc); 475152851Sariff num = sc->registered_channels++; 476167648Sariff ch->sgd_table = &sc->sgd_table[num * ATI_IXP_DMA_CHSEGS_MAX]; 477167648Sariff ch->sgd_addr = sc->sgd_addr + (num * ATI_IXP_DMA_CHSEGS_MAX * 478164614Sariff sizeof(struct atiixp_dma_op)); 479162931Sariff atiixp_disable_dma(ch); 480152851Sariff atiixp_unlock(sc); 481152851Sariff 482162931Sariff return (ch); 483152851Sariff} 484152851Sariff 485152851Sariffstatic int 486152851Sariffatiixp_chan_setformat(kobj_t obj, void *data, uint32_t format) 487152851Sariff{ 488152851Sariff struct atiixp_chinfo *ch = data; 489152851Sariff struct atiixp_info *sc = ch->parent; 490152851Sariff uint32_t value; 491152851Sariff 492152851Sariff atiixp_lock(sc); 493152851Sariff if (ch->dir == PCMDIR_REC) { 494152851Sariff value = atiixp_rd(sc, ATI_REG_CMD); 495152851Sariff value &= ~ATI_REG_CMD_INTERLEAVE_IN; 496155800Sariff if ((format & AFMT_32BIT) == 0) 497152851Sariff value |= ATI_REG_CMD_INTERLEAVE_IN; 498152851Sariff atiixp_wr(sc, ATI_REG_CMD, value); 499152851Sariff } else { 500152851Sariff value = atiixp_rd(sc, ATI_REG_OUT_DMA_SLOT); 501152851Sariff value &= ~ATI_REG_OUT_DMA_SLOT_MASK; 502152851Sariff /* We do not have support for more than 2 channels, _yet_. */ 503152851Sariff value |= ATI_REG_OUT_DMA_SLOT_BIT(3) | 504164614Sariff ATI_REG_OUT_DMA_SLOT_BIT(4); 505152851Sariff value |= 0x04 << ATI_REG_OUT_DMA_THRESHOLD_SHIFT; 506152851Sariff atiixp_wr(sc, ATI_REG_OUT_DMA_SLOT, value); 507152851Sariff value = atiixp_rd(sc, ATI_REG_CMD); 508152851Sariff value &= ~ATI_REG_CMD_INTERLEAVE_OUT; 509155800Sariff if ((format & AFMT_32BIT) == 0) 510152851Sariff value |= ATI_REG_CMD_INTERLEAVE_OUT; 511152851Sariff atiixp_wr(sc, ATI_REG_CMD, value); 512152851Sariff value = atiixp_rd(sc, ATI_REG_6CH_REORDER); 513152851Sariff value &= ~ATI_REG_6CH_REORDER_EN; 514152851Sariff atiixp_wr(sc, ATI_REG_6CH_REORDER, value); 515152851Sariff } 516153708Sariff ch->fmt = format; 517152851Sariff atiixp_unlock(sc); 518152851Sariff 519162931Sariff return (0); 520152851Sariff} 521152851Sariff 522193640Sariffstatic uint32_t 523152851Sariffatiixp_chan_setspeed(kobj_t obj, void *data, uint32_t spd) 524152851Sariff{ 525152851Sariff /* XXX We're supposed to do VRA/DRA processing right here */ 526162931Sariff return (ATI_IXP_BASE_RATE); 527152851Sariff} 528152851Sariff 529152851Sariffstatic int 530167648Sariffatiixp_chan_setfragments(kobj_t obj, void *data, 531167648Sariff uint32_t blksz, uint32_t blkcnt) 532152851Sariff{ 533152851Sariff struct atiixp_chinfo *ch = data; 534152851Sariff struct atiixp_info *sc = ch->parent; 535152851Sariff 536167648Sariff blksz &= ATI_IXP_BLK_ALIGN; 537152851Sariff 538167648Sariff if (blksz > (sndbuf_getmaxsize(ch->buffer) / ATI_IXP_DMA_CHSEGS_MIN)) 539167648Sariff blksz = sndbuf_getmaxsize(ch->buffer) / ATI_IXP_DMA_CHSEGS_MIN; 540167648Sariff if (blksz < ATI_IXP_BLK_MIN) 541167648Sariff blksz = ATI_IXP_BLK_MIN; 542167648Sariff if (blkcnt > ATI_IXP_DMA_CHSEGS_MAX) 543167648Sariff blkcnt = ATI_IXP_DMA_CHSEGS_MAX; 544167648Sariff if (blkcnt < ATI_IXP_DMA_CHSEGS_MIN) 545167648Sariff blkcnt = ATI_IXP_DMA_CHSEGS_MIN; 546167648Sariff 547167648Sariff while ((blksz * blkcnt) > sndbuf_getmaxsize(ch->buffer)) { 548167648Sariff if ((blkcnt >> 1) >= ATI_IXP_DMA_CHSEGS_MIN) 549167648Sariff blkcnt >>= 1; 550167648Sariff else if ((blksz >> 1) >= ATI_IXP_BLK_MIN) 551167648Sariff blksz >>= 1; 552167648Sariff else 553167648Sariff break; 554167648Sariff } 555167648Sariff 556164614Sariff if ((sndbuf_getblksz(ch->buffer) != blksz || 557167648Sariff sndbuf_getblkcnt(ch->buffer) != blkcnt) && 558167648Sariff sndbuf_resize(ch->buffer, blkcnt, blksz) != 0) 559164614Sariff device_printf(sc->dev, "%s: failed blksz=%u blkcnt=%u\n", 560167648Sariff __func__, blksz, blkcnt); 561152851Sariff 562164614Sariff ch->blksz = sndbuf_getblksz(ch->buffer); 563167648Sariff ch->blkcnt = sndbuf_getblkcnt(ch->buffer); 564164614Sariff 565193640Sariff return (0); 566167648Sariff} 567167648Sariff 568193640Sariffstatic uint32_t 569167648Sariffatiixp_chan_setblocksize(kobj_t obj, void *data, uint32_t blksz) 570167648Sariff{ 571167648Sariff struct atiixp_chinfo *ch = data; 572167648Sariff struct atiixp_info *sc = ch->parent; 573167648Sariff 574167648Sariff atiixp_chan_setfragments(obj, data, blksz, sc->blkcnt); 575167648Sariff 576164614Sariff return (ch->blksz); 577152851Sariff} 578152851Sariff 579152851Sariffstatic void 580152851Sariffatiixp_buildsgdt(struct atiixp_chinfo *ch) 581152851Sariff{ 582164614Sariff struct atiixp_info *sc = ch->parent; 583164614Sariff uint32_t addr, blksz, blkcnt; 584152851Sariff int i; 585152851Sariff 586152851Sariff addr = sndbuf_getbufaddr(ch->buffer); 587152851Sariff 588164614Sariff if (sc->polling != 0) { 589164614Sariff blksz = ch->blksz * ch->blkcnt; 590164614Sariff blkcnt = 1; 591164614Sariff } else { 592164614Sariff blksz = ch->blksz; 593164614Sariff blkcnt = ch->blkcnt; 594164614Sariff } 595164614Sariff 596164614Sariff for (i = 0; i < blkcnt; i++) { 597164614Sariff ch->sgd_table[i].addr = htole32(addr + (i * blksz)); 598152851Sariff ch->sgd_table[i].status = htole16(0); 599164614Sariff ch->sgd_table[i].size = htole16(blksz >> 2); 600162931Sariff ch->sgd_table[i].next = htole32((uint32_t)ch->sgd_addr + 601164614Sariff (((i + 1) % blkcnt) * sizeof(struct atiixp_dma_op))); 602152851Sariff } 603152851Sariff} 604152851Sariff 605162931Sariffstatic __inline uint32_t 606162931Sariffatiixp_dmapos(struct atiixp_chinfo *ch) 607152851Sariff{ 608152851Sariff struct atiixp_info *sc = ch->parent; 609162931Sariff uint32_t reg, addr, sz, retry; 610155800Sariff volatile uint32_t ptr; 611152851Sariff 612164614Sariff reg = ch->dt_cur_bit; 613155800Sariff addr = sndbuf_getbufaddr(ch->buffer); 614164614Sariff sz = ch->blkcnt * ch->blksz; 615162931Sariff retry = ATI_IXP_DMA_RETRY_MAX; 616155800Sariff 617155800Sariff do { 618162931Sariff ptr = atiixp_rd(sc, reg); 619155800Sariff if (ptr < addr) 620155800Sariff continue; 621155800Sariff ptr -= addr; 622162931Sariff if (ptr < sz) { 623164614Sariff#if 0 624162931Sariff#ifdef ATI_IXP_DEBUG 625164614Sariff if ((ptr & ~(ch->blksz - 1)) != ch->ptr) { 626162931Sariff uint32_t delta; 627152851Sariff 628164614Sariff delta = (sz + ptr - ch->prevptr) % sz; 629162931Sariff#ifndef ATI_IXP_DEBUG_VERBOSE 630164614Sariff if (delta < ch->blksz) 631155800Sariff#endif 632162931Sariff device_printf(sc->dev, 633162931Sariff "PCMDIR_%s: incoherent DMA " 634164614Sariff "prevptr=%u ptr=%u " 635164614Sariff "ptr=%u blkcnt=%u " 636164614Sariff "[delta=%u != blksz=%u] " 637162931Sariff "(%s)\n", 638162931Sariff (ch->dir == PCMDIR_PLAY) ? 639162931Sariff "PLAY" : "REC", 640164614Sariff ch->prevptr, ptr, 641164614Sariff ch->ptr, ch->blkcnt, 642164614Sariff delta, ch->blksz, 643164614Sariff (delta < ch->blksz) ? 644162931Sariff "OVERLAPPED!" : "Ok"); 645164614Sariff ch->ptr = ptr & ~(ch->blksz - 1); 646162931Sariff } 647164614Sariff ch->prevptr = ptr; 648162931Sariff#endif 649164614Sariff#endif 650162931Sariff return (ptr); 651162931Sariff } 652162931Sariff } while (--retry); 653155800Sariff 654162931Sariff device_printf(sc->dev, "PCMDIR_%s: invalid DMA pointer ptr=%u\n", 655164614Sariff (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC", ptr); 656162931Sariff 657162931Sariff return (0); 658152851Sariff} 659152851Sariff 660164614Sariffstatic __inline int 661164614Sariffatiixp_poll_channel(struct atiixp_chinfo *ch) 662164614Sariff{ 663164614Sariff uint32_t sz, delta; 664164614Sariff volatile uint32_t ptr; 665164614Sariff 666171329Sariff if (!(ch->flags & ATI_IXP_CHN_RUNNING)) 667164614Sariff return (0); 668164614Sariff 669164614Sariff sz = ch->blksz * ch->blkcnt; 670164614Sariff ptr = atiixp_dmapos(ch); 671164614Sariff ch->ptr = ptr; 672164614Sariff ptr %= sz; 673164614Sariff ptr &= ~(ch->blksz - 1); 674164614Sariff delta = (sz + ptr - ch->prevptr) % sz; 675164614Sariff 676164614Sariff if (delta < ch->blksz) 677164614Sariff return (0); 678164614Sariff 679164614Sariff ch->prevptr = ptr; 680164614Sariff 681164614Sariff return (1); 682164614Sariff} 683164614Sariff 684171329Sariff#define atiixp_chan_active(sc) (((sc)->pch.flags | (sc)->rch.flags) & \ 685171329Sariff ATI_IXP_CHN_RUNNING) 686164614Sariff 687164614Sariffstatic void 688164614Sariffatiixp_poll_callback(void *arg) 689164614Sariff{ 690164614Sariff struct atiixp_info *sc = arg; 691164614Sariff uint32_t trigger = 0; 692164614Sariff 693164614Sariff if (sc == NULL) 694164614Sariff return; 695164614Sariff 696164614Sariff atiixp_lock(sc); 697164614Sariff if (sc->polling == 0 || atiixp_chan_active(sc) == 0) { 698164614Sariff atiixp_unlock(sc); 699164614Sariff return; 700164614Sariff } 701164614Sariff 702164614Sariff trigger |= (atiixp_poll_channel(&sc->pch) != 0) ? 1 : 0; 703164614Sariff trigger |= (atiixp_poll_channel(&sc->rch) != 0) ? 2 : 0; 704164614Sariff 705164614Sariff /* XXX */ 706164614Sariff callout_reset(&sc->poll_timer, 1/*sc->poll_ticks*/, 707164614Sariff atiixp_poll_callback, sc); 708164614Sariff 709164614Sariff atiixp_unlock(sc); 710164614Sariff 711164614Sariff if (trigger & 1) 712164614Sariff chn_intr(sc->pch.channel); 713164614Sariff if (trigger & 2) 714164614Sariff chn_intr(sc->rch.channel); 715164614Sariff} 716164614Sariff 717162931Sariffstatic int 718164614Sariffatiixp_chan_trigger(kobj_t obj, void *data, int go) 719164614Sariff{ 720164614Sariff struct atiixp_chinfo *ch = data; 721164614Sariff struct atiixp_info *sc = ch->parent; 722164614Sariff uint32_t value; 723164614Sariff int pollticks; 724164614Sariff 725170521Sariff if (!PCMTRIG_COMMON(go)) 726170521Sariff return (0); 727170521Sariff 728164614Sariff atiixp_lock(sc); 729164614Sariff 730164614Sariff switch (go) { 731164614Sariff case PCMTRIG_START: 732164614Sariff atiixp_flush_dma(ch); 733164614Sariff atiixp_buildsgdt(ch); 734164614Sariff atiixp_wr(sc, ch->linkptr_bit, 0); 735164614Sariff atiixp_enable_dma(ch); 736164614Sariff atiixp_wr(sc, ch->linkptr_bit, 737164614Sariff (uint32_t)ch->sgd_addr | ATI_REG_LINKPTR_EN); 738164614Sariff if (sc->polling != 0) { 739164614Sariff ch->ptr = 0; 740164614Sariff ch->prevptr = 0; 741164614Sariff pollticks = ((uint64_t)hz * ch->blksz) / 742193640Sariff ((uint64_t)sndbuf_getalign(ch->buffer) * 743164614Sariff sndbuf_getspd(ch->buffer)); 744164614Sariff pollticks >>= 2; 745164614Sariff if (pollticks > hz) 746164614Sariff pollticks = hz; 747164614Sariff if (pollticks < 1) 748164614Sariff pollticks = 1; 749164614Sariff if (atiixp_chan_active(sc) == 0 || 750164614Sariff pollticks < sc->poll_ticks) { 751164614Sariff if (bootverbose) { 752164614Sariff if (atiixp_chan_active(sc) == 0) 753164614Sariff device_printf(sc->dev, 754164614Sariff "%s: pollticks=%d\n", 755164614Sariff __func__, pollticks); 756164614Sariff else 757164614Sariff device_printf(sc->dev, 758164614Sariff "%s: pollticks %d -> %d\n", 759164614Sariff __func__, sc->poll_ticks, 760164614Sariff pollticks); 761164614Sariff } 762164614Sariff sc->poll_ticks = pollticks; 763164614Sariff callout_reset(&sc->poll_timer, 1, 764164614Sariff atiixp_poll_callback, sc); 765164614Sariff } 766164614Sariff } 767171329Sariff ch->flags |= ATI_IXP_CHN_RUNNING; 768164614Sariff break; 769164614Sariff case PCMTRIG_STOP: 770164614Sariff case PCMTRIG_ABORT: 771164614Sariff atiixp_disable_dma(ch); 772164614Sariff atiixp_flush_dma(ch); 773171329Sariff ch->flags &= ~ATI_IXP_CHN_RUNNING; 774164614Sariff if (sc->polling != 0) { 775164614Sariff if (atiixp_chan_active(sc) == 0) { 776164614Sariff callout_stop(&sc->poll_timer); 777164614Sariff sc->poll_ticks = 1; 778164614Sariff } else { 779171329Sariff if (sc->pch.flags & ATI_IXP_CHN_RUNNING) 780164614Sariff ch = &sc->pch; 781164614Sariff else 782164614Sariff ch = &sc->rch; 783164614Sariff pollticks = ((uint64_t)hz * ch->blksz) / 784193640Sariff ((uint64_t)sndbuf_getalign(ch->buffer) * 785164614Sariff sndbuf_getspd(ch->buffer)); 786164614Sariff pollticks >>= 2; 787164614Sariff if (pollticks > hz) 788164614Sariff pollticks = hz; 789164614Sariff if (pollticks < 1) 790164614Sariff pollticks = 1; 791164614Sariff if (pollticks > sc->poll_ticks) { 792164614Sariff if (bootverbose) 793164614Sariff device_printf(sc->dev, 794164614Sariff "%s: pollticks %d -> %d\n", 795164614Sariff __func__, sc->poll_ticks, 796164614Sariff pollticks); 797164614Sariff sc->poll_ticks = pollticks; 798164614Sariff callout_reset(&sc->poll_timer, 799164614Sariff 1, atiixp_poll_callback, 800164614Sariff sc); 801164614Sariff } 802164614Sariff } 803164614Sariff } 804164614Sariff break; 805164614Sariff default: 806164614Sariff atiixp_unlock(sc); 807164614Sariff return (0); 808164614Sariff break; 809164614Sariff } 810164614Sariff 811164614Sariff /* Update bus busy status */ 812164614Sariff value = atiixp_rd(sc, ATI_REG_IER); 813164614Sariff if (atiixp_rd(sc, ATI_REG_CMD) & (ATI_REG_CMD_SEND_EN | 814164614Sariff ATI_REG_CMD_RECEIVE_EN | ATI_REG_CMD_SPDF_OUT_EN)) 815164614Sariff value |= ATI_REG_IER_SET_BUS_BUSY; 816164614Sariff else 817164614Sariff value &= ~ATI_REG_IER_SET_BUS_BUSY; 818164614Sariff atiixp_wr(sc, ATI_REG_IER, value); 819164614Sariff 820164614Sariff atiixp_unlock(sc); 821164614Sariff 822164614Sariff return (0); 823164614Sariff} 824164614Sariff 825193640Sariffstatic uint32_t 826162931Sariffatiixp_chan_getptr(kobj_t obj, void *data) 827162931Sariff{ 828162931Sariff struct atiixp_chinfo *ch = data; 829162931Sariff struct atiixp_info *sc = ch->parent; 830162931Sariff uint32_t ptr; 831162931Sariff 832162931Sariff atiixp_lock(sc); 833164614Sariff if (sc->polling != 0) 834164614Sariff ptr = ch->ptr; 835164614Sariff else 836164614Sariff ptr = atiixp_dmapos(ch); 837162931Sariff atiixp_unlock(sc); 838162931Sariff 839162931Sariff return (ptr); 840162931Sariff} 841162931Sariff 842152851Sariffstatic struct pcmchan_caps * 843152851Sariffatiixp_chan_getcaps(kobj_t obj, void *data) 844152851Sariff{ 845152851Sariff struct atiixp_chinfo *ch = data; 846152851Sariff 847152851Sariff if (ch->caps_32bit) 848162931Sariff return (&atiixp_caps_32bit); 849162931Sariff return (&atiixp_caps); 850152851Sariff} 851152851Sariff 852152851Sariffstatic kobj_method_t atiixp_chan_methods[] = { 853152851Sariff KOBJMETHOD(channel_init, atiixp_chan_init), 854152851Sariff KOBJMETHOD(channel_setformat, atiixp_chan_setformat), 855152851Sariff KOBJMETHOD(channel_setspeed, atiixp_chan_setspeed), 856152851Sariff KOBJMETHOD(channel_setblocksize, atiixp_chan_setblocksize), 857167648Sariff KOBJMETHOD(channel_setfragments, atiixp_chan_setfragments), 858152851Sariff KOBJMETHOD(channel_trigger, atiixp_chan_trigger), 859152851Sariff KOBJMETHOD(channel_getptr, atiixp_chan_getptr), 860152851Sariff KOBJMETHOD(channel_getcaps, atiixp_chan_getcaps), 861193640Sariff KOBJMETHOD_END 862152851Sariff}; 863152851SariffCHANNEL_DECLARE(atiixp_chan); 864152851Sariff 865152851Sariff/* 866152851Sariff * PCI driver interface 867152851Sariff */ 868152851Sariffstatic void 869152851Sariffatiixp_intr(void *p) 870152851Sariff{ 871152851Sariff struct atiixp_info *sc = p; 872152851Sariff uint32_t status, enable, detected_codecs; 873164614Sariff uint32_t trigger = 0; 874152851Sariff 875152851Sariff atiixp_lock(sc); 876164614Sariff if (sc->polling != 0) { 877164614Sariff atiixp_unlock(sc); 878164614Sariff return; 879164614Sariff } 880152851Sariff status = atiixp_rd(sc, ATI_REG_ISR); 881152851Sariff 882152851Sariff if (status == 0) { 883152851Sariff atiixp_unlock(sc); 884152851Sariff return; 885152851Sariff } 886152851Sariff 887171329Sariff if ((status & ATI_REG_ISR_OUT_STATUS) && 888171329Sariff (sc->pch.flags & ATI_IXP_CHN_RUNNING)) 889164614Sariff trigger |= 1; 890171329Sariff if ((status & ATI_REG_ISR_IN_STATUS) && 891171329Sariff (sc->rch.flags & ATI_IXP_CHN_RUNNING)) 892164614Sariff trigger |= 2; 893152851Sariff 894152851Sariff#if 0 895152851Sariff if (status & ATI_REG_ISR_IN_XRUN) { 896152851Sariff device_printf(sc->dev, 897152851Sariff "Recieve IN XRUN interrupt\n"); 898152851Sariff } 899152851Sariff if (status & ATI_REG_ISR_OUT_XRUN) { 900152851Sariff device_printf(sc->dev, 901152851Sariff "Recieve OUT XRUN interrupt\n"); 902152851Sariff } 903152851Sariff#endif 904152851Sariff 905152851Sariff if (status & CODEC_CHECK_BITS) { 906152851Sariff /* mark missing codecs as not ready */ 907152851Sariff detected_codecs = status & CODEC_CHECK_BITS; 908152851Sariff sc->codec_not_ready_bits |= detected_codecs; 909152851Sariff 910172568Skevlo /* disable detected interrupt sources */ 911152851Sariff enable = atiixp_rd(sc, ATI_REG_IER); 912152851Sariff enable &= ~detected_codecs; 913152851Sariff atiixp_wr(sc, ATI_REG_IER, enable); 914170720Sariff wakeup(sc); 915152851Sariff } 916152851Sariff 917152851Sariff /* acknowledge */ 918152851Sariff atiixp_wr(sc, ATI_REG_ISR, status); 919152851Sariff atiixp_unlock(sc); 920164614Sariff 921164614Sariff if (trigger & 1) 922164614Sariff chn_intr(sc->pch.channel); 923164614Sariff if (trigger & 2) 924164614Sariff chn_intr(sc->rch.channel); 925152851Sariff} 926152851Sariff 927152851Sariffstatic void 928152851Sariffatiixp_dma_cb(void *p, bus_dma_segment_t *bds, int a, int b) 929152851Sariff{ 930152851Sariff struct atiixp_info *sc = (struct atiixp_info *)p; 931152851Sariff sc->sgd_addr = bds->ds_addr; 932152851Sariff} 933152851Sariff 934152851Sariffstatic void 935152851Sariffatiixp_chip_pre_init(struct atiixp_info *sc) 936152851Sariff{ 937152851Sariff uint32_t value; 938152851Sariff 939152851Sariff atiixp_lock(sc); 940152851Sariff 941152851Sariff /* disable interrupts */ 942152851Sariff atiixp_disable_interrupts(sc); 943152851Sariff 944152851Sariff /* clear all DMA enables (preserving rest of settings) */ 945152851Sariff value = atiixp_rd(sc, ATI_REG_CMD); 946152851Sariff value &= ~(ATI_REG_CMD_IN_DMA_EN | ATI_REG_CMD_OUT_DMA_EN | 947164614Sariff ATI_REG_CMD_SPDF_OUT_EN ); 948152851Sariff atiixp_wr(sc, ATI_REG_CMD, value); 949152851Sariff 950152851Sariff /* reset aclink */ 951152851Sariff atiixp_reset_aclink(sc); 952152851Sariff 953152851Sariff sc->codec_not_ready_bits = 0; 954152851Sariff 955152851Sariff /* enable all codecs to interrupt as well as the new frame interrupt */ 956152851Sariff atiixp_wr(sc, ATI_REG_IER, CODEC_CHECK_BITS); 957152851Sariff 958152851Sariff atiixp_unlock(sc); 959152851Sariff} 960152851Sariff 961164614Sariffstatic int 962164614Sariffsysctl_atiixp_polling(SYSCTL_HANDLER_ARGS) 963164614Sariff{ 964164614Sariff struct atiixp_info *sc; 965164614Sariff device_t dev; 966164614Sariff int err, val; 967164614Sariff 968164614Sariff dev = oidp->oid_arg1; 969164614Sariff sc = pcm_getdevinfo(dev); 970164614Sariff if (sc == NULL) 971164614Sariff return (EINVAL); 972164614Sariff atiixp_lock(sc); 973164614Sariff val = sc->polling; 974164614Sariff atiixp_unlock(sc); 975170289Sdwmalone err = sysctl_handle_int(oidp, &val, 0, req); 976164614Sariff 977164614Sariff if (err || req->newptr == NULL) 978164614Sariff return (err); 979164614Sariff if (val < 0 || val > 1) 980164614Sariff return (EINVAL); 981164614Sariff 982164614Sariff atiixp_lock(sc); 983164614Sariff if (val != sc->polling) { 984164614Sariff if (atiixp_chan_active(sc) != 0) 985164614Sariff err = EBUSY; 986164614Sariff else if (val == 0) { 987164614Sariff atiixp_enable_interrupts(sc); 988164614Sariff sc->polling = 0; 989164614Sariff DELAY(1000); 990164614Sariff } else { 991164614Sariff atiixp_disable_interrupts(sc); 992164614Sariff sc->polling = 1; 993164614Sariff DELAY(1000); 994164614Sariff } 995164614Sariff } 996164614Sariff atiixp_unlock(sc); 997164614Sariff 998164614Sariff return (err); 999164614Sariff} 1000164614Sariff 1001152851Sariffstatic void 1002152851Sariffatiixp_chip_post_init(void *arg) 1003152851Sariff{ 1004152851Sariff struct atiixp_info *sc = (struct atiixp_info *)arg; 1005155800Sariff uint32_t subdev; 1006164614Sariff int i, timeout, found, polling; 1007152851Sariff char status[SND_STATUSLEN]; 1008152851Sariff 1009152851Sariff atiixp_lock(sc); 1010152851Sariff 1011152851Sariff if (sc->delayed_attach.ich_func) { 1012152851Sariff config_intrhook_disestablish(&sc->delayed_attach); 1013152851Sariff sc->delayed_attach.ich_func = NULL; 1014152851Sariff } 1015152851Sariff 1016164614Sariff polling = sc->polling; 1017164614Sariff sc->polling = 0; 1018164614Sariff 1019170720Sariff timeout = 10; 1020170720Sariff if (sc->codec_not_ready_bits == 0) { 1021170720Sariff /* wait for the interrupts to happen */ 1022170720Sariff do { 1023170720Sariff msleep(sc, sc->lock, PWAIT, "ixpslp", max(hz / 10, 1)); 1024170720Sariff if (sc->codec_not_ready_bits != 0) 1025170720Sariff break; 1026170720Sariff } while (--timeout); 1027170720Sariff } 1028152851Sariff 1029164614Sariff sc->polling = polling; 1030152851Sariff atiixp_disable_interrupts(sc); 1031152851Sariff 1032170720Sariff if (sc->codec_not_ready_bits == 0 && timeout == 0) { 1033152851Sariff device_printf(sc->dev, 1034152851Sariff "WARNING: timeout during codec detection; " 1035152851Sariff "codecs might be present but haven't interrupted\n"); 1036152851Sariff atiixp_unlock(sc); 1037157026Sariff goto postinitbad; 1038152851Sariff } 1039152851Sariff 1040152851Sariff found = 0; 1041152851Sariff 1042152851Sariff /* 1043152851Sariff * ATI IXP can have upto 3 codecs, but single codec should be 1044152851Sariff * suffice for now. 1045152851Sariff */ 1046164614Sariff if (!(sc->codec_not_ready_bits & ATI_REG_ISR_CODEC0_NOT_READY)) { 1047152851Sariff /* codec 0 present */ 1048152851Sariff sc->codec_found++; 1049152851Sariff sc->codec_idx = 0; 1050152851Sariff found++; 1051152851Sariff } 1052152851Sariff 1053164614Sariff if (!(sc->codec_not_ready_bits & ATI_REG_ISR_CODEC1_NOT_READY)) { 1054152851Sariff /* codec 1 present */ 1055152851Sariff sc->codec_found++; 1056152851Sariff } 1057152851Sariff 1058164614Sariff if (!(sc->codec_not_ready_bits & ATI_REG_ISR_CODEC2_NOT_READY)) { 1059152851Sariff /* codec 2 present */ 1060152851Sariff sc->codec_found++; 1061152851Sariff } 1062152851Sariff 1063152851Sariff atiixp_unlock(sc); 1064152851Sariff 1065152851Sariff if (found == 0) 1066157026Sariff goto postinitbad; 1067152851Sariff 1068152851Sariff /* create/init mixer */ 1069152851Sariff sc->codec = AC97_CREATE(sc->dev, sc, atiixp_ac97); 1070152851Sariff if (sc->codec == NULL) 1071152851Sariff goto postinitbad; 1072152851Sariff 1073164614Sariff subdev = (pci_get_subdevice(sc->dev) << 16) | 1074164614Sariff pci_get_subvendor(sc->dev); 1075155800Sariff switch (subdev) { 1076167502Sariff case 0x11831043: /* ASUS A6R */ 1077155800Sariff case 0x2043161f: /* Maxselect x710s - http://maxselect.ru/ */ 1078164614Sariff ac97_setflags(sc->codec, ac97_getflags(sc->codec) | 1079164614Sariff AC97_F_EAPD_INV); 1080155800Sariff break; 1081155800Sariff default: 1082155800Sariff break; 1083155800Sariff } 1084155800Sariff 1085152851Sariff mixer_init(sc->dev, ac97_getmixerclass(), sc->codec); 1086152851Sariff 1087152851Sariff if (pcm_register(sc->dev, sc, ATI_IXP_NPCHAN, ATI_IXP_NRCHAN)) 1088152851Sariff goto postinitbad; 1089152851Sariff 1090152851Sariff for (i = 0; i < ATI_IXP_NPCHAN; i++) 1091152851Sariff pcm_addchan(sc->dev, PCMDIR_PLAY, &atiixp_chan_class, sc); 1092152851Sariff for (i = 0; i < ATI_IXP_NRCHAN; i++) 1093152851Sariff pcm_addchan(sc->dev, PCMDIR_REC, &atiixp_chan_class, sc); 1094152851Sariff 1095164614Sariff SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev), 1096164614Sariff SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO, 1097164614Sariff "polling", CTLTYPE_INT | CTLFLAG_RW, sc->dev, sizeof(sc->dev), 1098164614Sariff sysctl_atiixp_polling, "I", "Enable polling mode"); 1099164614Sariff 1100162931Sariff snprintf(status, SND_STATUSLEN, "at memory 0x%lx irq %ld %s", 1101164614Sariff rman_get_start(sc->reg), rman_get_start(sc->irq), 1102164614Sariff PCM_KLDSTRING(snd_atiixp)); 1103152851Sariff 1104152851Sariff pcm_setstatus(sc->dev, status); 1105152851Sariff 1106152851Sariff atiixp_lock(sc); 1107164614Sariff if (sc->polling == 0) 1108164614Sariff atiixp_enable_interrupts(sc); 1109152851Sariff atiixp_unlock(sc); 1110152851Sariff 1111152851Sariff return; 1112152851Sariff 1113152851Sariffpostinitbad: 1114157026Sariff atiixp_release_resource(sc); 1115157026Sariff} 1116157026Sariff 1117157026Sariffstatic void 1118157026Sariffatiixp_release_resource(struct atiixp_info *sc) 1119157026Sariff{ 1120157026Sariff if (sc == NULL) 1121157026Sariff return; 1122170721Sariff if (sc->registered_channels != 0) { 1123170721Sariff atiixp_lock(sc); 1124170721Sariff sc->polling = 0; 1125170721Sariff callout_stop(&sc->poll_timer); 1126170721Sariff atiixp_unlock(sc); 1127170721Sariff callout_drain(&sc->poll_timer); 1128170721Sariff } 1129157026Sariff if (sc->codec) { 1130152851Sariff ac97_destroy(sc->codec); 1131157026Sariff sc->codec = NULL; 1132157026Sariff } 1133157026Sariff if (sc->ih) { 1134152851Sariff bus_teardown_intr(sc->dev, sc->irq, sc->ih); 1135167773Sariff sc->ih = NULL; 1136157026Sariff } 1137157026Sariff if (sc->reg) { 1138152851Sariff bus_release_resource(sc->dev, sc->regtype, sc->regid, sc->reg); 1139167773Sariff sc->reg = NULL; 1140157026Sariff } 1141157026Sariff if (sc->irq) { 1142152851Sariff bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irqid, sc->irq); 1143167773Sariff sc->irq = NULL; 1144157026Sariff } 1145157026Sariff if (sc->parent_dmat) { 1146152851Sariff bus_dma_tag_destroy(sc->parent_dmat); 1147167773Sariff sc->parent_dmat = NULL; 1148157026Sariff } 1149167773Sariff if (sc->sgd_dmamap) 1150152851Sariff bus_dmamap_unload(sc->sgd_dmat, sc->sgd_dmamap); 1151167773Sariff if (sc->sgd_table) { 1152167773Sariff bus_dmamem_free(sc->sgd_dmat, sc->sgd_table, sc->sgd_dmamap); 1153167773Sariff sc->sgd_table = NULL; 1154157026Sariff } 1155167773Sariff sc->sgd_dmamap = NULL; 1156157026Sariff if (sc->sgd_dmat) { 1157152851Sariff bus_dma_tag_destroy(sc->sgd_dmat); 1158167773Sariff sc->sgd_dmat = NULL; 1159157026Sariff } 1160157026Sariff if (sc->lock) { 1161152851Sariff snd_mtxfree(sc->lock); 1162157026Sariff sc->lock = NULL; 1163157026Sariff } 1164170721Sariff free(sc, M_DEVBUF); 1165152851Sariff} 1166152851Sariff 1167152851Sariffstatic int 1168152851Sariffatiixp_pci_probe(device_t dev) 1169152851Sariff{ 1170152851Sariff int i; 1171152851Sariff uint16_t devid, vendor; 1172152851Sariff 1173152851Sariff vendor = pci_get_vendor(dev); 1174152851Sariff devid = pci_get_device(dev); 1175162931Sariff for (i = 0; i < sizeof(atiixp_hw) / sizeof(atiixp_hw[0]); i++) { 1176152851Sariff if (vendor == atiixp_hw[i].vendor && 1177164614Sariff devid == atiixp_hw[i].devid) { 1178152851Sariff device_set_desc(dev, atiixp_hw[i].desc); 1179162931Sariff return (BUS_PROBE_DEFAULT); 1180152851Sariff } 1181152851Sariff } 1182152851Sariff 1183162931Sariff return (ENXIO); 1184152851Sariff} 1185152851Sariff 1186152851Sariffstatic int 1187152851Sariffatiixp_pci_attach(device_t dev) 1188152851Sariff{ 1189152851Sariff struct atiixp_info *sc; 1190152851Sariff int i; 1191152851Sariff 1192170721Sariff sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); 1193167608Sariff sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_atiixp softc"); 1194152851Sariff sc->dev = dev; 1195152851Sariff 1196164614Sariff callout_init(&sc->poll_timer, CALLOUT_MPSAFE); 1197164614Sariff sc->poll_ticks = 1; 1198164614Sariff 1199164614Sariff if (resource_int_value(device_get_name(sc->dev), 1200164614Sariff device_get_unit(sc->dev), "polling", &i) == 0 && i != 0) 1201164614Sariff sc->polling = 1; 1202164614Sariff else 1203164614Sariff sc->polling = 0; 1204164614Sariff 1205152851Sariff pci_enable_busmaster(dev); 1206152851Sariff 1207152851Sariff sc->regid = PCIR_BAR(0); 1208152851Sariff sc->regtype = SYS_RES_MEMORY; 1209164614Sariff sc->reg = bus_alloc_resource_any(dev, sc->regtype, 1210164614Sariff &sc->regid, RF_ACTIVE); 1211152851Sariff 1212152851Sariff if (!sc->reg) { 1213152851Sariff device_printf(dev, "unable to allocate register space\n"); 1214152851Sariff goto bad; 1215152851Sariff } 1216152851Sariff 1217152851Sariff sc->st = rman_get_bustag(sc->reg); 1218152851Sariff sc->sh = rman_get_bushandle(sc->reg); 1219152851Sariff 1220162931Sariff sc->bufsz = pcm_getbuffersize(dev, ATI_IXP_BUFSZ_MIN, 1221164614Sariff ATI_IXP_BUFSZ_DEFAULT, ATI_IXP_BUFSZ_MAX); 1222152851Sariff 1223152851Sariff sc->irqid = 0; 1224152851Sariff sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid, 1225164614Sariff RF_ACTIVE | RF_SHAREABLE); 1226164614Sariff if (!sc->irq || snd_setup_intr(dev, sc->irq, INTR_MPSAFE, 1227164614Sariff atiixp_intr, sc, &sc->ih)) { 1228152851Sariff device_printf(dev, "unable to map interrupt\n"); 1229152851Sariff goto bad; 1230152851Sariff } 1231152851Sariff 1232152851Sariff /* 1233152851Sariff * Let the user choose the best DMA segments. 1234152851Sariff */ 1235164614Sariff if (resource_int_value(device_get_name(dev), 1236164614Sariff device_get_unit(dev), "blocksize", &i) == 0 && i > 0) { 1237167648Sariff i &= ATI_IXP_BLK_ALIGN; 1238167648Sariff if (i < ATI_IXP_BLK_MIN) 1239167648Sariff i = ATI_IXP_BLK_MIN; 1240164614Sariff sc->blkcnt = sc->bufsz / i; 1241164614Sariff i = 0; 1242164614Sariff while (sc->blkcnt >> i) 1243164614Sariff i++; 1244164614Sariff sc->blkcnt = 1 << (i - 1); 1245164614Sariff if (sc->blkcnt < ATI_IXP_DMA_CHSEGS_MIN) 1246164614Sariff sc->blkcnt = ATI_IXP_DMA_CHSEGS_MIN; 1247164614Sariff else if (sc->blkcnt > ATI_IXP_DMA_CHSEGS_MAX) 1248164614Sariff sc->blkcnt = ATI_IXP_DMA_CHSEGS_MAX; 1249152851Sariff 1250164614Sariff } else 1251164614Sariff sc->blkcnt = ATI_IXP_DMA_CHSEGS; 1252155800Sariff 1253155800Sariff /* 1254152851Sariff * DMA tag for scatter-gather buffers and link pointers 1255152851Sariff */ 1256166904Snetchild if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2, 1257166904Snetchild /*boundary*/0, 1258152851Sariff /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 1259152851Sariff /*highaddr*/BUS_SPACE_MAXADDR, 1260152851Sariff /*filter*/NULL, /*filterarg*/NULL, 1261152851Sariff /*maxsize*/sc->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff, 1262152851Sariff /*flags*/0, /*lockfunc*/NULL, 1263152851Sariff /*lockarg*/NULL, &sc->parent_dmat) != 0) { 1264152851Sariff device_printf(dev, "unable to create dma tag\n"); 1265152851Sariff goto bad; 1266152851Sariff } 1267152851Sariff 1268166904Snetchild if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2, 1269166904Snetchild /*boundary*/0, 1270152851Sariff /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 1271152851Sariff /*highaddr*/BUS_SPACE_MAXADDR, 1272152851Sariff /*filter*/NULL, /*filterarg*/NULL, 1273167648Sariff /*maxsize*/ATI_IXP_DMA_CHSEGS_MAX * ATI_IXP_NCHANS * 1274164614Sariff sizeof(struct atiixp_dma_op), 1275152851Sariff /*nsegments*/1, /*maxsegz*/0x3ffff, 1276152851Sariff /*flags*/0, /*lockfunc*/NULL, 1277152851Sariff /*lockarg*/NULL, &sc->sgd_dmat) != 0) { 1278152851Sariff device_printf(dev, "unable to create dma tag\n"); 1279152851Sariff goto bad; 1280152851Sariff } 1281152851Sariff 1282162931Sariff if (bus_dmamem_alloc(sc->sgd_dmat, (void **)&sc->sgd_table, 1283164614Sariff BUS_DMA_NOWAIT, &sc->sgd_dmamap) == -1) 1284152851Sariff goto bad; 1285152851Sariff 1286162931Sariff if (bus_dmamap_load(sc->sgd_dmat, sc->sgd_dmamap, sc->sgd_table, 1287167648Sariff ATI_IXP_DMA_CHSEGS_MAX * ATI_IXP_NCHANS * 1288167648Sariff sizeof(struct atiixp_dma_op), atiixp_dma_cb, sc, 0)) 1289152851Sariff goto bad; 1290152851Sariff 1291152851Sariff 1292152851Sariff atiixp_chip_pre_init(sc); 1293152851Sariff 1294152851Sariff sc->delayed_attach.ich_func = atiixp_chip_post_init; 1295152851Sariff sc->delayed_attach.ich_arg = sc; 1296152851Sariff if (cold == 0 || 1297164614Sariff config_intrhook_establish(&sc->delayed_attach) != 0) { 1298152851Sariff sc->delayed_attach.ich_func = NULL; 1299152851Sariff atiixp_chip_post_init(sc); 1300152851Sariff } 1301152851Sariff 1302162931Sariff return (0); 1303152851Sariff 1304152851Sariffbad: 1305157026Sariff atiixp_release_resource(sc); 1306162931Sariff return (ENXIO); 1307152851Sariff} 1308152851Sariff 1309152851Sariffstatic int 1310152851Sariffatiixp_pci_detach(device_t dev) 1311152851Sariff{ 1312152851Sariff int r; 1313152851Sariff struct atiixp_info *sc; 1314152851Sariff 1315152851Sariff sc = pcm_getdevinfo(dev); 1316157026Sariff if (sc != NULL) { 1317157026Sariff if (sc->codec != NULL) { 1318157026Sariff r = pcm_unregister(dev); 1319157026Sariff if (r) 1320162931Sariff return (r); 1321157026Sariff } 1322157026Sariff sc->codec = NULL; 1323162931Sariff if (sc->st != 0 && sc->sh != 0) 1324162931Sariff atiixp_disable_interrupts(sc); 1325157026Sariff atiixp_release_resource(sc); 1326157026Sariff } 1327162931Sariff return (0); 1328152851Sariff} 1329152851Sariff 1330153708Sariffstatic int 1331153708Sariffatiixp_pci_suspend(device_t dev) 1332153708Sariff{ 1333153708Sariff struct atiixp_info *sc = pcm_getdevinfo(dev); 1334153708Sariff uint32_t value; 1335153708Sariff 1336153708Sariff /* quickly disable interrupts and save channels active state */ 1337153708Sariff atiixp_lock(sc); 1338153708Sariff atiixp_disable_interrupts(sc); 1339153708Sariff atiixp_unlock(sc); 1340153708Sariff 1341153708Sariff /* stop everything */ 1342171329Sariff if (sc->pch.flags & ATI_IXP_CHN_RUNNING) { 1343153708Sariff atiixp_chan_trigger(NULL, &sc->pch, PCMTRIG_STOP); 1344171329Sariff sc->pch.flags |= ATI_IXP_CHN_SUSPEND; 1345171329Sariff } 1346171329Sariff if (sc->rch.flags & ATI_IXP_CHN_RUNNING) { 1347153708Sariff atiixp_chan_trigger(NULL, &sc->rch, PCMTRIG_STOP); 1348171329Sariff sc->rch.flags |= ATI_IXP_CHN_SUSPEND; 1349171329Sariff } 1350153708Sariff 1351153708Sariff /* power down aclink and pci bus */ 1352153708Sariff atiixp_lock(sc); 1353153708Sariff value = atiixp_rd(sc, ATI_REG_CMD); 1354153708Sariff value |= ATI_REG_CMD_POWERDOWN | ATI_REG_CMD_AC_RESET; 1355153708Sariff atiixp_wr(sc, ATI_REG_CMD, ATI_REG_CMD_POWERDOWN); 1356153708Sariff atiixp_unlock(sc); 1357153708Sariff 1358162931Sariff return (0); 1359153708Sariff} 1360153708Sariff 1361153708Sariffstatic int 1362153708Sariffatiixp_pci_resume(device_t dev) 1363153708Sariff{ 1364153708Sariff struct atiixp_info *sc = pcm_getdevinfo(dev); 1365153708Sariff 1366153708Sariff atiixp_lock(sc); 1367153708Sariff /* reset / power up aclink */ 1368153708Sariff atiixp_reset_aclink(sc); 1369153708Sariff atiixp_unlock(sc); 1370153708Sariff 1371153708Sariff if (mixer_reinit(dev) == -1) { 1372153708Sariff device_printf(dev, "unable to reinitialize the mixer\n"); 1373162931Sariff return (ENXIO); 1374153708Sariff } 1375153708Sariff 1376153708Sariff /* 1377153708Sariff * Resume channel activities. Reset channel format regardless 1378153708Sariff * of its previous state. 1379153708Sariff */ 1380164614Sariff if (sc->pch.channel != NULL) { 1381164614Sariff if (sc->pch.fmt != 0) 1382153708Sariff atiixp_chan_setformat(NULL, &sc->pch, sc->pch.fmt); 1383171329Sariff if (sc->pch.flags & ATI_IXP_CHN_SUSPEND) { 1384171329Sariff sc->pch.flags &= ~ATI_IXP_CHN_SUSPEND; 1385153708Sariff atiixp_chan_trigger(NULL, &sc->pch, PCMTRIG_START); 1386171329Sariff } 1387153708Sariff } 1388164614Sariff if (sc->rch.channel != NULL) { 1389164614Sariff if (sc->rch.fmt != 0) 1390153708Sariff atiixp_chan_setformat(NULL, &sc->rch, sc->rch.fmt); 1391171329Sariff if (sc->rch.flags & ATI_IXP_CHN_SUSPEND) { 1392171329Sariff sc->rch.flags &= ~ATI_IXP_CHN_SUSPEND; 1393153708Sariff atiixp_chan_trigger(NULL, &sc->rch, PCMTRIG_START); 1394171329Sariff } 1395153708Sariff } 1396153708Sariff 1397153708Sariff /* enable interrupts */ 1398153708Sariff atiixp_lock(sc); 1399164614Sariff if (sc->polling == 0) 1400164614Sariff atiixp_enable_interrupts(sc); 1401153708Sariff atiixp_unlock(sc); 1402153708Sariff 1403162931Sariff return (0); 1404153708Sariff} 1405153708Sariff 1406152851Sariffstatic device_method_t atiixp_methods[] = { 1407152851Sariff DEVMETHOD(device_probe, atiixp_pci_probe), 1408152851Sariff DEVMETHOD(device_attach, atiixp_pci_attach), 1409152851Sariff DEVMETHOD(device_detach, atiixp_pci_detach), 1410153708Sariff DEVMETHOD(device_suspend, atiixp_pci_suspend), 1411153708Sariff DEVMETHOD(device_resume, atiixp_pci_resume), 1412152851Sariff { 0, 0 } 1413152851Sariff}; 1414152851Sariff 1415152851Sariffstatic driver_t atiixp_driver = { 1416152851Sariff "pcm", 1417152851Sariff atiixp_methods, 1418152851Sariff PCM_SOFTC_SIZE, 1419152851Sariff}; 1420152851Sariff 1421152851SariffDRIVER_MODULE(snd_atiixp, pci, atiixp_driver, pcm_devclass, 0, 0); 1422152851SariffMODULE_DEPEND(snd_atiixp, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 1423152851SariffMODULE_VERSION(snd_atiixp, 1); 1424