ym_acpi.c revision 1.7
1/* $NetBSD: ym_acpi.c,v 1.7 2009/05/12 09:29:46 cegger Exp $ */
2
3/*
4 * Copyright (c) 2006 Jasper Wallace <jasper@pointless.net>
5 * All rights reserved.
6 *
7 * Copyright (c) 2002 Jared D. McNeill <jmcneill@invisible.ca>
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. The name of the author may not be used to endorse or promote products
16 *    derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include <sys/cdefs.h>
32__KERNEL_RCSID(0, "$NetBSD: ym_acpi.c,v 1.7 2009/05/12 09:29:46 cegger Exp $");
33
34#include "mpu_ym.h"
35
36#include <sys/param.h>
37#include <sys/bus.h>
38
39#include <dev/acpi/acpivar.h>
40
41#include <dev/audio_if.h>
42
43#include <dev/ic/ad1848reg.h>
44#include <dev/isa/ad1848var.h>
45
46#include <dev/ic/opl3sa3reg.h>
47#include <dev/isa/wssreg.h>
48#include <dev/isa/ymvar.h>
49
50
51static int	ym_acpi_match(struct device *, cfdata_t, void *);
52static void	ym_acpi_attach(struct device *, struct device *, void *);
53
54CFATTACH_DECL(ym_acpi, sizeof(struct ym_softc), ym_acpi_match,
55    ym_acpi_attach, NULL, NULL);
56
57/*
58 * ym_acpi_match: autoconf(9) match routine
59 */
60static int
61ym_acpi_match(struct device *parent, cfdata_t match,
62    void *aux)
63{
64	struct acpi_attach_args *aa = aux;
65
66	if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
67		return 0;
68	/* Yamaha OPL3-SA2 or OPL3-SA3 */
69	if (strcmp("YMH0021", aa->aa_node->ad_devinfo->HardwareId.Value))
70		return 0;
71
72	return 1;
73}
74
75/*
76 * ym_acpi_attach: autoconf(9) attach routine
77 */
78static void
79ym_acpi_attach(struct device *parent, struct device *self, void *aux)
80{
81	struct ym_softc *sc = (struct ym_softc *)self;
82	struct acpi_attach_args *aa = aux;
83	struct acpi_resources res;
84	struct acpi_io *sb_io, *codec_io, *opl_io, *control_io;
85#if NMPU_YM > 0
86	struct acpi_io *mpu_io;
87#endif
88	struct acpi_irq *irq;
89	struct acpi_drq *playdrq, *recdrq;
90	struct ad1848_softc *ac = &sc->sc_ad1848.sc_ad1848;
91	ACPI_STATUS rv;
92
93	/* Parse our resources */
94	rv = acpi_resource_parse(&sc->sc_ad1848.sc_ad1848.sc_dev,
95	    aa->aa_node->ad_handle, "_CRS", &res,
96	    &acpi_resource_parse_ops_default);
97	if (ACPI_FAILURE(rv))
98		return;
99
100	/*
101	 * sc_sb_ioh	 @ 0
102	 * sc_ioh	 @ 1
103	 * sc_opl_ioh	 @ 2
104	 * sc_mpu_ioh	 @ 3
105	 * sc_controlioh @ 4
106	 */
107
108	/* Find and map our i/o registers */
109	sc->sc_iot = aa->aa_iot;
110	sb_io	 = acpi_res_io(&res, 0);
111	codec_io = acpi_res_io(&res, 1);
112	opl_io	 = acpi_res_io(&res, 2);
113#if NMPU_YM > 0
114	mpu_io	 = acpi_res_io(&res, 3);
115#endif
116	control_io = acpi_res_io(&res, 4);
117
118	if (sb_io == NULL || codec_io == NULL || opl_io == NULL ||
119#if NMPU_YM > 0
120	    mpu_io == NULL ||
121#endif
122	    control_io == NULL) {
123		aprint_error_dev(self, "unable to find i/o registers resource\n");
124		goto out;
125	}
126	if (bus_space_map(sc->sc_iot, sb_io->ar_base, sb_io->ar_length,
127	    0, &sc->sc_sb_ioh) != 0) {
128		aprint_error_dev(self, "unable to map i/o registers (sb)\n");
129		goto out;
130	}
131	if (bus_space_map(sc->sc_iot, codec_io->ar_base, codec_io->ar_length,
132	    0, &sc->sc_ioh) != 0) {
133		aprint_error_dev(self, "unable to map i/o registers (codec)\n");
134		goto out;
135	}
136	if (bus_space_map(sc->sc_iot, opl_io->ar_base, opl_io->ar_length,
137	    0, &sc->sc_opl_ioh) != 0) {
138		aprint_error_dev(self, "unable to map i/o registers (opl)\n");
139		goto out;
140	}
141#if NMPU_YM > 0
142	if (bus_space_map(sc->sc_iot, mpu_io->ar_base, mpu_io->ar_length,
143	    0, &sc->sc_mpu_ioh) != 0) {
144		aprint_error_dev(self, "unable to map i/o registers (mpu)\n");
145		goto out;
146	}
147#endif
148	if (bus_space_map(sc->sc_iot, control_io->ar_base,
149	    control_io->ar_length, 0, &sc->sc_controlioh) != 0) {
150		aprint_error_dev(self, "unable to map i/o registers (control)\n");
151		goto out;
152	}
153
154	sc->sc_ic = aa->aa_ic;
155
156	/* Find our IRQ */
157	irq = acpi_res_irq(&res, 0);
158	if (irq == NULL) {
159		aprint_error_dev(self, "unable to find irq resource\n");
160		/* XXX bus_space_unmap */
161		goto out;
162	}
163	sc->ym_irq = irq->ar_irq;
164
165	/* Find our playback and record DRQs */
166	playdrq = acpi_res_drq(&res, 0);
167	recdrq = acpi_res_drq(&res, 1);
168	if (playdrq == NULL) {
169		aprint_error_dev(self, "unable to find drq resources\n");
170		/* XXX bus_space_unmap */
171		goto out;
172	}
173	if (recdrq == NULL) {
174		/* half-duplex mode */
175		sc->ym_recdrq = sc->ym_playdrq = playdrq->ar_drq;
176	} else {
177		sc->ym_playdrq = playdrq->ar_drq;
178		sc->ym_recdrq = recdrq->ar_drq;
179	}
180
181	ac->sc_iot = sc->sc_iot;
182	if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, WSS_CODEC,
183	    AD1848_NPORT, &ac->sc_ioh)) {
184		aprint_error_dev(self, "bus_space_subregion failed\n");
185		/* XXX cleanup */
186		goto out;
187	}
188
189	aprint_normal_dev(self, "");
190
191	ac->mode = 2;
192	ac->MCE_bit = MODE_CHANGE_ENABLE;
193
194	sc->sc_ad1848.sc_ic = sc->sc_ic;
195
196	/* Attach our ym device */
197	ym_attach(sc);
198
199 out:
200	acpi_resource_cleanup(&res);
201}
202