tco.c revision 1.1.2.2 1 1.1.2.2 skrll /* $NetBSD: tco.c,v 1.1.2.2 2015/06/06 14:40:04 skrll Exp $ */
2 1.1.2.2 skrll
3 1.1.2.2 skrll /*-
4 1.1.2.2 skrll * Copyright (c) 2015 The NetBSD Foundation, Inc.
5 1.1.2.2 skrll * All rights reserved.
6 1.1.2.2 skrll *
7 1.1.2.2 skrll * This code is derived from software contributed to The NetBSD Foundation
8 1.1.2.2 skrll * by Minoura Makoto and Matthew R. Green.
9 1.1.2.2 skrll *
10 1.1.2.2 skrll * Redistribution and use in source and binary forms, with or without
11 1.1.2.2 skrll * modification, are permitted provided that the following conditions
12 1.1.2.2 skrll * are met:
13 1.1.2.2 skrll * 1. Redistributions of source code must retain the above copyright
14 1.1.2.2 skrll * notice, this list of conditions and the following disclaimer.
15 1.1.2.2 skrll * 2. Redistributions in binary form must reproduce the above copyright
16 1.1.2.2 skrll * notice, this list of conditions and the following disclaimer in the
17 1.1.2.2 skrll * documentation and/or other materials provided with the distribution.
18 1.1.2.2 skrll *
19 1.1.2.2 skrll * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1.2.2 skrll * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1.2.2 skrll * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1.2.2 skrll * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1.2.2 skrll * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1.2.2 skrll * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1.2.2 skrll * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1.2.2 skrll * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1.2.2 skrll * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1.2.2 skrll * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1.2.2 skrll * POSSIBILITY OF SUCH DAMAGE.
30 1.1.2.2 skrll */
31 1.1.2.2 skrll
32 1.1.2.2 skrll /*
33 1.1.2.2 skrll * Intel I/O Controller Hub (ICHn) watchdog timer
34 1.1.2.2 skrll */
35 1.1.2.2 skrll
36 1.1.2.2 skrll #include <sys/cdefs.h>
37 1.1.2.2 skrll __KERNEL_RCSID(0, "$NetBSD: tco.c,v 1.1.2.2 2015/06/06 14:40:04 skrll Exp $");
38 1.1.2.2 skrll
39 1.1.2.2 skrll #include <sys/types.h>
40 1.1.2.2 skrll #include <sys/param.h>
41 1.1.2.2 skrll #include <sys/systm.h>
42 1.1.2.2 skrll #include <sys/device.h>
43 1.1.2.2 skrll #include <sys/timetc.h>
44 1.1.2.2 skrll #include <sys/module.h>
45 1.1.2.2 skrll
46 1.1.2.2 skrll #include <dev/pci/pcivar.h>
47 1.1.2.2 skrll #include <dev/pci/pcireg.h>
48 1.1.2.2 skrll #include <dev/ic/i82801lpcreg.h>
49 1.1.2.2 skrll
50 1.1.2.2 skrll #include <dev/sysmon/sysmonvar.h>
51 1.1.2.2 skrll
52 1.1.2.2 skrll #include <arch/x86/pci/tco.h>
53 1.1.2.2 skrll
54 1.1.2.2 skrll #include "pcibvar.h"
55 1.1.2.2 skrll
56 1.1.2.2 skrll struct tco_softc{
57 1.1.2.2 skrll struct sysmon_wdog sc_smw;
58 1.1.2.2 skrll bus_space_tag_t sc_iot;
59 1.1.2.2 skrll bus_space_handle_t sc_ioh;
60 1.1.2.2 skrll bus_space_tag_t sc_rcbat;
61 1.1.2.2 skrll bus_space_handle_t sc_rcbah;
62 1.1.2.2 skrll struct pcib_softc * sc_pcib;
63 1.1.2.2 skrll int sc_armed;
64 1.1.2.2 skrll unsigned int sc_min_t;
65 1.1.2.2 skrll unsigned int sc_max_t;
66 1.1.2.2 skrll int sc_has_rcba;
67 1.1.2.2 skrll };
68 1.1.2.2 skrll
69 1.1.2.2 skrll static int tco_match(device_t, cfdata_t, void *);
70 1.1.2.2 skrll static void tco_attach(device_t, device_t, void *);
71 1.1.2.2 skrll static int tco_detach(device_t, int);
72 1.1.2.2 skrll
73 1.1.2.2 skrll static bool tco_suspend(device_t, const pmf_qual_t *);
74 1.1.2.2 skrll
75 1.1.2.2 skrll static int tcotimer_setmode(struct sysmon_wdog *);
76 1.1.2.2 skrll static int tcotimer_tickle(struct sysmon_wdog *);
77 1.1.2.2 skrll static void tcotimer_stop(struct tco_softc *);
78 1.1.2.2 skrll static void tcotimer_start(struct tco_softc *);
79 1.1.2.2 skrll static void tcotimer_status_reset(struct tco_softc *);
80 1.1.2.2 skrll static int tcotimer_disable_noreboot(device_t);
81 1.1.2.2 skrll
82 1.1.2.2 skrll CFATTACH_DECL3_NEW(tco, sizeof(struct tco_softc),
83 1.1.2.2 skrll tco_match, tco_attach, tco_detach, NULL, NULL, NULL, 0);
84 1.1.2.2 skrll
85 1.1.2.2 skrll /*
86 1.1.2.2 skrll * Autoconf callbacks.
87 1.1.2.2 skrll */
88 1.1.2.2 skrll static int
89 1.1.2.2 skrll tco_match(device_t parent, cfdata_t match, void *aux)
90 1.1.2.2 skrll {
91 1.1.2.2 skrll struct lpcib_tco_attach_args *ta = aux;
92 1.1.2.2 skrll
93 1.1.2.2 skrll if (ta->ta_iot != 0)
94 1.1.2.2 skrll return 1;
95 1.1.2.2 skrll
96 1.1.2.2 skrll return 0;
97 1.1.2.2 skrll }
98 1.1.2.2 skrll
99 1.1.2.2 skrll static void
100 1.1.2.2 skrll tco_attach(device_t parent, device_t self, void *aux)
101 1.1.2.2 skrll {
102 1.1.2.2 skrll struct tco_softc *sc = device_private(self);
103 1.1.2.2 skrll struct lpcib_tco_attach_args *ta = aux;
104 1.1.2.2 skrll uint32_t ioreg;
105 1.1.2.2 skrll
106 1.1.2.2 skrll /* Retrieve bus info shared with parent/siblings */
107 1.1.2.2 skrll
108 1.1.2.2 skrll sc->sc_iot = ta->ta_iot;
109 1.1.2.2 skrll sc->sc_ioh = ta->ta_ioh;
110 1.1.2.2 skrll sc->sc_rcbat = ta->ta_rcbat;
111 1.1.2.2 skrll sc->sc_rcbah = ta->ta_rcbah;
112 1.1.2.2 skrll sc->sc_pcib = ta->ta_pcib;
113 1.1.2.2 skrll sc->sc_has_rcba = ta->ta_has_rcba;
114 1.1.2.2 skrll
115 1.1.2.2 skrll /* Explicitly stop the TCO timer. */
116 1.1.2.2 skrll tcotimer_stop(sc);
117 1.1.2.2 skrll
118 1.1.2.2 skrll /*
119 1.1.2.2 skrll * Enable TCO timeout SMI only if the hardware reset does not
120 1.1.2.2 skrll * work. We don't know what the SMBIOS does.
121 1.1.2.2 skrll */
122 1.1.2.2 skrll ioreg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, LPCIB_SMI_EN);
123 1.1.2.2 skrll ioreg &= ~LPCIB_SMI_EN_TCO_EN;
124 1.1.2.2 skrll
125 1.1.2.2 skrll /*
126 1.1.2.2 skrll * Clear the No Reboot (NR) bit. If this fails, enabling the TCO_EN bit
127 1.1.2.2 skrll * in the SMI_EN register is the last chance.
128 1.1.2.2 skrll */
129 1.1.2.2 skrll if (tcotimer_disable_noreboot(self)) {
130 1.1.2.2 skrll ioreg |= LPCIB_SMI_EN_TCO_EN;
131 1.1.2.2 skrll }
132 1.1.2.2 skrll if ((ioreg & LPCIB_SMI_EN_GBL_SMI_EN) != 0) {
133 1.1.2.2 skrll bus_space_write_4(sc->sc_iot, sc->sc_ioh, LPCIB_SMI_EN, ioreg);
134 1.1.2.2 skrll }
135 1.1.2.2 skrll
136 1.1.2.2 skrll /* Reset the watchdog status registers. */
137 1.1.2.2 skrll tcotimer_status_reset(sc);
138 1.1.2.2 skrll
139 1.1.2.2 skrll /*
140 1.1.2.2 skrll * Register the driver with the sysmon watchdog framework.
141 1.1.2.2 skrll */
142 1.1.2.2 skrll sc->sc_smw.smw_name = device_xname(self);
143 1.1.2.2 skrll sc->sc_smw.smw_cookie = sc;
144 1.1.2.2 skrll sc->sc_smw.smw_setmode = tcotimer_setmode;
145 1.1.2.2 skrll sc->sc_smw.smw_tickle = tcotimer_tickle;
146 1.1.2.2 skrll
147 1.1.2.2 skrll /*
148 1.1.2.2 skrll * ICH6 or newer are limited to 2ticks min and 613ticks max.
149 1.1.2.2 skrll * 1sec 367secs
150 1.1.2.2 skrll *
151 1.1.2.2 skrll * ICH5 or older are limited to 4ticks min and 39ticks max.
152 1.1.2.2 skrll * 2secs 23secs
153 1.1.2.2 skrll */
154 1.1.2.2 skrll if (sc->sc_has_rcba) {
155 1.1.2.2 skrll sc->sc_max_t = LPCIB_TCOTIMER2_MAX_TICK;
156 1.1.2.2 skrll sc->sc_min_t = LPCIB_TCOTIMER2_MIN_TICK;
157 1.1.2.2 skrll } else {
158 1.1.2.2 skrll sc->sc_max_t = LPCIB_TCOTIMER_MAX_TICK;
159 1.1.2.2 skrll sc->sc_min_t = LPCIB_TCOTIMER_MIN_TICK;
160 1.1.2.2 skrll }
161 1.1.2.2 skrll sc->sc_smw.smw_period = lpcib_tcotimer_tick_to_second(sc->sc_max_t);
162 1.1.2.2 skrll
163 1.1.2.2 skrll aprint_normal(": TCO (watchdog) timer configured.\n");
164 1.1.2.2 skrll aprint_naive("\n");
165 1.1.2.2 skrll aprint_verbose_dev(self, "Min/Max interval %u/%u seconds\n",
166 1.1.2.2 skrll lpcib_tcotimer_tick_to_second(sc->sc_min_t),
167 1.1.2.2 skrll lpcib_tcotimer_tick_to_second(sc->sc_max_t));
168 1.1.2.2 skrll
169 1.1.2.2 skrll if (sysmon_wdog_register(&sc->sc_smw))
170 1.1.2.2 skrll aprint_error_dev(self, "unable to register TCO timer"
171 1.1.2.2 skrll "as a sysmon watchdog device.\n");
172 1.1.2.2 skrll
173 1.1.2.2 skrll if (!pmf_device_register(self, tco_suspend, NULL))
174 1.1.2.2 skrll aprint_error_dev(self, "unable to register with pmf\n");
175 1.1.2.2 skrll }
176 1.1.2.2 skrll
177 1.1.2.2 skrll static int
178 1.1.2.2 skrll tco_detach(device_t self, int flags)
179 1.1.2.2 skrll {
180 1.1.2.2 skrll struct tco_softc *sc = device_private(self);
181 1.1.2.2 skrll int rc;
182 1.1.2.2 skrll
183 1.1.2.2 skrll if ((rc = sysmon_wdog_unregister(&sc->sc_smw)) != 0) {
184 1.1.2.2 skrll if (rc == ERESTART)
185 1.1.2.2 skrll rc = EINTR;
186 1.1.2.2 skrll return rc;
187 1.1.2.2 skrll }
188 1.1.2.2 skrll
189 1.1.2.2 skrll /* Explicitly stop the TCO timer. */
190 1.1.2.2 skrll tcotimer_stop(sc);
191 1.1.2.2 skrll
192 1.1.2.2 skrll /* XXX Set No Reboot? */
193 1.1.2.2 skrll
194 1.1.2.2 skrll pmf_device_deregister(self);
195 1.1.2.2 skrll
196 1.1.2.2 skrll return 0;
197 1.1.2.2 skrll }
198 1.1.2.2 skrll
199 1.1.2.2 skrll static bool
200 1.1.2.2 skrll tco_suspend(device_t self, const pmf_qual_t *quals)
201 1.1.2.2 skrll {
202 1.1.2.2 skrll struct tco_softc *sc = device_private(self);
203 1.1.2.2 skrll
204 1.1.2.2 skrll /* Allow suspend only if watchdog is not armed */
205 1.1.2.2 skrll
206 1.1.2.2 skrll return ((sc->sc_smw.smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED);
207 1.1.2.2 skrll }
208 1.1.2.2 skrll
209 1.1.2.2 skrll /*
210 1.1.2.2 skrll * Sysmon watchdog callbacks.
211 1.1.2.2 skrll */
212 1.1.2.2 skrll static int
213 1.1.2.2 skrll tcotimer_setmode(struct sysmon_wdog *smw)
214 1.1.2.2 skrll {
215 1.1.2.2 skrll struct tco_softc *sc = smw->smw_cookie;
216 1.1.2.2 skrll unsigned int period;
217 1.1.2.2 skrll uint16_t ich6period = 0;
218 1.1.2.2 skrll uint8_t ich5period = 0;
219 1.1.2.2 skrll
220 1.1.2.2 skrll if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) {
221 1.1.2.2 skrll /* Stop the TCO timer. */
222 1.1.2.2 skrll tcotimer_stop(sc);
223 1.1.2.2 skrll } else {
224 1.1.2.2 skrll period = lpcib_tcotimer_second_to_tick(smw->smw_period);
225 1.1.2.2 skrll if (period < sc->sc_min_t || period > sc->sc_max_t)
226 1.1.2.2 skrll return EINVAL;
227 1.1.2.2 skrll
228 1.1.2.2 skrll /* Stop the TCO timer, */
229 1.1.2.2 skrll tcotimer_stop(sc);
230 1.1.2.2 skrll
231 1.1.2.2 skrll /* set the timeout, */
232 1.1.2.2 skrll if (sc->sc_has_rcba) {
233 1.1.2.2 skrll /* ICH6 or newer */
234 1.1.2.2 skrll ich6period = bus_space_read_2(sc->sc_iot, sc->sc_ioh,
235 1.1.2.2 skrll LPCIB_TCO_TMR2);
236 1.1.2.2 skrll ich6period &= 0xfc00;
237 1.1.2.2 skrll bus_space_write_2(sc->sc_iot, sc->sc_ioh,
238 1.1.2.2 skrll LPCIB_TCO_TMR2, ich6period | period);
239 1.1.2.2 skrll } else {
240 1.1.2.2 skrll /* ICH5 or older */
241 1.1.2.2 skrll ich5period = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
242 1.1.2.2 skrll LPCIB_TCO_TMR);
243 1.1.2.2 skrll ich5period &= 0xc0;
244 1.1.2.2 skrll bus_space_write_1(sc->sc_iot, sc->sc_ioh,
245 1.1.2.2 skrll LPCIB_TCO_TMR, ich5period | period);
246 1.1.2.2 skrll }
247 1.1.2.2 skrll
248 1.1.2.2 skrll /* and start/reload the timer. */
249 1.1.2.2 skrll tcotimer_start(sc);
250 1.1.2.2 skrll tcotimer_tickle(smw);
251 1.1.2.2 skrll }
252 1.1.2.2 skrll
253 1.1.2.2 skrll return 0;
254 1.1.2.2 skrll }
255 1.1.2.2 skrll
256 1.1.2.2 skrll static int
257 1.1.2.2 skrll tcotimer_tickle(struct sysmon_wdog *smw)
258 1.1.2.2 skrll {
259 1.1.2.2 skrll struct tco_softc *sc = smw->smw_cookie;
260 1.1.2.2 skrll
261 1.1.2.2 skrll /* any value is allowed */
262 1.1.2.2 skrll if (sc->sc_has_rcba)
263 1.1.2.2 skrll bus_space_write_2(sc->sc_iot, sc->sc_ioh, LPCIB_TCO_RLD, 1);
264 1.1.2.2 skrll else
265 1.1.2.2 skrll bus_space_write_1(sc->sc_iot, sc->sc_ioh, LPCIB_TCO_RLD, 1);
266 1.1.2.2 skrll
267 1.1.2.2 skrll return 0;
268 1.1.2.2 skrll }
269 1.1.2.2 skrll
270 1.1.2.2 skrll static void
271 1.1.2.2 skrll tcotimer_stop(struct tco_softc *sc)
272 1.1.2.2 skrll {
273 1.1.2.2 skrll uint16_t ioreg;
274 1.1.2.2 skrll
275 1.1.2.2 skrll ioreg = bus_space_read_2(sc->sc_iot, sc->sc_ioh, LPCIB_TCO1_CNT);
276 1.1.2.2 skrll ioreg |= LPCIB_TCO1_CNT_TCO_TMR_HLT;
277 1.1.2.2 skrll bus_space_write_2(sc->sc_iot, sc->sc_ioh, LPCIB_TCO1_CNT, ioreg);
278 1.1.2.2 skrll }
279 1.1.2.2 skrll
280 1.1.2.2 skrll static void
281 1.1.2.2 skrll tcotimer_start(struct tco_softc *sc)
282 1.1.2.2 skrll {
283 1.1.2.2 skrll uint16_t ioreg;
284 1.1.2.2 skrll
285 1.1.2.2 skrll ioreg = bus_space_read_2(sc->sc_iot, sc->sc_ioh, LPCIB_TCO1_CNT);
286 1.1.2.2 skrll ioreg &= ~LPCIB_TCO1_CNT_TCO_TMR_HLT;
287 1.1.2.2 skrll bus_space_write_2(sc->sc_iot, sc->sc_ioh, LPCIB_TCO1_CNT, ioreg);
288 1.1.2.2 skrll }
289 1.1.2.2 skrll
290 1.1.2.2 skrll static void
291 1.1.2.2 skrll tcotimer_status_reset(struct tco_softc *sc)
292 1.1.2.2 skrll {
293 1.1.2.2 skrll bus_space_write_2(sc->sc_iot, sc->sc_ioh, LPCIB_TCO1_STS,
294 1.1.2.2 skrll LPCIB_TCO1_STS_TIMEOUT);
295 1.1.2.2 skrll bus_space_write_2(sc->sc_iot, sc->sc_ioh, LPCIB_TCO2_STS,
296 1.1.2.2 skrll LPCIB_TCO2_STS_BOOT_STS);
297 1.1.2.2 skrll bus_space_write_2(sc->sc_iot, sc->sc_ioh, LPCIB_TCO2_STS,
298 1.1.2.2 skrll LPCIB_TCO2_STS_SECONDS_TO_STS);
299 1.1.2.2 skrll }
300 1.1.2.2 skrll
301 1.1.2.2 skrll /*
302 1.1.2.2 skrll * Clear the No Reboot (NR) bit, this enables reboots when the timer
303 1.1.2.2 skrll * reaches the timeout for the second time.
304 1.1.2.2 skrll */
305 1.1.2.2 skrll static int
306 1.1.2.2 skrll tcotimer_disable_noreboot(device_t self)
307 1.1.2.2 skrll {
308 1.1.2.2 skrll struct tco_softc *sc = device_private(self);
309 1.1.2.2 skrll
310 1.1.2.2 skrll if (sc->sc_has_rcba) {
311 1.1.2.2 skrll uint32_t status;
312 1.1.2.2 skrll
313 1.1.2.2 skrll status = bus_space_read_4(sc->sc_rcbat, sc->sc_rcbah,
314 1.1.2.2 skrll LPCIB_GCS_OFFSET);
315 1.1.2.2 skrll status &= ~LPCIB_GCS_NO_REBOOT;
316 1.1.2.2 skrll bus_space_write_4(sc->sc_rcbat, sc->sc_rcbah,
317 1.1.2.2 skrll LPCIB_GCS_OFFSET, status);
318 1.1.2.2 skrll status = bus_space_read_4(sc->sc_rcbat, sc->sc_rcbah,
319 1.1.2.2 skrll LPCIB_GCS_OFFSET);
320 1.1.2.2 skrll if (status & LPCIB_GCS_NO_REBOOT)
321 1.1.2.2 skrll goto error;
322 1.1.2.2 skrll } else {
323 1.1.2.2 skrll pcireg_t pcireg;
324 1.1.2.2 skrll
325 1.1.2.2 skrll pcireg = pci_conf_read(sc->sc_pcib->sc_pc, sc->sc_pcib->sc_tag,
326 1.1.2.2 skrll LPCIB_PCI_GEN_STA);
327 1.1.2.2 skrll if (pcireg & LPCIB_PCI_GEN_STA_NO_REBOOT) {
328 1.1.2.2 skrll /* TCO timeout reset is disabled; try to enable it */
329 1.1.2.2 skrll pcireg &= ~LPCIB_PCI_GEN_STA_NO_REBOOT;
330 1.1.2.2 skrll pci_conf_write(sc->sc_pcib->sc_pc, sc->sc_pcib->sc_tag,
331 1.1.2.2 skrll LPCIB_PCI_GEN_STA, pcireg);
332 1.1.2.2 skrll if (pcireg & LPCIB_PCI_GEN_STA_NO_REBOOT)
333 1.1.2.2 skrll goto error;
334 1.1.2.2 skrll }
335 1.1.2.2 skrll }
336 1.1.2.2 skrll
337 1.1.2.2 skrll return 0;
338 1.1.2.2 skrll error:
339 1.1.2.2 skrll aprint_error_dev(self, "TCO timer reboot disabled by hardware; "
340 1.1.2.2 skrll "hope SMBIOS properly handles it.\n");
341 1.1.2.2 skrll return EINVAL;
342 1.1.2.2 skrll }
343 1.1.2.2 skrll
344 1.1.2.2 skrll MODULE(MODULE_CLASS_DRIVER, tco, "sysmon_wdog");
345 1.1.2.2 skrll
346 1.1.2.2 skrll #ifdef _MODULE
347 1.1.2.2 skrll #include "ioconf.c"
348 1.1.2.2 skrll #endif
349 1.1.2.2 skrll
350 1.1.2.2 skrll static int
351 1.1.2.2 skrll tco_modcmd(modcmd_t cmd, void *arg)
352 1.1.2.2 skrll {
353 1.1.2.2 skrll int ret = 0;
354 1.1.2.2 skrll
355 1.1.2.2 skrll switch (cmd) {
356 1.1.2.2 skrll case MODULE_CMD_INIT:
357 1.1.2.2 skrll #ifdef _MODULE
358 1.1.2.2 skrll ret = config_init_component(cfdriver_ioconf_tco,
359 1.1.2.2 skrll cfattach_ioconf_tco,
360 1.1.2.2 skrll cfdata_ioconf_tco);
361 1.1.2.2 skrll #endif
362 1.1.2.2 skrll break;
363 1.1.2.2 skrll case MODULE_CMD_FINI:
364 1.1.2.2 skrll #ifdef _MODULE
365 1.1.2.2 skrll ret = config_fini_component(cfdriver_ioconf_tco,
366 1.1.2.2 skrll cfattach_ioconf_tco,
367 1.1.2.2 skrll cfdata_ioconf_tco);
368 1.1.2.2 skrll #endif
369 1.1.2.2 skrll break;
370 1.1.2.2 skrll default:
371 1.1.2.2 skrll ret = ENOTTY;
372 1.1.2.2 skrll }
373 1.1.2.2 skrll
374 1.1.2.2 skrll return ret;
375 1.1.2.2 skrll }
376