NetBSD Problem Report #40284

From ryo@lab.misakimix.org  Sun Dec 28 13:41:59 2008
Return-Path: <ryo@lab.misakimix.org>
Received: from mail.netbsd.org (mail.netbsd.org [204.152.190.11])
	by narn.NetBSD.org (Postfix) with ESMTP id 5F97763BC75
	for <gnats-bugs@gnats.NetBSD.org>; Sun, 28 Dec 2008 13:41:59 +0000 (UTC)
Message-Id: <20081228134115.1D2FF45A4B9@lab.misakimix.org>
Date: Sun, 28 Dec 2008 22:41:15 +0900 (JST)
From: ryo@nerv.org
Reply-To: ryo@nerv.org
To: gnats-bugs@gnats.NetBSD.org
Subject: add AMD Geode CS5536 audio driver
X-Send-Pr-Version: 3.95

>Number:         40284
>Category:       port-i386
>Synopsis:       add AMD Geode CS5536 audio driver
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    jmcneill
>State:          closed
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Dec 28 13:45:01 +0000 2008
>Closed-Date:    Sun Dec 28 15:19:50 +0000 2008
>Last-Modified:  Fri May 01 01:25:00 +0000 2009
>Originator:     Ryo Shimizu
>Release:        NetBSD 5.99.5
>Organization:
>Environment:
System: NetBSD msr 5.99.5 NetBSD 5.99.5 (KOHJINSHA) #51: Sun Dec 28 07:47:59 JST 2008  ryo@moveq.nerv.org:/usr/src/sys/arch/i386/compile/KOHJINSHA i386
Architecture: i386
Machine: i386
>Description:
	gcscaudio - AMD Geode CS5536 integrated AC'97 audio device driver

	The gcscaudio driver provides suport for AMD Geode CS5536 chip.
	CS5536 and this driver support 1,2,4,6(5.1) channels output,
	1,2 channels input and full-duplex.

	This driver tested only on KOHJINSHA SA5SX04, and
	5.1ch output is not tested. (not wired on SA5SX04)

>How-To-Repeat:
	Boot a kernel on AMD Geode LX chipset.

	NetBSD 5.99.5 (KOHJINSHA) #50: Sun Dec 28 07:39:13 JST 2008
	        ryo@moveq.nerv.org:/usr/src/sys/arch/i386/compile/KOHJINSHA
	total memory = 1007 MB
	avail memory = 982 MB
	timecounter: Timecounters tick every 10.000 msec
	timecounter: Timecounter "i8254" frequency 1193182 Hz quality 100
	KOHJINSHA Co.,Ltd SA Series (Rev 1.00)
	mainbus0 (root)
	pci_addr_fixup: 000:15:0 0x1022 0x2090 new address 0x00005800
	cpu0 at mainbus0: AMD 586-class, 498MHz, id 0x5a2
	   :
	Advanced Micro Devices CS5536 Audio (audio multimedia, revision 0x01) at pci0 dev 15 function 3 not configured
	   :

>Fix:
	apply this patch.

diff -auNr NetBSD.orig/sys/arch/i386/conf/files.i386 NetBSD/sys/arch/i386/conf/files.i386
--- NetBSD.orig/sys/arch/i386/conf/files.i386	2008-12-20 21:41:19.000000000 +0900
+++ NetBSD/sys/arch/i386/conf/files.i386	2008-12-21 07:08:50.000000000 +0900
@@ -189,6 +189,11 @@
 attach	gcscide at pci
 file	arch/i386/pci/gcscide.c 	gcscide

+# AMD Geode CS5536 Companion Audio
+device	gcscaudio: audiobus, auconv, mulaw, ac97, aurateconv
+attach	gcscaudio at pci
+file	arch/i386/pci/gcscaudio.c	gcscaudio
+
 # AMD Geode CS5536 Companion EHCI
 device	gcscehci: usbus
 attach	gcscehci at pci
diff -auNr NetBSD.orig/sys/arch/i386/pci/gcscaudio.c NetBSD/sys/arch/i386/pci/gcscaudio.c
--- NetBSD.orig/sys/arch/i386/pci/gcscaudio.c	1970-01-01 09:00:00.000000000 +0900
+++ NetBSD/sys/arch/i386/pci/gcscaudio.c	2008-12-28 07:05:32.000000000 +0900
@@ -0,0 +1,1339 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2008 SHIMIZU Ryo <ryo@nerv.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/queue.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <dev/pci/pcidevs.h>
+#include <dev/pci/pcivar.h>
+
+#include <sys/audioio.h>
+#include <dev/audio_if.h>
+#include <dev/mulaw.h>
+#include <dev/auconv.h>
+#include <dev/ic/ac97reg.h>
+#include <dev/ic/ac97var.h>
+
+#include <arch/i386/pci/gcscaudioreg.h>
+
+
+#define	GCSCAUDIO_NPRDTABLE	256	/* including a JMP-PRD for loop */
+#define	GCSCAUDIO_PRD_SIZE_MAX	65532	/* limited by CS5536 Controller */
+#define	GCSCAUDIO_BUFSIZE_MAX	(GCSCAUDIO_PRD_SIZE_MAX * (GCSCAUDIO_NPRDTABLE - 1))
+
+struct gcscaudio_prd {
+	/* PRD table for play/rec */
+	struct gcscaudio_prdtables {
+#define	PRD_TABLE_FRONT		0
+#define	PRD_TABLE_SURR		1
+#define	PRD_TABLE_CENTER	2
+#define	PRD_TABLE_LFE		3
+#define	PRD_TABLE_REC		4
+#define	PRD_TABLE_MAX		5
+		struct acc_prd prdtbl[PRD_TABLE_MAX][GCSCAUDIO_NPRDTABLE];
+	} *p_prdtables;
+	bus_dmamap_t p_prdmap;
+	bus_dma_segment_t p_prdsegs[1];
+	int p_prdnseg;
+};
+
+struct gcscaudio_dma {
+	LIST_ENTRY(gcscaudio_dma) list;
+	bus_dmamap_t map;
+	void *addr;
+	size_t size;
+	bus_dma_segment_t segs[1];
+	int nseg;
+};
+
+struct gcscaudio_softc_ch {
+	void (*ch_intr)(void *);
+	void *ch_intr_arg;
+	struct audio_params ch_params;
+};
+
+struct gcscaudio_softc {
+	struct device sc_dev;
+	pci_chipset_tag_t sc_pc;
+	pcitag_t sc_pt;
+	void *sc_ih;
+	bus_space_tag_t sc_iot;
+	bus_space_handle_t sc_ioh;
+	bus_size_t sc_ios;
+	bus_dma_tag_t sc_dmat;
+
+	/* allocated DMA buffer list */
+	LIST_HEAD(, gcscaudio_dma) sc_dmalist;
+
+#define GCSCAUDIO_MAXFORMATS	4
+	struct audio_format sc_formats[GCSCAUDIO_MAXFORMATS];
+	int sc_nformats;
+	struct audio_encoding_set *sc_encodings;
+
+	/* AC97 codec */
+	struct ac97_host_if host_if;
+	struct ac97_codec_if *codec_if;
+
+	/* input, output channels */
+	struct gcscaudio_softc_ch sc_play;
+	struct gcscaudio_softc_ch sc_rec;
+	struct gcscaudio_prd sc_prd;
+
+	/* multi channel splitter work; {4,6}ch stream to {2,4} DMA buffers */
+	void *sc_mch_split_buf;
+	void *sc_mch_split_start;
+	int sc_mch_split_off;
+	int sc_mch_split_size;
+	int sc_mch_split_blksize;
+	void (*sc_mch_splitter)(void *, void *, int, int);
+	bool sc_spdif;
+};
+
+/* for cfattach */
+static int gcscaudio_match(device_t, struct cfdata *, void *);
+static void gcscaudio_attach(device_t, device_t, void *);
+
+/* for audio_hw_if */
+static int gcscaudio_open(void *, int);
+static void gcscaudio_close(void *);
+static int gcscaudio_query_encoding(void *, struct audio_encoding *);
+static int gcscaudio_set_params(void *, int, int, audio_params_t *,
+                                audio_params_t *, stream_filter_list_t *,
+                                stream_filter_list_t *);
+static int gcscaudio_round_blocksize(void *, int, int, const audio_params_t *);
+static int gcscaudio_halt_output(void *);
+static int gcscaudio_halt_input(void *);
+static int gcscaudio_getdev(void *, struct audio_device *);
+static int gcscaudio_set_port(void *, mixer_ctrl_t *);
+static int gcscaudio_get_port(void *, mixer_ctrl_t *);
+static int gcscaudio_query_devinfo(void *, mixer_devinfo_t *);
+static void *gcscaudio_malloc(void *, int, size_t, struct malloc_type *, int);
+static void gcscaudio_free(void *, void *, struct malloc_type *);
+static size_t gcscaudio_round_buffersize(void *, int, size_t);
+static paddr_t gcscaudio_mappage(void *, void *, off_t, int);
+static int gcscaudio_get_props(void *);
+static int gcscaudio_trigger_output(void *, void *, void *, int,
+                                    void (*)(void *), void *,
+                                    const audio_params_t *);
+static int gcscaudio_trigger_input(void *, void *, void *, int,
+                                   void (*)(void *), void *,
+                                   const audio_params_t *);
+static bool gcscaudio_resume(device_t PMF_FN_PROTO);
+static int gcscaudio_intr(void *);
+
+/* for codec_if */
+static int gcscaudio_attach_codec(void *, struct ac97_codec_if *);
+static int gcscaudio_write_codec(void *, uint8_t, uint16_t);
+static int gcscaudio_read_codec(void *, uint8_t, uint16_t *);
+static int gcscaudio_reset_codec(void *);
+static void gcscaudio_spdif_event_codec(void *, bool);
+
+/* misc */
+static int gcscaudio_append_formats(struct gcscaudio_softc *,
+                                    const struct audio_format *);
+static int gcscaudio_wait_ready_codec(struct gcscaudio_softc *sc, const char *);
+static int gcscaudio_set_params_ch(struct gcscaudio_softc *,
+                                   struct gcscaudio_softc_ch *, int,
+                                   audio_params_t *, stream_filter_list_t *);
+static int gcscaudio_allocate_dma(struct gcscaudio_softc *, size_t, void **,
+                                  bus_dma_segment_t *, int, int *,
+                                  int, bus_dmamap_t *);
+
+
+CFATTACH_DECL(gcscaudio, sizeof (struct gcscaudio_softc),
+    gcscaudio_match, gcscaudio_attach, NULL, NULL);
+
+
+static struct audio_device gcscaudio_device = {
+	"AMD Geode CS5536",
+	"",
+	"gcscaudio"
+};
+
+static const struct audio_hw_if gcscaudio_hw_if = {
+	.open			= gcscaudio_open,
+	.close			= gcscaudio_close,
+	.drain			= NULL,
+	.query_encoding		= gcscaudio_query_encoding,
+	.set_params		= gcscaudio_set_params,
+	.round_blocksize	= gcscaudio_round_blocksize,
+	.commit_settings	= NULL,
+	.init_output		= NULL,
+	.init_input		= NULL,
+	.start_output		= NULL,
+	.start_input		= NULL,
+	.halt_output		= gcscaudio_halt_output,
+	.halt_input		= gcscaudio_halt_input,
+	.speaker_ctl		= NULL,
+	.getdev			= gcscaudio_getdev,
+	.setfd			= NULL,
+	.set_port		= gcscaudio_set_port,
+	.get_port		= gcscaudio_get_port,
+	.query_devinfo		= gcscaudio_query_devinfo,
+	.allocm			= gcscaudio_malloc,
+	.freem			= gcscaudio_free,
+	.round_buffersize	= gcscaudio_round_buffersize,
+	.mappage		= gcscaudio_mappage,
+	.get_props		= gcscaudio_get_props,
+	.trigger_output		= gcscaudio_trigger_output,
+	.trigger_input		= gcscaudio_trigger_input,
+	.dev_ioctl		= NULL,
+	.powerstate		= NULL
+};
+
+static const struct audio_format gcscaudio_formats_2ch = {
+	NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_LE, 16, 16,
+	2, AUFMT_STEREO, 0, {8000, 48000}
+};
+
+static const struct audio_format gcscaudio_formats_4ch = {
+	NULL, AUMODE_PLAY, AUDIO_ENCODING_SLINEAR_LE, 16, 16,
+	4, AUFMT_SURROUND4, 0, {8000, 48000}
+};
+
+static const struct audio_format gcscaudio_formats_6ch = {
+	NULL, AUMODE_PLAY, AUDIO_ENCODING_SLINEAR_LE, 16, 16,
+	6, AUFMT_DOLBY_5_1, 0, {8000, 48000}
+};
+
+static int
+gcscaudio_match(device_t parent, struct cfdata *match, void *aux)
+{
+	struct pci_attach_args *pa;
+
+	pa = (struct pci_attach_args *)aux;
+	if ((PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD) &&
+	    (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_CS5536_AUDIO))
+		return 1;
+
+	return 0;
+}
+
+static int
+gcscaudio_append_formats(struct gcscaudio_softc *sc,
+                         const struct audio_format *format)
+{
+	if (sc->sc_nformats >= GCSCAUDIO_MAXFORMATS) {
+		aprint_error_dev(&sc->sc_dev, "too many formats\n");
+		return EINVAL;
+	}
+	sc->sc_formats[sc->sc_nformats++] = *format;
+	return 0;
+}
+
+static void
+gcscaudio_attach(device_t parent, device_t self, void *aux)
+{
+	struct gcscaudio_softc *sc;
+	struct pci_attach_args *pa;
+	const char *intrstr;
+	pci_intr_handle_t ih;
+	int rc, i;
+
+	sc = device_private(self);
+
+	aprint_naive(": Audio controller\n");
+
+	pa = aux;
+	sc->sc_pc = pa->pa_pc;
+	sc->sc_pt = pa->pa_tag;
+	sc->sc_dmat = pa->pa_dmat;
+	LIST_INIT(&sc->sc_dmalist);
+	sc->sc_mch_split_buf = NULL;
+
+	aprint_normal(": AMD Geode CS5536 Audio\n");
+
+	if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_IO, 0,
+	    &sc->sc_iot, &sc->sc_ioh, NULL, &sc->sc_ios)) {
+		aprint_error_dev(&sc->sc_dev, "can't map i/o space\n");
+		return;
+	}
+
+	if (pci_intr_map(pa, &ih)) {
+		aprint_error_dev(&sc->sc_dev, "couldn't map interrupt\n");
+		goto attach_failure_unmap;
+	}
+	intrstr = pci_intr_string(sc->sc_pc, ih);
+
+	sc->sc_ih = pci_intr_establish(sc->sc_pc, ih, IPL_AUDIO,
+	    gcscaudio_intr, sc);
+	if (sc->sc_ih == NULL) {
+		aprint_error_dev(&sc->sc_dev, "couldn't establish interrupt");
+		if (intrstr != NULL)
+			aprint_normal(" at %s", intrstr);
+		aprint_normal("\n");
+		goto attach_failure_unmap;
+	}
+
+	aprint_normal_dev(&sc->sc_dev, "interrupting at %s\n", intrstr);
+
+
+	if (gcscaudio_allocate_dma(sc, sizeof(*sc->sc_prd.p_prdtables),
+	    (void **)&(sc->sc_prd.p_prdtables), sc->sc_prd.p_prdsegs, 1,
+	    &(sc->sc_prd.p_prdnseg), M_WAITOK, &(sc->sc_prd.p_prdmap)) != 0)
+		goto attach_failure_intr;
+
+	sc->host_if.arg = sc;
+	sc->host_if.attach = gcscaudio_attach_codec;
+	sc->host_if.read = gcscaudio_read_codec;
+	sc->host_if.write = gcscaudio_write_codec;
+	sc->host_if.reset = gcscaudio_reset_codec;
+	sc->host_if.spdif_event = gcscaudio_spdif_event_codec;
+
+	if ((rc = ac97_attach(&sc->host_if, self)) != 0) {
+		aprint_error_dev(&sc->sc_dev,
+		    "can't attach codec (error=%d)\n", rc);
+		goto attach_failure_intr;
+	}
+
+	if (!pmf_device_register(self, NULL, gcscaudio_resume))
+		aprint_error_dev(self, "couldn't establish power handler\n");
+
+
+	sc->sc_nformats = 0;
+	gcscaudio_append_formats(sc, &gcscaudio_formats_2ch);
+	if (AC97_IS_4CH(sc->codec_if))
+		gcscaudio_append_formats(sc, &gcscaudio_formats_4ch);
+	if (AC97_IS_6CH(sc->codec_if))
+		gcscaudio_append_formats(sc, &gcscaudio_formats_6ch);
+	if (AC97_IS_FIXED_RATE(sc->codec_if)) {
+		for (i = 0; i < sc->sc_nformats; i++) {
+			sc->sc_formats[i].frequency_type = 1;
+			sc->sc_formats[i].frequency[0] = 48000;
+		}
+	}
+
+	if ((rc = auconv_create_encodings(sc->sc_formats, sc->sc_nformats,
+	    &sc->sc_encodings)) != 0) {
+		aprint_error_dev(self,
+		    "auconv_create_encoding: error=%d\n", rc);
+		goto attach_failure_codec;
+	}
+
+	audio_attach_mi(&gcscaudio_hw_if, sc, &sc->sc_dev);
+	sc->codec_if->vtbl->unlock(sc->codec_if);
+	return;
+
+attach_failure_codec:
+	sc->codec_if->vtbl->detach(sc->codec_if);
+attach_failure_intr:
+	pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
+attach_failure_unmap:
+	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
+	return;
+}
+
+static int
+gcscaudio_attach_codec(void *arg, struct ac97_codec_if *codec_if)
+{
+	struct gcscaudio_softc *sc;
+
+	sc = (struct gcscaudio_softc *)arg;
+	sc->codec_if = codec_if;
+	return 0;
+}
+
+static int
+gcscaudio_reset_codec(void *arg)
+{
+	struct gcscaudio_softc *sc;
+	sc = (struct gcscaudio_softc *)arg;
+
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_CODEC_CNTL,
+	    ACC_CODEC_CNTL_LNK_WRM_RST |
+	    ACC_CODEC_CNTL_CMD_NEW);
+
+	if (gcscaudio_wait_ready_codec(sc, "reset timeout\n"))
+		return 1;
+
+	return 0;
+}
+
+static void
+gcscaudio_spdif_event_codec(void *arg, bool flag)
+{
+	struct gcscaudio_softc *sc;
+
+	sc = (struct gcscaudio_softc *)arg;
+	sc->sc_spdif = flag;
+}
+
+static int
+gcscaudio_wait_ready_codec(struct gcscaudio_softc *sc, const char *timeout_msg)
+{
+	int i;
+
+#define GCSCAUDIO_WAIT_READY_CODEC_TIMEOUT	500
+	for (i = GCSCAUDIO_WAIT_READY_CODEC_TIMEOUT; (i >= 0) &&
+	    (bus_space_read_4(sc->sc_iot, sc->sc_ioh, ACC_CODEC_CNTL) &
+	    ACC_CODEC_CNTL_CMD_NEW); i--)
+		delay(1);
+
+	if (i < 0) {
+		aprint_error_dev(&sc->sc_dev, timeout_msg);
+		return 1;
+	}
+
+	return 0;
+}
+
+static int
+gcscaudio_write_codec(void *arg, uint8_t reg, uint16_t val)
+{
+	struct gcscaudio_softc *sc;
+
+	sc = (struct gcscaudio_softc *)arg;
+
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_CODEC_CNTL,
+	    ACC_CODEC_CNTL_WRITE_CMD |
+	    ACC_CODEC_CNTL_CMD_NEW |
+	    ACC_CODEC_REG2ADDR(reg) |
+	    (val & ACC_CODEC_CNTL_CMD_DATA_MASK));
+
+	if (gcscaudio_wait_ready_codec(sc, "codec write timeout\n"))
+		return 1;
+
+#ifdef GCSCAUDIO_CODEC_DEBUG
+	aprint_error_dev(&sc->sc_dev, "codec write: reg=0x%02x, val=0x%04x\n",
+	    reg, val);
+#endif
+
+	return 0;
+}
+
+static int
+gcscaudio_read_codec(void *arg, uint8_t reg, uint16_t *val)
+{
+	struct gcscaudio_softc *sc;
+	uint32_t v;
+	int i;
+
+	sc = (struct gcscaudio_softc *)arg;
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_CODEC_CNTL,
+	    ACC_CODEC_CNTL_READ_CMD | ACC_CODEC_CNTL_CMD_NEW |
+	    ACC_CODEC_REG2ADDR(reg));
+
+	if (gcscaudio_wait_ready_codec(sc, "codec write timeout for reading"))
+		return 1;
+
+#define GCSCAUDIO_READ_CODEC_TIMEOUT	50
+	for (i = GCSCAUDIO_READ_CODEC_TIMEOUT; i >= 0; i--) {
+		v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, ACC_CODEC_STATUS);
+		if ((v & ACC_CODEC_STATUS_STS_NEW) &&
+		    (ACC_CODEC_ADDR2REG(v) == reg))
+			break;
+
+		delay(10);
+	}
+
+	if (i < 0) {
+		aprint_error_dev(&sc->sc_dev, "codec read timeout\n");
+		return 1;
+	}
+
+#ifdef GCSCAUDIO_CODEC_DEBUG
+	aprint_error_dev(&sc->sc_dev, "codec read: reg=0x%02x, val=0x%04x\n",
+	    reg, v & ACC_CODEC_STATUS_STS_DATA_MASK);
+#endif
+
+	*val = v;
+	return 0;
+}
+
+static int
+gcscaudio_open(void *arg, int flags)
+{
+	struct gcscaudio_softc *sc;
+
+	sc = (struct gcscaudio_softc *)arg;
+	sc->codec_if->vtbl->lock(sc->codec_if);
+	return 0;
+}
+
+static void
+gcscaudio_close(void *arg)
+{
+	struct gcscaudio_softc *sc;
+
+	sc = (struct gcscaudio_softc *)arg;
+	sc->codec_if->vtbl->unlock(sc->codec_if);
+}
+
+static int
+gcscaudio_query_encoding(void *arg, struct audio_encoding *fp)
+{
+	struct gcscaudio_softc *sc;
+
+	sc = (struct gcscaudio_softc *)arg;
+	return auconv_query_encoding(sc->sc_encodings, fp);
+}
+
+static int
+gcscaudio_set_params_ch(struct gcscaudio_softc *sc,
+                        struct gcscaudio_softc_ch *ch, int mode,
+                        audio_params_t *p, stream_filter_list_t *fil)
+{
+	int error, idx;
+
+	if ((p->sample_rate < 8000) || (p->sample_rate > 48000))
+		return EINVAL;
+
+	if (p->precision != 8 && p->precision != 16)
+		return EINVAL;
+
+	if ((idx = auconv_set_converter(sc->sc_formats, sc->sc_nformats,
+	    mode, p, TRUE, fil)) < 0)
+		return EINVAL;
+
+	if (fil->req_size > 0)
+		p = &fil->filters[0].param;
+
+	if (mode == AUMODE_PLAY) {
+		if (!AC97_IS_FIXED_RATE(sc->codec_if)) {
+			/* setup rate of DAC/ADC */
+			if ((error = sc->codec_if->vtbl->set_rate(sc->codec_if,
+			    AC97_REG_PCM_LR_ADC_RATE, &p->sample_rate)) != 0)
+				return error;
+
+			/* additional rate of DAC for Surround */
+			if ((p->channels >= 4) &&
+			    (error = sc->codec_if->vtbl->set_rate(sc->codec_if,
+			    AC97_REG_PCM_SURR_DAC_RATE, &p->sample_rate)) != 0)
+				return error;
+
+			/* additional rate of DAC for LowFrequencyEffect */
+			if ((p->channels == 6) &&
+			    (error = sc->codec_if->vtbl->set_rate(sc->codec_if,
+			    AC97_REG_PCM_LFE_DAC_RATE, &p->sample_rate)) != 0)
+				return error;
+		}
+	}
+
+	if (mode == AUMODE_RECORD) {
+		if (!AC97_IS_FIXED_RATE(sc->codec_if)) {
+			/* setup rate of DAC/ADC */
+			if ((error = sc->codec_if->vtbl->set_rate(sc->codec_if,
+			    AC97_REG_PCM_FRONT_DAC_RATE, &p->sample_rate)) != 0)
+				return error;
+		}
+	}
+
+	ch->ch_params = *p;
+	return 0;
+}
+
+static int
+gcscaudio_set_params(void *arg, int setmode, int usemode,
+                     audio_params_t *play, audio_params_t *rec,
+                     stream_filter_list_t *pfil, stream_filter_list_t *rfil)
+{
+	struct gcscaudio_softc *sc;
+	int error;
+
+	sc = (struct gcscaudio_softc *)arg;
+
+	if (setmode & AUMODE_PLAY) {
+		if ((error = gcscaudio_set_params_ch(sc, &sc->sc_play,
+		    AUMODE_PLAY, play, pfil)) != 0)
+			return error;
+	}
+	if (setmode & AUMODE_RECORD) {
+		if ((error = gcscaudio_set_params_ch(sc, &sc->sc_rec,
+		    AUMODE_RECORD, rec, rfil)) != 0)
+			return error;
+	}
+
+	return 0;
+}
+
+static int
+gcscaudio_round_blocksize(void *arg, int blk, int mode,
+                          const audio_params_t *param)
+{
+	blk &= -4;
+	if (blk > GCSCAUDIO_PRD_SIZE_MAX)
+		blk = GCSCAUDIO_PRD_SIZE_MAX;
+
+	return blk;
+}
+
+static int
+gcscaudio_halt_output(void *arg)
+{
+	struct gcscaudio_softc *sc;
+
+	sc = (struct gcscaudio_softc *)arg;
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM0_CMD,
+	    ACC_BMx_CMD_BM_CTL_DISABLE);
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM4_CMD,
+	    ACC_BMx_CMD_BM_CTL_DISABLE);
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM6_CMD,
+	    ACC_BMx_CMD_BM_CTL_DISABLE);
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM7_CMD,
+	    ACC_BMx_CMD_BM_CTL_DISABLE);
+	sc->sc_play.ch_intr = NULL;
+
+	/* channel splitter */
+	sc->sc_mch_splitter = NULL;
+	if (sc->sc_mch_split_buf)
+		gcscaudio_free(sc, sc->sc_mch_split_buf, M_DEVBUF);
+	sc->sc_mch_split_buf = NULL;
+
+	return 0;
+}
+
+static int
+gcscaudio_halt_input(void *arg)
+{
+	struct gcscaudio_softc *sc;
+
+	sc = (struct gcscaudio_softc *)arg;
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM1_CMD,
+	    ACC_BMx_CMD_BM_CTL_DISABLE);
+	sc->sc_rec.ch_intr = NULL;
+	return 0;
+}
+
+static int
+gcscaudio_getdev(void *addr, struct audio_device *retp)
+{
+	*retp = gcscaudio_device;
+	return 0;
+}
+
+static int
+gcscaudio_set_port(void *addr, mixer_ctrl_t *cp)
+{
+	struct gcscaudio_softc *sc;
+
+	sc = addr;
+	return sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp);
+}
+
+static int
+gcscaudio_get_port(void *addr, mixer_ctrl_t *cp)
+{
+	struct gcscaudio_softc *sc;
+
+	sc = addr;
+	return sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp);
+}
+
+static int
+gcscaudio_query_devinfo(void *addr, mixer_devinfo_t *dip)
+{
+	struct gcscaudio_softc *sc;
+
+	sc = addr;
+	return sc->codec_if->vtbl->query_devinfo(sc->codec_if, dip);
+}
+
+static void *
+gcscaudio_malloc(void *arg, int direction, size_t size,
+                 struct malloc_type *pool, int flags)
+{
+	struct gcscaudio_softc *sc;
+	struct gcscaudio_dma *p;
+	int error;
+
+	sc = (struct gcscaudio_softc *)arg;
+
+	p = malloc(sizeof(*p), pool, flags);
+	if (p == NULL)
+		return NULL;
+	p->size = size;
+
+	error = gcscaudio_allocate_dma(sc, size, &p->addr,
+	    p->segs, sizeof(p->segs)/sizeof(p->segs[0]), &p->nseg,
+	    BUS_DMA_NOWAIT, &p->map);
+
+	if (error) {
+		free(p, pool);
+		return NULL;
+	}
+
+	LIST_INSERT_HEAD(&sc->sc_dmalist, p, list);
+	return p->addr;
+}
+
+static void
+gcscaudio_free(void *arg, void *ptr, struct malloc_type *pool)
+{
+	struct gcscaudio_softc *sc;
+	struct gcscaudio_dma *p;
+
+	sc = (struct gcscaudio_softc *)arg;
+
+	LIST_FOREACH(p, &sc->sc_dmalist, list) {
+		if (p->addr == ptr) {
+			bus_dmamap_unload(sc->sc_dmat, p->map);
+			bus_dmamap_destroy(sc->sc_dmat, p->map);
+			bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size);
+			bus_dmamem_free(sc->sc_dmat, p->segs, p->nseg);
+
+			LIST_REMOVE(p, list);
+			free(p, pool);
+			break;
+		}
+	}
+}
+
+static paddr_t
+gcscaudio_mappage(void *arg, void *mem, off_t off, int prot)
+{
+	struct gcscaudio_softc *sc;
+	struct gcscaudio_dma *p;
+
+	if (off < 0)
+		return -1;
+
+	sc = (struct gcscaudio_softc *)arg;
+	LIST_FOREACH(p, &sc->sc_dmalist, list) {
+		if (p->addr == mem) {
+			return bus_dmamem_mmap(sc->sc_dmat, p->segs, p->nseg,
+			    off, prot, BUS_DMA_WAITOK);
+		}
+	}
+
+	return -1;
+}
+
+static size_t
+gcscaudio_round_buffersize(void *addr, int direction, size_t size)
+{
+	if (size > GCSCAUDIO_BUFSIZE_MAX)
+		size = GCSCAUDIO_BUFSIZE_MAX;
+
+	return size;
+}
+
+static int
+gcscaudio_get_props(void *addr)
+{
+	struct gcscaudio_softc *sc;
+	int props;
+
+	sc = (struct gcscaudio_softc *)addr;
+	props = AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX;
+	/*
+	 * Even if the codec is fixed-rate, set_param() succeeds for any sample
+	 * rate because of aurateconv.  Applications can't know what rate the
+	 * device can process in the case of mmap().
+	 */
+	if (!AC97_IS_FIXED_RATE(sc->codec_if))
+		props |= AUDIO_PROP_MMAP;
+	return props;
+}
+
+static int
+build_prdtables(struct gcscaudio_softc *sc, int prdidx,
+                void *addr, size_t size, int blksize, int blklen, int blkoff)
+{
+	struct gcscaudio_dma *p;
+	struct acc_prd *prdp;
+	bus_addr_t paddr;
+	int i;
+
+	/* get physical address of start */
+	paddr = (bus_addr_t)0;
+	LIST_FOREACH(p, &sc->sc_dmalist, list) {
+		if (p->addr == addr) {
+			paddr = p->map->dm_segs[0].ds_addr;
+			break;
+		}
+	}
+	if (!paddr) {
+		aprint_error_dev(&sc->sc_dev,
+		    "bad addr %p\n", addr);
+		return EINVAL;
+	}
+
+#define PRDADDR(prdidx,idx) \
+	(sc->sc_prd.p_prdmap->dm_segs[0].ds_addr) + sizeof(struct acc_prd) * \
+	(((prdidx) * GCSCAUDIO_NPRDTABLE) + (idx))
+
+	/*
+	 * build PRD table
+	 *   prdtbl[] = <PRD0>, <PRD1>, <PRD2>, ..., <PRDn>, <jmp to PRD0>
+	 */
+	prdp = sc->sc_prd.p_prdtables->prdtbl[prdidx];
+	for (i = 0; size > 0; size -= blksize, i++) {
+		prdp[i].address = paddr + blksize * i + blkoff;
+		prdp[i].ctrlsize =
+		    (size < blklen ? size : blklen) | ACC_BMx_PRD_CTRL_EOP;
+	}
+	prdp[i].address = PRDADDR(prdidx, 0);
+	prdp[i].ctrlsize = ACC_BMx_PRD_CTRL_JMP;
+
+	bus_dmamap_sync(sc->sc_dmat, sc->sc_prd.p_prdmap, 0,
+	    sizeof(struct acc_prd) * i, BUS_DMASYNC_PREWRITE);
+
+	return 0;
+}
+
+static void
+split_buffer_4ch(void *dst, void *src, int size, int blksize)
+{
+	int left, i;
+	uint16_t *s, *d;
+
+	/*
+	 * src[blk0]: L,R,SL,SR,L,R,SL,SR,L,R,SL,SR,....
+	 * src[blk1]: L,R,SL,SR,L,R,SL,SR,L,R,SL,SR,....
+	 * src[blk2]: L,R,SL,SR,L,R,SL,SR,L,R,SL,SR,....
+	 *     :
+	 *
+	 *   rearrange to
+	 *
+	 * src[blk0]: L,R,L,R,L,R,L,R,..
+	 * src[blk1]: L,R,L,R,L,R,L,R,..
+	 * src[blk2]: L,R,L,R,L,R,L,R,..
+	 *     :
+	 * dst[blk0]: SL,SR,SL,SR,SL,SR,SL,SR,..
+	 * dst[blk1]: SL,SR,SL,SR,SL,SR,SL,SR,..
+	 * dst[blk2]: SL,SR,SL,SR,SL,SR,SL,SR,..
+	 *     :
+	 */
+	for (left = size; left > 0; left -= blksize) {
+		s = (uint16_t *)src;
+		d = (uint16_t *)dst;
+		for (i = 0; i < blksize / sizeof(uint16_t) / 4; i++) {
+			/* L,R,SL,SR -> SL,SR */
+			s++;
+			s++;
+			*d++ = *s++;
+			*d++ = *s++;
+		}
+
+		s = (uint16_t *)src;
+		d = (uint16_t *)src;
+		for (i = 0; i < blksize / sizeof(uint16_t) / 2 / 2; i++) {
+			/* L,R,SL,SR -> L,R */
+			*d++ = *s++;
+			*d++ = *s++;
+			s++;
+			s++;
+		}
+
+		src = (char *)src + blksize;
+		dst = (char *)dst + blksize;
+	}
+}
+
+static void
+split_buffer_6ch(void *dst, void *src, int size, int blksize)
+{
+	int left, i;
+	uint16_t *s, *d, *dc, *dl;
+
+	/*
+	 * by default, treat as WAV style 5.1ch order
+	 *   5.1ch(WAV): L R C LFE SL SR
+	 *   5.1ch(AAC): C L R SL SR LFE
+	 *        :
+	 */
+
+	/*
+	 * src[blk0]: L,R,C,LFE,SL,SR,L,R,C,LFE,SL,SR,...
+	 * src[blk1]: L,R,C,LFE,SL,SR,L,R,C,LFE,SL,SR,...
+	 * src[blk2]: L,R,C,LFE,SL,SR,L,R,C,LFE,SL,SR,...
+	 *     :
+	 * src[N-1] : L,R,C,LFE,SL,SR,L,R,C,LFE,SL,SR,...
+	 *
+	 *   rearrange to
+	 *
+	 * src[blk0]: L,R,L,R,..
+	 * src[blk1]: L,R,L,R,..
+	 * src[blk2]: L,R,L,R,..
+	 *     :
+	 *
+	 * dst[blk0]: SL,SR,SL,SR,..
+	 * dst[blk1]: SL,SR,SL,SR,..
+	 * dst[blk2]: SL,SR,SL,SR,..
+	 *     :
+	 *
+	 * dst[N/2+0]: C,C,C,..
+	 * dst[N/2+1]: C,C,C,..
+	 *     :
+	 *
+	 * dst[N/2+N/4+0]: LFE,LFE,LFE,..
+	 * dst[N/2+N/4+1]: LFE,LFE,LFE,..
+	 *     :
+	 */
+
+	for (left = size; left > 0; left -= blksize) {
+		s = (uint16_t *)src;
+		d = (uint16_t *)dst;
+		dc = (uint16_t *)((char *)dst + blksize / 2);
+		dl = (uint16_t *)((char *)dst + blksize / 2 + blksize / 4);
+		for (i = 0; i < blksize / sizeof(uint16_t) / 6; i++) {
+#ifdef GCSCAUDIO_5_1CH_AAC_ORDER
+			/*
+			 * AAC: [C,L,R,SL,SR,LFE]
+			 *  => [SL,SR]
+			 *  => [C]
+			 *  => [LFE]
+			 */
+			*dc++ = s[0];	/* C */
+			*dl++ = s[5];	/* LFE */
+			*d++ = s[3];	/* SL */
+			*d++ = s[4];	/* SR */
+#else
+			/*
+			 * WAV: [L,R,C,LFE,SL,SR]
+			 *  => [SL,SR]
+			 *  => [C]
+			 *  => [LFE]
+			 */
+			*dc++ = s[2];	/* C */
+			*dl++ = s[3];	/* LFE */
+			*d++ = s[4];	/* SL */
+			*d++ = s[5];	/* SR */
+#endif
+			s += 6;
+		}
+
+		s = (uint16_t *)src;
+		d = (uint16_t *)src;
+		for (i = 0; i < blksize / sizeof(uint16_t) / 2 / 2; i++) {
+#ifdef GCSCAUDIO_5_1CH_AAC_ORDER
+			/* AAC: [C,L,R,SL,SR,LFE] => [L,R] */
+			*d++ = s[1];
+			*d++ = s[2];
+#else
+			/* WAV: [L,R,C,LFE,SL,SR] => [L,R] */
+			*d++ = s[0];
+			*d++ = s[1];
+#endif
+			s += 6;
+		}
+
+		src = (char *)src + blksize;
+		dst = (char *)dst + blksize;
+	}
+}
+
+static void
+channel_splitter(struct gcscaudio_softc *sc)
+{
+	int splitsize, left;
+	void *src, *dst;
+
+	if (sc->sc_mch_splitter == NULL)
+		return;
+
+	left = sc->sc_mch_split_size - sc->sc_mch_split_off;
+	splitsize = sc->sc_mch_split_blksize;
+	if (left < splitsize)
+		splitsize = left;
+
+	src = (char *)sc->sc_mch_split_start + sc->sc_mch_split_off;
+	dst = (char *)sc->sc_mch_split_buf + sc->sc_mch_split_off;
+
+	sc->sc_mch_splitter(dst, src, splitsize, sc->sc_mch_split_blksize);
+
+	sc->sc_mch_split_off += sc->sc_mch_split_blksize;
+	if (sc->sc_mch_split_off >= sc->sc_mch_split_size)
+		sc->sc_mch_split_off = 0;
+}
+
+static int
+gcscaudio_trigger_output(void *addr, void *start, void *end, int blksize,
+                         void (*intr)(void *), void *arg,
+                         const audio_params_t *param)
+{
+	struct gcscaudio_softc *sc;
+	size_t size;
+
+	sc = (struct gcscaudio_softc *)addr;
+	sc->sc_play.ch_intr = intr;
+	sc->sc_play.ch_intr_arg = arg;
+	size = (char *)end - (char *)start;
+
+	switch (sc->sc_play.ch_params.channels) {
+	case 2:
+		if (build_prdtables(sc, PRD_TABLE_FRONT, start, size, blksize,
+		    blksize, 0))
+			return EINVAL;
+
+		if (!AC97_IS_4CH(sc->codec_if)) {
+			/*
+			 * output 2ch PCM to FRONT.LR(BM0)
+			 *
+			 * 2ch: L,R,L,R,L,R,L,R,... => BM0: L,R,L,R,L,R,L,R,...
+			 *
+			 */
+			bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM0_PRD,
+			    PRDADDR(PRD_TABLE_FRONT, 0));
+
+			/* start DMA transfer */
+			bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM0_CMD,
+			    ACC_BMx_CMD_WRITE |
+			    ACC_BMx_CMD_BYTE_ORD_EL |
+			    ACC_BMx_CMD_BM_CTL_ENABLE);
+		} else {
+			/*
+			 * output same PCM to FRONT.LR(BM0) and SURROUND.LR(BM6).
+			 * CENTER(BM4) and LFE(BM7) doesn't sound.
+			 *
+			 * 2ch: L,R,L,R,L,R,L,R,... => BM0: L,R,L,R,L,R,L,R,...
+			 *                             BM6: (same of BM0)
+			 *                             BM4: none
+			 *                             BM7: none
+			 */
+			bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM0_PRD,
+			    PRDADDR(PRD_TABLE_FRONT, 0));
+			bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM6_PRD,
+			    PRDADDR(PRD_TABLE_FRONT, 0));
+
+			/* start DMA transfer */
+			bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM0_CMD,
+			    ACC_BMx_CMD_WRITE |
+			    ACC_BMx_CMD_BYTE_ORD_EL |
+			    ACC_BMx_CMD_BM_CTL_ENABLE);
+			bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM6_CMD,
+			    ACC_BMx_CMD_WRITE |
+			    ACC_BMx_CMD_BYTE_ORD_EL |
+			    ACC_BMx_CMD_BM_CTL_ENABLE);
+		}
+		break;
+	case 4:
+		/*
+		 * output 4ch PCM split to FRONT.LR(BM0) and SURROUND.LR(BM6).
+		 * CENTER(BM4) and LFE(BM7) doesn't sound.
+		 *
+		 * rearrange ordered channel to continuous per channel
+		 *
+		 *   4ch: L,R,SL,SR,L,R,SL,SR,... => BM0: L,R,L,R,...
+		 *                                   BM6: SL,SR,SL,SR,...
+		 *                                   BM4: none
+		 *                                   BM7: none
+		 */
+		if (sc->sc_mch_split_buf)
+			gcscaudio_free(sc, sc->sc_mch_split_buf, M_DEVBUF);
+
+		if ((sc->sc_mch_split_buf = gcscaudio_malloc(sc, AUMODE_PLAY,
+		    size, M_DEVBUF, M_WAITOK)) == NULL)
+			return ENOMEM;
+
+		/*
+		 * 1st and 2nd blocks are split immediately.
+		 * Other blocks will be split synchronous with intr.
+		 */
+		split_buffer_4ch(sc->sc_mch_split_buf, start, blksize * 2,
+		    blksize);
+
+		sc->sc_mch_split_start = start;
+		sc->sc_mch_split_size = size;
+		sc->sc_mch_split_blksize = blksize;
+		sc->sc_mch_split_off = (blksize * 2) % size;
+		sc->sc_mch_splitter = split_buffer_4ch;	/* split function */
+
+		if (build_prdtables(sc, PRD_TABLE_FRONT, start, size, blksize,
+		    blksize / 2, 0))
+			return EINVAL;
+		if (build_prdtables(sc, PRD_TABLE_SURR, sc->sc_mch_split_buf,
+		    size, blksize, blksize / 2, 0))
+			return EINVAL;
+
+		bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM0_PRD,
+		    PRDADDR(PRD_TABLE_FRONT, 0));
+		bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM6_PRD,
+		    PRDADDR(PRD_TABLE_SURR, 0));
+
+		/* start DMA transfer */
+		bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM0_CMD,
+		    ACC_BMx_CMD_WRITE |
+		    ACC_BMx_CMD_BYTE_ORD_EL |
+		    ACC_BMx_CMD_BM_CTL_ENABLE);
+		bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM6_CMD,
+		    ACC_BMx_CMD_WRITE |
+		    ACC_BMx_CMD_BYTE_ORD_EL |
+		    ACC_BMx_CMD_BM_CTL_ENABLE);
+		break;
+	case 6:
+		/*
+		 * output 6ch PCM split to
+		 * FRONT.LR(BM0), SURROUND.LR(BM6), CENTER(BM4) and LFE(BM7)
+		 *
+		 * rearrange ordered channel to continuous per channel
+		 *
+		 *   5.1ch: L,R,C,LFE,SL,SR,... => BM0: L,R,...
+		 *                                 BM4: C,...
+		 *                                 BM6: SL,SR,...
+		 *                                 BM7: LFE,...
+		 *
+		 */
+		if (sc->sc_mch_split_buf)
+			gcscaudio_free(sc, sc->sc_mch_split_buf, M_DEVBUF);
+
+		if ((sc->sc_mch_split_buf = gcscaudio_malloc(sc, AUMODE_PLAY,
+		    size, M_DEVBUF, M_WAITOK)) == NULL)
+			return ENOMEM;
+
+		/*
+		 * 1st and 2nd blocks are split immediately.
+		 * Other block will be split synchronous with intr.
+		 */
+		split_buffer_6ch(sc->sc_mch_split_buf, start, blksize * 2,
+		    blksize);
+
+		sc->sc_mch_split_start = start;
+		sc->sc_mch_split_size = size;
+		sc->sc_mch_split_blksize = blksize;
+		sc->sc_mch_split_off = (blksize * 2) % size;
+		sc->sc_mch_splitter = split_buffer_6ch;	/* split function */
+
+		if (build_prdtables(sc, PRD_TABLE_FRONT, start, size, blksize,
+		    blksize / 3, 0))
+			return EINVAL;
+		if (build_prdtables(sc, PRD_TABLE_CENTER, sc->sc_mch_split_buf,
+		    size, blksize, blksize / 3, blksize / 2))
+			return EINVAL;
+		if (build_prdtables(sc, PRD_TABLE_SURR, sc->sc_mch_split_buf,
+		    size, blksize, blksize / 3, 0))
+			return EINVAL;
+		if (build_prdtables(sc, PRD_TABLE_LFE, sc->sc_mch_split_buf,
+		    size, blksize, blksize / 3, blksize / 2 + blksize / 4))
+			return EINVAL;
+
+		bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM0_PRD,
+		    PRDADDR(PRD_TABLE_FRONT, 0));
+		bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM4_PRD,
+		    PRDADDR(PRD_TABLE_CENTER, 0));
+		bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM6_PRD,
+		    PRDADDR(PRD_TABLE_SURR, 0));
+		bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM7_PRD,
+		    PRDADDR(PRD_TABLE_LFE, 0));
+
+		/* start DMA transfer */
+		bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM0_CMD,
+		    ACC_BMx_CMD_WRITE | ACC_BMx_CMD_BYTE_ORD_EL |
+		    ACC_BMx_CMD_BM_CTL_ENABLE);
+		bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM4_CMD,
+		    ACC_BMx_CMD_WRITE | ACC_BMx_CMD_BYTE_ORD_EL |
+		    ACC_BMx_CMD_BM_CTL_ENABLE);
+		bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM6_CMD,
+		    ACC_BMx_CMD_WRITE | ACC_BMx_CMD_BYTE_ORD_EL |
+		    ACC_BMx_CMD_BM_CTL_ENABLE);
+		bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM7_CMD,
+		    ACC_BMx_CMD_WRITE | ACC_BMx_CMD_BYTE_ORD_EL |
+		    ACC_BMx_CMD_BM_CTL_ENABLE);
+		break;
+	}
+
+	return 0;
+}
+
+static int
+gcscaudio_trigger_input(void *addr, void *start, void *end, int blksize,
+                        void (*intr)(void *), void *arg,
+                        const audio_params_t *param)
+{
+	struct gcscaudio_softc *sc;
+	size_t size;
+
+	sc = (struct gcscaudio_softc *)addr;
+	sc->sc_rec.ch_intr = intr;
+	sc->sc_rec.ch_intr_arg = arg;
+	size = (char *)end - (char *)start;
+
+	if (build_prdtables(sc, PRD_TABLE_REC, start, size, blksize, blksize, 0))
+		return EINVAL;
+
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM1_PRD,
+	    PRDADDR(PRD_TABLE_REC, 0));
+
+	/* start transfer */
+	bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM1_CMD,
+	    ACC_BMx_CMD_READ |
+	    ACC_BMx_CMD_BYTE_ORD_EL |
+	    ACC_BMx_CMD_BM_CTL_ENABLE);
+
+	return 0;
+}
+
+static int
+gcscaudio_intr(void *arg)
+{
+	struct gcscaudio_softc *sc;
+	uint16_t intr;
+	uint8_t bmstat;
+	int nintr;
+
+	nintr = 0;
+	sc = (struct gcscaudio_softc *)arg;
+	intr = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ACC_IRQ_STATUS);
+	if (intr == 0)
+		return 0;
+
+	/* Front output */
+	if (intr & ACC_IRQ_STATUS_BM0_IRQ_STS) {
+		bmstat = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ACC_BM0_STATUS);
+		if (bmstat & ACC_BMx_STATUS_BM_EOP_ERR)
+			aprint_normal_dev(&sc->sc_dev, "BM0: Bus Master Error\n");
+		if (!(bmstat & ACC_BMx_STATUS_EOP))
+			aprint_normal_dev(&sc->sc_dev, "BM0: NO End of Page?\n");
+
+		if (sc->sc_play.ch_intr) {
+			sc->sc_play.ch_intr(sc->sc_play.ch_intr_arg);
+			channel_splitter(sc);
+		}
+		nintr++;
+	}
+
+	/* Center output */
+	if (intr & ACC_IRQ_STATUS_BM4_IRQ_STS) {
+		bmstat = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ACC_BM4_STATUS);
+		if (bmstat & ACC_BMx_STATUS_BM_EOP_ERR)
+			aprint_normal_dev(&sc->sc_dev, "BM4: Bus Master Error\n");
+		if (!(bmstat & ACC_BMx_STATUS_EOP))
+			aprint_normal_dev(&sc->sc_dev, "BM4: NO End of Page?\n");
+
+		nintr++;
+	}
+
+	/* Surround output */
+	if (intr & ACC_IRQ_STATUS_BM6_IRQ_STS) {
+		bmstat = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ACC_BM6_STATUS);
+		if (bmstat & ACC_BMx_STATUS_BM_EOP_ERR)
+			aprint_normal_dev(&sc->sc_dev, "BM6: Bus Master Error\n");
+		if (!(bmstat & ACC_BMx_STATUS_EOP))
+			aprint_normal_dev(&sc->sc_dev, "BM6: NO End of Page?\n");
+
+		nintr++;
+	}
+
+	/* LowFrequencyEffect output */
+	if (intr & ACC_IRQ_STATUS_BM7_IRQ_STS) {
+		bmstat = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ACC_BM7_STATUS);
+		if (bmstat & ACC_BMx_STATUS_BM_EOP_ERR)
+			aprint_normal_dev(&sc->sc_dev, "BM7: Bus Master Error\n");
+		if (!(bmstat & ACC_BMx_STATUS_EOP))
+			aprint_normal_dev(&sc->sc_dev, "BM7: NO End of Page?\n");
+
+		nintr++;
+	}
+
+	/* record */
+	if (intr & ACC_IRQ_STATUS_BM1_IRQ_STS) {
+		bmstat = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ACC_BM1_STATUS);
+		if (bmstat & ACC_BMx_STATUS_BM_EOP_ERR)
+			aprint_normal_dev(&sc->sc_dev, "BM1: Bus Master Error\n");
+		if (!(bmstat & ACC_BMx_STATUS_EOP))
+			aprint_normal_dev(&sc->sc_dev, "BM1: NO End of Page?\n");
+
+		if (sc->sc_rec.ch_intr) {
+			sc->sc_rec.ch_intr(sc->sc_rec.ch_intr_arg);
+		}
+		nintr++;
+	}
+
+#ifdef GCSCAUDIO_DEBUG
+	if (intr & ACC_IRQ_STATUS_IRQ_STS)
+		aprint_normal_dev(&sc->sc_dev, "Codec GPIO IRQ Status\n");
+	if (intr & ACC_IRQ_STATUS_WU_IRQ_STS)
+		aprint_normal_dev(&sc->sc_dev, "Codec GPIO Wakeup IRQ Status\n");
+	if (intr & ACC_IRQ_STATUS_BM2_IRQ_STS)
+		aprint_normal_dev(&sc->sc_dev, "Audio Bus Master 2 IRQ Status\n");
+	if (intr & ACC_IRQ_STATUS_BM3_IRQ_STS)
+		aprint_normal_dev(&sc->sc_dev, "Audio Bus Master 3 IRQ Status\n");
+	if (intr & ACC_IRQ_STATUS_BM5_IRQ_STS)
+		aprint_normal_dev(&sc->sc_dev, "Audio Bus Master 5 IRQ Status\n");
+#endif
+
+	return nintr ? 1 : 0;
+}
+
+static bool
+gcscaudio_resume(device_t dv PMF_FN_ARGS)
+{
+	struct gcscaudio_softc *sc = device_private(dv);
+
+	gcscaudio_reset_codec(sc);
+	DELAY(1000);
+	(sc->codec_if->vtbl->restore_ports)(sc->codec_if);
+
+	return true;
+}
+
+static int
+gcscaudio_allocate_dma(struct gcscaudio_softc *sc, size_t size, void **addrp,
+                       bus_dma_segment_t *seglist, int nseg, int *rsegp,
+                       int flags, bus_dmamap_t *mapp)
+{
+	int error;
+
+	if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, seglist,
+	    nseg, rsegp, flags)) != 0) {
+		aprint_error_dev(&sc->sc_dev,
+		    "unable to allocate DMA buffer, error=%d\n", error);
+		goto fail_alloc;
+	}
+
+	if ((error = bus_dmamem_map(sc->sc_dmat, seglist, nseg, size, addrp,
+	    BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
+		aprint_error_dev(&sc->sc_dev,
+		    "unable to map DMA buffer, error=%d\n",
+		    error);
+		goto fail_map;
+	}
+
+	if ((error = bus_dmamap_create(sc->sc_dmat, size, nseg, size, 0,
+	    BUS_DMA_NOWAIT, mapp)) != 0) {
+		aprint_error_dev(&sc->sc_dev,
+		    "unable to create DMA map, error=%d\n", error);
+		goto fail_create;
+	}
+
+	if ((error = bus_dmamap_load(sc->sc_dmat, *mapp, *addrp, size, NULL,
+	    BUS_DMA_NOWAIT)) != 0) {
+		aprint_error_dev(&sc->sc_dev,
+		    "unable to load DMA map, error=%d\n", error);
+		goto fail_load;
+	}
+
+	return 0;
+
+fail_load:
+	bus_dmamap_destroy(sc->sc_dmat, *mapp);
+fail_create:
+	bus_dmamem_unmap(sc->sc_dmat, *addrp, size);
+fail_map:
+	bus_dmamem_free(sc->sc_dmat, seglist, nseg);
+fail_alloc:
+	return error;
+}
diff -auNr NetBSD.orig/sys/arch/i386/pci/gcscaudioreg.h NetBSD/sys/arch/i386/pci/gcscaudioreg.h
--- NetBSD.orig/sys/arch/i386/pci/gcscaudioreg.h	1970-01-01 09:00:00.000000000 +0900
+++ NetBSD/sys/arch/i386/pci/gcscaudioreg.h	2008-12-28 07:06:51.000000000 +0900
@@ -0,0 +1,151 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2008 SHIMIZU Ryo <ryo@nerv.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _I386_PCI_GCSCAUDIOREG_H_
+#define _I386_PCI_GCSCAUDIOREG_H_
+
+/*
+ * Reference:
+ *  - AMD Geode CS5536 Companion Device Data Book
+ *    http://www.amd.com/files/connectivitysolutions/geode/geode_lx/33238G_cs5536_db.pdf
+ */
+
+#define ACC_GLD_MSR_CAP			0x51500000	/* GeodeLinkDevice Capabilities */
+
+/*
+ * AC97 Audio Codec Controller (ACC) Registers
+ */
+#define ACC_GPIO_STATUS			0x00		/* Codec GPIO Status Register */
+# define ACC_GPIO_STATUS_GPIO_EN	0x80000000	/* GPIO Enable */
+# define ACC_GPIO_STATUS_INT_EN		0x40000000	/* Codec GPIO Interrupt Enable */
+# define ACC_GPIO_STATUS_WU_INT_EN	0x20000000	/* Codec GPIO Wakeup Interrupt Enable */
+# define ACC_GPIO_STATUS_INT_FLAG	0x00200000	/* Codec GPIO Interrupt Flag (Read to Clear) */
+# define ACC_GPIO_STATUS_WU_INT_FLAG	0x00100000	/* Codec GPIO Wakeup Interrupt Flag (Read to Clear) */
+# define ACC_GPIO_STATUS_PIN_STS_MASK	0x000fffff	/* Codec GPIO Pin Status (Read Only) */
+
+#define ACC_GPIO_CNTL			0x04		/* Codec GPIO Control Register */
+# define ACC_GPIO_CNTL_PIN_DATA_MASK	0x000fffff	/* Codec GPIO Pin Data */
+
+#define ACC_CODEC_REG2ADDR(reg)	(((reg) & 0x7f) << 24)
+#define ACC_CODEC_ADDR2REG(adr)	(((adr) >> 24) & 0x7f)
+
+#define ACC_CODEC_STATUS		0x08		/* Codec Status Register */
+# define ACC_CODEC_STATUS_STS_ADD_MASK	0xff000000	/* Codec Status Address (Read Only) */
+# define ACC_CODEC_STATUS_PRM_RDY_STS	0x00800000	/* Primary Codec Ready (Read Only) */
+# define ACC_CODEC_STATUS_SEC_RDY_STS	0x00400000	/* Secondary Codec Ready (Read Only) */
+# define ACC_CODEC_STATUS_SDATAIN2_EN	0x00200000	/* Enable Second Serial Data Input (AC_S_IN2) */
+# define ACC_CODEC_STATUS_BM5_SEL	0x00100000	/* Audio Bus Master 5 AC97 Slot Select */
+# define ACC_CODEC_STATUS_BM4_SEL	0x00080000	/* Audio Bus Master 4 AC97 Slot Select */
+# define ACC_CODEC_STATUS_STS_NEW	0x00020000	/* Codec Status New (Read to Clear) */
+# define ACC_CODEC_STATUS_STS_DATA_MASK	0x0000ffff	/* Codec Status Data (Read Only) */
+
+#define ACC_CODEC_CNTL			0x0c		/* Codec Control Register */
+# define ACC_CODEC_CNTL_RW_CMD		0x80000000	/* Codec Read/Write Command */
+# define ACC_CODEC_CNTL_READ_CMD	0x80000000	/* Codec Read Command */
+# define ACC_CODEC_CNTL_WRITE_CMD	0x00000000	/* Codec Write Command */
+# define ACC_CODEC_CNTL_ADD_MASK	0x7f000000	/* CMD_ADD Codec Command Address */
+# define ACC_CODEC_CNTL_COMM_SEL_MASK	0x00c00000	/* COMM_SEL Audio Codec Communication */
+# define ACC_CODEC_CNTL_PD_PRIM		0x00200000	/* Power-down Semaphore for Primary Codec */
+# define ACC_CODEC_CNTL_PD_SEC		0x00100000	/* Power-down Semaphore for Secondary Codec */
+# define ACC_CODEC_CNTL_LNK_SHTDWN	0x00040000	/* AC Link Shutdown */
+# define ACC_CODEC_CNTL_LNK_WRM_RST	0x00020000	/* AC Link Warm Reset */
+# define ACC_CODEC_CNTL_CMD_NEW		0x00010000	/* Codec Command New */
+# define ACC_CODEC_CNTL_CMD_DATA_MASK	0x0000ffff	/* Codec Command Data */
+
+#define ACC_IRQ_STATUS			0x12		/* Second Level Audio IRQ Status Register */
+# define ACC_IRQ_STATUS_BM7_IRQ_STS	0x0200		/* Audio Bus Master 7 IRQ Status */
+# define ACC_IRQ_STATUS_BM6_IRQ_STS	0x0100		/* Audio Bus Master 6 IRQ Status */
+# define ACC_IRQ_STATUS_BM5_IRQ_STS	0x0080		/* Audio Bus Master 5 IRQ Status */
+# define ACC_IRQ_STATUS_BM4_IRQ_STS	0x0040		/* Audio Bus Master 4 IRQ Status */
+# define ACC_IRQ_STATUS_BM3_IRQ_STS	0x0020		/* Audio Bus Master 3 IRQ Status */
+# define ACC_IRQ_STATUS_BM2_IRQ_STS	0x0010		/* Audio Bus Master 2 IRQ Status */
+# define ACC_IRQ_STATUS_BM1_IRQ_STS	0x0008		/* Audio Bus Master 1 IRQ Status */
+# define ACC_IRQ_STATUS_BM0_IRQ_STS	0x0004		/* Audio Bus Master 0 IRQ Status */
+# define ACC_IRQ_STATUS_WU_IRQ_STS	0x0002		/* Codec GPIO Wakeup IRQ Status */
+# define ACC_IRQ_STATUS_IRQ_STS		0x0001		/* Codec GPIO IRQ Status */
+
+#define ACC_ENGINE_CNTL			0x14		/* Bus Master Engine Control Register */
+# define ACC_ENGINE_CNTL_SSND_MODE	0x00000001	/* Surround Sound (5.1) Synchronization Mode */
+
+#define ACC_BM0_CMD			0x20		/* Bus Master 0 Command */
+#define ACC_BM0_STATUS			0x21		/* Bus Master 0 IRQ Status */
+#define ACC_BM0_PRD			0x24		/* Bus Master 0 PRD Table Address */
+#define ACC_BM1_CMD			0x28		/* Bus Master 1 Command */
+#define ACC_BM1_STATUS			0x29		/* Bus Master 1 IRQ Status */
+#define ACC_BM1_PRD			0x2c		/* Bus Master 1 PRD Table Address */
+#define ACC_BM2_CMD			0x30		/* Bus Master 2 Command */
+#define ACC_BM2_STATUS			0x31		/* Bus Master 2 IRQ Status */
+#define ACC_BM2_PRD			0x34		/* Bus Master 2 PRD Table Address */
+#define ACC_BM3_CMD			0x38		/* Bus Master 3 Command */
+#define ACC_BM3_STATUS			0x39		/* Bus Master 3 IRQ Status */
+#define ACC_BM3_PRD			0x3c		/* Bus Master 3 PRD Table Address */
+#define ACC_BM4_CMD			0x40		/* Bus Master 4 Command */
+#define ACC_BM4_STATUS			0x41		/* Bus Master 4 IRQ Status */
+#define ACC_BM4_PRD			0x44		/* Bus Master 4 PRD Table Address */
+#define ACC_BM5_CMD			0x48		/* Bus Master 5 Command */
+#define ACC_BM5_STATUS			0x49		/* Bus Master 5 IRQ Status */
+#define ACC_BM5_PRD			0x4c		/* Bus Master 5 PRD Table Address */
+#define ACC_BM6_CMD			0x50		/* Bus Master 6 Command */
+#define ACC_BM6_STATUS			0x51		/* Bus Master 6 IRQ Status */
+#define ACC_BM6_PRD			0x54		/* Bus Master 6 PRD Table Address */
+#define ACC_BM7_CMD			0x58		/* Bus Master 7 Command */
+#define ACC_BM7_STATUS			0x59		/* Bus Master 7 IRQ Status */
+#define ACC_BM7_PRD			0x5c		/* Bus Master 7 PRD Table Address */
+# define ACC_BMx_CMD_RW_MASK		0x08
+# define ACC_BMx_CMD_READ		0x08		/* Codec to Memory */
+# define ACC_BMx_CMD_WRITE		0x00		/* Memory to Codec */
+# define ACC_BMx_CMD_BYTE_ORD_MASK	0x04
+# define ACC_BMx_CMD_BYTE_ORD_EL	0x00		/* Little Endian */
+# define ACC_BMx_CMD_BYTE_ORD_EB	0x04		/* Big Endian */
+# define ACC_BMx_CMD_BM_CTL_MASK	0x03
+# define ACC_BMx_CMD_BM_CTL_DISABLE	0x00		/* Disable bus master */
+# define ACC_BMx_CMD_BM_CTL_ENABLE	0x01		/* Enable bus master */
+# define ACC_BMx_CMD_BM_CTL_PAUSE	0x03		/* Pause bus master */
+# define ACC_BMx_STATUS_BM_EOP_ERR	0x02		/* Bus Master Error */
+# define ACC_BMx_STATUS_EOP		0x01		/* End of Page */
+
+/* PRD - Physical Region Descriptor Table (addressed by ACC_BMx_PRD) */
+struct acc_prd {
+	uint32_t address;
+	uint32_t ctrlsize;
+#define ACC_BMx_PRD_CTRL_EOT		0x80000000
+#define ACC_BMx_PRD_CTRL_EOP		0x40000000
+#define ACC_BMx_PRD_CTRL_JMP		0x20000000
+#define ACC_BMx_PRD_SIZE_MASK		0x0000ffff
+};
+
+#define ACC_BM0_PNTR			0x60		/* Bus Master 0 DMA Pointer */
+#define ACC_BM1_PNTR			0x64		/* Bus Master 1 DMA Pointer */
+#define ACC_BM2_PNTR			0x68		/* Bus Master 2 DMA Pointer */
+#define ACC_BM3_PNTR			0x6C		/* Bus Master 3 DMA Pointer */
+#define ACC_BM4_PNTR			0x70		/* Bus Master 4 DMA Pointer */
+#define ACC_BM5_PNTR			0x74		/* Bus Master 5 DMA Pointer */
+#define ACC_BM6_PNTR			0x78		/* Bus Master 6 DMA Pointer */
+#define ACC_BM7_PNTR			0x7C		/* Bus Master 7 DMA Pointer */
+
+#endif /* _I386_PCI_GCSCAUDIOREG_H_ */

>Release-Note:

>Audit-Trail:

Responsible-Changed-From-To: port-i386-maintainer->jmcneill
Responsible-Changed-By: jmcneill@NetBSD.org
Responsible-Changed-When: Sun, 28 Dec 2008 14:46:16 +0000
Responsible-Changed-Why:
I'm looking at it.


State-Changed-From-To: open->closed
State-Changed-By: jmcneill@NetBSD.org
State-Changed-When: Sun, 28 Dec 2008 15:19:50 +0000
State-Changed-Why:
The driver has been imported to sys/dev/pci, thank you for you contribution!


From: "Jared D. McNeill" <jmcneill@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/40284 CVS commit: src/sys/dev/pci
Date: Sun, 28 Dec 2008 15:16:25 +0000 (UTC)

 Module Name:	src
 Committed By:	jmcneill
 Date:		Sun Dec 28 15:16:25 UTC 2008

 Modified Files:
 	src/sys/dev/pci: files.pci
 Added Files:
 	src/sys/dev/pci: gcscaudio.c gcscaudioreg.h

 Log Message:
 PR# port-i386/40284: add AMD Geode CS5536 audio driver; written by
 SHIMIZU Ryo <ryo@nerv.org>


 To generate a diff of this commit:
 cvs rdiff -r1.308 -r1.309 src/sys/dev/pci/files.pci
 cvs rdiff -r0 -r1.1 src/sys/dev/pci/gcscaudio.c \
     src/sys/dev/pci/gcscaudioreg.h

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

From: "Jared D. McNeill" <jmcneill@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/40284 CVS commit: src/sys/arch/i386/conf
Date: Sun, 28 Dec 2008 15:18:21 +0000 (UTC)

 Module Name:	src
 Committed By:	jmcneill
 Date:		Sun Dec 28 15:18:21 UTC 2008

 Modified Files:
 	src/sys/arch/i386/conf: ALL GENERIC

 Log Message:
 PR# port-i386/40284: add AMD Geode CS5536 audio driver; add gcscaudio(4)
 to i386 GENERIC and ALL kernels


 To generate a diff of this commit:
 cvs rdiff -r1.186 -r1.187 src/sys/arch/i386/conf/ALL
 cvs rdiff -r1.921 -r1.922 src/sys/arch/i386/conf/GENERIC

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

From: Soren Jacobsen <snj@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/40284 CVS commit: [netbsd-5] src/sys/dev/pci
Date: Fri, 1 May 2009 01:19:10 +0000

 Module Name:	src
 Committed By:	snj
 Date:		Fri May  1 01:19:09 UTC 2009

 Modified Files:
 	src/sys/dev/pci [netbsd-5]: files.pci
 Added Files:
 	src/sys/dev/pci [netbsd-5]: gcscaudio.c gcscaudioreg.h

 Log Message:
 Pull up following revision(s) (requested by jmcneill in ticket #260):
 	sys/dev/pci/files.pci: revision 1.309
 	sys/dev/pci/gcscaudio.c: revision 1.1
 	sys/dev/pci/gcscaudioreg.h: revision 1.1
 PR# port-i386/40284: add AMD Geode CS5536 audio driver; written by
 SHIMIZU Ryo <ryo@nerv.org>


 To generate a diff of this commit:
 cvs rdiff -u -r1.308 -r1.308.2.1 src/sys/dev/pci/files.pci
 cvs rdiff -u -r0 -r1.1.8.2 src/sys/dev/pci/gcscaudio.c \
     src/sys/dev/pci/gcscaudioreg.h

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

From: Soren Jacobsen <snj@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/40284 CVS commit: [netbsd-5] src/sys/arch/i386/conf
Date: Fri, 1 May 2009 01:20:42 +0000

 Module Name:	src
 Committed By:	snj
 Date:		Fri May  1 01:20:42 UTC 2009

 Modified Files:
 	src/sys/arch/i386/conf [netbsd-5]: ALL GENERIC

 Log Message:
 Pull up following revision(s) (requested by jmcneill in ticket #260):
 	sys/arch/i386/conf/ALL: revision 1.187
 	sys/arch/i386/conf/GENERIC: revision 1.922
 PR# port-i386/40284: add AMD Geode CS5536 audio driver; add gcscaudio(4)
 to i386 GENERIC and ALL kernels


 To generate a diff of this commit:
 cvs rdiff -u -r1.183.4.1 -r1.183.4.2 src/sys/arch/i386/conf/ALL
 cvs rdiff -u -r1.915.2.3 -r1.915.2.4 src/sys/arch/i386/conf/GENERIC

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2007 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.