1 /* $NetBSD: fdc_acpi.c,v 1.35 2009/02/17 12:46:01 jmcneill Exp $ */
4 * Copyright (c) 2002 Jared D. McNeill <jmcneill@invisible.ca>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * ACPI attachment for the PC Floppy Controller driver, based on
30 * sys/arch/i386/pnpbios/fdc_pnpbios.c by Jason R. Thorpe
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: fdc_acpi.c,v 1.35 2009/02/17 12:46:01 jmcneill Exp $");
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/callout.h>
41 #include <sys/device.h>
44 #include <sys/queue.h>
53 #include <dev/isa/isavar.h>
54 #include <dev/isa/isadmavar.h>
56 #include <dev/acpi/acpica.h>
57 #include <dev/acpi/acpireg.h>
58 #include <dev/acpi/acpivar.h>
60 #include <dev/isa/fdcvar.h>
61 #include <dev/isa/fdvar.h>
62 #include <dev/isa/fdreg.h>
64 #include <dev/acpi/fdc_acpireg.h>
66 #define _COMPONENT ACPI_RESOURCE_COMPONENT
67 ACPI_MODULE_NAME ("fdc_acpi")
69 static int fdc_acpi_match(device_t
, cfdata_t
, void *);
70 static void fdc_acpi_attach(device_t
, device_t
, void *);
72 struct fdc_acpi_softc
{
73 struct fdc_softc sc_fdc
;
74 bus_space_handle_t sc_baseioh
;
75 struct acpi_devnode
*sc_node
; /* ACPI devnode */
78 static int fdc_acpi_enumerate(struct fdc_acpi_softc
*);
79 static void fdc_acpi_getknownfds(struct fdc_acpi_softc
*);
81 static const struct fd_type
*fdc_acpi_nvtotype(const char *, int, int);
83 CFATTACH_DECL_NEW(fdc_acpi
, sizeof(struct fdc_acpi_softc
), fdc_acpi_match
,
84 fdc_acpi_attach
, NULL
, NULL
);
87 * Supported device IDs
90 static const char * const fdc_acpi_ids
[] = {
91 "PNP07??", /* PC standard floppy disk controller */
96 * fdc_acpi_match: autoconf(9) match routine
99 fdc_acpi_match(device_t parent
, cfdata_t match
, void *aux
)
101 struct acpi_attach_args
*aa
= aux
;
103 if (aa
->aa_node
->ad_type
!= ACPI_TYPE_DEVICE
)
106 return acpi_match_hid(aa
->aa_node
->ad_devinfo
, fdc_acpi_ids
);
110 * fdc_acpi_attach: autoconf(9) attach routine
113 fdc_acpi_attach(device_t parent
, device_t self
, void *aux
)
115 struct fdc_acpi_softc
*asc
= device_private(self
);
116 struct fdc_softc
*sc
= &asc
->sc_fdc
;
117 struct acpi_attach_args
*aa
= aux
;
118 struct acpi_io
*io
, *ctlio
;
119 struct acpi_irq
*irq
;
120 struct acpi_drq
*drq
;
121 struct acpi_resources res
;
125 sc
->sc_ic
= aa
->aa_ic
;
126 asc
->sc_node
= aa
->aa_node
;
128 /* parse resources */
129 rv
= acpi_resource_parse(sc
->sc_dev
, aa
->aa_node
->ad_handle
, "_CRS",
130 &res
, &acpi_resource_parse_ops_default
);
131 if (ACPI_FAILURE(rv
))
134 /* find our i/o registers */
135 io
= acpi_res_io(&res
, 0);
137 aprint_error_dev(sc
->sc_dev
,
138 "unable to find i/o register resource\n");
143 irq
= acpi_res_irq(&res
, 0);
145 aprint_error_dev(sc
->sc_dev
, "unable to find irq resource\n");
150 drq
= acpi_res_drq(&res
, 0);
152 aprint_error_dev(sc
->sc_dev
, "unable to find drq resource\n");
155 sc
->sc_drq
= drq
->ar_drq
;
157 sc
->sc_iot
= aa
->aa_iot
;
158 if (bus_space_map(sc
->sc_iot
, io
->ar_base
, io
->ar_length
,
159 0, &asc
->sc_baseioh
)) {
160 aprint_error_dev(sc
->sc_dev
, "can't map i/o space\n");
164 switch (io
->ar_length
) {
166 sc
->sc_ioh
= asc
->sc_baseioh
;
169 if (bus_space_subregion(sc
->sc_iot
, asc
->sc_baseioh
, 2, 4,
171 aprint_error_dev(sc
->sc_dev
,
172 "unable to subregion i/o space\n");
177 aprint_error_dev(sc
->sc_dev
,
178 "unknown size: %d of io mapping\n", io
->ar_length
);
183 * omitting the controller I/O port. (One has to exist for there to
184 * be a working fdc). Just try and force the mapping in.
186 ctlio
= acpi_res_io(&res
, 1);
188 if (bus_space_map(sc
->sc_iot
, io
->ar_base
+ io
->ar_length
+ 1,
189 1, 0, &sc
->sc_fdctlioh
)) {
190 aprint_error_dev(sc
->sc_dev
,
191 "unable to force map ctl i/o space\n");
194 aprint_verbose_dev(sc
->sc_dev
,
195 "ctl io %x did't probe. Forced attach\n",
196 io
->ar_base
+ io
->ar_length
+ 1);
198 if (bus_space_map(sc
->sc_iot
, ctlio
->ar_base
, ctlio
->ar_length
,
199 0, &sc
->sc_fdctlioh
)) {
200 aprint_error_dev(sc
->sc_dev
,
201 "unable to map ctl i/o space\n");
206 sc
->sc_ih
= isa_intr_establish(aa
->aa_ic
, irq
->ar_irq
,
207 (irq
->ar_type
== ACPI_EDGE_SENSITIVE
) ? IST_EDGE
: IST_LEVEL
,
208 IPL_BIO
, fdcintr
, sc
);
210 /* Setup direct configuration of floppy drives */
211 sc
->sc_present
= fdc_acpi_enumerate(asc
);
212 if (sc
->sc_present
>= 0) {
214 fdc_acpi_getknownfds(asc
);
217 * XXX if there is no _FDE control method, attempt to
220 #ifdef ACPI_FDC_DEBUG
221 aprint_debug_dev(sc
->sc_dev
,
222 "unable to enumerate, attempting normal probe\n");
229 acpi_resource_cleanup(&res
);
233 fdc_acpi_enumerate(struct fdc_acpi_softc
*asc
)
235 struct fdc_softc
*sc
= &asc
->sc_fdc
;
242 rv
= acpi_eval_struct(asc
->sc_node
->ad_handle
, "_FDE", &abuf
);
243 if (ACPI_FAILURE(rv
)) {
244 #ifdef ACPI_FDC_DEBUG
245 aprint_normal_dev(sc
->sc_dev
, "failed to evaluate _FDE: %s\n",
246 AcpiFormatException(rv
));
250 fde
= (ACPI_OBJECT
*)abuf
.Pointer
;
251 if (fde
->Type
!= ACPI_TYPE_BUFFER
) {
252 aprint_error_dev(sc
->sc_dev
, "expected BUFFER, got %d\n",
256 if (fde
->Buffer
.Length
< 5 * sizeof(UINT32
)) {
257 aprint_error_dev(sc
->sc_dev
,
258 "expected buffer len of %lu, got %d\n",
259 (unsigned long)(5 * sizeof(UINT32
)), fde
->Buffer
.Length
);
263 p
= (UINT32
*) fde
->Buffer
.Pointer
;
266 * Indexes 0 through 3 are each UINT32 booleans. True if a drive
270 for (i
= 0; i
< 4; i
++) {
271 if (p
[i
]) drives
|= (1 << i
);
272 #ifdef ACPI_FDC_DEBUG
273 aprint_normal_dev(sc
->sc_dev
, "drive %d %sattached\n", i
,
279 * p[4] reports tape presence. Possible values:
280 * 0 - Unknown if device is present
281 * 1 - Device is present
282 * 2 - Device is never present
285 * we don't currently use this.
289 ACPI_FREE(abuf
.Pointer
);
294 fdc_acpi_getknownfds(struct fdc_acpi_softc
*asc
)
296 struct fdc_softc
*sc
= &asc
->sc_fdc
;
297 ACPI_OBJECT
*fdi
, *e
;
302 for (i
= 0; i
< 4; i
++) {
303 if ((sc
->sc_present
& (1 << i
)) == 0)
305 rv
= acpi_eval_struct(asc
->sc_node
->ad_handle
, "_FDI", &abuf
);
306 if (ACPI_FAILURE(rv
)) {
307 #ifdef ACPI_FDC_DEBUG
308 aprint_normal_dev(sc
->sc_dev
,
309 "failed to evaluate _FDI: %s on drive %d\n",
310 AcpiFormatException(rv
), i
);
312 /* XXX if _FDI fails, assume 1.44MB floppy */
313 sc
->sc_knownfds
[i
] = &fdc_acpi_fdtypes
[0];
316 fdi
= (ACPI_OBJECT
*)abuf
.Pointer
;
317 if (fdi
->Type
!= ACPI_TYPE_PACKAGE
) {
318 aprint_error_dev(sc
->sc_dev
,
319 "expected PACKAGE, got %d\n", fdi
->Type
);
322 e
= fdi
->Package
.Elements
;
323 sc
->sc_knownfds
[i
] = fdc_acpi_nvtotype(
324 device_xname(sc
->sc_dev
),
325 e
[1].Integer
.Value
, e
[0].Integer
.Value
);
327 /* if fdc_acpi_nvtotype returns NULL, don't attach drive */
328 if (!sc
->sc_knownfds
[i
])
329 sc
->sc_present
&= ~(1 << i
);
332 ACPI_FREE(abuf
.Pointer
);
336 static const struct fd_type
*
337 fdc_acpi_nvtotype(const char *fdc
, int nvraminfo
, int drive
)
341 type
= (drive
== 0 ? nvraminfo
: nvraminfo
<< 4) & 0xf0;
343 case ACPI_FDC_DISKETTE_NONE
:
345 case ACPI_FDC_DISKETTE_12M
:
346 return &fdc_acpi_fdtypes
[1];
347 case ACPI_FDC_DISKETTE_TYPE5
:
348 case ACPI_FDC_DISKETTE_TYPE6
:
349 case ACPI_FDC_DISKETTE_144M
:
350 return &fdc_acpi_fdtypes
[0];
351 case ACPI_FDC_DISKETTE_360K
:
352 return &fdc_acpi_fdtypes
[3];
353 case ACPI_FDC_DISKETTE_720K
:
354 return &fdc_acpi_fdtypes
[4];
356 #ifdef ACPI_FDC_DEBUG
357 aprint_normal("%s: drive %d: unknown device type 0x%x\n",