atiixp.c revision 167648
1168404Spjd/*-
2168404Spjd * Copyright (c) 2005 Ariff Abdullah <ariff@FreeBSD.org>
3168404Spjd * All rights reserved.
4168404Spjd *
5168404Spjd * Redistribution and use in source and binary forms, with or without
6168404Spjd * modification, are permitted provided that the following conditions
7168404Spjd * are met:
8168404Spjd * 1. Redistributions of source code must retain the above copyright
9168404Spjd *    notice, this list of conditions and the following disclaimer.
10168404Spjd * 2. Redistributions in binary form must reproduce the above copyright
11168404Spjd *    notice, this list of conditions and the following disclaimer in the
12168404Spjd *    documentation and/or other materials provided with the distribution.
13168404Spjd *
14168404Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15168404Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16168404Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17168404Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18168404Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19168404Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20168404Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21168404Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
22185029Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23168404Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF
24168404Spjd * SUCH DAMAGE.
25168404Spjd */
26168404Spjd
27168404Spjd/*
28168404Spjd * FreeBSD pcm driver for ATI IXP 150/200/250/300 AC97 controllers
29168404Spjd *
30168404Spjd * Features
31168404Spjd *	* 16bit playback / recording
32168404Spjd *	* 32bit native playback - yay!
33168404Spjd *	* 32bit native recording (seems broken on few hardwares)
34168404Spjd *
35168404Spjd * Issues / TODO:
36168404Spjd *	* SPDIF
37168404Spjd *	* Support for more than 2 channels.
38168404Spjd *	* VRA ? VRM ? DRA ?
39168404Spjd *	* 32bit native recording seems broken on few hardwares, most
40168404Spjd *	  probably because of incomplete VRA/DRA cleanup.
41168404Spjd *
42168404Spjd *
43168404Spjd * Thanks goes to:
44168404Spjd *
45168404Spjd *   Shaharil @ SCAN Associates whom relentlessly providing me the
46168404Spjd *   mind blowing Acer Ferrari 4002 WLMi with this ATI IXP hardware.
47168404Spjd *
48168404Spjd *   Reinoud Zandijk <reinoud@NetBSD.org> (auixp), which this driver is
49168404Spjd *   largely based upon although large part of it has been reworked. His
50168404Spjd *   driver is the primary reference and pretty much well documented.
51168404Spjd *
52168404Spjd *   Takashi Iwai (ALSA snd-atiixp), for register definitions and some
53168404Spjd *   random ninja hackery.
54168404Spjd */
55168404Spjd
56168404Spjd#include <dev/sound/pcm/sound.h>
57168404Spjd#include <dev/sound/pcm/ac97.h>
58168404Spjd
59208372Smm#include <dev/pci/pcireg.h>
60208372Smm#include <dev/pci/pcivar.h>
61168404Spjd#include <sys/sysctl.h>
62168404Spjd#include <sys/endian.h>
63168404Spjd
64168404Spjd#include <dev/sound/pci/atiixp.h>
65168404Spjd
66168404SpjdSND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/atiixp.c 167648 2007-03-16 17:18:17Z ariff $");
67168404Spjd
68168404Spjd#define ATI_IXP_DMA_RETRY_MAX	100
69168404Spjd
70168404Spjd#define ATI_IXP_BUFSZ_MIN	4096
71168404Spjd#define ATI_IXP_BUFSZ_MAX	65536
72168404Spjd#define ATI_IXP_BUFSZ_DEFAULT	16384
73168404Spjd
74168404Spjd#define ATI_IXP_BLK_MIN		32
75168404Spjd#define ATI_IXP_BLK_ALIGN	(~(ATI_IXP_BLK_MIN - 1))
76168404Spjd
77168404Spjdstruct atiixp_dma_op {
78168404Spjd	volatile uint32_t addr;
79168404Spjd	volatile uint16_t status;
80168404Spjd	volatile uint16_t size;
81168404Spjd	volatile uint32_t next;
82168404Spjd};
83168404Spjd
84168404Spjdstruct atiixp_info;
85168404Spjd
86168404Spjdstruct atiixp_chinfo {
87168404Spjd	struct snd_dbuf *buffer;
88168404Spjd	struct pcm_channel *channel;
89208372Smm	struct atiixp_info *parent;
90168404Spjd	struct atiixp_dma_op *sgd_table;
91168404Spjd	bus_addr_t sgd_addr;
92168404Spjd	uint32_t enable_bit, flush_bit, linkptr_bit, dt_cur_bit;
93168404Spjd	uint32_t blksz, blkcnt;
94168404Spjd	uint32_t ptr, prevptr;
95168404Spjd	uint32_t fmt;
96168404Spjd	int caps_32bit, dir, active;
97168404Spjd};
98168404Spjd
99168404Spjdstruct atiixp_info {
100168404Spjd	device_t dev;
101168404Spjd
102168404Spjd	bus_space_tag_t st;
103168404Spjd	bus_space_handle_t sh;
104168404Spjd	bus_dma_tag_t parent_dmat;
105168404Spjd	bus_dma_tag_t sgd_dmat;
106168404Spjd	bus_dmamap_t sgd_dmamap;
107168404Spjd	bus_addr_t sgd_addr;
108168404Spjd
109168404Spjd	struct resource *reg, *irq;
110168404Spjd	int regtype, regid, irqid;
111168404Spjd	void *ih;
112168404Spjd	struct ac97_info *codec;
113168404Spjd
114168404Spjd	struct atiixp_chinfo pch;
115168404Spjd	struct atiixp_chinfo rch;
116168404Spjd	struct atiixp_dma_op *sgd_table;
117168404Spjd	struct intr_config_hook delayed_attach;
118168404Spjd
119168404Spjd	uint32_t bufsz;
120168404Spjd	uint32_t codec_not_ready_bits, codec_idx, codec_found;
121168404Spjd	uint32_t blkcnt;
122168404Spjd	int registered_channels;
123168404Spjd
124168404Spjd	struct mtx *lock;
125168404Spjd	struct callout poll_timer;
126168404Spjd	int poll_ticks, polling;
127168404Spjd};
128168404Spjd
129168404Spjd#define atiixp_rd(_sc, _reg)	\
130168404Spjd		bus_space_read_4((_sc)->st, (_sc)->sh, _reg)
131168404Spjd#define atiixp_wr(_sc, _reg, _val)	\
132168404Spjd		bus_space_write_4((_sc)->st, (_sc)->sh, _reg, _val)
133168404Spjd
134168404Spjd#define atiixp_lock(_sc)	snd_mtxlock((_sc)->lock)
135168404Spjd#define atiixp_unlock(_sc)	snd_mtxunlock((_sc)->lock)
136168404Spjd#define atiixp_assert(_sc)	snd_mtxassert((_sc)->lock)
137168404Spjd
138168404Spjdstatic uint32_t atiixp_fmt_32bit[] = {
139168404Spjd	AFMT_STEREO | AFMT_S16_LE,
140168404Spjd	AFMT_STEREO | AFMT_S32_LE,
141168404Spjd	0
142168404Spjd};
143168404Spjd
144168404Spjdstatic uint32_t atiixp_fmt[] = {
145168404Spjd	AFMT_STEREO | AFMT_S16_LE,
146168404Spjd	0
147168404Spjd};
148168404Spjd
149168404Spjdstatic struct pcmchan_caps atiixp_caps_32bit = {
150168404Spjd	ATI_IXP_BASE_RATE,
151168404Spjd	ATI_IXP_BASE_RATE,
152168404Spjd	atiixp_fmt_32bit, 0
153168404Spjd};
154168404Spjd
155168404Spjdstatic struct pcmchan_caps atiixp_caps = {
156168404Spjd	ATI_IXP_BASE_RATE,
157168404Spjd	ATI_IXP_BASE_RATE,
158168404Spjd	atiixp_fmt, 0
159168404Spjd};
160168404Spjd
161168404Spjdstatic const struct {
162168404Spjd	uint16_t vendor;
163168404Spjd	uint16_t devid;
164168404Spjd	char	 *desc;
165168404Spjd} atiixp_hw[] = {
166168404Spjd	{ ATI_VENDOR_ID, ATI_IXP_200_ID, "ATI IXP 200" },
167168404Spjd	{ ATI_VENDOR_ID, ATI_IXP_300_ID, "ATI IXP 300" },
168168404Spjd	{ ATI_VENDOR_ID, ATI_IXP_400_ID, "ATI IXP 400" },
169168404Spjd};
170168404Spjd
171168404Spjdstatic void atiixp_enable_interrupts(struct atiixp_info *);
172168404Spjdstatic void atiixp_disable_interrupts(struct atiixp_info *);
173168404Spjdstatic void atiixp_reset_aclink(struct atiixp_info *);
174168404Spjdstatic void atiixp_flush_dma(struct atiixp_chinfo *);
175168404Spjdstatic void atiixp_enable_dma(struct atiixp_chinfo *);
176168404Spjdstatic void atiixp_disable_dma(struct atiixp_chinfo *);
177168404Spjd
178168404Spjdstatic int atiixp_waitready_codec(struct atiixp_info *);
179168404Spjdstatic int atiixp_rdcd(kobj_t, void *, int);
180168404Spjdstatic int atiixp_wrcd(kobj_t, void *, int, uint32_t);
181168404Spjd
182168404Spjdstatic void  *atiixp_chan_init(kobj_t, void *, struct snd_dbuf *,
183168404Spjd						struct pcm_channel *, int);
184168404Spjdstatic int    atiixp_chan_setformat(kobj_t, void *, uint32_t);
185168404Spjdstatic int    atiixp_chan_setspeed(kobj_t, void *, uint32_t);
186168404Spjdstatic int    atiixp_chan_setfragments(kobj_t, void *, uint32_t, uint32_t);
187168404Spjdstatic int    atiixp_chan_setblocksize(kobj_t, void *, uint32_t);
188168404Spjdstatic void   atiixp_buildsgdt(struct atiixp_chinfo *);
189168404Spjdstatic int    atiixp_chan_trigger(kobj_t, void *, int);
190168404Spjdstatic __inline uint32_t atiixp_dmapos(struct atiixp_chinfo *);
191168404Spjdstatic int    atiixp_chan_getptr(kobj_t, void *);
192168404Spjdstatic struct pcmchan_caps *atiixp_chan_getcaps(kobj_t, void *);
193168404Spjd
194168404Spjdstatic void atiixp_intr(void *);
195168404Spjdstatic void atiixp_dma_cb(void *, bus_dma_segment_t *, int, int);
196168404Spjdstatic void atiixp_chip_pre_init(struct atiixp_info *);
197168404Spjdstatic void atiixp_chip_post_init(void *);
198168404Spjdstatic void atiixp_release_resource(struct atiixp_info *);
199168404Spjdstatic int  atiixp_pci_probe(device_t);
200168404Spjdstatic int  atiixp_pci_attach(device_t);
201168404Spjdstatic int  atiixp_pci_detach(device_t);
202168404Spjdstatic int  atiixp_pci_suspend(device_t);
203168404Spjdstatic int  atiixp_pci_resume(device_t);
204168404Spjd
205168404Spjd/*
206168404Spjd * ATI IXP helper functions
207168404Spjd */
208168404Spjdstatic void
209168404Spjdatiixp_enable_interrupts(struct atiixp_info *sc)
210168404Spjd{
211168404Spjd	uint32_t value;
212168404Spjd
213168404Spjd	/* clear all pending */
214168404Spjd	atiixp_wr(sc, ATI_REG_ISR, 0xffffffff);
215168404Spjd
216168404Spjd	/* enable all relevant interrupt sources we can handle */
217168404Spjd	value = atiixp_rd(sc, ATI_REG_IER);
218168404Spjd
219168404Spjd	value |= ATI_REG_IER_IO_STATUS_EN;
220168404Spjd
221168404Spjd	/*
222168404Spjd	 * Disable / ignore internal xrun/spdf interrupt flags
223168404Spjd	 * since it doesn't interest us (for now).
224168404Spjd	 */
225168404Spjd#if 1
226168404Spjd	value &= ~(ATI_REG_IER_IN_XRUN_EN | ATI_REG_IER_OUT_XRUN_EN |
227168404Spjd	    ATI_REG_IER_SPDF_XRUN_EN | ATI_REG_IER_SPDF_STATUS_EN);
228168404Spjd#else
229168404Spjd	value |= ATI_REG_IER_IN_XRUN_EN;
230168404Spjd	value |= ATI_REG_IER_OUT_XRUN_EN;
231168404Spjd
232168404Spjd	value |= ATI_REG_IER_SPDF_XRUN_EN;
233168404Spjd	value |= ATI_REG_IER_SPDF_STATUS_EN;
234168404Spjd#endif
235168404Spjd
236168404Spjd	atiixp_wr(sc, ATI_REG_IER, value);
237168404Spjd}
238168404Spjd
239168404Spjdstatic void
240168404Spjdatiixp_disable_interrupts(struct atiixp_info *sc)
241168404Spjd{
242168404Spjd	/* disable all interrupt sources */
243168404Spjd	atiixp_wr(sc, ATI_REG_IER, 0);
244185029Spjd
245185029Spjd	/* clear all pending */
246185029Spjd	atiixp_wr(sc, ATI_REG_ISR, 0xffffffff);
247185029Spjd}
248185029Spjd
249185029Spjdstatic void
250185029Spjdatiixp_reset_aclink(struct atiixp_info *sc)
251185029Spjd{
252185029Spjd	uint32_t value, timeout;
253185029Spjd
254185029Spjd	/* if power is down, power it up */
255185029Spjd	value = atiixp_rd(sc, ATI_REG_CMD);
256185029Spjd	if (value & ATI_REG_CMD_POWERDOWN) {
257185029Spjd		/* explicitly enable power */
258185029Spjd		value &= ~ATI_REG_CMD_POWERDOWN;
259185029Spjd		atiixp_wr(sc, ATI_REG_CMD, value);
260185029Spjd
261168404Spjd		/* have to wait at least 10 usec for it to initialise */
262168404Spjd		DELAY(20);
263168404Spjd	}
264168404Spjd
265168404Spjd	/* perform a soft reset */
266168404Spjd	value  = atiixp_rd(sc, ATI_REG_CMD);
267168404Spjd	value |= ATI_REG_CMD_AC_SOFT_RESET;
268168404Spjd	atiixp_wr(sc, ATI_REG_CMD, value);
269168404Spjd
270168404Spjd	/* need to read the CMD reg and wait aprox. 10 usec to init */
271168404Spjd	value  = atiixp_rd(sc, ATI_REG_CMD);
272168404Spjd	DELAY(20);
273168404Spjd
274168404Spjd	/* clear soft reset flag again */
275168404Spjd	value  = atiixp_rd(sc, ATI_REG_CMD);
276168404Spjd	value &= ~ATI_REG_CMD_AC_SOFT_RESET;
277168404Spjd	atiixp_wr(sc, ATI_REG_CMD, value);
278168404Spjd
279168404Spjd	/* check if the ac-link is working; reset device otherwise */
280168404Spjd	timeout = 10;
281168404Spjd	value = atiixp_rd(sc, ATI_REG_CMD);
282168404Spjd	while (!(value & ATI_REG_CMD_ACLINK_ACTIVE) && --timeout) {
283168404Spjd#if 0
284168404Spjd		device_printf(sc->dev, "not up; resetting aclink hardware\n");
285168404Spjd#endif
286168404Spjd
287168404Spjd		/* dip aclink reset but keep the acsync */
288168404Spjd		value &= ~ATI_REG_CMD_AC_RESET;
289168404Spjd		value |=  ATI_REG_CMD_AC_SYNC;
290168404Spjd		atiixp_wr(sc, ATI_REG_CMD, value);
291168404Spjd
292168404Spjd		/* need to read CMD again and wait again (clocking in issue?) */
293168404Spjd		value = atiixp_rd(sc, ATI_REG_CMD);
294168404Spjd		DELAY(20);
295168404Spjd
296168404Spjd		/* assert aclink reset again */
297168404Spjd		value = atiixp_rd(sc, ATI_REG_CMD);
298168404Spjd		value |=  ATI_REG_CMD_AC_RESET;
299168404Spjd		atiixp_wr(sc, ATI_REG_CMD, value);
300168404Spjd
301168404Spjd		/* check if its active now */
302168404Spjd		value = atiixp_rd(sc, ATI_REG_CMD);
303168404Spjd	}
304185029Spjd
305168404Spjd	if (timeout == 0)
306168404Spjd		device_printf(sc->dev, "giving up aclink reset\n");
307168404Spjd#if 0
308168404Spjd	if (timeout != 10)
309168404Spjd		device_printf(sc->dev, "aclink hardware reset successful\n");
310168404Spjd#endif
311168404Spjd
312168404Spjd	/* assert reset and sync for safety */
313168404Spjd	value  = atiixp_rd(sc, ATI_REG_CMD);
314168404Spjd	value |= ATI_REG_CMD_AC_SYNC | ATI_REG_CMD_AC_RESET;
315168404Spjd	atiixp_wr(sc, ATI_REG_CMD, value);
316168404Spjd}
317168404Spjd
318168404Spjdstatic void
319168404Spjdatiixp_flush_dma(struct atiixp_chinfo *ch)
320168404Spjd{
321168404Spjd	atiixp_wr(ch->parent, ATI_REG_FIFO_FLUSH, ch->flush_bit);
322168404Spjd}
323168404Spjd
324168404Spjdstatic void
325168404Spjdatiixp_enable_dma(struct atiixp_chinfo *ch)
326168404Spjd{
327168404Spjd	uint32_t value;
328168404Spjd
329168404Spjd	value = atiixp_rd(ch->parent, ATI_REG_CMD);
330168404Spjd	if (!(value & ch->enable_bit)) {
331168404Spjd		value |= ch->enable_bit;
332168404Spjd		atiixp_wr(ch->parent, ATI_REG_CMD, value);
333168404Spjd	}
334168404Spjd}
335168404Spjd
336168404Spjdstatic void
337168404Spjdatiixp_disable_dma(struct atiixp_chinfo *ch)
338168404Spjd{
339185029Spjd	uint32_t value;
340168404Spjd
341168404Spjd	value = atiixp_rd(ch->parent, ATI_REG_CMD);
342168404Spjd	if (value & ch->enable_bit) {
343168404Spjd		value &= ~ch->enable_bit;
344168404Spjd		atiixp_wr(ch->parent, ATI_REG_CMD, value);
345168404Spjd	}
346168404Spjd}
347168404Spjd
348168404Spjd/*
349168404Spjd * AC97 interface
350168404Spjd */
351168404Spjdstatic int
352168404Spjdatiixp_waitready_codec(struct atiixp_info *sc)
353168404Spjd{
354168404Spjd	int timeout = 500;
355168404Spjd
356168404Spjd	do {
357168404Spjd		if ((atiixp_rd(sc, ATI_REG_PHYS_OUT_ADDR) &
358168404Spjd		    ATI_REG_PHYS_OUT_ADDR_EN) == 0)
359168404Spjd			return (0);
360168404Spjd		DELAY(1);
361168404Spjd	} while (--timeout);
362168404Spjd
363168404Spjd	return (-1);
364168404Spjd}
365168404Spjd
366168404Spjdstatic int
367168404Spjdatiixp_rdcd(kobj_t obj, void *devinfo, int reg)
368168404Spjd{
369168404Spjd	struct atiixp_info *sc = devinfo;
370168404Spjd	uint32_t data;
371168404Spjd	int timeout;
372168404Spjd
373168404Spjd	if (atiixp_waitready_codec(sc))
374168404Spjd		return (-1);
375168404Spjd
376168404Spjd	data = (reg << ATI_REG_PHYS_OUT_ADDR_SHIFT) |
377168404Spjd	    ATI_REG_PHYS_OUT_ADDR_EN | ATI_REG_PHYS_OUT_RW | sc->codec_idx;
378168404Spjd
379168404Spjd	atiixp_wr(sc, ATI_REG_PHYS_OUT_ADDR, data);
380168404Spjd
381168404Spjd	if (atiixp_waitready_codec(sc))
382168404Spjd		return (-1);
383185029Spjd
384168404Spjd	timeout = 500;
385168404Spjd	do {
386168404Spjd		data = atiixp_rd(sc, ATI_REG_PHYS_IN_ADDR);
387168404Spjd		if (data & ATI_REG_PHYS_IN_READ_FLAG)
388168404Spjd			return (data >> ATI_REG_PHYS_IN_DATA_SHIFT);
389168404Spjd		DELAY(1);
390168404Spjd	} while (--timeout);
391168404Spjd
392168404Spjd	if (reg < 0x7c)
393168404Spjd		device_printf(sc->dev, "codec read timeout! (reg 0x%x)\n", reg);
394168404Spjd
395168404Spjd	return (-1);
396168404Spjd}
397168404Spjd
398168404Spjdstatic int
399168404Spjdatiixp_wrcd(kobj_t obj, void *devinfo, int reg, uint32_t data)
400168404Spjd{
401168404Spjd	struct atiixp_info *sc = devinfo;
402168404Spjd
403168404Spjd	if (atiixp_waitready_codec(sc))
404168404Spjd		return (-1);
405168404Spjd
406168404Spjd	data = (data << ATI_REG_PHYS_OUT_DATA_SHIFT) |
407168404Spjd	    (((uint32_t)reg) << ATI_REG_PHYS_OUT_ADDR_SHIFT) |
408168404Spjd	    ATI_REG_PHYS_OUT_ADDR_EN | sc->codec_idx;
409168404Spjd
410168404Spjd	atiixp_wr(sc, ATI_REG_PHYS_OUT_ADDR, data);
411185029Spjd
412168404Spjd	return (0);
413168404Spjd}
414168404Spjd
415168404Spjdstatic kobj_method_t atiixp_ac97_methods[] = {
416168404Spjd	KOBJMETHOD(ac97_read,		atiixp_rdcd),
417168404Spjd	KOBJMETHOD(ac97_write,		atiixp_wrcd),
418168404Spjd	{ 0, 0 }
419200726Sdelphij};
420168404SpjdAC97_DECLARE(atiixp_ac97);
421168404Spjd
422168404Spjd/*
423168404Spjd * Playback / Record channel interface
424168404Spjd */
425168404Spjdstatic void *
426168404Spjdatiixp_chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
427168404Spjd					struct pcm_channel *c, int dir)
428168404Spjd{
429168404Spjd	struct atiixp_info *sc = devinfo;
430168404Spjd	struct atiixp_chinfo *ch;
431168404Spjd	int num;
432185029Spjd
433168404Spjd	atiixp_lock(sc);
434200726Sdelphij
435200726Sdelphij	if (dir == PCMDIR_PLAY) {
436200726Sdelphij		ch = &sc->pch;
437200726Sdelphij		ch->linkptr_bit = ATI_REG_OUT_DMA_LINKPTR;
438200726Sdelphij		ch->enable_bit = ATI_REG_CMD_OUT_DMA_EN | ATI_REG_CMD_SEND_EN;
439200726Sdelphij		ch->flush_bit = ATI_REG_FIFO_OUT_FLUSH;
440200726Sdelphij		ch->dt_cur_bit = ATI_REG_OUT_DMA_DT_CUR;
441200726Sdelphij		/* Native 32bit playback working properly */
442200726Sdelphij		ch->caps_32bit = 1;
443168404Spjd	} else {
444200726Sdelphij		ch = &sc->rch;
445200726Sdelphij		ch->linkptr_bit = ATI_REG_IN_DMA_LINKPTR;
446196703Spjd		ch->enable_bit = ATI_REG_CMD_IN_DMA_EN | ATI_REG_CMD_RECEIVE_EN;
447196703Spjd		ch->flush_bit = ATI_REG_FIFO_IN_FLUSH;
448196703Spjd		ch->dt_cur_bit = ATI_REG_IN_DMA_DT_CUR;
449168404Spjd		/* XXX Native 32bit recording appear to be broken */
450168404Spjd		ch->caps_32bit = 1;
451168404Spjd	}
452168404Spjd
453168404Spjd	ch->buffer = b;
454168404Spjd	ch->parent = sc;
455168404Spjd	ch->channel = c;
456168404Spjd	ch->dir = dir;
457168404Spjd	ch->blkcnt = sc->blkcnt;
458196703Spjd	ch->blksz = sc->bufsz / ch->blkcnt;
459168404Spjd
460168404Spjd	atiixp_unlock(sc);
461168404Spjd
462168404Spjd	if (sndbuf_alloc(ch->buffer, sc->parent_dmat, sc->bufsz) == -1)
463196703Spjd		return (NULL);
464196703Spjd
465185029Spjd	atiixp_lock(sc);
466185029Spjd	num = sc->registered_channels++;
467185029Spjd	ch->sgd_table = &sc->sgd_table[num * ATI_IXP_DMA_CHSEGS_MAX];
468185029Spjd	ch->sgd_addr = sc->sgd_addr + (num * ATI_IXP_DMA_CHSEGS_MAX *
469185029Spjd	    sizeof(struct atiixp_dma_op));
470168404Spjd	atiixp_disable_dma(ch);
471168404Spjd	atiixp_unlock(sc);
472168404Spjd
473168404Spjd	return (ch);
474168404Spjd}
475168404Spjd
476168404Spjdstatic int
477168404Spjdatiixp_chan_setformat(kobj_t obj, void *data, uint32_t format)
478168404Spjd{
479168404Spjd	struct atiixp_chinfo *ch = data;
480168404Spjd	struct atiixp_info *sc = ch->parent;
481168404Spjd	uint32_t value;
482168404Spjd
483168404Spjd	atiixp_lock(sc);
484168404Spjd	if (ch->dir == PCMDIR_REC) {
485168404Spjd		value = atiixp_rd(sc, ATI_REG_CMD);
486168404Spjd		value &= ~ATI_REG_CMD_INTERLEAVE_IN;
487168404Spjd		if ((format & AFMT_32BIT) == 0)
488168404Spjd			value |= ATI_REG_CMD_INTERLEAVE_IN;
489168404Spjd		atiixp_wr(sc, ATI_REG_CMD, value);
490168404Spjd	} else {
491168404Spjd		value = atiixp_rd(sc, ATI_REG_OUT_DMA_SLOT);
492168404Spjd		value &= ~ATI_REG_OUT_DMA_SLOT_MASK;
493168404Spjd		/* We do not have support for more than 2 channels, _yet_. */
494168404Spjd		value |= ATI_REG_OUT_DMA_SLOT_BIT(3) |
495168404Spjd		    ATI_REG_OUT_DMA_SLOT_BIT(4);
496168404Spjd		value |= 0x04 << ATI_REG_OUT_DMA_THRESHOLD_SHIFT;
497168404Spjd		atiixp_wr(sc, ATI_REG_OUT_DMA_SLOT, value);
498168404Spjd		value = atiixp_rd(sc, ATI_REG_CMD);
499168404Spjd		value &= ~ATI_REG_CMD_INTERLEAVE_OUT;
500168404Spjd		if ((format & AFMT_32BIT) == 0)
501168404Spjd			value |= ATI_REG_CMD_INTERLEAVE_OUT;
502168404Spjd		atiixp_wr(sc, ATI_REG_CMD, value);
503168404Spjd		value = atiixp_rd(sc, ATI_REG_6CH_REORDER);
504168404Spjd		value &= ~ATI_REG_6CH_REORDER_EN;
505168404Spjd		atiixp_wr(sc, ATI_REG_6CH_REORDER, value);
506168404Spjd	}
507168404Spjd	ch->fmt = format;
508168404Spjd	atiixp_unlock(sc);
509168404Spjd
510168404Spjd	return (0);
511168404Spjd}
512168404Spjd
513168404Spjdstatic int
514168404Spjdatiixp_chan_setspeed(kobj_t obj, void *data, uint32_t spd)
515168404Spjd{
516168404Spjd	/* XXX We're supposed to do VRA/DRA processing right here */
517168404Spjd	return (ATI_IXP_BASE_RATE);
518168404Spjd}
519168404Spjd
520168404Spjdstatic int
521168404Spjdatiixp_chan_setfragments(kobj_t obj, void *data,
522168404Spjd					uint32_t blksz, uint32_t blkcnt)
523168404Spjd{
524168404Spjd	struct atiixp_chinfo *ch = data;
525168404Spjd	struct atiixp_info *sc = ch->parent;
526168404Spjd
527168404Spjd	blksz &= ATI_IXP_BLK_ALIGN;
528168404Spjd
529168404Spjd	if (blksz > (sndbuf_getmaxsize(ch->buffer) / ATI_IXP_DMA_CHSEGS_MIN))
530168404Spjd		blksz = sndbuf_getmaxsize(ch->buffer) / ATI_IXP_DMA_CHSEGS_MIN;
531168404Spjd	if (blksz < ATI_IXP_BLK_MIN)
532168404Spjd		blksz = ATI_IXP_BLK_MIN;
533168404Spjd	if (blkcnt > ATI_IXP_DMA_CHSEGS_MAX)
534168404Spjd		blkcnt = ATI_IXP_DMA_CHSEGS_MAX;
535168404Spjd	if (blkcnt < ATI_IXP_DMA_CHSEGS_MIN)
536168404Spjd		blkcnt = ATI_IXP_DMA_CHSEGS_MIN;
537168404Spjd
538168404Spjd	while ((blksz * blkcnt) > sndbuf_getmaxsize(ch->buffer)) {
539168404Spjd		if ((blkcnt >> 1) >= ATI_IXP_DMA_CHSEGS_MIN)
540168404Spjd			blkcnt >>= 1;
541168404Spjd		else if ((blksz >> 1) >= ATI_IXP_BLK_MIN)
542168404Spjd			blksz >>= 1;
543168404Spjd		else
544168404Spjd			break;
545168404Spjd	}
546168404Spjd
547185029Spjd	if ((sndbuf_getblksz(ch->buffer) != blksz ||
548185029Spjd	    sndbuf_getblkcnt(ch->buffer) != blkcnt) &&
549185029Spjd	    sndbuf_resize(ch->buffer, blkcnt, blksz) != 0)
550185029Spjd		device_printf(sc->dev, "%s: failed blksz=%u blkcnt=%u\n",
551185029Spjd		    __func__, blksz, blkcnt);
552185029Spjd
553168404Spjd	ch->blksz = sndbuf_getblksz(ch->buffer);
554168404Spjd	ch->blkcnt = sndbuf_getblkcnt(ch->buffer);
555168404Spjd
556168404Spjd	return (1);
557168404Spjd}
558168404Spjd
559168404Spjdstatic int
560168404Spjdatiixp_chan_setblocksize(kobj_t obj, void *data, uint32_t blksz)
561168404Spjd{
562168404Spjd	struct atiixp_chinfo *ch = data;
563168404Spjd	struct atiixp_info *sc = ch->parent;
564168404Spjd
565168404Spjd	atiixp_chan_setfragments(obj, data, blksz, sc->blkcnt);
566168404Spjd
567168404Spjd	return (ch->blksz);
568168404Spjd}
569168404Spjd
570168404Spjdstatic void
571168404Spjdatiixp_buildsgdt(struct atiixp_chinfo *ch)
572168404Spjd{
573168404Spjd	struct atiixp_info *sc = ch->parent;
574168404Spjd	uint32_t addr, blksz, blkcnt;
575168404Spjd	int i;
576168404Spjd
577168404Spjd	addr = sndbuf_getbufaddr(ch->buffer);
578168404Spjd
579168404Spjd	if (sc->polling != 0) {
580168404Spjd		blksz = ch->blksz * ch->blkcnt;
581168404Spjd		blkcnt = 1;
582168404Spjd	} else {
583168404Spjd		blksz = ch->blksz;
584168404Spjd		blkcnt = ch->blkcnt;
585168404Spjd	}
586168404Spjd
587168404Spjd	for (i = 0; i < blkcnt; i++) {
588168404Spjd		ch->sgd_table[i].addr = htole32(addr + (i * blksz));
589168404Spjd		ch->sgd_table[i].status = htole16(0);
590168404Spjd		ch->sgd_table[i].size = htole16(blksz >> 2);
591168404Spjd		ch->sgd_table[i].next = htole32((uint32_t)ch->sgd_addr +
592168404Spjd		    (((i + 1) % blkcnt) * sizeof(struct atiixp_dma_op)));
593168404Spjd	}
594168404Spjd}
595168404Spjd
596185029Spjdstatic __inline uint32_t
597168404Spjdatiixp_dmapos(struct atiixp_chinfo *ch)
598185029Spjd{
599185029Spjd	struct atiixp_info *sc = ch->parent;
600168404Spjd	uint32_t reg, addr, sz, retry;
601168404Spjd	volatile uint32_t ptr;
602168404Spjd
603168404Spjd	reg = ch->dt_cur_bit;
604168404Spjd	addr = sndbuf_getbufaddr(ch->buffer);
605168404Spjd	sz = ch->blkcnt * ch->blksz;
606168404Spjd	retry = ATI_IXP_DMA_RETRY_MAX;
607168404Spjd
608168404Spjd	do {
609168404Spjd		ptr = atiixp_rd(sc, reg);
610168404Spjd		if (ptr < addr)
611168404Spjd			continue;
612168404Spjd		ptr -= addr;
613168404Spjd		if (ptr < sz) {
614168404Spjd#if 0
615168404Spjd#ifdef ATI_IXP_DEBUG
616168404Spjd			if ((ptr & ~(ch->blksz - 1)) != ch->ptr) {
617168404Spjd				uint32_t delta;
618168404Spjd
619168404Spjd				delta = (sz + ptr - ch->prevptr) % sz;
620168404Spjd#ifndef ATI_IXP_DEBUG_VERBOSE
621168404Spjd				if (delta < ch->blksz)
622168404Spjd#endif
623168404Spjd					device_printf(sc->dev,
624168404Spjd						"PCMDIR_%s: incoherent DMA "
625168404Spjd						"prevptr=%u ptr=%u "
626168404Spjd						"ptr=%u blkcnt=%u "
627168404Spjd						"[delta=%u != blksz=%u] "
628168404Spjd						"(%s)\n",
629168404Spjd						(ch->dir == PCMDIR_PLAY) ?
630168404Spjd						"PLAY" : "REC",
631168404Spjd						ch->prevptr, ptr,
632168404Spjd						ch->ptr, ch->blkcnt,
633168404Spjd						delta, ch->blksz,
634168404Spjd						(delta < ch->blksz) ?
635168404Spjd						"OVERLAPPED!" : "Ok");
636168404Spjd				ch->ptr = ptr & ~(ch->blksz - 1);
637168404Spjd			}
638168404Spjd			ch->prevptr = ptr;
639185029Spjd#endif
640185029Spjd#endif
641185029Spjd			return (ptr);
642185029Spjd		}
643185029Spjd	} while (--retry);
644185029Spjd
645168404Spjd	device_printf(sc->dev, "PCMDIR_%s: invalid DMA pointer ptr=%u\n",
646168404Spjd	    (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC", ptr);
647185029Spjd
648185029Spjd	return (0);
649185029Spjd}
650185029Spjd
651185029Spjdstatic __inline int
652185029Spjdatiixp_poll_channel(struct atiixp_chinfo *ch)
653185029Spjd{
654185029Spjd	uint32_t sz, delta;
655168404Spjd	volatile uint32_t ptr;
656168404Spjd
657168404Spjd	if (ch->active == 0)
658168404Spjd		return (0);
659168404Spjd
660168404Spjd	sz = ch->blksz * ch->blkcnt;
661168404Spjd	ptr = atiixp_dmapos(ch);
662185029Spjd	ch->ptr = ptr;
663168404Spjd	ptr %= sz;
664185029Spjd	ptr &= ~(ch->blksz - 1);
665168404Spjd	delta = (sz + ptr - ch->prevptr) % sz;
666168404Spjd
667168404Spjd	if (delta < ch->blksz)
668168404Spjd		return (0);
669168404Spjd
670168404Spjd	ch->prevptr = ptr;
671168404Spjd
672168404Spjd	return (1);
673168404Spjd}
674168404Spjd
675168404Spjd#define atiixp_chan_active(sc)	((sc)->pch.active + (sc)->rch.active)
676168404Spjd
677168404Spjdstatic void
678168404Spjdatiixp_poll_callback(void *arg)
679168404Spjd{
680168404Spjd	struct atiixp_info *sc = arg;
681168404Spjd	uint32_t trigger = 0;
682168404Spjd
683168404Spjd	if (sc == NULL)
684168404Spjd		return;
685168404Spjd
686168404Spjd	atiixp_lock(sc);
687168404Spjd	if (sc->polling == 0 || atiixp_chan_active(sc) == 0) {
688168404Spjd		atiixp_unlock(sc);
689168404Spjd		return;
690168404Spjd	}
691168404Spjd
692168404Spjd	trigger |= (atiixp_poll_channel(&sc->pch) != 0) ? 1 : 0;
693168404Spjd	trigger |= (atiixp_poll_channel(&sc->rch) != 0) ? 2 : 0;
694168404Spjd
695168404Spjd	/* XXX */
696168404Spjd	callout_reset(&sc->poll_timer, 1/*sc->poll_ticks*/,
697168404Spjd	    atiixp_poll_callback, sc);
698168404Spjd
699168404Spjd	atiixp_unlock(sc);
700185029Spjd
701168404Spjd	if (trigger & 1)
702168404Spjd		chn_intr(sc->pch.channel);
703168404Spjd	if (trigger & 2)
704168404Spjd		chn_intr(sc->rch.channel);
705168404Spjd}
706168404Spjd
707168404Spjdstatic int
708168404Spjdatiixp_chan_trigger(kobj_t obj, void *data, int go)
709168404Spjd{
710168404Spjd	struct atiixp_chinfo *ch = data;
711168404Spjd	struct atiixp_info *sc = ch->parent;
712168404Spjd	uint32_t value;
713168404Spjd	int pollticks;
714168404Spjd
715168404Spjd	atiixp_lock(sc);
716168404Spjd
717168404Spjd	switch (go) {
718168404Spjd	case PCMTRIG_START:
719168404Spjd		atiixp_flush_dma(ch);
720168404Spjd		atiixp_buildsgdt(ch);
721168404Spjd		atiixp_wr(sc, ch->linkptr_bit, 0);
722168404Spjd		atiixp_enable_dma(ch);
723185029Spjd		atiixp_wr(sc, ch->linkptr_bit,
724168404Spjd		    (uint32_t)ch->sgd_addr | ATI_REG_LINKPTR_EN);
725168404Spjd		if (sc->polling != 0) {
726168404Spjd			ch->ptr = 0;
727168404Spjd			ch->prevptr = 0;
728168404Spjd			pollticks = ((uint64_t)hz * ch->blksz) /
729168404Spjd			    ((uint64_t)sndbuf_getbps(ch->buffer) *
730168404Spjd			    sndbuf_getspd(ch->buffer));
731168404Spjd			pollticks >>= 2;
732168404Spjd			if (pollticks > hz)
733168404Spjd				pollticks = hz;
734168404Spjd			if (pollticks < 1)
735168404Spjd				pollticks = 1;
736168404Spjd			if (atiixp_chan_active(sc) == 0 ||
737168404Spjd			    pollticks < sc->poll_ticks) {
738168404Spjd			    	if (bootverbose) {
739168404Spjd					if (atiixp_chan_active(sc) == 0)
740168404Spjd						device_printf(sc->dev,
741168404Spjd						    "%s: pollticks=%d\n",
742168404Spjd						    __func__, pollticks);
743168404Spjd					else
744168404Spjd						device_printf(sc->dev,
745168404Spjd						    "%s: pollticks %d -> %d\n",
746168404Spjd						    __func__, sc->poll_ticks,
747168404Spjd						    pollticks);
748168404Spjd				}
749168404Spjd				sc->poll_ticks = pollticks;
750168404Spjd				callout_reset(&sc->poll_timer, 1,
751168404Spjd				    atiixp_poll_callback, sc);
752168404Spjd			}
753168404Spjd		}
754168404Spjd		ch->active = 1;
755168404Spjd		break;
756168404Spjd	case PCMTRIG_STOP:
757168404Spjd	case PCMTRIG_ABORT:
758168404Spjd		atiixp_disable_dma(ch);
759168404Spjd		atiixp_flush_dma(ch);
760168404Spjd		ch->active = 0;
761168404Spjd		if (sc->polling != 0) {
762168404Spjd			if (atiixp_chan_active(sc) == 0) {
763168404Spjd				callout_stop(&sc->poll_timer);
764168404Spjd				sc->poll_ticks = 1;
765168404Spjd			} else {
766168404Spjd				if (sc->pch.active != 0)
767168404Spjd					ch = &sc->pch;
768168404Spjd				else
769168404Spjd					ch = &sc->rch;
770168404Spjd				pollticks = ((uint64_t)hz * ch->blksz) /
771185029Spjd				    ((uint64_t)sndbuf_getbps(ch->buffer) *
772168404Spjd				    sndbuf_getspd(ch->buffer));
773168404Spjd				pollticks >>= 2;
774168404Spjd				if (pollticks > hz)
775168404Spjd					pollticks = hz;
776168404Spjd				if (pollticks < 1)
777168404Spjd					pollticks = 1;
778168404Spjd				if (pollticks > sc->poll_ticks) {
779168404Spjd					if (bootverbose)
780168404Spjd						device_printf(sc->dev,
781168404Spjd						    "%s: pollticks %d -> %d\n",
782168404Spjd						    __func__, sc->poll_ticks,
783168404Spjd						    pollticks);
784168404Spjd					sc->poll_ticks = pollticks;
785168404Spjd					callout_reset(&sc->poll_timer,
786168404Spjd					    1, atiixp_poll_callback,
787168404Spjd					    sc);
788168404Spjd				}
789168404Spjd			}
790168404Spjd		}
791168404Spjd		break;
792168404Spjd	default:
793168404Spjd		atiixp_unlock(sc);
794168404Spjd		return (0);
795168404Spjd		break;
796185029Spjd	}
797168404Spjd
798168404Spjd	/* Update bus busy status */
799168404Spjd	value = atiixp_rd(sc, ATI_REG_IER);
800168404Spjd	if (atiixp_rd(sc, ATI_REG_CMD) & (ATI_REG_CMD_SEND_EN |
801168404Spjd	    ATI_REG_CMD_RECEIVE_EN | ATI_REG_CMD_SPDF_OUT_EN))
802168404Spjd		value |= ATI_REG_IER_SET_BUS_BUSY;
803168404Spjd	else
804168404Spjd		value &= ~ATI_REG_IER_SET_BUS_BUSY;
805168404Spjd	atiixp_wr(sc, ATI_REG_IER, value);
806185029Spjd
807185029Spjd	atiixp_unlock(sc);
808185029Spjd
809168404Spjd	return (0);
810185029Spjd}
811185029Spjd
812168404Spjdstatic int
813168404Spjdatiixp_chan_getptr(kobj_t obj, void *data)
814168404Spjd{
815168404Spjd	struct atiixp_chinfo *ch = data;
816168404Spjd	struct atiixp_info *sc = ch->parent;
817168404Spjd	uint32_t ptr;
818168404Spjd
819168404Spjd	atiixp_lock(sc);
820185029Spjd	if (sc->polling != 0)
821168404Spjd		ptr = ch->ptr;
822168404Spjd	else
823168404Spjd		ptr = atiixp_dmapos(ch);
824168404Spjd	atiixp_unlock(sc);
825168404Spjd
826168404Spjd	return (ptr);
827168404Spjd}
828168404Spjd
829168404Spjdstatic struct pcmchan_caps *
830168404Spjdatiixp_chan_getcaps(kobj_t obj, void *data)
831168404Spjd{
832185029Spjd	struct atiixp_chinfo *ch = data;
833168404Spjd
834185029Spjd	if (ch->caps_32bit)
835168404Spjd		return (&atiixp_caps_32bit);
836168404Spjd	return (&atiixp_caps);
837168404Spjd}
838168404Spjd
839168404Spjdstatic kobj_method_t atiixp_chan_methods[] = {
840168404Spjd	KOBJMETHOD(channel_init,		atiixp_chan_init),
841168404Spjd	KOBJMETHOD(channel_setformat,		atiixp_chan_setformat),
842185029Spjd	KOBJMETHOD(channel_setspeed,		atiixp_chan_setspeed),
843185029Spjd	KOBJMETHOD(channel_setblocksize,	atiixp_chan_setblocksize),
844185029Spjd	KOBJMETHOD(channel_setfragments,	atiixp_chan_setfragments),
845185029Spjd	KOBJMETHOD(channel_trigger,		atiixp_chan_trigger),
846185029Spjd	KOBJMETHOD(channel_getptr,		atiixp_chan_getptr),
847185029Spjd	KOBJMETHOD(channel_getcaps,		atiixp_chan_getcaps),
848185029Spjd	{ 0, 0 }
849185029Spjd};
850185029SpjdCHANNEL_DECLARE(atiixp_chan);
851185029Spjd
852185029Spjd/*
853185029Spjd * PCI driver interface
854185029Spjd */
855185029Spjdstatic void
856185029Spjdatiixp_intr(void *p)
857185029Spjd{
858168404Spjd	struct atiixp_info *sc = p;
859168404Spjd	uint32_t status, enable, detected_codecs;
860168404Spjd	uint32_t trigger = 0;
861168404Spjd
862168404Spjd	atiixp_lock(sc);
863168404Spjd	if (sc->polling != 0) {
864168404Spjd		atiixp_unlock(sc);
865168404Spjd		return;
866168404Spjd	}
867168404Spjd	status = atiixp_rd(sc, ATI_REG_ISR);
868168404Spjd
869168404Spjd	if (status == 0) {
870168404Spjd		atiixp_unlock(sc);
871168404Spjd		return;
872168404Spjd	}
873168404Spjd
874168404Spjd	if ((status & ATI_REG_ISR_OUT_STATUS) && sc->pch.active != 0)
875168404Spjd		trigger |= 1;
876168404Spjd	if ((status & ATI_REG_ISR_IN_STATUS) && sc->rch.active != 0)
877168404Spjd		trigger |= 2;
878168404Spjd
879168404Spjd#if 0
880168404Spjd	if (status & ATI_REG_ISR_IN_XRUN) {
881168404Spjd		device_printf(sc->dev,
882168404Spjd			"Recieve IN XRUN interrupt\n");
883168404Spjd	}
884168404Spjd	if (status & ATI_REG_ISR_OUT_XRUN) {
885168404Spjd		device_printf(sc->dev,
886168404Spjd			"Recieve OUT XRUN interrupt\n");
887168404Spjd	}
888168404Spjd#endif
889168404Spjd
890168404Spjd	if (status & CODEC_CHECK_BITS) {
891168404Spjd		/* mark missing codecs as not ready */
892168404Spjd		detected_codecs = status & CODEC_CHECK_BITS;
893168404Spjd		sc->codec_not_ready_bits |= detected_codecs;
894168404Spjd
895168404Spjd		/* disable detected interupt sources */
896168404Spjd		enable  = atiixp_rd(sc, ATI_REG_IER);
897168404Spjd		enable &= ~detected_codecs;
898168404Spjd		atiixp_wr(sc, ATI_REG_IER, enable);
899168404Spjd	}
900168404Spjd
901168404Spjd	/* acknowledge */
902168404Spjd	atiixp_wr(sc, ATI_REG_ISR, status);
903168404Spjd	atiixp_unlock(sc);
904168404Spjd
905168404Spjd	if (trigger & 1)
906168404Spjd		chn_intr(sc->pch.channel);
907168404Spjd	if (trigger & 2)
908168404Spjd		chn_intr(sc->rch.channel);
909185029Spjd}
910185029Spjd
911168404Spjdstatic void
912168404Spjdatiixp_dma_cb(void *p, bus_dma_segment_t *bds, int a, int b)
913168404Spjd{
914168404Spjd	struct atiixp_info *sc = (struct atiixp_info *)p;
915168404Spjd	sc->sgd_addr = bds->ds_addr;
916168404Spjd}
917168404Spjd
918168404Spjdstatic void
919168404Spjdatiixp_chip_pre_init(struct atiixp_info *sc)
920168404Spjd{
921168404Spjd	uint32_t value;
922168404Spjd
923168404Spjd	atiixp_lock(sc);
924168404Spjd
925168404Spjd	/* disable interrupts */
926168404Spjd	atiixp_disable_interrupts(sc);
927168404Spjd
928168404Spjd	/* clear all DMA enables (preserving rest of settings) */
929168404Spjd	value = atiixp_rd(sc, ATI_REG_CMD);
930168404Spjd	value &= ~(ATI_REG_CMD_IN_DMA_EN | ATI_REG_CMD_OUT_DMA_EN |
931168404Spjd	    ATI_REG_CMD_SPDF_OUT_EN );
932168404Spjd	atiixp_wr(sc, ATI_REG_CMD, value);
933168404Spjd
934168404Spjd	/* reset aclink */
935168404Spjd	atiixp_reset_aclink(sc);
936168404Spjd
937168404Spjd	sc->codec_not_ready_bits = 0;
938168404Spjd
939168404Spjd	/* enable all codecs to interrupt as well as the new frame interrupt */
940168404Spjd	atiixp_wr(sc, ATI_REG_IER, CODEC_CHECK_BITS);
941168404Spjd
942168404Spjd	atiixp_unlock(sc);
943168404Spjd}
944168404Spjd
945168404Spjd#ifdef SND_DYNSYSCTL
946168404Spjdstatic int
947168404Spjdsysctl_atiixp_polling(SYSCTL_HANDLER_ARGS)
948168404Spjd{
949168404Spjd	struct atiixp_info *sc;
950168404Spjd	device_t dev;
951168404Spjd	int err, val;
952168404Spjd
953168404Spjd	dev = oidp->oid_arg1;
954168404Spjd	sc = pcm_getdevinfo(dev);
955168404Spjd	if (sc == NULL)
956168404Spjd		return (EINVAL);
957168404Spjd	atiixp_lock(sc);
958168404Spjd	val = sc->polling;
959168404Spjd	atiixp_unlock(sc);
960168404Spjd	err = sysctl_handle_int(oidp, &val, sizeof(val), req);
961168404Spjd
962168404Spjd	if (err || req->newptr == NULL)
963168404Spjd		return (err);
964168404Spjd	if (val < 0 || val > 1)
965168404Spjd		return (EINVAL);
966168404Spjd
967168404Spjd	atiixp_lock(sc);
968168404Spjd	if (val != sc->polling) {
969168404Spjd		if (atiixp_chan_active(sc) != 0)
970168404Spjd			err = EBUSY;
971185029Spjd		else if (val == 0) {
972168404Spjd			atiixp_enable_interrupts(sc);
973185029Spjd			sc->polling = 0;
974168404Spjd			DELAY(1000);
975168404Spjd		} else {
976168404Spjd			atiixp_disable_interrupts(sc);
977185029Spjd			sc->polling = 1;
978185029Spjd			DELAY(1000);
979168404Spjd		}
980168404Spjd	}
981168404Spjd	atiixp_unlock(sc);
982168404Spjd
983168404Spjd	return (err);
984168404Spjd}
985168404Spjd#endif
986168404Spjd
987168404Spjdstatic void
988168404Spjdatiixp_chip_post_init(void *arg)
989168404Spjd{
990168404Spjd	struct atiixp_info *sc = (struct atiixp_info *)arg;
991185029Spjd	uint32_t subdev;
992185029Spjd	int i, timeout, found, polling;
993168404Spjd	char status[SND_STATUSLEN];
994168404Spjd
995168404Spjd	atiixp_lock(sc);
996185029Spjd
997185029Spjd	if (sc->delayed_attach.ich_func) {
998185029Spjd		config_intrhook_disestablish(&sc->delayed_attach);
999185029Spjd		sc->delayed_attach.ich_func = NULL;
1000185029Spjd	}
1001185029Spjd
1002185029Spjd	polling = sc->polling;
1003168404Spjd	sc->polling = 0;
1004168404Spjd
1005168404Spjd	/* wait for the interrupts to happen */
1006168404Spjd	timeout = 100;
1007168404Spjd	do {
1008168404Spjd		msleep(sc, sc->lock, PWAIT, "ixpslp", 1);
1009168404Spjd		if (sc->codec_not_ready_bits)
1010168404Spjd			break;
1011168404Spjd	} while (--timeout);
1012168404Spjd
1013168404Spjd	sc->polling = polling;
1014168404Spjd	atiixp_disable_interrupts(sc);
1015168404Spjd
1016168404Spjd	if (timeout == 0) {
1017168404Spjd		device_printf(sc->dev,
1018168404Spjd			"WARNING: timeout during codec detection; "
1019168404Spjd			"codecs might be present but haven't interrupted\n");
1020168404Spjd		atiixp_unlock(sc);
1021168404Spjd		goto postinitbad;
1022168404Spjd	}
1023168404Spjd
1024168404Spjd	found = 0;
1025168404Spjd
1026168404Spjd	/*
1027168404Spjd	 * ATI IXP can have upto 3 codecs, but single codec should be
1028168404Spjd	 * suffice for now.
1029168404Spjd	 */
1030168404Spjd	if (!(sc->codec_not_ready_bits & ATI_REG_ISR_CODEC0_NOT_READY)) {
1031168404Spjd		/* codec 0 present */
1032168404Spjd		sc->codec_found++;
1033168404Spjd		sc->codec_idx = 0;
1034168404Spjd		found++;
1035185029Spjd	}
1036168404Spjd
1037168404Spjd	if (!(sc->codec_not_ready_bits & ATI_REG_ISR_CODEC1_NOT_READY)) {
1038185029Spjd		/* codec 1 present */
1039185029Spjd		sc->codec_found++;
1040185029Spjd	}
1041168404Spjd
1042185029Spjd	if (!(sc->codec_not_ready_bits & ATI_REG_ISR_CODEC2_NOT_READY)) {
1043185029Spjd		/* codec 2 present */
1044185029Spjd		sc->codec_found++;
1045185029Spjd	}
1046185029Spjd
1047168404Spjd	atiixp_unlock(sc);
1048185029Spjd
1049185029Spjd	if (found == 0)
1050185029Spjd		goto postinitbad;
1051185029Spjd
1052185029Spjd	/* create/init mixer */
1053185029Spjd	sc->codec = AC97_CREATE(sc->dev, sc, atiixp_ac97);
1054185029Spjd	if (sc->codec == NULL)
1055185029Spjd		goto postinitbad;
1056185029Spjd
1057185029Spjd	subdev = (pci_get_subdevice(sc->dev) << 16) |
1058185029Spjd	    pci_get_subvendor(sc->dev);
1059185029Spjd	switch (subdev) {
1060185029Spjd	case 0x11831043:	/* ASUS A6R */
1061185029Spjd	case 0x2043161f:	/* Maxselect x710s - http://maxselect.ru/ */
1062168404Spjd		ac97_setflags(sc->codec, ac97_getflags(sc->codec) |
1063185029Spjd		    AC97_F_EAPD_INV);
1064168404Spjd		break;
1065185029Spjd	default:
1066185029Spjd		break;
1067168404Spjd	}
1068185029Spjd
1069185029Spjd	mixer_init(sc->dev, ac97_getmixerclass(), sc->codec);
1070185029Spjd
1071185029Spjd	if (pcm_register(sc->dev, sc, ATI_IXP_NPCHAN, ATI_IXP_NRCHAN))
1072185029Spjd		goto postinitbad;
1073185029Spjd
1074185029Spjd	for (i = 0; i < ATI_IXP_NPCHAN; i++)
1075185029Spjd		pcm_addchan(sc->dev, PCMDIR_PLAY, &atiixp_chan_class, sc);
1076185029Spjd	for (i = 0; i < ATI_IXP_NRCHAN; i++)
1077185029Spjd		pcm_addchan(sc->dev, PCMDIR_REC, &atiixp_chan_class, sc);
1078185029Spjd
1079185029Spjd#ifdef SND_DYNSYSCTL
1080185029Spjd	SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev),
1081185029Spjd	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO,
1082185029Spjd	    "polling", CTLTYPE_INT | CTLFLAG_RW, sc->dev, sizeof(sc->dev),
1083185029Spjd	    sysctl_atiixp_polling, "I", "Enable polling mode");
1084185029Spjd#endif
1085185029Spjd
1086185029Spjd	snprintf(status, SND_STATUSLEN, "at memory 0x%lx irq %ld %s",
1087185029Spjd	    rman_get_start(sc->reg), rman_get_start(sc->irq),
1088185029Spjd	    PCM_KLDSTRING(snd_atiixp));
1089185029Spjd
1090185029Spjd	pcm_setstatus(sc->dev, status);
1091168404Spjd
1092168404Spjd	atiixp_lock(sc);
1093168404Spjd	if (sc->polling == 0)
1094185029Spjd		atiixp_enable_interrupts(sc);
1095185029Spjd	atiixp_unlock(sc);
1096185029Spjd
1097185029Spjd	return;
1098185029Spjd
1099168404Spjdpostinitbad:
1100168404Spjd	atiixp_release_resource(sc);
1101168404Spjd}
1102185029Spjd
1103185029Spjdstatic void
1104185029Spjdatiixp_release_resource(struct atiixp_info *sc)
1105168404Spjd{
1106185029Spjd	if (sc == NULL)
1107185029Spjd		return;
1108185029Spjd	if (sc->codec) {
1109185029Spjd		ac97_destroy(sc->codec);
1110185029Spjd		sc->codec = NULL;
1111185029Spjd	}
1112185029Spjd	if (sc->ih) {
1113185029Spjd		bus_teardown_intr(sc->dev, sc->irq, sc->ih);
1114185029Spjd		sc->ih = 0;
1115185029Spjd	}
1116185029Spjd	if (sc->reg) {
1117185029Spjd		bus_release_resource(sc->dev, sc->regtype, sc->regid, sc->reg);
1118168404Spjd		sc->reg = 0;
1119185029Spjd	}
1120185029Spjd	if (sc->irq) {
1121185029Spjd		bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irqid, sc->irq);
1122185029Spjd		sc->irq = 0;
1123185029Spjd	}
1124168404Spjd	if (sc->parent_dmat) {
1125168404Spjd		bus_dma_tag_destroy(sc->parent_dmat);
1126168404Spjd		sc->parent_dmat = 0;
1127168404Spjd	}
1128168404Spjd	if (sc->sgd_dmamap) {
1129168404Spjd		bus_dmamap_unload(sc->sgd_dmat, sc->sgd_dmamap);
1130168404Spjd		sc->sgd_dmamap = 0;
1131168404Spjd	}
1132168404Spjd	if (sc->sgd_dmat) {
1133168404Spjd		bus_dma_tag_destroy(sc->sgd_dmat);
1134168404Spjd		sc->sgd_dmat = 0;
1135168404Spjd	}
1136168404Spjd	if (sc->lock) {
1137168404Spjd		snd_mtxfree(sc->lock);
1138168404Spjd		sc->lock = NULL;
1139168404Spjd	}
1140168404Spjd}
1141168404Spjd
1142168404Spjdstatic int
1143185029Spjdatiixp_pci_probe(device_t dev)
1144168404Spjd{
1145168404Spjd	int i;
1146185029Spjd	uint16_t devid, vendor;
1147185029Spjd
1148185029Spjd	vendor = pci_get_vendor(dev);
1149168404Spjd	devid = pci_get_device(dev);
1150168404Spjd	for (i = 0; i < sizeof(atiixp_hw) / sizeof(atiixp_hw[0]); i++) {
1151168404Spjd		if (vendor == atiixp_hw[i].vendor &&
1152168404Spjd		    devid == atiixp_hw[i].devid) {
1153168404Spjd			device_set_desc(dev, atiixp_hw[i].desc);
1154168404Spjd			return (BUS_PROBE_DEFAULT);
1155168404Spjd		}
1156168404Spjd	}
1157168404Spjd
1158168404Spjd	return (ENXIO);
1159168404Spjd}
1160168404Spjd
1161168404Spjdstatic int
1162168404Spjdatiixp_pci_attach(device_t dev)
1163168404Spjd{
1164168404Spjd	struct atiixp_info *sc;
1165168404Spjd	int i;
1166168404Spjd
1167168404Spjd	if ((sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) {
1168168404Spjd		device_printf(dev, "cannot allocate softc\n");
1169168404Spjd		return (ENXIO);
1170168404Spjd	}
1171168404Spjd
1172168404Spjd	sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_atiixp softc");
1173168404Spjd	sc->dev = dev;
1174168404Spjd
1175168404Spjd	callout_init(&sc->poll_timer, CALLOUT_MPSAFE);
1176168404Spjd	sc->poll_ticks = 1;
1177168404Spjd
1178168404Spjd	if (resource_int_value(device_get_name(sc->dev),
1179168404Spjd	    device_get_unit(sc->dev), "polling", &i) == 0 && i != 0)
1180168404Spjd		sc->polling = 1;
1181168404Spjd	else
1182168404Spjd		sc->polling = 0;
1183168404Spjd
1184168404Spjd	pci_set_powerstate(dev, PCI_POWERSTATE_D0);
1185168404Spjd	pci_enable_busmaster(dev);
1186168404Spjd
1187168404Spjd	sc->regid = PCIR_BAR(0);
1188168404Spjd	sc->regtype = SYS_RES_MEMORY;
1189168404Spjd	sc->reg = bus_alloc_resource_any(dev, sc->regtype,
1190168404Spjd	    &sc->regid, RF_ACTIVE);
1191168404Spjd
1192168404Spjd	if (!sc->reg) {
1193168404Spjd		device_printf(dev, "unable to allocate register space\n");
1194168404Spjd		goto bad;
1195168404Spjd	}
1196168404Spjd
1197168404Spjd	sc->st = rman_get_bustag(sc->reg);
1198168404Spjd	sc->sh = rman_get_bushandle(sc->reg);
1199168404Spjd
1200168404Spjd	sc->bufsz = pcm_getbuffersize(dev, ATI_IXP_BUFSZ_MIN,
1201168404Spjd	    ATI_IXP_BUFSZ_DEFAULT, ATI_IXP_BUFSZ_MAX);
1202168404Spjd
1203168404Spjd	sc->irqid = 0;
1204168404Spjd	sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid,
1205168404Spjd	    RF_ACTIVE | RF_SHAREABLE);
1206168404Spjd	if (!sc->irq || snd_setup_intr(dev, sc->irq, INTR_MPSAFE,
1207168404Spjd	    atiixp_intr, sc, &sc->ih)) {
1208168404Spjd		device_printf(dev, "unable to map interrupt\n");
1209168404Spjd		goto bad;
1210168404Spjd	}
1211185029Spjd
1212168404Spjd	/*
1213168404Spjd	 * Let the user choose the best DMA segments.
1214168404Spjd	 */
1215168404Spjd	if (resource_int_value(device_get_name(dev),
1216168404Spjd	    device_get_unit(dev), "blocksize", &i) == 0 && i > 0) {
1217168404Spjd		i &= ATI_IXP_BLK_ALIGN;
1218168404Spjd		if (i < ATI_IXP_BLK_MIN)
1219168404Spjd			i = ATI_IXP_BLK_MIN;
1220168404Spjd		sc->blkcnt = sc->bufsz / i;
1221168404Spjd		i = 0;
1222168404Spjd		while (sc->blkcnt >> i)
1223168404Spjd			i++;
1224168404Spjd		sc->blkcnt = 1 << (i - 1);
1225168404Spjd		if (sc->blkcnt < ATI_IXP_DMA_CHSEGS_MIN)
1226168404Spjd			sc->blkcnt = ATI_IXP_DMA_CHSEGS_MIN;
1227168404Spjd		else if (sc->blkcnt > ATI_IXP_DMA_CHSEGS_MAX)
1228168404Spjd			sc->blkcnt = ATI_IXP_DMA_CHSEGS_MAX;
1229168404Spjd
1230168404Spjd	} else
1231168404Spjd		sc->blkcnt = ATI_IXP_DMA_CHSEGS;
1232168404Spjd
1233168404Spjd	/*
1234168404Spjd	 * DMA tag for scatter-gather buffers and link pointers
1235168404Spjd	 */
1236168404Spjd	if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2,
1237168404Spjd		/*boundary*/0,
1238168404Spjd		/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
1239168404Spjd		/*highaddr*/BUS_SPACE_MAXADDR,
1240168404Spjd		/*filter*/NULL, /*filterarg*/NULL,
1241168404Spjd		/*maxsize*/sc->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff,
1242168404Spjd		/*flags*/0, /*lockfunc*/NULL,
1243185029Spjd		/*lockarg*/NULL, &sc->parent_dmat) != 0) {
1244168404Spjd		device_printf(dev, "unable to create dma tag\n");
1245168404Spjd		goto bad;
1246168404Spjd	}
1247168404Spjd
1248168404Spjd	if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2,
1249168404Spjd		/*boundary*/0,
1250168404Spjd		/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
1251185029Spjd		/*highaddr*/BUS_SPACE_MAXADDR,
1252185029Spjd		/*filter*/NULL, /*filterarg*/NULL,
1253168404Spjd		/*maxsize*/ATI_IXP_DMA_CHSEGS_MAX * ATI_IXP_NCHANS *
1254168404Spjd		sizeof(struct atiixp_dma_op),
1255168404Spjd		/*nsegments*/1, /*maxsegz*/0x3ffff,
1256168404Spjd		/*flags*/0, /*lockfunc*/NULL,
1257185029Spjd		/*lockarg*/NULL, &sc->sgd_dmat) != 0) {
1258185029Spjd		device_printf(dev, "unable to create dma tag\n");
1259185029Spjd		goto bad;
1260185029Spjd	}
1261168404Spjd
1262168404Spjd	if (bus_dmamem_alloc(sc->sgd_dmat, (void **)&sc->sgd_table,
1263168404Spjd	    BUS_DMA_NOWAIT, &sc->sgd_dmamap) == -1)
1264168404Spjd		goto bad;
1265168404Spjd
1266168404Spjd	if (bus_dmamap_load(sc->sgd_dmat, sc->sgd_dmamap, sc->sgd_table,
1267168404Spjd	    ATI_IXP_DMA_CHSEGS_MAX * ATI_IXP_NCHANS *
1268168404Spjd	    sizeof(struct atiixp_dma_op), atiixp_dma_cb, sc, 0))
1269185029Spjd		goto bad;
1270185029Spjd
1271185029Spjd
1272185029Spjd	atiixp_chip_pre_init(sc);
1273185029Spjd
1274185029Spjd	sc->delayed_attach.ich_func = atiixp_chip_post_init;
1275185029Spjd	sc->delayed_attach.ich_arg = sc;
1276185029Spjd	if (cold == 0 ||
1277185029Spjd	    config_intrhook_establish(&sc->delayed_attach) != 0) {
1278185029Spjd		sc->delayed_attach.ich_func = NULL;
1279185029Spjd		atiixp_chip_post_init(sc);
1280185029Spjd	}
1281168404Spjd
1282168404Spjd	return (0);
1283168404Spjd
1284168404Spjdbad:
1285168404Spjd	atiixp_release_resource(sc);
1286168404Spjd	return (ENXIO);
1287168404Spjd}
1288168404Spjd
1289168404Spjdstatic int
1290168404Spjdatiixp_pci_detach(device_t dev)
1291168404Spjd{
1292185029Spjd	int r;
1293185029Spjd	struct atiixp_info *sc;
1294185029Spjd
1295185029Spjd	sc = pcm_getdevinfo(dev);
1296168404Spjd	if (sc != NULL) {
1297168404Spjd		if (sc->codec != NULL) {
1298168404Spjd			r = pcm_unregister(dev);
1299168404Spjd			if (r)
1300168404Spjd				return (r);
1301168404Spjd		}
1302185029Spjd		sc->codec = NULL;
1303185029Spjd		if (sc->st != 0 && sc->sh != 0)
1304168404Spjd			atiixp_disable_interrupts(sc);
1305168404Spjd		atiixp_release_resource(sc);
1306168404Spjd		free(sc, M_DEVBUF);
1307168404Spjd	}
1308168404Spjd	return (0);
1309168404Spjd}
1310168404Spjd
1311168404Spjdstatic int
1312168404Spjdatiixp_pci_suspend(device_t dev)
1313168404Spjd{
1314168404Spjd	struct atiixp_info *sc = pcm_getdevinfo(dev);
1315185029Spjd	uint32_t value;
1316168404Spjd
1317185029Spjd	/* quickly disable interrupts and save channels active state */
1318168404Spjd	atiixp_lock(sc);
1319168404Spjd	atiixp_disable_interrupts(sc);
1320168404Spjd	atiixp_unlock(sc);
1321168404Spjd
1322168404Spjd	/* stop everything */
1323168404Spjd	if (sc->pch.active != 0)
1324168404Spjd		atiixp_chan_trigger(NULL, &sc->pch, PCMTRIG_STOP);
1325168404Spjd	if (sc->rch.active != 0)
1326168404Spjd		atiixp_chan_trigger(NULL, &sc->rch, PCMTRIG_STOP);
1327168404Spjd
1328168404Spjd	/* power down aclink and pci bus */
1329168404Spjd	atiixp_lock(sc);
1330168404Spjd	value = atiixp_rd(sc, ATI_REG_CMD);
1331185029Spjd	value |= ATI_REG_CMD_POWERDOWN | ATI_REG_CMD_AC_RESET;
1332168404Spjd	atiixp_wr(sc, ATI_REG_CMD, ATI_REG_CMD_POWERDOWN);
1333168404Spjd	pci_set_powerstate(dev, PCI_POWERSTATE_D3);
1334185029Spjd	atiixp_unlock(sc);
1335168404Spjd
1336185029Spjd	return (0);
1337185029Spjd}
1338185029Spjd
1339185029Spjdstatic int
1340168404Spjdatiixp_pci_resume(device_t dev)
1341185029Spjd{
1342168404Spjd	struct atiixp_info *sc = pcm_getdevinfo(dev);
1343168404Spjd
1344168404Spjd	atiixp_lock(sc);
1345168404Spjd	/* power up pci bus */
1346168404Spjd	pci_set_powerstate(dev, PCI_POWERSTATE_D0);
1347168404Spjd	pci_enable_io(dev, SYS_RES_MEMORY);
1348168404Spjd	pci_enable_busmaster(dev);
1349168404Spjd	/* reset / power up aclink */
1350168404Spjd	atiixp_reset_aclink(sc);
1351168404Spjd	atiixp_unlock(sc);
1352168404Spjd
1353168404Spjd	if (mixer_reinit(dev) == -1) {
1354168404Spjd		device_printf(dev, "unable to reinitialize the mixer\n");
1355168404Spjd		return (ENXIO);
1356168404Spjd	}
1357168404Spjd
1358168404Spjd	/*
1359168404Spjd	 * Resume channel activities. Reset channel format regardless
1360185029Spjd	 * of its previous state.
1361185029Spjd	 */
1362168404Spjd	if (sc->pch.channel != NULL) {
1363168404Spjd		if (sc->pch.fmt != 0)
1364185029Spjd			atiixp_chan_setformat(NULL, &sc->pch, sc->pch.fmt);
1365168404Spjd		if (sc->pch.active != 0)
1366168404Spjd			atiixp_chan_trigger(NULL, &sc->pch, PCMTRIG_START);
1367168404Spjd	}
1368168404Spjd	if (sc->rch.channel != NULL) {
1369168404Spjd		if (sc->rch.fmt != 0)
1370185029Spjd			atiixp_chan_setformat(NULL, &sc->rch, sc->rch.fmt);
1371168404Spjd		if (sc->rch.active != 0)
1372168404Spjd			atiixp_chan_trigger(NULL, &sc->rch, PCMTRIG_START);
1373168404Spjd	}
1374168404Spjd
1375185029Spjd	/* enable interrupts */
1376168404Spjd	atiixp_lock(sc);
1377168404Spjd	if (sc->polling == 0)
1378185029Spjd		atiixp_enable_interrupts(sc);
1379168404Spjd	atiixp_unlock(sc);
1380168404Spjd
1381168404Spjd	return (0);
1382185029Spjd}
1383185029Spjd
1384168404Spjdstatic device_method_t atiixp_methods[] = {
1385168404Spjd	DEVMETHOD(device_probe,		atiixp_pci_probe),
1386185029Spjd	DEVMETHOD(device_attach,	atiixp_pci_attach),
1387185029Spjd	DEVMETHOD(device_detach,	atiixp_pci_detach),
1388168404Spjd	DEVMETHOD(device_suspend,	atiixp_pci_suspend),
1389168404Spjd	DEVMETHOD(device_resume,	atiixp_pci_resume),
1390168404Spjd	{ 0, 0 }
1391168404Spjd};
1392185029Spjd
1393168404Spjdstatic driver_t atiixp_driver = {
1394168404Spjd	"pcm",
1395168404Spjd	atiixp_methods,
1396168404Spjd	PCM_SOFTC_SIZE,
1397185029Spjd};
1398168404Spjd
1399168404SpjdDRIVER_MODULE(snd_atiixp, pci, atiixp_driver, pcm_devclass, 0, 0);
1400168404SpjdMODULE_DEPEND(snd_atiixp, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
1401168404SpjdMODULE_VERSION(snd_atiixp, 1);
1402168404Spjd