xref: /illumos-gate/usr/src/uts/intel/io/acpica/acpica_ec.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  * Copyright 2011 Joyent, Inc.  All rights reserved.
25  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
26  */
27 /*
28  * Solaris x86 ACPI CA Embedded Controller operation region handler
29  */
30 
31 #include <sys/file.h>
32 #include <sys/errno.h>
33 #include <sys/conf.h>
34 #include <sys/modctl.h>
35 #include <sys/open.h>
36 #include <sys/stat.h>
37 #include <sys/ddi.h>
38 #include <sys/sunddi.h>
39 #include <sys/note.h>
40 #include <sys/atomic.h>
41 
42 #include <sys/acpi/acpi.h>
43 #include <sys/acpica.h>
44 
45 /*
46  * EC status bits
47  * Low to high
48  *	Output buffer full?
49  *	Input buffer full?
50  *	<reserved>
51  *	Data register is command byte?
52  *	Burst mode enabled?
53  *	SCI event?
54  *	SMI event?
55  *	<reserved>
56  */
57 #define	EC_OBF	(0x01)
58 #define	EC_IBF	(0x02)
59 #define	EC_DRC	(0x08)
60 #define	EC_BME	(0x10)
61 #define	EC_SCI	(0x20)
62 #define	EC_SMI	(0x40)
63 
64 /*
65  * EC commands
66  */
67 #define	EC_RD	(0x80)
68 #define	EC_WR	(0x81)
69 #define	EC_BE	(0x82)
70 #define	EC_BD	(0x83)
71 #define	EC_QR	(0x84)
72 
73 #define	IO_PORT_DES (0x47)
74 
75 /*
76  * EC softstate
77  */
78 static struct ec_softstate {
79 	uint8_t	 ec_ok;		/* != 0 if we have ec_base, ec_sc */
80 	uint16_t ec_base;	/* base of EC I/O port - data */
81 	uint16_t ec_sc;		/* EC status/command */
82 	ACPI_HANDLE ec_dev_hdl;	/* EC device handle */
83 	ACPI_HANDLE ec_gpe_hdl;	/* GPE info */
84 	ACPI_INTEGER ec_gpe_bit;
85 	kmutex_t    ec_mutex;	/* serialize access to EC */
86 } ec;
87 
88 /* I/O port range descriptor */
89 typedef struct io_port_des {
90 	uint8_t type;
91 	uint8_t decode;
92 	uint8_t min_base_lo;
93 	uint8_t min_base_hi;
94 	uint8_t max_base_lo;
95 	uint8_t max_base_hi;
96 	uint8_t align;
97 	uint8_t len;
98 } io_port_des_t;
99 
100 /*
101  * Patchable to ignore an ECDT, in case using that
102  * causes problems on someone's system.
103  */
104 int ec_ignore_ecdt = 0;
105 
106 /*
107  * Patchable timeout values for EC input-buffer-full-clear
108  * and output-buffer-full-set. These are in 10uS units and
109  * default to 1 second.
110  */
111 int ibf_clear_timeout = 100000;
112 int obf_set_timeout = 100000;
113 
114 /*
115  * ACPI CA EC address space handler support functions
116  */
117 
118 /*
119  * Busy-wait for IBF to clear
120  * return < 0 for time out, 0 for no error
121  */
122 static int
123 ec_wait_ibf_clear(int sc_addr)
124 {
125 	int	cnt;
126 
127 	cnt = ibf_clear_timeout;
128 	while (inb(sc_addr) & EC_IBF) {
129 		if (cnt-- <= 0)
130 			return (-1);
131 		drv_usecwait(10);
132 	}
133 	return (0);
134 }
135 
136 /*
137  * Busy-wait for OBF to set
138  * return < 0 for time out, 0 for no error
139  */
140 static int
141 ec_wait_obf_set(int sc_addr)
142 {
143 	int	cnt;
144 
145 	cnt = obf_set_timeout;
146 	while (!(inb(sc_addr) & EC_OBF)) {
147 		if (cnt-- <= 0)
148 			return (-1);
149 		drv_usecwait(10);
150 	}
151 	return (0);
152 }
153 
154 /*
155  * Only called from ec_handler(), which validates ec_ok
156  */
157 static int
158 ec_rd(int addr)
159 {
160 	int	cnt, rv;
161 	uint8_t sc;
162 
163 	mutex_enter(&ec.ec_mutex);
164 	sc = inb(ec.ec_sc);
165 
166 #ifdef	DEBUG
167 	if (sc & EC_IBF) {
168 		cmn_err(CE_NOTE, "!ec_rd: IBF already set");
169 	}
170 
171 	if (sc & EC_OBF) {
172 		cmn_err(CE_NOTE, "!ec_rd: OBF already set");
173 	}
174 #endif
175 
176 	outb(ec.ec_sc, EC_RD);	/* output a read command */
177 	if (ec_wait_ibf_clear(ec.ec_sc) < 0) {
178 		cmn_err(CE_NOTE, "!ec_rd:1: timed-out waiting "
179 		    "for IBF to clear");
180 		mutex_exit(&ec.ec_mutex);
181 		return (-1);
182 	}
183 
184 	outb(ec.ec_base, addr);	/* output addr */
185 	if (ec_wait_ibf_clear(ec.ec_sc) < 0) {
186 		cmn_err(CE_NOTE, "!ec_rd:2: timed-out waiting "
187 		    "for IBF to clear");
188 		mutex_exit(&ec.ec_mutex);
189 		return (-1);
190 	}
191 	if (ec_wait_obf_set(ec.ec_sc) < 0) {
192 		cmn_err(CE_NOTE, "!ec_rd:1: timed-out waiting "
193 		    "for OBF to set");
194 		mutex_exit(&ec.ec_mutex);
195 		return (-1);
196 	}
197 
198 	rv = inb(ec.ec_base);
199 	mutex_exit(&ec.ec_mutex);
200 	return (rv);
201 }
202 
203 /*
204  * Only called from ec_handler(), which validates ec_ok
205  */
206 static int
207 ec_wr(int addr, uint8_t val)
208 {
209 	int	cnt;
210 	uint8_t sc;
211 
212 	mutex_enter(&ec.ec_mutex);
213 	sc = inb(ec.ec_sc);
214 
215 #ifdef	DEBUG
216 	if (sc & EC_IBF) {
217 		cmn_err(CE_NOTE, "!ec_wr: IBF already set");
218 	}
219 
220 	if (sc & EC_OBF) {
221 		cmn_err(CE_NOTE, "!ec_wr: OBF already set");
222 	}
223 #endif
224 
225 	outb(ec.ec_sc, EC_WR);	/* output a write command */
226 	if (ec_wait_ibf_clear(ec.ec_sc) < 0) {
227 		cmn_err(CE_NOTE, "!ec_wr:1: timed-out waiting "
228 		    "for IBF to clear");
229 		mutex_exit(&ec.ec_mutex);
230 		return (-1);
231 	}
232 
233 	outb(ec.ec_base, addr);	/* output addr */
234 	if (ec_wait_ibf_clear(ec.ec_sc) < 0) {
235 		cmn_err(CE_NOTE, "!ec_wr:2: timed-out waiting "
236 		    "for IBF to clear");
237 		mutex_exit(&ec.ec_mutex);
238 		return (-1);
239 	}
240 
241 	outb(ec.ec_base, val);	/* write data */
242 	if (ec_wait_ibf_clear(ec.ec_sc) < 0) {
243 		cmn_err(CE_NOTE, "!ec_wr:3: timed-out waiting "
244 		    "for IBF to clear");
245 		mutex_exit(&ec.ec_mutex);
246 		return (-1);
247 	}
248 
249 	mutex_exit(&ec.ec_mutex);
250 	return (0);
251 }
252 
253 /*
254  * Only called from ec_gpe_callback(), which validates ec_ok
255  */
256 static int
257 ec_query(void)
258 {
259 	int	cnt, rv;
260 	uint8_t	sc;
261 
262 	mutex_enter(&ec.ec_mutex);
263 	outb(ec.ec_sc, EC_QR);	/* output a query command */
264 	if (ec_wait_ibf_clear(ec.ec_sc) < 0) {
265 		cmn_err(CE_NOTE, "!ec_query:1: timed-out waiting "
266 		    "for IBF to clear");
267 		mutex_exit(&ec.ec_mutex);
268 		return (-1);
269 	}
270 
271 	if (ec_wait_obf_set(ec.ec_sc) < 0) {
272 		cmn_err(CE_NOTE, "!ec_query:1: timed-out waiting "
273 		    "for OBF to set");
274 		mutex_exit(&ec.ec_mutex);
275 		return (-1);
276 	}
277 
278 	rv = inb(ec.ec_base);
279 	mutex_exit(&ec.ec_mutex);
280 	return (rv);
281 }
282 
283 /*
284  * ACPI CA EC address space handler
285  * Requires: ec.ec_sc, ec.ec_base
286  */
287 static ACPI_STATUS
288 ec_handler(UINT32 func, ACPI_PHYSICAL_ADDRESS addr, UINT32 width,
289 	UINT64 *val, void *context, void *regcontext)
290 {
291 	_NOTE(ARGUNUSED(context, regcontext))
292 	int i, tw, tmp;
293 
294 	/* Guard against unexpected invocation */
295 	if (ec.ec_ok == 0)
296 		return (AE_ERROR);
297 
298 	/*
299 	 * Add safety checks for BIOSes not strictly compliant
300 	 * with ACPI spec
301 	 */
302 	if ((width % 8) != 0) {
303 		cmn_err(CE_NOTE, "!ec_handler: invalid width %d", width);
304 		return (AE_BAD_PARAMETER);
305 	}
306 	if (val == NULL) {
307 		cmn_err(CE_NOTE, "!ec_handler: NULL value pointer");
308 		return (AE_BAD_PARAMETER);
309 	}
310 
311 	while (width > 0) {
312 
313 		/* One UINT64 *val at a time. */
314 		tw = min(width, 64);
315 
316 		if (func == ACPI_READ)
317 			*val = 0;
318 
319 		/* Do I/O of up to 64 bits */
320 		for (i = 0; i < tw; i += 8, addr++) {
321 			switch (func) {
322 			case ACPI_READ:
323 				tmp = ec_rd(addr);
324 				if (tmp < 0)
325 					return (AE_ERROR);
326 				*val |= ((UINT64)tmp) << i;
327 				break;
328 			case ACPI_WRITE:
329 				tmp = ((*val) >> i) & 0xFF;
330 				if (ec_wr(addr, (uint8_t)tmp) < 0)
331 					return (AE_ERROR);
332 				break;
333 			default:
334 				return (AE_ERROR);
335 			}
336 		}
337 		val++;
338 		width -= tw;
339 	}
340 
341 	return (AE_OK);
342 }
343 
344 /*
345  * Called via taskq entry enqueued by ec_gpe_handler,
346  * which validates ec_ok
347  */
348 static void
349 ec_gpe_callback(void *ctx)
350 {
351 	_NOTE(ARGUNUSED(ctx))
352 	char		query_str[5];
353 	int		query;
354 
355 	if (!(inb(ec.ec_sc) & EC_SCI))
356 		goto out;
357 
358 	query = ec_query();
359 	if (query < 0)
360 		goto out;
361 
362 	(void) snprintf(query_str, 5, "_Q%02X", (uint8_t)query);
363 	(void) AcpiEvaluateObject(ec.ec_dev_hdl, query_str, NULL, NULL);
364 
365 out:
366 	AcpiFinishGpe(ec.ec_gpe_hdl, ec.ec_gpe_bit);
367 }
368 
369 static UINT32
370 ec_gpe_handler(ACPI_HANDLE GpeDevice, UINT32 GpeNumber, void *ctx)
371 {
372 	_NOTE(ARGUNUSED(GpeDevice))
373 	_NOTE(ARGUNUSED(GpeNumber))
374 	_NOTE(ARGUNUSED(ctx))
375 
376 	/*
377 	 * With ec_ok==0, we will not install a GPE handler,
378 	 * so this is just paranoia.  But if this were to
379 	 * happen somehow, don't add the taskq entry, and
380 	 * tell the caller we're done with this GPE call.
381 	 */
382 	if (ec.ec_ok == 0)
383 		return (ACPI_REENABLE_GPE);
384 
385 	AcpiOsExecute(OSL_GPE_HANDLER, ec_gpe_callback, NULL);
386 
387 	/*
388 	 * Returning zero tells the ACPI system that we will
389 	 * handle this event asynchronously.
390 	 */
391 	return (0);
392 }
393 
394 /*
395  * Some systems describe the EC using an "ECDT" (table).
396  * If we find one use it (unless ec_ignore_ecdt is set).
397  * Modern systems don't provide an ECDT.
398  */
399 static ACPI_STATUS
400 ec_probe_ecdt(void)
401 {
402 	ACPI_TABLE_HEADER *th;
403 	ACPI_TABLE_ECDT *ecdt;
404 	ACPI_HANDLE	dev_hdl;
405 	ACPI_STATUS	status;
406 
407 	status = AcpiGetTable(ACPI_SIG_ECDT, 1, &th);
408 #ifndef DEBUG
409 	if (status == AE_NOT_FOUND)
410 		return (status);
411 #endif
412 	if (ACPI_FAILURE(status)) {
413 		cmn_err(CE_NOTE, "!acpica: ECDT not found");
414 		return (status);
415 	}
416 	if (ec_ignore_ecdt) {
417 		/* pretend it was not found */
418 		cmn_err(CE_NOTE, "!acpica: ECDT ignored");
419 		return (AE_NOT_FOUND);
420 	}
421 
422 	ecdt = (ACPI_TABLE_ECDT *)th;
423 	if (ecdt->Control.BitWidth != 8 ||
424 	    ecdt->Data.BitWidth != 8) {
425 		cmn_err(CE_NOTE, "!acpica: bad ECDT I/O width");
426 		return (AE_BAD_VALUE);
427 	}
428 	status = AcpiGetHandle(NULL, (char *)ecdt->Id, &dev_hdl);
429 	if (ACPI_FAILURE(status)) {
430 		cmn_err(CE_NOTE, "!acpica: no ECDT device handle");
431 		return (status);
432 	}
433 
434 	/*
435 	 * Success.  Save info for attach.
436 	 */
437 	ec.ec_base = ecdt->Data.Address;
438 	ec.ec_sc = ecdt->Control.Address;
439 	ec.ec_dev_hdl = dev_hdl;
440 	ec.ec_gpe_hdl = NULL;
441 	ec.ec_gpe_bit = ecdt->Gpe;
442 	ec.ec_ok = 1;
443 
444 #ifdef DEBUG
445 	cmn_err(CE_NOTE, "!acpica:ec_probe_ecdt: success");
446 #endif
447 	return (0);
448 }
449 
450 /*
451  * Called from AcpiWalkDevices() when an EC device is found
452  */
453 static ACPI_STATUS
454 ec_find(ACPI_HANDLE obj, UINT32 nest, void *context, void **rv)
455 {
456 	_NOTE(ARGUNUSED(nest, rv))
457 
458 	*((ACPI_HANDLE *)context) = obj;
459 	return (AE_OK);
460 }
461 
462 /*
463  * Normal way to get the details about the EC,
464  * by searching the name space.
465  */
466 static ACPI_STATUS
467 ec_probe_ns(void)
468 {
469 	ACPI_HANDLE dev_hdl;
470 	ACPI_BUFFER buf, crs;
471 	ACPI_OBJECT *gpe_obj;
472 	ACPI_HANDLE gpe_hdl;
473 	ACPI_INTEGER gpe_bit;
474 	ACPI_STATUS status;
475 	int i, io_port_cnt;
476 	uint16_t ec_sc, ec_base;
477 
478 	dev_hdl = NULL;
479 	(void) AcpiGetDevices("PNP0C09", &ec_find, (void *)&dev_hdl, NULL);
480 	if (dev_hdl == NULL) {
481 #ifdef DEBUG
482 		/* Not an error, just no EC on this machine. */
483 		cmn_err(CE_WARN, "!acpica:ec_probe_ns: "
484 		    "PNP0C09 not found");
485 #endif
486 		return (AE_NOT_FOUND);
487 	}
488 
489 	/*
490 	 * Find ec_base and ec_sc addresses
491 	 */
492 	crs.Length = ACPI_ALLOCATE_BUFFER;
493 	status = AcpiEvaluateObjectTyped(dev_hdl, "_CRS", NULL, &crs,
494 	    ACPI_TYPE_BUFFER);
495 	if (ACPI_FAILURE(status)) {
496 		cmn_err(CE_WARN, "!acpica:ec_probe_ns: "
497 		    "_CRS object evaluate failed");
498 		return (status);
499 	}
500 
501 	for (i = 0, io_port_cnt = 0;
502 	    i < ((ACPI_OBJECT *)crs.Pointer)->Buffer.Length; i++) {
503 		io_port_des_t *io_port;
504 		uint8_t *tmp;
505 
506 		tmp = ((ACPI_OBJECT *)crs.Pointer)->Buffer.Pointer + i;
507 		if (*tmp != IO_PORT_DES)
508 			continue;
509 		io_port = (io_port_des_t *)tmp;
510 		/*
511 		 * first port is ec_base and second is ec_sc
512 		 */
513 		if (io_port_cnt == 0)
514 			ec_base = (io_port->min_base_hi << 8) |
515 			    io_port->min_base_lo;
516 		if (io_port_cnt == 1)
517 			ec_sc = (io_port->min_base_hi << 8) |
518 			    io_port->min_base_lo;
519 
520 		io_port_cnt++;
521 		/*
522 		 * Increment ahead to next struct.
523 		 */
524 		i += 7;
525 	}
526 	AcpiOsFree(crs.Pointer);
527 	if (io_port_cnt < 2) {
528 		cmn_err(CE_WARN, "!acpica:ec_probe_ns: "
529 		    "_CRS parse failed");
530 		return (AE_BAD_VALUE);
531 	}
532 
533 	/*
534 	 * Get the GPE info.
535 	 */
536 	buf.Length = ACPI_ALLOCATE_BUFFER;
537 	status = AcpiEvaluateObject(dev_hdl, "_GPE", NULL, &buf);
538 	if (ACPI_FAILURE(status)) {
539 		cmn_err(CE_WARN, "!acpica:ec_probe_ns: "
540 		    "_GPE object evaluate");
541 		return (status);
542 	}
543 	gpe_obj = (ACPI_OBJECT *)buf.Pointer;
544 	/*
545 	 * process the GPE description
546 	 */
547 	switch (gpe_obj->Type) {
548 	case ACPI_TYPE_INTEGER:
549 		gpe_hdl = NULL;
550 		gpe_bit = gpe_obj->Integer.Value;
551 		break;
552 	case ACPI_TYPE_PACKAGE:
553 		if (gpe_obj->Package.Count != 2)
554 			goto bad_gpe;
555 		gpe_obj = gpe_obj->Package.Elements;
556 		if (gpe_obj[1].Type != ACPI_TYPE_INTEGER)
557 			goto bad_gpe;
558 		gpe_hdl = gpe_obj[0].Reference.Handle;
559 		gpe_bit = gpe_obj[1].Integer.Value;
560 		break;
561 	bad_gpe:
562 	default:
563 		status = AE_BAD_VALUE;
564 		break;
565 	}
566 	AcpiOsFree(buf.Pointer);
567 	if (ACPI_FAILURE(status)) {
568 		cmn_err(CE_WARN, "!acpica:ec_probe_ns: "
569 		    "_GPE parse failed");
570 		return (status);
571 	}
572 
573 	/*
574 	 * Success.  Save info for attach.
575 	 */
576 	ec.ec_base = ec_base;
577 	ec.ec_sc = ec_sc;
578 	ec.ec_dev_hdl = dev_hdl;
579 	ec.ec_gpe_hdl = gpe_hdl;
580 	ec.ec_gpe_bit = gpe_bit;
581 	ec.ec_ok = 1;
582 
583 #ifdef DEBUG
584 	cmn_err(CE_NOTE, "!acpica:ec_probe_ns: success");
585 #endif
586 	return (0);
587 }
588 
589 /*
590  * Setup the Embedded Controller (EC) address space handler.
591  * Entered only if one of the EC probe methods found an EC.
592  */
593 static void
594 ec_init(void)
595 {
596 	ACPI_STATUS rc;
597 	int x;
598 
599 	/* paranoia */
600 	if (ec.ec_ok == 0)
601 		return;
602 
603 	/*
604 	 * Drain the EC data register if something is left over from
605 	 * legacy mode
606 	 */
607 	if (inb(ec.ec_sc) & EC_OBF) {
608 		x = inb(ec.ec_base);	/* read and discard value */
609 #ifdef	DEBUG
610 		cmn_err(CE_NOTE, "!EC had something: 0x%x", x);
611 #endif
612 	}
613 
614 	/*
615 	 * Install an "EC address space" handler.
616 	 *
617 	 * This call does a name space walk under the passed
618 	 * object looking for child objects with an EC space
619 	 * region for which to install this handler.  Using
620 	 * the ROOT object makes sure we find them all.
621 	 *
622 	 * XXX: Some systems return an error from this call
623 	 * after a partial success, i.e. where the NS walk
624 	 * installs on some nodes and fails on other nodes.
625 	 * In such cases, disabling the EC and GPE handlers
626 	 * makes things worse, so just report the error and
627 	 * leave the EC handler enabled.
628 	 *
629 	 * At one point, it seemed that doing this part of
630 	 * EC setup earlier may help, which is why this is
631 	 * now a separate function from ec_attach.  Someone
632 	 * needs to figure our why some systems give us an
633 	 * error return from this call.  (TODO)
634 	 */
635 	rc = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
636 	    ACPI_ADR_SPACE_EC, &ec_handler, NULL, NULL);
637 	if (rc != AE_OK) {
638 		cmn_err(CE_WARN, "!acpica:ec_init: "
639 		    "install AS handler, rc=0x%x", rc);
640 		return;
641 	}
642 #ifdef DEBUG
643 	cmn_err(CE_NOTE, "!acpica:ec_init: success");
644 #endif
645 }
646 
647 /*
648  * Attach the EC General-Purpose Event (GPE) handler.
649  */
650 static void
651 ec_attach(void)
652 {
653 	ACPI_STATUS rc;
654 
655 	/*
656 	 * Guard against call without probe results.
657 	 */
658 	if (ec.ec_ok == 0) {
659 		cmn_err(CE_WARN, "!acpica:ec_attach: "
660 		    "no EC device found");
661 		return;
662 	}
663 
664 	/*
665 	 * Install the GPE handler and enable it.
666 	 */
667 	rc = AcpiInstallGpeHandler(ec.ec_gpe_hdl, ec.ec_gpe_bit,
668 	    ACPI_GPE_EDGE_TRIGGERED, ec_gpe_handler, NULL);
669 	if (rc != AE_OK) {
670 		cmn_err(CE_WARN, "!acpica:ec_attach: "
671 		    "install GPE handler, rc=0x%x", rc);
672 		goto errout;
673 	}
674 
675 	rc = AcpiEnableGpe(ec.ec_gpe_hdl, ec.ec_gpe_bit);
676 	if (rc != AE_OK) {
677 		cmn_err(CE_WARN, "!acpica:ec_attach: "
678 		    "enable GPE handler, rc=0x%x", rc);
679 		goto errout;
680 	}
681 
682 #ifdef DEBUG
683 	cmn_err(CE_NOTE, "!acpica:ec_attach: success");
684 #endif
685 	return;
686 
687 errout:
688 	AcpiRemoveGpeHandler(ec.ec_gpe_hdl, ec.ec_gpe_bit,
689 	    ec_gpe_handler);
690 }
691 
692 /*
693  * System Management Bus Controller (SMBC)
694  * These also go through the EC.
695  * (not yet supported)
696  */
697 static void
698 smbus_attach(void)
699 {
700 #ifdef	DEBUG
701 	ACPI_HANDLE obj;
702 
703 	obj = NULL;
704 	(void) AcpiGetDevices("ACPI0001", &ec_find, (void *)&obj, NULL);
705 	if (obj != NULL) {
706 		cmn_err(CE_NOTE, "!acpica: found an SMBC Version 1.0");
707 	}
708 
709 	obj = NULL;
710 	(void) AcpiGetDevices("ACPI0005", &ec_find, (void *)&obj, NULL);
711 	if (obj != NULL) {
712 		cmn_err(CE_NOTE, "!acpica: found an SMBC Version 2.0");
713 	}
714 #endif	/* DEBUG */
715 }
716 
717 /*
718  * Initialize the EC, if present.
719  */
720 void
721 acpica_ec_init(void)
722 {
723 	ACPI_STATUS rc;
724 
725 	/*
726 	 * Initialize EC mutex here
727 	 */
728 	mutex_init(&ec.ec_mutex, NULL, MUTEX_DRIVER, NULL);
729 
730 	/*
731 	 * First search the ACPI tables for an ECDT, and
732 	 * if not found, search the name space for it.
733 	 */
734 	rc = ec_probe_ecdt();
735 	if (ACPI_FAILURE(rc))
736 		rc = ec_probe_ns();
737 	if (ACPI_SUCCESS(rc)) {
738 		ec_init();
739 		ec_attach();
740 	}
741 	smbus_attach();
742 }
743