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
1100297000Sjhibbits	snprintf(status, SND_STATUSLEN, "at memory 0x%jx irq %jd %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	}
1149267581Sjhb	if (sc->sgd_addr) {
1150152851Sariff		bus_dmamap_unload(sc->sgd_dmat, sc->sgd_dmamap);
1151267581Sjhb		sc->sgd_addr = 0;
1152267581Sjhb	}
1153167773Sariff	if (sc->sgd_table) {
1154167773Sariff		bus_dmamem_free(sc->sgd_dmat, sc->sgd_table, sc->sgd_dmamap);
1155167773Sariff		sc->sgd_table = NULL;
1156157026Sariff	}
1157157026Sariff	if (sc->sgd_dmat) {
1158152851Sariff		bus_dma_tag_destroy(sc->sgd_dmat);
1159167773Sariff		sc->sgd_dmat = NULL;
1160157026Sariff	}
1161157026Sariff	if (sc->lock) {
1162152851Sariff		snd_mtxfree(sc->lock);
1163157026Sariff		sc->lock = NULL;
1164157026Sariff	}
1165170721Sariff	free(sc, M_DEVBUF);
1166152851Sariff}
1167152851Sariff
1168152851Sariffstatic int
1169152851Sariffatiixp_pci_probe(device_t dev)
1170152851Sariff{
1171152851Sariff	int i;
1172152851Sariff	uint16_t devid, vendor;
1173152851Sariff
1174152851Sariff	vendor = pci_get_vendor(dev);
1175152851Sariff	devid = pci_get_device(dev);
1176162931Sariff	for (i = 0; i < sizeof(atiixp_hw) / sizeof(atiixp_hw[0]); i++) {
1177152851Sariff		if (vendor == atiixp_hw[i].vendor &&
1178164614Sariff		    devid == atiixp_hw[i].devid) {
1179152851Sariff			device_set_desc(dev, atiixp_hw[i].desc);
1180162931Sariff			return (BUS_PROBE_DEFAULT);
1181152851Sariff		}
1182152851Sariff	}
1183152851Sariff
1184162931Sariff	return (ENXIO);
1185152851Sariff}
1186152851Sariff
1187152851Sariffstatic int
1188152851Sariffatiixp_pci_attach(device_t dev)
1189152851Sariff{
1190152851Sariff	struct atiixp_info *sc;
1191152851Sariff	int i;
1192152851Sariff
1193170721Sariff	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
1194167608Sariff	sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_atiixp softc");
1195152851Sariff	sc->dev = dev;
1196152851Sariff
1197283291Sjkim	callout_init(&sc->poll_timer, 1);
1198164614Sariff	sc->poll_ticks = 1;
1199164614Sariff
1200164614Sariff	if (resource_int_value(device_get_name(sc->dev),
1201164614Sariff	    device_get_unit(sc->dev), "polling", &i) == 0 && i != 0)
1202164614Sariff		sc->polling = 1;
1203164614Sariff	else
1204164614Sariff		sc->polling = 0;
1205164614Sariff
1206152851Sariff	pci_enable_busmaster(dev);
1207152851Sariff
1208152851Sariff	sc->regid = PCIR_BAR(0);
1209152851Sariff	sc->regtype = SYS_RES_MEMORY;
1210164614Sariff	sc->reg = bus_alloc_resource_any(dev, sc->regtype,
1211164614Sariff	    &sc->regid, RF_ACTIVE);
1212152851Sariff
1213152851Sariff	if (!sc->reg) {
1214152851Sariff		device_printf(dev, "unable to allocate register space\n");
1215152851Sariff		goto bad;
1216152851Sariff	}
1217152851Sariff
1218152851Sariff	sc->st = rman_get_bustag(sc->reg);
1219152851Sariff	sc->sh = rman_get_bushandle(sc->reg);
1220152851Sariff
1221162931Sariff	sc->bufsz = pcm_getbuffersize(dev, ATI_IXP_BUFSZ_MIN,
1222164614Sariff	    ATI_IXP_BUFSZ_DEFAULT, ATI_IXP_BUFSZ_MAX);
1223152851Sariff
1224152851Sariff	sc->irqid = 0;
1225152851Sariff	sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid,
1226164614Sariff	    RF_ACTIVE | RF_SHAREABLE);
1227164614Sariff	if (!sc->irq || snd_setup_intr(dev, sc->irq, INTR_MPSAFE,
1228164614Sariff	    atiixp_intr, sc, &sc->ih)) {
1229152851Sariff		device_printf(dev, "unable to map interrupt\n");
1230152851Sariff		goto bad;
1231152851Sariff	}
1232152851Sariff
1233152851Sariff	/*
1234152851Sariff	 * Let the user choose the best DMA segments.
1235152851Sariff	 */
1236164614Sariff	if (resource_int_value(device_get_name(dev),
1237164614Sariff	    device_get_unit(dev), "blocksize", &i) == 0 && i > 0) {
1238167648Sariff		i &= ATI_IXP_BLK_ALIGN;
1239167648Sariff		if (i < ATI_IXP_BLK_MIN)
1240167648Sariff			i = ATI_IXP_BLK_MIN;
1241164614Sariff		sc->blkcnt = sc->bufsz / i;
1242164614Sariff		i = 0;
1243164614Sariff		while (sc->blkcnt >> i)
1244164614Sariff			i++;
1245164614Sariff		sc->blkcnt = 1 << (i - 1);
1246164614Sariff		if (sc->blkcnt < ATI_IXP_DMA_CHSEGS_MIN)
1247164614Sariff			sc->blkcnt = ATI_IXP_DMA_CHSEGS_MIN;
1248164614Sariff		else if (sc->blkcnt > ATI_IXP_DMA_CHSEGS_MAX)
1249164614Sariff			sc->blkcnt = ATI_IXP_DMA_CHSEGS_MAX;
1250152851Sariff
1251164614Sariff	} else
1252164614Sariff		sc->blkcnt = ATI_IXP_DMA_CHSEGS;
1253155800Sariff
1254155800Sariff	/*
1255152851Sariff	 * DMA tag for scatter-gather buffers and link pointers
1256152851Sariff	 */
1257166904Snetchild	if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2,
1258166904Snetchild		/*boundary*/0,
1259152851Sariff		/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
1260152851Sariff		/*highaddr*/BUS_SPACE_MAXADDR,
1261152851Sariff		/*filter*/NULL, /*filterarg*/NULL,
1262152851Sariff		/*maxsize*/sc->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff,
1263152851Sariff		/*flags*/0, /*lockfunc*/NULL,
1264152851Sariff		/*lockarg*/NULL, &sc->parent_dmat) != 0) {
1265152851Sariff		device_printf(dev, "unable to create dma tag\n");
1266152851Sariff		goto bad;
1267152851Sariff	}
1268152851Sariff
1269166904Snetchild	if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2,
1270166904Snetchild		/*boundary*/0,
1271152851Sariff		/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
1272152851Sariff		/*highaddr*/BUS_SPACE_MAXADDR,
1273152851Sariff		/*filter*/NULL, /*filterarg*/NULL,
1274167648Sariff		/*maxsize*/ATI_IXP_DMA_CHSEGS_MAX * ATI_IXP_NCHANS *
1275164614Sariff		sizeof(struct atiixp_dma_op),
1276152851Sariff		/*nsegments*/1, /*maxsegz*/0x3ffff,
1277152851Sariff		/*flags*/0, /*lockfunc*/NULL,
1278152851Sariff		/*lockarg*/NULL, &sc->sgd_dmat) != 0) {
1279152851Sariff		device_printf(dev, "unable to create dma tag\n");
1280152851Sariff		goto bad;
1281152851Sariff	}
1282152851Sariff
1283162931Sariff	if (bus_dmamem_alloc(sc->sgd_dmat, (void **)&sc->sgd_table,
1284164614Sariff	    BUS_DMA_NOWAIT, &sc->sgd_dmamap) == -1)
1285152851Sariff		goto bad;
1286152851Sariff
1287162931Sariff	if (bus_dmamap_load(sc->sgd_dmat, sc->sgd_dmamap, sc->sgd_table,
1288167648Sariff	    ATI_IXP_DMA_CHSEGS_MAX * ATI_IXP_NCHANS *
1289167648Sariff	    sizeof(struct atiixp_dma_op), atiixp_dma_cb, sc, 0))
1290152851Sariff		goto bad;
1291152851Sariff
1292152851Sariff
1293152851Sariff	atiixp_chip_pre_init(sc);
1294152851Sariff
1295152851Sariff	sc->delayed_attach.ich_func = atiixp_chip_post_init;
1296152851Sariff	sc->delayed_attach.ich_arg = sc;
1297152851Sariff	if (cold == 0 ||
1298164614Sariff	    config_intrhook_establish(&sc->delayed_attach) != 0) {
1299152851Sariff		sc->delayed_attach.ich_func = NULL;
1300152851Sariff		atiixp_chip_post_init(sc);
1301152851Sariff	}
1302152851Sariff
1303162931Sariff	return (0);
1304152851Sariff
1305152851Sariffbad:
1306157026Sariff	atiixp_release_resource(sc);
1307162931Sariff	return (ENXIO);
1308152851Sariff}
1309152851Sariff
1310152851Sariffstatic int
1311152851Sariffatiixp_pci_detach(device_t dev)
1312152851Sariff{
1313152851Sariff	int r;
1314152851Sariff	struct atiixp_info *sc;
1315152851Sariff
1316152851Sariff	sc = pcm_getdevinfo(dev);
1317157026Sariff	if (sc != NULL) {
1318157026Sariff		if (sc->codec != NULL) {
1319157026Sariff			r = pcm_unregister(dev);
1320157026Sariff			if (r)
1321162931Sariff				return (r);
1322157026Sariff		}
1323157026Sariff		sc->codec = NULL;
1324162931Sariff		if (sc->st != 0 && sc->sh != 0)
1325162931Sariff			atiixp_disable_interrupts(sc);
1326157026Sariff		atiixp_release_resource(sc);
1327157026Sariff	}
1328162931Sariff	return (0);
1329152851Sariff}
1330152851Sariff
1331153708Sariffstatic int
1332153708Sariffatiixp_pci_suspend(device_t dev)
1333153708Sariff{
1334153708Sariff	struct atiixp_info *sc = pcm_getdevinfo(dev);
1335153708Sariff	uint32_t value;
1336153708Sariff
1337153708Sariff	/* quickly disable interrupts and save channels active state */
1338153708Sariff	atiixp_lock(sc);
1339153708Sariff	atiixp_disable_interrupts(sc);
1340153708Sariff	atiixp_unlock(sc);
1341153708Sariff
1342153708Sariff	/* stop everything */
1343171329Sariff	if (sc->pch.flags & ATI_IXP_CHN_RUNNING) {
1344153708Sariff		atiixp_chan_trigger(NULL, &sc->pch, PCMTRIG_STOP);
1345171329Sariff		sc->pch.flags |= ATI_IXP_CHN_SUSPEND;
1346171329Sariff	}
1347171329Sariff	if (sc->rch.flags & ATI_IXP_CHN_RUNNING) {
1348153708Sariff		atiixp_chan_trigger(NULL, &sc->rch, PCMTRIG_STOP);
1349171329Sariff		sc->rch.flags |= ATI_IXP_CHN_SUSPEND;
1350171329Sariff	}
1351153708Sariff
1352153708Sariff	/* power down aclink and pci bus */
1353153708Sariff	atiixp_lock(sc);
1354153708Sariff	value = atiixp_rd(sc, ATI_REG_CMD);
1355153708Sariff	value |= ATI_REG_CMD_POWERDOWN | ATI_REG_CMD_AC_RESET;
1356153708Sariff	atiixp_wr(sc, ATI_REG_CMD, ATI_REG_CMD_POWERDOWN);
1357153708Sariff	atiixp_unlock(sc);
1358153708Sariff
1359162931Sariff	return (0);
1360153708Sariff}
1361153708Sariff
1362153708Sariffstatic int
1363153708Sariffatiixp_pci_resume(device_t dev)
1364153708Sariff{
1365153708Sariff	struct atiixp_info *sc = pcm_getdevinfo(dev);
1366153708Sariff
1367153708Sariff	atiixp_lock(sc);
1368153708Sariff	/* reset / power up aclink */
1369153708Sariff	atiixp_reset_aclink(sc);
1370153708Sariff	atiixp_unlock(sc);
1371153708Sariff
1372153708Sariff	if (mixer_reinit(dev) == -1) {
1373153708Sariff		device_printf(dev, "unable to reinitialize the mixer\n");
1374162931Sariff		return (ENXIO);
1375153708Sariff	}
1376153708Sariff
1377153708Sariff	/*
1378153708Sariff	 * Resume channel activities. Reset channel format regardless
1379153708Sariff	 * of its previous state.
1380153708Sariff	 */
1381164614Sariff	if (sc->pch.channel != NULL) {
1382164614Sariff		if (sc->pch.fmt != 0)
1383153708Sariff			atiixp_chan_setformat(NULL, &sc->pch, sc->pch.fmt);
1384171329Sariff		if (sc->pch.flags & ATI_IXP_CHN_SUSPEND) {
1385171329Sariff			sc->pch.flags &= ~ATI_IXP_CHN_SUSPEND;
1386153708Sariff			atiixp_chan_trigger(NULL, &sc->pch, PCMTRIG_START);
1387171329Sariff		}
1388153708Sariff	}
1389164614Sariff	if (sc->rch.channel != NULL) {
1390164614Sariff		if (sc->rch.fmt != 0)
1391153708Sariff			atiixp_chan_setformat(NULL, &sc->rch, sc->rch.fmt);
1392171329Sariff		if (sc->rch.flags & ATI_IXP_CHN_SUSPEND) {
1393171329Sariff			sc->rch.flags &= ~ATI_IXP_CHN_SUSPEND;
1394153708Sariff			atiixp_chan_trigger(NULL, &sc->rch, PCMTRIG_START);
1395171329Sariff		}
1396153708Sariff	}
1397153708Sariff
1398153708Sariff	/* enable interrupts */
1399153708Sariff	atiixp_lock(sc);
1400164614Sariff	if (sc->polling == 0)
1401164614Sariff		atiixp_enable_interrupts(sc);
1402153708Sariff	atiixp_unlock(sc);
1403153708Sariff
1404162931Sariff	return (0);
1405153708Sariff}
1406153708Sariff
1407152851Sariffstatic device_method_t atiixp_methods[] = {
1408152851Sariff	DEVMETHOD(device_probe,		atiixp_pci_probe),
1409152851Sariff	DEVMETHOD(device_attach,	atiixp_pci_attach),
1410152851Sariff	DEVMETHOD(device_detach,	atiixp_pci_detach),
1411153708Sariff	DEVMETHOD(device_suspend,	atiixp_pci_suspend),
1412153708Sariff	DEVMETHOD(device_resume,	atiixp_pci_resume),
1413152851Sariff	{ 0, 0 }
1414152851Sariff};
1415152851Sariff
1416152851Sariffstatic driver_t atiixp_driver = {
1417152851Sariff	"pcm",
1418152851Sariff	atiixp_methods,
1419152851Sariff	PCM_SOFTC_SIZE,
1420152851Sariff};
1421152851Sariff
1422152851SariffDRIVER_MODULE(snd_atiixp, pci, atiixp_driver, pcm_devclass, 0, 0);
1423152851SariffMODULE_DEPEND(snd_atiixp, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
1424152851SariffMODULE_VERSION(snd_atiixp, 1);
1425