ym_acpi.c revision 1.2
1/* $NetBSD: ym_acpi.c,v 1.2 2006/10/12 01:30:55 christos 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.2 2006/10/12 01:30:55 christos Exp $");
33
34#include "mpu_ym.h"
35
36#include <sys/param.h>
37#include <machine/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 *, struct cfdata *, 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 __unused, struct cfdata *match __unused,
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 __unused, 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	aprint_naive("\n");
94	aprint_normal("\n");
95
96	/* Parse our resources */
97	rv = acpi_resource_parse(&sc->sc_ad1848.sc_ad1848.sc_dev,
98	    aa->aa_node->ad_handle, "_CRS", &res,
99	    &acpi_resource_parse_ops_default);
100	if (ACPI_FAILURE(rv))
101		return;
102
103	/*
104	 * sc_sb_ioh	 @ 0
105	 * sc_ioh	 @ 1
106	 * sc_opl_ioh	 @ 2
107	 * sc_mpu_ioh	 @ 3
108	 * sc_controlioh @ 4
109	 */
110
111	/* Find and map our i/o registers */
112	sc->sc_iot = aa->aa_iot;
113	sb_io	 = acpi_res_io(&res, 0);
114	codec_io = acpi_res_io(&res, 1);
115	opl_io	 = acpi_res_io(&res, 2);
116#if NMPU_YM > 0
117	mpu_io	 = acpi_res_io(&res, 3);
118#endif
119	control_io = acpi_res_io(&res, 4);
120
121	if (sb_io == NULL || codec_io == NULL || opl_io == NULL ||
122#if NMPU_YM > 0
123	    mpu_io == NULL ||
124#endif
125	    control_io == NULL) {
126		aprint_error("%s: unable to find i/o registers resource\n",
127		    self->dv_xname);
128		goto out;
129	}
130	if (bus_space_map(sc->sc_iot, sb_io->ar_base, sb_io->ar_length,
131	    0, &sc->sc_sb_ioh) != 0) {
132		aprint_error("%s: unable to map i/o registers (sb)\n",
133		    self->dv_xname);
134		goto out;
135	}
136	if (bus_space_map(sc->sc_iot, codec_io->ar_base, codec_io->ar_length,
137	    0, &sc->sc_ioh) != 0) {
138		aprint_error("%s: unable to map i/o registers (codec)\n",
139		    self->dv_xname);
140		goto out;
141	}
142	if (bus_space_map(sc->sc_iot, opl_io->ar_base, opl_io->ar_length,
143	    0, &sc->sc_opl_ioh) != 0) {
144		aprint_error("%s: unable to map i/o registers (opl)\n",
145		    self->dv_xname);
146		goto out;
147	}
148#if NMPU_YM > 0
149	if (bus_space_map(sc->sc_iot, mpu_io->ar_base, mpu_io->ar_length,
150	    0, &sc->sc_mpu_ioh) != 0) {
151		aprint_error("%s: unable to map i/o registers (mpu)\n",
152		    self->dv_xname);
153		goto out;
154	}
155#endif
156	if (bus_space_map(sc->sc_iot, control_io->ar_base,
157	    control_io->ar_length, 0, &sc->sc_controlioh) != 0) {
158		aprint_error("%s: unable to map i/o registers (control)\n",
159		    self->dv_xname);
160		goto out;
161	}
162
163	sc->sc_ic = aa->aa_ic;
164
165	/* Find our IRQ */
166	irq = acpi_res_irq(&res, 0);
167	if (irq == NULL) {
168		aprint_error("%s: unable to find irq resource\n",
169		    self->dv_xname);
170		/* XXX bus_space_unmap */
171		goto out;
172	}
173	sc->ym_irq = irq->ar_irq;
174
175	/* Find our playback and record DRQs */
176	playdrq = acpi_res_drq(&res, 0);
177	recdrq = acpi_res_drq(&res, 1);
178	if (playdrq == NULL) {
179		aprint_error("%s: unable to find drq resources\n",
180		    self->dv_xname);
181		/* XXX bus_space_unmap */
182		goto out;
183	}
184	if (recdrq == NULL) {
185		/* half-duplex mode */
186		sc->ym_recdrq = sc->ym_playdrq = playdrq->ar_drq;
187	} else {
188		sc->ym_playdrq = playdrq->ar_drq;
189		sc->ym_recdrq = recdrq->ar_drq;
190	}
191
192	ac->sc_iot = sc->sc_iot;
193	if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, WSS_CODEC,
194	    AD1848_NPORT, &ac->sc_ioh)) {
195		aprint_error("%s: bus_space_subregion failed\n",
196		    self->dv_xname);
197		/* XXX cleanup */
198		goto out;
199	}
200
201	aprint_normal("%s", self->dv_xname);
202
203	ac->mode = 2;
204	ac->MCE_bit = MODE_CHANGE_ENABLE;
205
206	sc->sc_ad1848.sc_ic = sc->sc_ic;
207
208	/* Attach our ym device */
209	ym_attach(sc);
210
211 out:
212	acpi_resource_cleanup(&res);
213}
214