17c478bd9Sstevel@tonic-gate /*
28e56767dSsmall  * CDDL HEADER START
38e56767dSsmall  *
48e56767dSsmall  * The contents of this file are subject to the terms of the
527f7c583Smyers  * Common Development and Distribution License (the "License").
627f7c583Smyers  * You may not use this file except in compliance with the License.
78e56767dSsmall  *
88e56767dSsmall  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98e56767dSsmall  * or http://www.opensolaris.org/os/licensing.
108e56767dSsmall  * See the License for the specific language governing permissions
118e56767dSsmall  * and limitations under the License.
128e56767dSsmall  *
138e56767dSsmall  * When distributing Covered Code, include this CDDL HEADER in each
148e56767dSsmall  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158e56767dSsmall  * If applicable, add the following below this CDDL HEADER, with the
168e56767dSsmall  * fields enclosed by brackets "[]" replaced with your own identifying
178e56767dSsmall  * information: Portions Copyright [yyyy] [name of copyright owner]
188e56767dSsmall  *
198e56767dSsmall  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22a3463f0aSDana Myers  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
24*26f3cdf0SGordon Ross  * Copyright 2011 Joyent, Inc.  All rights reserved.
25*26f3cdf0SGordon Ross  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
267c478bd9Sstevel@tonic-gate  */
278e56767dSsmall /*
288e56767dSsmall  * Solaris x86 ACPI CA Embedded Controller operation region handler
298e56767dSsmall  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <sys/file.h>
327c478bd9Sstevel@tonic-gate #include <sys/errno.h>
337c478bd9Sstevel@tonic-gate #include <sys/conf.h>
347c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
357c478bd9Sstevel@tonic-gate #include <sys/open.h>
367c478bd9Sstevel@tonic-gate #include <sys/stat.h>
377c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
387c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
397c478bd9Sstevel@tonic-gate #include <sys/note.h>
40a3463f0aSDana Myers #include <sys/atomic.h>
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #include <sys/acpi/acpi.h>
437c478bd9Sstevel@tonic-gate #include <sys/acpica.h>
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate /*
467c478bd9Sstevel@tonic-gate  * EC status bits
47*26f3cdf0SGordon Ross  * Low to high
48*26f3cdf0SGordon Ross  *	Output buffer full?
49*26f3cdf0SGordon Ross  *	Input buffer full?
50*26f3cdf0SGordon Ross  *	<reserved>
51*26f3cdf0SGordon Ross  *	Data register is command byte?
52*26f3cdf0SGordon Ross  *	Burst mode enabled?
53*26f3cdf0SGordon Ross  *	SCI event?
54*26f3cdf0SGordon Ross  *	SMI event?
55*26f3cdf0SGordon Ross  *	<reserved>
567c478bd9Sstevel@tonic-gate  */
577c478bd9Sstevel@tonic-gate #define	EC_OBF	(0x01)
58*26f3cdf0SGordon Ross #define	EC_IBF	(0x02)
59*26f3cdf0SGordon Ross #define	EC_DRC	(0x08)
60*26f3cdf0SGordon Ross #define	EC_BME	(0x10)
617c478bd9Sstevel@tonic-gate #define	EC_SCI	(0x20)
62*26f3cdf0SGordon Ross #define	EC_SMI	(0x40)
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate /*
657c478bd9Sstevel@tonic-gate  * EC commands
667c478bd9Sstevel@tonic-gate  */
677c478bd9Sstevel@tonic-gate #define	EC_RD	(0x80)
687c478bd9Sstevel@tonic-gate #define	EC_WR	(0x81)
697c478bd9Sstevel@tonic-gate #define	EC_BE	(0x82)
707c478bd9Sstevel@tonic-gate #define	EC_BD	(0x83)
717c478bd9Sstevel@tonic-gate #define	EC_QR	(0x84)
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate #define	IO_PORT_DES (0x47)
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate /*
767c478bd9Sstevel@tonic-gate  * EC softstate
777c478bd9Sstevel@tonic-gate  */
78*26f3cdf0SGordon Ross static struct ec_softstate {
79*26f3cdf0SGordon Ross 	uint8_t	 ec_ok;		/* != 0 if we have ec_base, ec_sc */
807c478bd9Sstevel@tonic-gate 	uint16_t ec_base;	/* base of EC I/O port - data */
81*26f3cdf0SGordon Ross 	uint16_t ec_sc;		/* EC status/command */
82*26f3cdf0SGordon Ross 	ACPI_HANDLE ec_dev_hdl;	/* EC device handle */
83*26f3cdf0SGordon Ross 	ACPI_HANDLE ec_gpe_hdl;	/* GPE info */
84*26f3cdf0SGordon Ross 	ACPI_INTEGER ec_gpe_bit;
85450d6964Smyers 	kmutex_t    ec_mutex;	/* serialize access to EC */
867c478bd9Sstevel@tonic-gate } ec;
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate /* I/O port range descriptor */
897c478bd9Sstevel@tonic-gate typedef struct io_port_des {
907c478bd9Sstevel@tonic-gate 	uint8_t type;
917c478bd9Sstevel@tonic-gate 	uint8_t decode;
927c478bd9Sstevel@tonic-gate 	uint8_t min_base_lo;
937c478bd9Sstevel@tonic-gate 	uint8_t min_base_hi;
947c478bd9Sstevel@tonic-gate 	uint8_t max_base_lo;
957c478bd9Sstevel@tonic-gate 	uint8_t max_base_hi;
967c478bd9Sstevel@tonic-gate 	uint8_t align;
977c478bd9Sstevel@tonic-gate 	uint8_t len;
987c478bd9Sstevel@tonic-gate } io_port_des_t;
997c478bd9Sstevel@tonic-gate 
100*26f3cdf0SGordon Ross /*
101*26f3cdf0SGordon Ross  * Patchable to ignore an ECDT, in case using that
102*26f3cdf0SGordon Ross  * causes problems on someone's system.
103*26f3cdf0SGordon Ross  */
104*26f3cdf0SGordon Ross int ec_ignore_ecdt = 0;
105*26f3cdf0SGordon Ross 
106a3463f0aSDana Myers /*
107a3463f0aSDana Myers  * Patchable timeout values for EC input-buffer-full-clear
108a3463f0aSDana Myers  * and output-buffer-full-set. These are in 10uS units and
109a3463f0aSDana Myers  * default to 1 second.
110a3463f0aSDana Myers  */
111a3463f0aSDana Myers int ibf_clear_timeout = 100000;
112a3463f0aSDana Myers int obf_set_timeout = 100000;
113a3463f0aSDana Myers 
1147c478bd9Sstevel@tonic-gate /*
115*26f3cdf0SGordon Ross  * ACPI CA EC address space handler support functions
1167c478bd9Sstevel@tonic-gate  */
117*26f3cdf0SGordon Ross 
118*26f3cdf0SGordon Ross /*
119*26f3cdf0SGordon Ross  * Busy-wait for IBF to clear
120*26f3cdf0SGordon Ross  * return < 0 for time out, 0 for no error
121*26f3cdf0SGordon Ross  */
122*26f3cdf0SGordon Ross static int
ec_wait_ibf_clear(int sc_addr)123*26f3cdf0SGordon Ross ec_wait_ibf_clear(int sc_addr)
1247c478bd9Sstevel@tonic-gate {
125*26f3cdf0SGordon Ross 	int	cnt;
1267c478bd9Sstevel@tonic-gate 
127*26f3cdf0SGordon Ross 	cnt = ibf_clear_timeout;
128*26f3cdf0SGordon Ross 	while (inb(sc_addr) & EC_IBF) {
129*26f3cdf0SGordon Ross 		if (cnt-- <= 0)
130*26f3cdf0SGordon Ross 			return (-1);
131*26f3cdf0SGordon Ross 		drv_usecwait(10);
132*26f3cdf0SGordon Ross 	}
133*26f3cdf0SGordon Ross 	return (0);
134*26f3cdf0SGordon Ross }
135*26f3cdf0SGordon Ross 
136*26f3cdf0SGordon Ross /*
137*26f3cdf0SGordon Ross  * Busy-wait for OBF to set
138*26f3cdf0SGordon Ross  * return < 0 for time out, 0 for no error
139*26f3cdf0SGordon Ross  */
140*26f3cdf0SGordon Ross static int
ec_wait_obf_set(int sc_addr)141*26f3cdf0SGordon Ross ec_wait_obf_set(int sc_addr)
142*26f3cdf0SGordon Ross {
143*26f3cdf0SGordon Ross 	int	cnt;
144*26f3cdf0SGordon Ross 
145*26f3cdf0SGordon Ross 	cnt = obf_set_timeout;
146*26f3cdf0SGordon Ross 	while (!(inb(sc_addr) & EC_OBF)) {
147*26f3cdf0SGordon Ross 		if (cnt-- <= 0)
148*26f3cdf0SGordon Ross 			return (-1);
149*26f3cdf0SGordon Ross 		drv_usecwait(10);
150*26f3cdf0SGordon Ross 	}
151*26f3cdf0SGordon Ross 	return (0);
1527c478bd9Sstevel@tonic-gate }
1537c478bd9Sstevel@tonic-gate 
154a3463f0aSDana Myers /*
155a3463f0aSDana Myers  * Only called from ec_handler(), which validates ec_ok
156a3463f0aSDana Myers  */
1577c478bd9Sstevel@tonic-gate static int
ec_rd(int addr)1587c478bd9Sstevel@tonic-gate ec_rd(int addr)
1597c478bd9Sstevel@tonic-gate {
160450d6964Smyers 	int	cnt, rv;
161450d6964Smyers 	uint8_t sc;
162450d6964Smyers 
163450d6964Smyers 	mutex_enter(&ec.ec_mutex);
164450d6964Smyers 	sc = inb(ec.ec_sc);
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate #ifdef	DEBUG
1677c478bd9Sstevel@tonic-gate 	if (sc & EC_IBF) {
1687c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "!ec_rd: IBF already set");
1697c478bd9Sstevel@tonic-gate 	}
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 	if (sc & EC_OBF) {
1727c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "!ec_rd: OBF already set");
1737c478bd9Sstevel@tonic-gate 	}
1747c478bd9Sstevel@tonic-gate #endif
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	outb(ec.ec_sc, EC_RD);	/* output a read command */
177450d6964Smyers 	if (ec_wait_ibf_clear(ec.ec_sc) < 0) {
178450d6964Smyers 		cmn_err(CE_NOTE, "!ec_rd:1: timed-out waiting "
179450d6964Smyers 		    "for IBF to clear");
180450d6964Smyers 		mutex_exit(&ec.ec_mutex);
181450d6964Smyers 		return (-1);
1827c478bd9Sstevel@tonic-gate 	}
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	outb(ec.ec_base, addr);	/* output addr */
185450d6964Smyers 	if (ec_wait_ibf_clear(ec.ec_sc) < 0) {
186450d6964Smyers 		cmn_err(CE_NOTE, "!ec_rd:2: timed-out waiting "
187450d6964Smyers 		    "for IBF to clear");
188450d6964Smyers 		mutex_exit(&ec.ec_mutex);
189450d6964Smyers 		return (-1);
1907c478bd9Sstevel@tonic-gate 	}
191450d6964Smyers 	if (ec_wait_obf_set(ec.ec_sc) < 0) {
192450d6964Smyers 		cmn_err(CE_NOTE, "!ec_rd:1: timed-out waiting "
193450d6964Smyers 		    "for OBF to set");
194450d6964Smyers 		mutex_exit(&ec.ec_mutex);
195450d6964Smyers 		return (-1);
1967c478bd9Sstevel@tonic-gate 	}
1977c478bd9Sstevel@tonic-gate 
198450d6964Smyers 	rv = inb(ec.ec_base);
199450d6964Smyers 	mutex_exit(&ec.ec_mutex);
200450d6964Smyers 	return (rv);
2017c478bd9Sstevel@tonic-gate }
2027c478bd9Sstevel@tonic-gate 
203a3463f0aSDana Myers /*
204a3463f0aSDana Myers  * Only called from ec_handler(), which validates ec_ok
205a3463f0aSDana Myers  */
2067c478bd9Sstevel@tonic-gate static int
ec_wr(int addr,uint8_t val)207*26f3cdf0SGordon Ross ec_wr(int addr, uint8_t val)
2087c478bd9Sstevel@tonic-gate {
2097c478bd9Sstevel@tonic-gate 	int	cnt;
210450d6964Smyers 	uint8_t sc;
211450d6964Smyers 
212450d6964Smyers 	mutex_enter(&ec.ec_mutex);
213450d6964Smyers 	sc = inb(ec.ec_sc);
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate #ifdef	DEBUG
2167c478bd9Sstevel@tonic-gate 	if (sc & EC_IBF) {
2177c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "!ec_wr: IBF already set");
2187c478bd9Sstevel@tonic-gate 	}
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	if (sc & EC_OBF) {
2217c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "!ec_wr: OBF already set");
2227c478bd9Sstevel@tonic-gate 	}
2237c478bd9Sstevel@tonic-gate #endif
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	outb(ec.ec_sc, EC_WR);	/* output a write command */
226450d6964Smyers 	if (ec_wait_ibf_clear(ec.ec_sc) < 0) {
227450d6964Smyers 		cmn_err(CE_NOTE, "!ec_wr:1: timed-out waiting "
228450d6964Smyers 		    "for IBF to clear");
229450d6964Smyers 		mutex_exit(&ec.ec_mutex);
230450d6964Smyers 		return (-1);
2317c478bd9Sstevel@tonic-gate 	}
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 	outb(ec.ec_base, addr);	/* output addr */
234450d6964Smyers 	if (ec_wait_ibf_clear(ec.ec_sc) < 0) {
235450d6964Smyers 		cmn_err(CE_NOTE, "!ec_wr:2: timed-out waiting "
236450d6964Smyers 		    "for IBF to clear");
237450d6964Smyers 		mutex_exit(&ec.ec_mutex);
238450d6964Smyers 		return (-1);
2397c478bd9Sstevel@tonic-gate 	}
2407c478bd9Sstevel@tonic-gate 
241*26f3cdf0SGordon Ross 	outb(ec.ec_base, val);	/* write data */
242450d6964Smyers 	if (ec_wait_ibf_clear(ec.ec_sc) < 0) {
243450d6964Smyers 		cmn_err(CE_NOTE, "!ec_wr:3: timed-out waiting "
244450d6964Smyers 		    "for IBF to clear");
245450d6964Smyers 		mutex_exit(&ec.ec_mutex);
246450d6964Smyers 		return (-1);
2477c478bd9Sstevel@tonic-gate 	}
2487c478bd9Sstevel@tonic-gate 
249450d6964Smyers 	mutex_exit(&ec.ec_mutex);
2507c478bd9Sstevel@tonic-gate 	return (0);
2517c478bd9Sstevel@tonic-gate }
2527c478bd9Sstevel@tonic-gate 
253a3463f0aSDana Myers /*
254a3463f0aSDana Myers  * Only called from ec_gpe_callback(), which validates ec_ok
255a3463f0aSDana Myers  */
2567c478bd9Sstevel@tonic-gate static int
ec_query(void)2577c478bd9Sstevel@tonic-gate ec_query(void)
2587c478bd9Sstevel@tonic-gate {
259450d6964Smyers 	int	cnt, rv;
260450d6964Smyers 	uint8_t	sc;
2617c478bd9Sstevel@tonic-gate 
262450d6964Smyers 	mutex_enter(&ec.ec_mutex);
2637c478bd9Sstevel@tonic-gate 	outb(ec.ec_sc, EC_QR);	/* output a query command */
264450d6964Smyers 	if (ec_wait_ibf_clear(ec.ec_sc) < 0) {
265450d6964Smyers 		cmn_err(CE_NOTE, "!ec_query:1: timed-out waiting "
266450d6964Smyers 		    "for IBF to clear");
267450d6964Smyers 		mutex_exit(&ec.ec_mutex);
268450d6964Smyers 		return (-1);
2697c478bd9Sstevel@tonic-gate 	}
2707c478bd9Sstevel@tonic-gate 
271450d6964Smyers 	if (ec_wait_obf_set(ec.ec_sc) < 0) {
272450d6964Smyers 		cmn_err(CE_NOTE, "!ec_query:1: timed-out waiting "
273450d6964Smyers 		    "for OBF to set");
274450d6964Smyers 		mutex_exit(&ec.ec_mutex);
275450d6964Smyers 		return (-1);
2767c478bd9Sstevel@tonic-gate 	}
2777c478bd9Sstevel@tonic-gate 
278450d6964Smyers 	rv = inb(ec.ec_base);
279450d6964Smyers 	mutex_exit(&ec.ec_mutex);
280450d6964Smyers 	return (rv);
2817c478bd9Sstevel@tonic-gate }
2827c478bd9Sstevel@tonic-gate 
283*26f3cdf0SGordon Ross /*
284*26f3cdf0SGordon Ross  * ACPI CA EC address space handler
285*26f3cdf0SGordon Ross  * Requires: ec.ec_sc, ec.ec_base
286*26f3cdf0SGordon Ross  */
2877c478bd9Sstevel@tonic-gate static ACPI_STATUS
ec_handler(UINT32 func,ACPI_PHYSICAL_ADDRESS addr,UINT32 width,UINT64 * val,void * context,void * regcontext)2887c478bd9Sstevel@tonic-gate ec_handler(UINT32 func, ACPI_PHYSICAL_ADDRESS addr, UINT32 width,
289*26f3cdf0SGordon Ross 	UINT64 *val, void *context, void *regcontext)
2907c478bd9Sstevel@tonic-gate {
291450d6964Smyers 	_NOTE(ARGUNUSED(context, regcontext))
292*26f3cdf0SGordon Ross 	int i, tw, tmp;
2937c478bd9Sstevel@tonic-gate 
294a3463f0aSDana Myers 	/* Guard against unexpected invocation */
295a3463f0aSDana Myers 	if (ec.ec_ok == 0)
296a3463f0aSDana Myers 		return (AE_ERROR);
297a3463f0aSDana Myers 
298450d6964Smyers 	/*
299450d6964Smyers 	 * Add safety checks for BIOSes not strictly compliant
300450d6964Smyers 	 * with ACPI spec
301450d6964Smyers 	 */
302*26f3cdf0SGordon Ross 	if ((width % 8) != 0) {
303a3463f0aSDana Myers 		cmn_err(CE_NOTE, "!ec_handler: invalid width %d", width);
304*26f3cdf0SGordon Ross 		return (AE_BAD_PARAMETER);
305*26f3cdf0SGordon Ross 	}
306*26f3cdf0SGordon Ross 	if (val == NULL) {
307*26f3cdf0SGordon Ross 		cmn_err(CE_NOTE, "!ec_handler: NULL value pointer");
308*26f3cdf0SGordon Ross 		return (AE_BAD_PARAMETER);
309450d6964Smyers 	}
310450d6964Smyers 
311*26f3cdf0SGordon Ross 	while (width > 0) {
312*26f3cdf0SGordon Ross 
313*26f3cdf0SGordon Ross 		/* One UINT64 *val at a time. */
314*26f3cdf0SGordon Ross 		tw = min(width, 64);
315*26f3cdf0SGordon Ross 
316*26f3cdf0SGordon Ross 		if (func == ACPI_READ)
317*26f3cdf0SGordon Ross 			*val = 0;
318*26f3cdf0SGordon Ross 
319*26f3cdf0SGordon Ross 		/* Do I/O of up to 64 bits */
320*26f3cdf0SGordon Ross 		for (i = 0; i < tw; i += 8, addr++) {
321*26f3cdf0SGordon Ross 			switch (func) {
322*26f3cdf0SGordon Ross 			case ACPI_READ:
323*26f3cdf0SGordon Ross 				tmp = ec_rd(addr);
324*26f3cdf0SGordon Ross 				if (tmp < 0)
325*26f3cdf0SGordon Ross 					return (AE_ERROR);
326*26f3cdf0SGordon Ross 				*val |= ((UINT64)tmp) << i;
327*26f3cdf0SGordon Ross 				break;
328*26f3cdf0SGordon Ross 			case ACPI_WRITE:
329*26f3cdf0SGordon Ross 				tmp = ((*val) >> i) & 0xFF;
330*26f3cdf0SGordon Ross 				if (ec_wr(addr, (uint8_t)tmp) < 0)
331*26f3cdf0SGordon Ross 					return (AE_ERROR);
332*26f3cdf0SGordon Ross 				break;
333*26f3cdf0SGordon Ross 			default:
334*26f3cdf0SGordon Ross 				return (AE_ERROR);
335*26f3cdf0SGordon Ross 			}
336*26f3cdf0SGordon Ross 		}
337*26f3cdf0SGordon Ross 		val++;
338*26f3cdf0SGordon Ross 		width -= tw;
3397c478bd9Sstevel@tonic-gate 	}
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 	return (AE_OK);
3427c478bd9Sstevel@tonic-gate }
3437c478bd9Sstevel@tonic-gate 
344*26f3cdf0SGordon Ross /*
345*26f3cdf0SGordon Ross  * Called via taskq entry enqueued by ec_gpe_handler,
346*26f3cdf0SGordon Ross  * which validates ec_ok
347*26f3cdf0SGordon Ross  */
3487c478bd9Sstevel@tonic-gate static void
ec_gpe_callback(void * ctx)3497c478bd9Sstevel@tonic-gate ec_gpe_callback(void *ctx)
3507c478bd9Sstevel@tonic-gate {
3517c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(ctx))
3527c478bd9Sstevel@tonic-gate 	char		query_str[5];
353450d6964Smyers 	int		query;
354450d6964Smyers 
355450d6964Smyers 	if (!(inb(ec.ec_sc) & EC_SCI))
356*26f3cdf0SGordon Ross 		goto out;
357a3463f0aSDana Myers 
358450d6964Smyers 	query = ec_query();
359*26f3cdf0SGordon Ross 	if (query < 0)
360*26f3cdf0SGordon Ross 		goto out;
361*26f3cdf0SGordon Ross 
362*26f3cdf0SGordon Ross 	(void) snprintf(query_str, 5, "_Q%02X", (uint8_t)query);
363*26f3cdf0SGordon Ross 	(void) AcpiEvaluateObject(ec.ec_dev_hdl, query_str, NULL, NULL);
3647c478bd9Sstevel@tonic-gate 
365*26f3cdf0SGordon Ross out:
366*26f3cdf0SGordon Ross 	AcpiFinishGpe(ec.ec_gpe_hdl, ec.ec_gpe_bit);
3677c478bd9Sstevel@tonic-gate }
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate static UINT32
ec_gpe_handler(ACPI_HANDLE GpeDevice,UINT32 GpeNumber,void * ctx)370*26f3cdf0SGordon Ross ec_gpe_handler(ACPI_HANDLE GpeDevice, UINT32 GpeNumber, void *ctx)
3717c478bd9Sstevel@tonic-gate {
372*26f3cdf0SGordon Ross 	_NOTE(ARGUNUSED(GpeDevice))
373*26f3cdf0SGordon Ross 	_NOTE(ARGUNUSED(GpeNumber))
3747c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(ctx))
3757c478bd9Sstevel@tonic-gate 
376*26f3cdf0SGordon Ross 	/*
377*26f3cdf0SGordon Ross 	 * With ec_ok==0, we will not install a GPE handler,
378*26f3cdf0SGordon Ross 	 * so this is just paranoia.  But if this were to
379*26f3cdf0SGordon Ross 	 * happen somehow, don't add the taskq entry, and
380*26f3cdf0SGordon Ross 	 * tell the caller we're done with this GPE call.
381*26f3cdf0SGordon Ross 	 */
382*26f3cdf0SGordon Ross 	if (ec.ec_ok == 0)
383*26f3cdf0SGordon Ross 		return (ACPI_REENABLE_GPE);
384*26f3cdf0SGordon Ross 
38527f7c583Smyers 	AcpiOsExecute(OSL_GPE_HANDLER, ec_gpe_callback, NULL);
386*26f3cdf0SGordon Ross 
387*26f3cdf0SGordon Ross 	/*
388*26f3cdf0SGordon Ross 	 * Returning zero tells the ACPI system that we will
389*26f3cdf0SGordon Ross 	 * handle this event asynchronously.
390*26f3cdf0SGordon Ross 	 */
3917c478bd9Sstevel@tonic-gate 	return (0);
3927c478bd9Sstevel@tonic-gate }
3937c478bd9Sstevel@tonic-gate 
394450d6964Smyers /*
395*26f3cdf0SGordon Ross  * Some systems describe the EC using an "ECDT" (table).
396*26f3cdf0SGordon Ross  * If we find one use it (unless ec_ignore_ecdt is set).
397*26f3cdf0SGordon Ross  * Modern systems don't provide an ECDT.
398450d6964Smyers  */
399*26f3cdf0SGordon Ross static ACPI_STATUS
ec_probe_ecdt(void)400*26f3cdf0SGordon Ross ec_probe_ecdt(void)
401450d6964Smyers {
402*26f3cdf0SGordon Ross 	ACPI_TABLE_HEADER *th;
403*26f3cdf0SGordon Ross 	ACPI_TABLE_ECDT *ecdt;
404*26f3cdf0SGordon Ross 	ACPI_HANDLE	dev_hdl;
405*26f3cdf0SGordon Ross 	ACPI_STATUS	status;
406*26f3cdf0SGordon Ross 
407*26f3cdf0SGordon Ross 	status = AcpiGetTable(ACPI_SIG_ECDT, 1, &th);
408*26f3cdf0SGordon Ross #ifndef DEBUG
409*26f3cdf0SGordon Ross 	if (status == AE_NOT_FOUND)
410*26f3cdf0SGordon Ross 		return (status);
411*26f3cdf0SGordon Ross #endif
412*26f3cdf0SGordon Ross 	if (ACPI_FAILURE(status)) {
413*26f3cdf0SGordon Ross 		cmn_err(CE_NOTE, "!acpica: ECDT not found");
414*26f3cdf0SGordon Ross 		return (status);
415*26f3cdf0SGordon Ross 	}
416*26f3cdf0SGordon Ross 	if (ec_ignore_ecdt) {
417*26f3cdf0SGordon Ross 		/* pretend it was not found */
418*26f3cdf0SGordon Ross 		cmn_err(CE_NOTE, "!acpica: ECDT ignored");
419*26f3cdf0SGordon Ross 		return (AE_NOT_FOUND);
420*26f3cdf0SGordon Ross 	}
421450d6964Smyers 
422*26f3cdf0SGordon Ross 	ecdt = (ACPI_TABLE_ECDT *)th;
423*26f3cdf0SGordon Ross 	if (ecdt->Control.BitWidth != 8 ||
424*26f3cdf0SGordon Ross 	    ecdt->Data.BitWidth != 8) {
425*26f3cdf0SGordon Ross 		cmn_err(CE_NOTE, "!acpica: bad ECDT I/O width");
426*26f3cdf0SGordon Ross 		return (AE_BAD_VALUE);
427*26f3cdf0SGordon Ross 	}
428*26f3cdf0SGordon Ross 	status = AcpiGetHandle(NULL, (char *)ecdt->Id, &dev_hdl);
429*26f3cdf0SGordon Ross 	if (ACPI_FAILURE(status)) {
430*26f3cdf0SGordon Ross 		cmn_err(CE_NOTE, "!acpica: no ECDT device handle");
431*26f3cdf0SGordon Ross 		return (status);
432450d6964Smyers 	}
433*26f3cdf0SGordon Ross 
434*26f3cdf0SGordon Ross 	/*
435*26f3cdf0SGordon Ross 	 * Success.  Save info for attach.
436*26f3cdf0SGordon Ross 	 */
437*26f3cdf0SGordon Ross 	ec.ec_base = ecdt->Data.Address;
438*26f3cdf0SGordon Ross 	ec.ec_sc = ecdt->Control.Address;
439*26f3cdf0SGordon Ross 	ec.ec_dev_hdl = dev_hdl;
440*26f3cdf0SGordon Ross 	ec.ec_gpe_hdl = NULL;
441*26f3cdf0SGordon Ross 	ec.ec_gpe_bit = ecdt->Gpe;
442*26f3cdf0SGordon Ross 	ec.ec_ok = 1;
443*26f3cdf0SGordon Ross 
444*26f3cdf0SGordon Ross #ifdef DEBUG
445*26f3cdf0SGordon Ross 	cmn_err(CE_NOTE, "!acpica:ec_probe_ecdt: success");
446*26f3cdf0SGordon Ross #endif
447450d6964Smyers 	return (0);
448450d6964Smyers }
449450d6964Smyers 
450450d6964Smyers /*
451*26f3cdf0SGordon Ross  * Called from AcpiWalkDevices() when an EC device is found
452450d6964Smyers  */
453*26f3cdf0SGordon Ross static ACPI_STATUS
ec_find(ACPI_HANDLE obj,UINT32 nest,void * context,void ** rv)454*26f3cdf0SGordon Ross ec_find(ACPI_HANDLE obj, UINT32 nest, void *context, void **rv)
455450d6964Smyers {
456*26f3cdf0SGordon Ross 	_NOTE(ARGUNUSED(nest, rv))
457450d6964Smyers 
458*26f3cdf0SGordon Ross 	*((ACPI_HANDLE *)context) = obj;
459*26f3cdf0SGordon Ross 	return (AE_OK);
460450d6964Smyers }
461450d6964Smyers 
4627c478bd9Sstevel@tonic-gate /*
463*26f3cdf0SGordon Ross  * Normal way to get the details about the EC,
464*26f3cdf0SGordon Ross  * by searching the name space.
4657c478bd9Sstevel@tonic-gate  */
4667c478bd9Sstevel@tonic-gate static ACPI_STATUS
ec_probe_ns(void)467*26f3cdf0SGordon Ross ec_probe_ns(void)
4687c478bd9Sstevel@tonic-gate {
469*26f3cdf0SGordon Ross 	ACPI_HANDLE dev_hdl;
4707c478bd9Sstevel@tonic-gate 	ACPI_BUFFER buf, crs;
471*26f3cdf0SGordon Ross 	ACPI_OBJECT *gpe_obj;
472*26f3cdf0SGordon Ross 	ACPI_HANDLE gpe_hdl;
473*26f3cdf0SGordon Ross 	ACPI_INTEGER gpe_bit;
474*26f3cdf0SGordon Ross 	ACPI_STATUS status;
475*26f3cdf0SGordon Ross 	int i, io_port_cnt;
476*26f3cdf0SGordon Ross 	uint16_t ec_sc, ec_base;
477*26f3cdf0SGordon Ross 
478*26f3cdf0SGordon Ross 	dev_hdl = NULL;
479*26f3cdf0SGordon Ross 	(void) AcpiGetDevices("PNP0C09", &ec_find, (void *)&dev_hdl, NULL);
480*26f3cdf0SGordon Ross 	if (dev_hdl == NULL) {
481*26f3cdf0SGordon Ross #ifdef DEBUG
482*26f3cdf0SGordon Ross 		/* Not an error, just no EC on this machine. */
483*26f3cdf0SGordon Ross 		cmn_err(CE_WARN, "!acpica:ec_probe_ns: "
484*26f3cdf0SGordon Ross 		    "PNP0C09 not found");
485*26f3cdf0SGordon Ross #endif
486*26f3cdf0SGordon Ross 		return (AE_NOT_FOUND);
487*26f3cdf0SGordon Ross 	}
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 	/*
4907c478bd9Sstevel@tonic-gate 	 * Find ec_base and ec_sc addresses
4917c478bd9Sstevel@tonic-gate 	 */
4927c478bd9Sstevel@tonic-gate 	crs.Length = ACPI_ALLOCATE_BUFFER;
493*26f3cdf0SGordon Ross 	status = AcpiEvaluateObjectTyped(dev_hdl, "_CRS", NULL, &crs,
494*26f3cdf0SGordon Ross 	    ACPI_TYPE_BUFFER);
495*26f3cdf0SGordon Ross 	if (ACPI_FAILURE(status)) {
496*26f3cdf0SGordon Ross 		cmn_err(CE_WARN, "!acpica:ec_probe_ns: "
497*26f3cdf0SGordon Ross 		    "_CRS object evaluate failed");
498*26f3cdf0SGordon Ross 		return (status);
4997c478bd9Sstevel@tonic-gate 	}
5007c478bd9Sstevel@tonic-gate 
501db2bae30SDana Myers 	for (i = 0, io_port_cnt = 0;
502db2bae30SDana Myers 	    i < ((ACPI_OBJECT *)crs.Pointer)->Buffer.Length; i++) {
5037c478bd9Sstevel@tonic-gate 		io_port_des_t *io_port;
5047c478bd9Sstevel@tonic-gate 		uint8_t *tmp;
5057c478bd9Sstevel@tonic-gate 
506db2bae30SDana Myers 		tmp = ((ACPI_OBJECT *)crs.Pointer)->Buffer.Pointer + i;
5077c478bd9Sstevel@tonic-gate 		if (*tmp != IO_PORT_DES)
5087c478bd9Sstevel@tonic-gate 			continue;
5097c478bd9Sstevel@tonic-gate 		io_port = (io_port_des_t *)tmp;
5107c478bd9Sstevel@tonic-gate 		/*
511*26f3cdf0SGordon Ross 		 * first port is ec_base and second is ec_sc
5127c478bd9Sstevel@tonic-gate 		 */
513*26f3cdf0SGordon Ross 		if (io_port_cnt == 0)
514*26f3cdf0SGordon Ross 			ec_base = (io_port->min_base_hi << 8) |
5157c478bd9Sstevel@tonic-gate 			    io_port->min_base_lo;
516*26f3cdf0SGordon Ross 		if (io_port_cnt == 1)
517*26f3cdf0SGordon Ross 			ec_sc = (io_port->min_base_hi << 8) |
5187c478bd9Sstevel@tonic-gate 			    io_port->min_base_lo;
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 		io_port_cnt++;
5217c478bd9Sstevel@tonic-gate 		/*
5227c478bd9Sstevel@tonic-gate 		 * Increment ahead to next struct.
5237c478bd9Sstevel@tonic-gate 		 */
5247c478bd9Sstevel@tonic-gate 		i += 7;
5257c478bd9Sstevel@tonic-gate 	}
5267c478bd9Sstevel@tonic-gate 	AcpiOsFree(crs.Pointer);
527*26f3cdf0SGordon Ross 	if (io_port_cnt < 2) {
528*26f3cdf0SGordon Ross 		cmn_err(CE_WARN, "!acpica:ec_probe_ns: "
529*26f3cdf0SGordon Ross 		    "_CRS parse failed");
530*26f3cdf0SGordon Ross 		return (AE_BAD_VALUE);
531450d6964Smyers 	}
532450d6964Smyers 
5337c478bd9Sstevel@tonic-gate 	/*
534*26f3cdf0SGordon Ross 	 * Get the GPE info.
5357c478bd9Sstevel@tonic-gate 	 */
5367c478bd9Sstevel@tonic-gate 	buf.Length = ACPI_ALLOCATE_BUFFER;
537*26f3cdf0SGordon Ross 	status = AcpiEvaluateObject(dev_hdl, "_GPE", NULL, &buf);
538*26f3cdf0SGordon Ross 	if (ACPI_FAILURE(status)) {
539*26f3cdf0SGordon Ross 		cmn_err(CE_WARN, "!acpica:ec_probe_ns: "
540*26f3cdf0SGordon Ross 		    "_GPE object evaluate");
541*26f3cdf0SGordon Ross 		return (status);
5427c478bd9Sstevel@tonic-gate 	}
543*26f3cdf0SGordon Ross 	gpe_obj = (ACPI_OBJECT *)buf.Pointer;
5447c478bd9Sstevel@tonic-gate 	/*
545*26f3cdf0SGordon Ross 	 * process the GPE description
5467c478bd9Sstevel@tonic-gate 	 */
547*26f3cdf0SGordon Ross 	switch (gpe_obj->Type) {
548*26f3cdf0SGordon Ross 	case ACPI_TYPE_INTEGER:
549*26f3cdf0SGordon Ross 		gpe_hdl = NULL;
550*26f3cdf0SGordon Ross 		gpe_bit = gpe_obj->Integer.Value;
551*26f3cdf0SGordon Ross 		break;
552*26f3cdf0SGordon Ross 	case ACPI_TYPE_PACKAGE:
553*26f3cdf0SGordon Ross 		if (gpe_obj->Package.Count != 2)
554*26f3cdf0SGordon Ross 			goto bad_gpe;
555*26f3cdf0SGordon Ross 		gpe_obj = gpe_obj->Package.Elements;
556*26f3cdf0SGordon Ross 		if (gpe_obj[1].Type != ACPI_TYPE_INTEGER)
557*26f3cdf0SGordon Ross 			goto bad_gpe;
558*26f3cdf0SGordon Ross 		gpe_hdl = gpe_obj[0].Reference.Handle;
559*26f3cdf0SGordon Ross 		gpe_bit = gpe_obj[1].Integer.Value;
560*26f3cdf0SGordon Ross 		break;
561*26f3cdf0SGordon Ross 	bad_gpe:
562*26f3cdf0SGordon Ross 	default:
563*26f3cdf0SGordon Ross 		status = AE_BAD_VALUE;
564*26f3cdf0SGordon Ross 		break;
565*26f3cdf0SGordon Ross 	}
566*26f3cdf0SGordon Ross 	AcpiOsFree(buf.Pointer);
567*26f3cdf0SGordon Ross 	if (ACPI_FAILURE(status)) {
568*26f3cdf0SGordon Ross 		cmn_err(CE_WARN, "!acpica:ec_probe_ns: "
569*26f3cdf0SGordon Ross 		    "_GPE parse failed");
570*26f3cdf0SGordon Ross 		return (status);
571*26f3cdf0SGordon Ross 	}
5727c478bd9Sstevel@tonic-gate 
573a3463f0aSDana Myers 	/*
574*26f3cdf0SGordon Ross 	 * Success.  Save info for attach.
575a3463f0aSDana Myers 	 */
576*26f3cdf0SGordon Ross 	ec.ec_base = ec_base;
577*26f3cdf0SGordon Ross 	ec.ec_sc = ec_sc;
578*26f3cdf0SGordon Ross 	ec.ec_dev_hdl = dev_hdl;
579*26f3cdf0SGordon Ross 	ec.ec_gpe_hdl = gpe_hdl;
580*26f3cdf0SGordon Ross 	ec.ec_gpe_bit = gpe_bit;
581a3463f0aSDana Myers 	ec.ec_ok = 1;
582a3463f0aSDana Myers 
583*26f3cdf0SGordon Ross #ifdef DEBUG
584*26f3cdf0SGordon Ross 	cmn_err(CE_NOTE, "!acpica:ec_probe_ns: success");
585*26f3cdf0SGordon Ross #endif
586*26f3cdf0SGordon Ross 	return (0);
587*26f3cdf0SGordon Ross }
588*26f3cdf0SGordon Ross 
589*26f3cdf0SGordon Ross /*
590*26f3cdf0SGordon Ross  * Setup the Embedded Controller (EC) address space handler.
591*26f3cdf0SGordon Ross  * Entered only if one of the EC probe methods found an EC.
592*26f3cdf0SGordon Ross  */
593*26f3cdf0SGordon Ross static void
ec_init(void)594*26f3cdf0SGordon Ross ec_init(void)
595*26f3cdf0SGordon Ross {
596*26f3cdf0SGordon Ross 	ACPI_STATUS rc;
597*26f3cdf0SGordon Ross 	int x;
598*26f3cdf0SGordon Ross 
599*26f3cdf0SGordon Ross 	/* paranoia */
600*26f3cdf0SGordon Ross 	if (ec.ec_ok == 0)
601*26f3cdf0SGordon Ross 		return;
602450d6964Smyers 
603450d6964Smyers 	/*
604*26f3cdf0SGordon Ross 	 * Drain the EC data register if something is left over from
605*26f3cdf0SGordon Ross 	 * legacy mode
606a3463f0aSDana Myers 	 */
607*26f3cdf0SGordon Ross 	if (inb(ec.ec_sc) & EC_OBF) {
608*26f3cdf0SGordon Ross 		x = inb(ec.ec_base);	/* read and discard value */
609*26f3cdf0SGordon Ross #ifdef	DEBUG
610*26f3cdf0SGordon Ross 		cmn_err(CE_NOTE, "!EC had something: 0x%x", x);
611*26f3cdf0SGordon Ross #endif
612*26f3cdf0SGordon Ross 	}
613a3463f0aSDana Myers 
614a3463f0aSDana Myers 	/*
615*26f3cdf0SGordon Ross 	 * Install an "EC address space" handler.
616*26f3cdf0SGordon Ross 	 *
617*26f3cdf0SGordon Ross 	 * This call does a name space walk under the passed
618*26f3cdf0SGordon Ross 	 * object looking for child objects with an EC space
619*26f3cdf0SGordon Ross 	 * region for which to install this handler.  Using
620*26f3cdf0SGordon Ross 	 * the ROOT object makes sure we find them all.
621*26f3cdf0SGordon Ross 	 *
622*26f3cdf0SGordon Ross 	 * XXX: Some systems return an error from this call
623*26f3cdf0SGordon Ross 	 * after a partial success, i.e. where the NS walk
624*26f3cdf0SGordon Ross 	 * installs on some nodes and fails on other nodes.
625*26f3cdf0SGordon Ross 	 * In such cases, disabling the EC and GPE handlers
626*26f3cdf0SGordon Ross 	 * makes things worse, so just report the error and
627*26f3cdf0SGordon Ross 	 * leave the EC handler enabled.
628*26f3cdf0SGordon Ross 	 *
629*26f3cdf0SGordon Ross 	 * At one point, it seemed that doing this part of
630*26f3cdf0SGordon Ross 	 * EC setup earlier may help, which is why this is
631*26f3cdf0SGordon Ross 	 * now a separate function from ec_attach.  Someone
632*26f3cdf0SGordon Ross 	 * needs to figure our why some systems give us an
633*26f3cdf0SGordon Ross 	 * error return from this call.  (TODO)
634450d6964Smyers 	 */
635*26f3cdf0SGordon Ross 	rc = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
636*26f3cdf0SGordon Ross 	    ACPI_ADR_SPACE_EC, &ec_handler, NULL, NULL);
637*26f3cdf0SGordon Ross 	if (rc != AE_OK) {
638*26f3cdf0SGordon Ross 		cmn_err(CE_WARN, "!acpica:ec_init: "
639*26f3cdf0SGordon Ross 		    "install AS handler, rc=0x%x", rc);
640*26f3cdf0SGordon Ross 		return;
6417c478bd9Sstevel@tonic-gate 	}
642*26f3cdf0SGordon Ross #ifdef DEBUG
643*26f3cdf0SGordon Ross 	cmn_err(CE_NOTE, "!acpica:ec_init: success");
644*26f3cdf0SGordon Ross #endif
6457c478bd9Sstevel@tonic-gate }
6467c478bd9Sstevel@tonic-gate 
647*26f3cdf0SGordon Ross /*
648*26f3cdf0SGordon Ross  * Attach the EC General-Purpose Event (GPE) handler.
649*26f3cdf0SGordon Ross  */
650*26f3cdf0SGordon Ross static void
ec_attach(void)651*26f3cdf0SGordon Ross ec_attach(void)
6527c478bd9Sstevel@tonic-gate {
653*26f3cdf0SGordon Ross 	ACPI_STATUS rc;
6547c478bd9Sstevel@tonic-gate 
655*26f3cdf0SGordon Ross 	/*
656*26f3cdf0SGordon Ross 	 * Guard against call without probe results.
657*26f3cdf0SGordon Ross 	 */
658*26f3cdf0SGordon Ross 	if (ec.ec_ok == 0) {
659*26f3cdf0SGordon Ross 		cmn_err(CE_WARN, "!acpica:ec_attach: "
660*26f3cdf0SGordon Ross 		    "no EC device found");
661*26f3cdf0SGordon Ross 		return;
662*26f3cdf0SGordon Ross 	}
6637c478bd9Sstevel@tonic-gate 
664*26f3cdf0SGordon Ross 	/*
665*26f3cdf0SGordon Ross 	 * Install the GPE handler and enable it.
666*26f3cdf0SGordon Ross 	 */
667*26f3cdf0SGordon Ross 	rc = AcpiInstallGpeHandler(ec.ec_gpe_hdl, ec.ec_gpe_bit,
668*26f3cdf0SGordon Ross 	    ACPI_GPE_EDGE_TRIGGERED, ec_gpe_handler, NULL);
669*26f3cdf0SGordon Ross 	if (rc != AE_OK) {
670*26f3cdf0SGordon Ross 		cmn_err(CE_WARN, "!acpica:ec_attach: "
671*26f3cdf0SGordon Ross 		    "install GPE handler, rc=0x%x", rc);
672*26f3cdf0SGordon Ross 		goto errout;
673*26f3cdf0SGordon Ross 	}
6747c478bd9Sstevel@tonic-gate 
675*26f3cdf0SGordon Ross 	rc = AcpiEnableGpe(ec.ec_gpe_hdl, ec.ec_gpe_bit);
676*26f3cdf0SGordon Ross 	if (rc != AE_OK) {
677*26f3cdf0SGordon Ross 		cmn_err(CE_WARN, "!acpica:ec_attach: "
678*26f3cdf0SGordon Ross 		    "enable GPE handler, rc=0x%x", rc);
679*26f3cdf0SGordon Ross 		goto errout;
680*26f3cdf0SGordon Ross 	}
6817c478bd9Sstevel@tonic-gate 
682*26f3cdf0SGordon Ross #ifdef DEBUG
683*26f3cdf0SGordon Ross 	cmn_err(CE_NOTE, "!acpica:ec_attach: success");
684*26f3cdf0SGordon Ross #endif
685*26f3cdf0SGordon Ross 	return;
686*26f3cdf0SGordon Ross 
687*26f3cdf0SGordon Ross errout:
688*26f3cdf0SGordon Ross 	AcpiRemoveGpeHandler(ec.ec_gpe_hdl, ec.ec_gpe_bit,
689*26f3cdf0SGordon Ross 	    ec_gpe_handler);
6907c478bd9Sstevel@tonic-gate }
6917c478bd9Sstevel@tonic-gate 
692*26f3cdf0SGordon Ross /*
693*26f3cdf0SGordon Ross  * System Management Bus Controller (SMBC)
694*26f3cdf0SGordon Ross  * These also go through the EC.
695*26f3cdf0SGordon Ross  * (not yet supported)
696*26f3cdf0SGordon Ross  */
6977c478bd9Sstevel@tonic-gate static void
smbus_attach(void)698*26f3cdf0SGordon Ross smbus_attach(void)
6997c478bd9Sstevel@tonic-gate {
700*26f3cdf0SGordon Ross #ifdef	DEBUG
701*26f3cdf0SGordon Ross 	ACPI_HANDLE obj;
7027c478bd9Sstevel@tonic-gate 
703*26f3cdf0SGordon Ross 	obj = NULL;
704*26f3cdf0SGordon Ross 	(void) AcpiGetDevices("ACPI0001", &ec_find, (void *)&obj, NULL);
705*26f3cdf0SGordon Ross 	if (obj != NULL) {
706*26f3cdf0SGordon Ross 		cmn_err(CE_NOTE, "!acpica: found an SMBC Version 1.0");
7077c478bd9Sstevel@tonic-gate 	}
7087c478bd9Sstevel@tonic-gate 
709*26f3cdf0SGordon Ross 	obj = NULL;
710*26f3cdf0SGordon Ross 	(void) AcpiGetDevices("ACPI0005", &ec_find, (void *)&obj, NULL);
711*26f3cdf0SGordon Ross 	if (obj != NULL) {
712*26f3cdf0SGordon Ross 		cmn_err(CE_NOTE, "!acpica: found an SMBC Version 2.0");
713*26f3cdf0SGordon Ross 	}
714*26f3cdf0SGordon Ross #endif	/* DEBUG */
7157c478bd9Sstevel@tonic-gate }
7167c478bd9Sstevel@tonic-gate 
717*26f3cdf0SGordon Ross /*
718*26f3cdf0SGordon Ross  * Initialize the EC, if present.
719*26f3cdf0SGordon Ross  */
7207c478bd9Sstevel@tonic-gate void
acpica_ec_init(void)7217c478bd9Sstevel@tonic-gate acpica_ec_init(void)
7227c478bd9Sstevel@tonic-gate {
723*26f3cdf0SGordon Ross 	ACPI_STATUS rc;
724*26f3cdf0SGordon Ross 
7257c478bd9Sstevel@tonic-gate 	/*
726*26f3cdf0SGordon Ross 	 * Initialize EC mutex here
7277c478bd9Sstevel@tonic-gate 	 */
728*26f3cdf0SGordon Ross 	mutex_init(&ec.ec_mutex, NULL, MUTEX_DRIVER, NULL);
729a3463f0aSDana Myers 
7307c478bd9Sstevel@tonic-gate 	/*
731*26f3cdf0SGordon Ross 	 * First search the ACPI tables for an ECDT, and
732*26f3cdf0SGordon Ross 	 * if not found, search the name space for it.
7337c478bd9Sstevel@tonic-gate 	 */
734*26f3cdf0SGordon Ross 	rc = ec_probe_ecdt();
735*26f3cdf0SGordon Ross 	if (ACPI_FAILURE(rc))
736*26f3cdf0SGordon Ross 		rc = ec_probe_ns();
737*26f3cdf0SGordon Ross 	if (ACPI_SUCCESS(rc)) {
738*26f3cdf0SGordon Ross 		ec_init();
739*26f3cdf0SGordon Ross 		ec_attach();
740*26f3cdf0SGordon Ross 	}
741*26f3cdf0SGordon Ross 	smbus_attach();
7427c478bd9Sstevel@tonic-gate }
743