Home | History | Annotate | Line # | Download | only in acpi
smbus_acpi.c revision 1.9.2.3
      1  1.9.2.3  yamt /* $NetBSD: smbus_acpi.c,v 1.9.2.3 2010/08/11 22:53:16 yamt Exp $ */
      2  1.9.2.2  yamt 
      3  1.9.2.2  yamt /*-
      4  1.9.2.2  yamt  * Copyright (c) 2009 The NetBSD Foundation, Inc.
      5  1.9.2.2  yamt  * All rights reserved.
      6  1.9.2.2  yamt  *
      7  1.9.2.2  yamt  * This code is derived from software contributed to The NetBSD Foundation
      8  1.9.2.2  yamt  * by Paul Goyette
      9  1.9.2.2  yamt  *
     10  1.9.2.2  yamt  * Redistribution and use in source and binary forms, with or without
     11  1.9.2.2  yamt  * modification, are permitted provided that the following conditions
     12  1.9.2.2  yamt  * are met:
     13  1.9.2.2  yamt  * 1. Redistributions of source code must retain the above copyright
     14  1.9.2.2  yamt  *    notice, this list of conditions and the following disclaimer.
     15  1.9.2.2  yamt  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.9.2.2  yamt  *    notice, this list of conditions and the following disclaimer in the
     17  1.9.2.2  yamt  *    documentation and/or other materials provided with the distribution.
     18  1.9.2.2  yamt  *
     19  1.9.2.2  yamt  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  1.9.2.2  yamt  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  1.9.2.2  yamt  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  1.9.2.2  yamt  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  1.9.2.2  yamt  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  1.9.2.2  yamt  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  1.9.2.2  yamt  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  1.9.2.2  yamt  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  1.9.2.2  yamt  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  1.9.2.2  yamt  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  1.9.2.2  yamt  * POSSIBILITY OF SUCH DAMAGE.
     30  1.9.2.2  yamt  */
     31  1.9.2.2  yamt 
     32  1.9.2.2  yamt /*
     33  1.9.2.2  yamt  * ACPI SMBus Controller driver
     34  1.9.2.2  yamt  *
     35  1.9.2.2  yamt  * See http://smbus.org/specs/smbus_cmi10.pdf for specifications
     36  1.9.2.2  yamt  */
     37  1.9.2.2  yamt 
     38  1.9.2.2  yamt #include <sys/cdefs.h>
     39  1.9.2.3  yamt __KERNEL_RCSID(0, "$NetBSD: smbus_acpi.c,v 1.9.2.3 2010/08/11 22:53:16 yamt Exp $");
     40  1.9.2.2  yamt 
     41  1.9.2.2  yamt #include <sys/param.h>
     42  1.9.2.2  yamt #include <sys/device.h>
     43  1.9.2.2  yamt #include <sys/callout.h>
     44  1.9.2.2  yamt #include <sys/kernel.h>
     45  1.9.2.2  yamt #include <sys/mutex.h>
     46  1.9.2.2  yamt #include <sys/systm.h>
     47  1.9.2.2  yamt 
     48  1.9.2.2  yamt #include <dev/acpi/acpireg.h>
     49  1.9.2.2  yamt #include <dev/acpi/acpivar.h>
     50  1.9.2.2  yamt 
     51  1.9.2.2  yamt #include <dev/i2c/i2cvar.h>
     52  1.9.2.2  yamt 
     53  1.9.2.2  yamt #define _COMPONENT		ACPI_BUS_COMPONENT
     54  1.9.2.2  yamt ACPI_MODULE_NAME		("smbus_acpi")
     55  1.9.2.2  yamt 
     56  1.9.2.2  yamt /*
     57  1.9.2.3  yamt  * ACPI SMBus CMI protocol codes.
     58  1.9.2.2  yamt  */
     59  1.9.2.2  yamt #define	ACPI_SMBUS_RD_QUICK	0x03
     60  1.9.2.2  yamt #define	ACPI_SMBUS_RCV_BYTE	0x05
     61  1.9.2.2  yamt #define	ACPI_SMBUS_RD_BYTE	0x07
     62  1.9.2.2  yamt #define	ACPI_SMBUS_RD_WORD	0x09
     63  1.9.2.2  yamt #define	ACPI_SMBUS_RD_BLOCK	0x0B
     64  1.9.2.2  yamt #define	ACPI_SMBUS_WR_QUICK	0x02
     65  1.9.2.2  yamt #define	ACPI_SMBUS_SND_BYTE	0x04
     66  1.9.2.2  yamt #define	ACPI_SMBUS_WR_BYTE	0x06
     67  1.9.2.2  yamt #define	ACPI_SMBUS_WR_WORD	0x08
     68  1.9.2.2  yamt #define	ACPI_SMBUS_WR_BLOCK	0x0A
     69  1.9.2.2  yamt #define	ACPI_SMBUS_PROCESS_CALL	0x0C
     70  1.9.2.2  yamt 
     71  1.9.2.2  yamt struct acpi_smbus_softc {
     72  1.9.2.2  yamt 	struct acpi_devnode 	*sc_devnode;
     73  1.9.2.2  yamt 	struct callout		sc_callout;
     74  1.9.2.2  yamt 	struct i2c_controller	sc_i2c_tag;
     75  1.9.2.2  yamt 	device_t		sc_dv;
     76  1.9.2.2  yamt 	kmutex_t		sc_i2c_mutex;
     77  1.9.2.2  yamt 	int			sc_poll_alert;
     78  1.9.2.2  yamt };
     79  1.9.2.2  yamt 
     80  1.9.2.2  yamt static int	acpi_smbus_match(device_t, cfdata_t, void *);
     81  1.9.2.2  yamt static void	acpi_smbus_attach(device_t, device_t, void *);
     82  1.9.2.2  yamt static int	acpi_smbus_detach(device_t, int);
     83  1.9.2.3  yamt static int	acpi_smbus_poll_alert(ACPI_HANDLE, int *);
     84  1.9.2.2  yamt static int	acpi_smbus_acquire_bus(void *, int);
     85  1.9.2.2  yamt static void	acpi_smbus_release_bus(void *, int);
     86  1.9.2.2  yamt static int	acpi_smbus_exec(void *, i2c_op_t, i2c_addr_t, const void *,
     87  1.9.2.2  yamt 				size_t, void *, size_t, int);
     88  1.9.2.2  yamt static void	acpi_smbus_alerts(struct acpi_smbus_softc *);
     89  1.9.2.2  yamt static void	acpi_smbus_tick(void *);
     90  1.9.2.2  yamt static void	acpi_smbus_notify_handler(ACPI_HANDLE, uint32_t, void *);
     91  1.9.2.2  yamt 
     92  1.9.2.2  yamt struct SMB_UDID {
     93  1.9.2.2  yamt 	uint8_t		dev_cap;
     94  1.9.2.2  yamt 	uint8_t		vers_rev;
     95  1.9.2.2  yamt 	uint16_t	vendor;
     96  1.9.2.2  yamt 	uint16_t	device;
     97  1.9.2.2  yamt 	uint16_t	interface;
     98  1.9.2.2  yamt 	uint16_t	subsys_vendor;
     99  1.9.2.2  yamt 	uint16_t	subsys_device;
    100  1.9.2.2  yamt 	uint8_t		reserved[4];
    101  1.9.2.2  yamt };
    102  1.9.2.2  yamt 
    103  1.9.2.2  yamt struct SMB_DEVICE {
    104  1.9.2.2  yamt 	uint8_t		slave_addr;
    105  1.9.2.2  yamt 	uint8_t		reserved;
    106  1.9.2.2  yamt 	struct SMB_UDID	dev_id;
    107  1.9.2.2  yamt };
    108  1.9.2.2  yamt 
    109  1.9.2.2  yamt struct SMB_INFO {
    110  1.9.2.2  yamt 	uint8_t		struct_ver;
    111  1.9.2.2  yamt 	uint8_t		spec_ver;
    112  1.9.2.2  yamt 	uint8_t		hw_cap;
    113  1.9.2.2  yamt 	uint8_t		poll_int;
    114  1.9.2.2  yamt 	uint8_t		dev_count;
    115  1.9.2.2  yamt 	struct SMB_DEVICE device[1];
    116  1.9.2.2  yamt };
    117  1.9.2.2  yamt 
    118  1.9.2.2  yamt static const char * const smbus_acpi_ids[] = {
    119  1.9.2.2  yamt 	"SMBUS01",	/* SMBus CMI v1.0 */
    120  1.9.2.2  yamt 	NULL
    121  1.9.2.2  yamt };
    122  1.9.2.2  yamt 
    123  1.9.2.2  yamt CFATTACH_DECL_NEW(acpismbus, sizeof(struct acpi_smbus_softc),
    124  1.9.2.2  yamt     acpi_smbus_match, acpi_smbus_attach, acpi_smbus_detach, NULL);
    125  1.9.2.2  yamt 
    126  1.9.2.2  yamt static int
    127  1.9.2.2  yamt acpi_smbus_match(device_t parent, cfdata_t match, void *aux)
    128  1.9.2.2  yamt {
    129  1.9.2.2  yamt 	struct acpi_attach_args *aa = aux;
    130  1.9.2.2  yamt 
    131  1.9.2.2  yamt 	if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
    132  1.9.2.2  yamt 		return 0;
    133  1.9.2.2  yamt 
    134  1.9.2.2  yamt 	if (acpi_match_hid(aa->aa_node->ad_devinfo, smbus_acpi_ids) == 0)
    135  1.9.2.2  yamt 		return 0;
    136  1.9.2.2  yamt 
    137  1.9.2.3  yamt 	return acpi_smbus_poll_alert(aa->aa_node->ad_handle, NULL);
    138  1.9.2.2  yamt }
    139  1.9.2.2  yamt 
    140  1.9.2.2  yamt static void
    141  1.9.2.2  yamt acpi_smbus_attach(device_t parent, device_t self, void *aux)
    142  1.9.2.2  yamt {
    143  1.9.2.2  yamt 	struct acpi_smbus_softc *sc = device_private(self);
    144  1.9.2.2  yamt 	struct acpi_attach_args *aa = aux;
    145  1.9.2.2  yamt 	struct i2cbus_attach_args iba;
    146  1.9.2.2  yamt 
    147  1.9.2.2  yamt 	aprint_naive("\n");
    148  1.9.2.2  yamt 
    149  1.9.2.2  yamt 	sc->sc_devnode = aa->aa_node;
    150  1.9.2.2  yamt 	sc->sc_dv = self;
    151  1.9.2.2  yamt 	sc->sc_poll_alert = 2;
    152  1.9.2.2  yamt 
    153  1.9.2.3  yamt 	/* Attach I2C bus. */
    154  1.9.2.2  yamt 	mutex_init(&sc->sc_i2c_mutex, MUTEX_DEFAULT, IPL_NONE);
    155  1.9.2.3  yamt 
    156  1.9.2.2  yamt 	sc->sc_i2c_tag.ic_cookie = sc;
    157  1.9.2.2  yamt 	sc->sc_i2c_tag.ic_acquire_bus = acpi_smbus_acquire_bus;
    158  1.9.2.2  yamt 	sc->sc_i2c_tag.ic_release_bus = acpi_smbus_release_bus;
    159  1.9.2.2  yamt 	sc->sc_i2c_tag.ic_exec = acpi_smbus_exec;
    160  1.9.2.2  yamt 
    161  1.9.2.3  yamt 	(void)acpi_smbus_poll_alert(aa->aa_node->ad_handle,&sc->sc_poll_alert);
    162  1.9.2.2  yamt 
    163  1.9.2.3  yamt 	/* If failed, fall-back to polling. */
    164  1.9.2.3  yamt 	if (acpi_register_notify(sc->sc_devnode,
    165  1.9.2.3  yamt 		acpi_smbus_notify_handler) != true)
    166  1.9.2.3  yamt 		sc->sc_poll_alert = 2;
    167  1.9.2.2  yamt 
    168  1.9.2.2  yamt 	callout_init(&sc->sc_callout, 0);
    169  1.9.2.2  yamt 	callout_setfunc(&sc->sc_callout, acpi_smbus_tick, self);
    170  1.9.2.2  yamt 
    171  1.9.2.2  yamt 	if (sc->sc_poll_alert != 0) {
    172  1.9.2.3  yamt 		aprint_debug(": alert_poll %d sec", sc->sc_poll_alert);
    173  1.9.2.2  yamt 		callout_schedule(&sc->sc_callout, sc->sc_poll_alert * hz);
    174  1.9.2.2  yamt 	}
    175  1.9.2.2  yamt 
    176  1.9.2.3  yamt 	aprint_normal("\n");
    177  1.9.2.2  yamt 
    178  1.9.2.3  yamt 	(void)memset(&iba, 0, sizeof(iba));
    179  1.9.2.3  yamt 	(void)pmf_device_register(self, NULL, NULL);
    180  1.9.2.2  yamt 
    181  1.9.2.3  yamt 	iba.iba_tag = &sc->sc_i2c_tag;
    182  1.9.2.2  yamt 
    183  1.9.2.3  yamt 	(void)config_found_ia(self, "i2cbus", &iba, iicbus_print);
    184  1.9.2.3  yamt }
    185  1.9.2.2  yamt 
    186  1.9.2.3  yamt static int
    187  1.9.2.3  yamt acpi_smbus_detach(device_t self, int flags)
    188  1.9.2.3  yamt {
    189  1.9.2.3  yamt 	struct acpi_smbus_softc *sc = device_private(self);
    190  1.9.2.2  yamt 
    191  1.9.2.3  yamt 	pmf_device_deregister(self);
    192  1.9.2.3  yamt 	acpi_deregister_notify(sc->sc_devnode);
    193  1.9.2.2  yamt 
    194  1.9.2.3  yamt 	callout_halt(&sc->sc_callout, NULL);
    195  1.9.2.3  yamt 	callout_destroy(&sc->sc_callout);
    196  1.9.2.2  yamt 
    197  1.9.2.3  yamt 	mutex_destroy(&sc->sc_i2c_mutex);
    198  1.9.2.2  yamt 
    199  1.9.2.3  yamt 	return 0;
    200  1.9.2.2  yamt }
    201  1.9.2.2  yamt 
    202  1.9.2.2  yamt static int
    203  1.9.2.3  yamt acpi_smbus_poll_alert(ACPI_HANDLE hdl, int *alert)
    204  1.9.2.2  yamt {
    205  1.9.2.3  yamt 	struct SMB_INFO *info;
    206  1.9.2.3  yamt 	ACPI_BUFFER smi_buf;
    207  1.9.2.3  yamt 	ACPI_OBJECT *e, *p;
    208  1.9.2.2  yamt 	ACPI_STATUS rv;
    209  1.9.2.2  yamt 
    210  1.9.2.3  yamt 	/*
    211  1.9.2.3  yamt 	 * Retrieve polling interval for SMBus Alerts.
    212  1.9.2.3  yamt 	 */
    213  1.9.2.3  yamt 	rv = acpi_eval_struct(hdl, "_SBI", &smi_buf);
    214  1.9.2.2  yamt 
    215  1.9.2.2  yamt 	if (ACPI_FAILURE(rv))
    216  1.9.2.3  yamt 		return 0;
    217  1.9.2.2  yamt 
    218  1.9.2.3  yamt 	p = smi_buf.Pointer;
    219  1.9.2.2  yamt 
    220  1.9.2.3  yamt 	if (p->Type != ACPI_TYPE_PACKAGE) {
    221  1.9.2.3  yamt 		rv = AE_TYPE;
    222  1.9.2.3  yamt 		goto out;
    223  1.9.2.3  yamt 	}
    224  1.9.2.2  yamt 
    225  1.9.2.3  yamt 	if (p->Package.Count == 0) {
    226  1.9.2.3  yamt 		rv = AE_LIMIT;
    227  1.9.2.3  yamt 		goto out;
    228  1.9.2.3  yamt 	}
    229  1.9.2.2  yamt 
    230  1.9.2.3  yamt 	e = p->Package.Elements;
    231  1.9.2.3  yamt 
    232  1.9.2.3  yamt 	if (e[0].Type != ACPI_TYPE_INTEGER) {
    233  1.9.2.3  yamt 		rv = AE_TYPE;
    234  1.9.2.3  yamt 		goto out;
    235  1.9.2.3  yamt 	}
    236  1.9.2.3  yamt 
    237  1.9.2.3  yamt 	/* Verify CMI version. */
    238  1.9.2.3  yamt 	if (e[0].Integer.Value != 0x10) {
    239  1.9.2.3  yamt 		rv = AE_SUPPORT;
    240  1.9.2.3  yamt 		goto out;
    241  1.9.2.3  yamt 	}
    242  1.9.2.3  yamt 
    243  1.9.2.3  yamt 	if (alert != NULL) {
    244  1.9.2.3  yamt 
    245  1.9.2.3  yamt 		if (p->Package.Count < 2)
    246  1.9.2.3  yamt 			goto out;
    247  1.9.2.3  yamt 
    248  1.9.2.3  yamt 		if (e[1].Type != ACPI_TYPE_BUFFER)
    249  1.9.2.3  yamt 			goto out;
    250  1.9.2.3  yamt 
    251  1.9.2.3  yamt 		info = (struct SMB_INFO *)(e[1].Buffer.Pointer);
    252  1.9.2.3  yamt 		*alert = info->poll_int;
    253  1.9.2.3  yamt 	}
    254  1.9.2.3  yamt 
    255  1.9.2.3  yamt out:
    256  1.9.2.3  yamt 	if (smi_buf.Pointer != NULL)
    257  1.9.2.3  yamt 		ACPI_FREE(smi_buf.Pointer);
    258  1.9.2.3  yamt 
    259  1.9.2.3  yamt 	return (ACPI_FAILURE(rv)) ? 0 : 1;
    260  1.9.2.2  yamt }
    261  1.9.2.2  yamt 
    262  1.9.2.2  yamt static int
    263  1.9.2.2  yamt acpi_smbus_acquire_bus(void *cookie, int flags)
    264  1.9.2.2  yamt {
    265  1.9.2.2  yamt         struct acpi_smbus_softc *sc = cookie;
    266  1.9.2.2  yamt 
    267  1.9.2.2  yamt         mutex_enter(&sc->sc_i2c_mutex);
    268  1.9.2.3  yamt 
    269  1.9.2.2  yamt         return 0;
    270  1.9.2.2  yamt }
    271  1.9.2.2  yamt 
    272  1.9.2.2  yamt static void
    273  1.9.2.2  yamt acpi_smbus_release_bus(void *cookie, int flags)
    274  1.9.2.2  yamt {
    275  1.9.2.2  yamt         struct acpi_smbus_softc *sc = cookie;
    276  1.9.2.2  yamt 
    277  1.9.2.2  yamt         mutex_exit(&sc->sc_i2c_mutex);
    278  1.9.2.2  yamt }
    279  1.9.2.2  yamt static int
    280  1.9.2.2  yamt acpi_smbus_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
    281  1.9.2.2  yamt 	const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
    282  1.9.2.2  yamt {
    283  1.9.2.2  yamt         struct acpi_smbus_softc *sc = cookie;
    284  1.9.2.2  yamt 	const uint8_t *c = cmdbuf;
    285  1.9.2.2  yamt 	uint8_t *b = buf, *xb;
    286  1.9.2.3  yamt 	const char *path;
    287  1.9.2.2  yamt 	ACPI_OBJECT_LIST args;
    288  1.9.2.2  yamt 	ACPI_OBJECT arg[5];
    289  1.9.2.2  yamt 	ACPI_OBJECT *p, *e;
    290  1.9.2.3  yamt 	ACPI_BUFFER smbuf;
    291  1.9.2.3  yamt 	ACPI_STATUS rv;
    292  1.9.2.3  yamt 	int i, r, xlen;
    293  1.9.2.3  yamt 
    294  1.9.2.3  yamt 	/*
    295  1.9.2.3  yamt 	 *	arg[0] : protocol
    296  1.9.2.3  yamt 	 *	arg[1] : slave address
    297  1.9.2.3  yamt 	 *	arg[2] : command
    298  1.9.2.3  yamt 	 *	arg[3] : data length
    299  1.9.2.3  yamt 	 *	arg[4] : data
    300  1.9.2.3  yamt 	 */
    301  1.9.2.3  yamt 	for (i = r = 0; i < __arraycount(arg); i++)
    302  1.9.2.3  yamt 		arg[i].Type = ACPI_TYPE_INTEGER;
    303  1.9.2.3  yamt 
    304  1.9.2.3  yamt 	args.Pointer = arg;
    305  1.9.2.2  yamt 
    306  1.9.2.2  yamt 	smbuf.Pointer = NULL;
    307  1.9.2.2  yamt 	smbuf.Length = ACPI_ALLOCATE_LOCAL_BUFFER;
    308  1.9.2.3  yamt 
    309  1.9.2.2  yamt 	arg[1].Integer.Value = addr;
    310  1.9.2.3  yamt 
    311  1.9.2.2  yamt 	if (I2C_OP_READ_P(op)) {
    312  1.9.2.3  yamt 
    313  1.9.2.3  yamt 		path = "_SBR";
    314  1.9.2.2  yamt 		args.Count = 3;
    315  1.9.2.3  yamt 
    316  1.9.2.3  yamt 		switch (len) {
    317  1.9.2.3  yamt 
    318  1.9.2.3  yamt 		case 0:
    319  1.9.2.3  yamt 			arg[0].Integer.Value = (cmdlen != 0) ?
    320  1.9.2.3  yamt 			    ACPI_SMBUS_RCV_BYTE : ACPI_SMBUS_RD_QUICK;
    321  1.9.2.3  yamt 
    322  1.9.2.2  yamt 			arg[2].Integer.Value = 0;
    323  1.9.2.3  yamt 			break;
    324  1.9.2.3  yamt 
    325  1.9.2.3  yamt 		case 1:
    326  1.9.2.2  yamt 			arg[0].Integer.Value = ACPI_SMBUS_RD_BYTE;
    327  1.9.2.3  yamt 			arg[2].Integer.Value = *c;
    328  1.9.2.3  yamt 			break;
    329  1.9.2.3  yamt 
    330  1.9.2.3  yamt 		case 2:
    331  1.9.2.2  yamt 			arg[0].Integer.Value = ACPI_SMBUS_RD_WORD;
    332  1.9.2.3  yamt 			arg[2].Integer.Value = *c;
    333  1.9.2.3  yamt 			break;
    334  1.9.2.3  yamt 
    335  1.9.2.3  yamt 		default:
    336  1.9.2.2  yamt 			arg[0].Integer.Value = ACPI_SMBUS_RD_BLOCK;
    337  1.9.2.3  yamt 			arg[2].Integer.Value = *c;
    338  1.9.2.3  yamt 			break;
    339  1.9.2.3  yamt 		}
    340  1.9.2.3  yamt 
    341  1.9.2.2  yamt 	} else {
    342  1.9.2.3  yamt 
    343  1.9.2.3  yamt 		path = "_SBW";
    344  1.9.2.2  yamt 		args.Count = 5;
    345  1.9.2.3  yamt 
    346  1.9.2.2  yamt 		arg[3].Integer.Value = len;
    347  1.9.2.3  yamt 
    348  1.9.2.3  yamt 		switch (len) {
    349  1.9.2.3  yamt 
    350  1.9.2.3  yamt 		case 0:
    351  1.9.2.2  yamt 			if (cmdlen == 0) {
    352  1.9.2.2  yamt 				arg[2].Integer.Value = 0;
    353  1.9.2.2  yamt 				arg[0].Integer.Value = ACPI_SMBUS_WR_QUICK;
    354  1.9.2.2  yamt 			} else {
    355  1.9.2.2  yamt 				arg[2].Integer.Value = *c;
    356  1.9.2.2  yamt 				arg[0].Integer.Value = ACPI_SMBUS_SND_BYTE;
    357  1.9.2.2  yamt 			}
    358  1.9.2.3  yamt 
    359  1.9.2.3  yamt 			arg[4].Integer.Value = 0;
    360  1.9.2.3  yamt 			break;
    361  1.9.2.3  yamt 
    362  1.9.2.3  yamt 		case 1:
    363  1.9.2.2  yamt 			arg[0].Integer.Value = ACPI_SMBUS_WR_BYTE;
    364  1.9.2.3  yamt 			arg[2].Integer.Value = *c;
    365  1.9.2.2  yamt 			arg[4].Integer.Value = *b;
    366  1.9.2.3  yamt 			break;
    367  1.9.2.3  yamt 
    368  1.9.2.3  yamt 		case 2:
    369  1.9.2.2  yamt 			arg[0].Integer.Value = ACPI_SMBUS_WR_WORD;
    370  1.9.2.3  yamt 			arg[2].Integer.Value = *c;
    371  1.9.2.2  yamt 			arg[4].Integer.Value = *b++;
    372  1.9.2.2  yamt 			arg[4].Integer.Value += (*b--) << 8;
    373  1.9.2.3  yamt 			break;
    374  1.9.2.3  yamt 
    375  1.9.2.3  yamt 		default:
    376  1.9.2.2  yamt 			arg[0].Integer.Value = ACPI_SMBUS_WR_BLOCK;
    377  1.9.2.3  yamt 			arg[2].Integer.Value = *c;
    378  1.9.2.2  yamt 			arg[4].Type = ACPI_TYPE_BUFFER;
    379  1.9.2.2  yamt 			arg[4].Buffer.Pointer = buf;
    380  1.9.2.3  yamt 			arg[4].Buffer.Length = (len < 32) ? len : 32;
    381  1.9.2.3  yamt 			break;
    382  1.9.2.2  yamt 		}
    383  1.9.2.2  yamt 	}
    384  1.9.2.3  yamt 
    385  1.9.2.3  yamt 	rv = AcpiEvaluateObject(sc->sc_devnode->ad_handle, path, &args,&smbuf);
    386  1.9.2.3  yamt 
    387  1.9.2.2  yamt 	if (ACPI_FAILURE(rv))
    388  1.9.2.3  yamt 		goto out;
    389  1.9.2.3  yamt 
    390  1.9.2.3  yamt 	p = smbuf.Pointer;
    391  1.9.2.3  yamt 
    392  1.9.2.3  yamt 	if (p->Type != ACPI_TYPE_PACKAGE) {
    393  1.9.2.3  yamt 		rv = AE_TYPE;
    394  1.9.2.3  yamt 		goto out;
    395  1.9.2.3  yamt 	}
    396  1.9.2.3  yamt 
    397  1.9.2.3  yamt 	if (p->Package.Count < 1) {
    398  1.9.2.3  yamt 		rv = AE_LIMIT;
    399  1.9.2.3  yamt 		goto out;
    400  1.9.2.3  yamt 	}
    401  1.9.2.3  yamt 
    402  1.9.2.3  yamt 	e = p->Package.Elements;
    403  1.9.2.3  yamt 
    404  1.9.2.3  yamt 	if (e->Type != ACPI_TYPE_INTEGER) {
    405  1.9.2.3  yamt 		rv = AE_TYPE;
    406  1.9.2.3  yamt 		goto out;
    407  1.9.2.3  yamt 	}
    408  1.9.2.3  yamt 
    409  1.9.2.3  yamt 	ACPI_DEBUG_PRINT((ACPI_DB_DEBUG_OBJECT,
    410  1.9.2.3  yamt 		"return status: %"PRIu64"\n", e[0].Integer.Value));
    411  1.9.2.3  yamt 
    412  1.9.2.3  yamt 	if (e[0].Integer.Value != 0) {
    413  1.9.2.3  yamt 		rv = AE_BAD_VALUE;
    414  1.9.2.3  yamt 		goto out;
    415  1.9.2.3  yamt 	}
    416  1.9.2.3  yamt 
    417  1.9.2.3  yamt 	/*
    418  1.9.2.3  yamt 	 * For read operations, copy data to user buffer.
    419  1.9.2.3  yamt 	 */
    420  1.9.2.3  yamt 	if (I2C_OP_READ_P(op)) {
    421  1.9.2.3  yamt 
    422  1.9.2.3  yamt 		if (p->Package.Count < 3) {
    423  1.9.2.3  yamt 			rv = AE_LIMIT;
    424  1.9.2.3  yamt 			goto out;
    425  1.9.2.2  yamt 		}
    426  1.9.2.2  yamt 
    427  1.9.2.3  yamt 		if (e[1].Type != ACPI_TYPE_INTEGER) {
    428  1.9.2.3  yamt 			rv = AE_TYPE;
    429  1.9.2.3  yamt 			goto out;
    430  1.9.2.3  yamt 		}
    431  1.9.2.3  yamt 
    432  1.9.2.3  yamt 		xlen = e[1].Integer.Value;
    433  1.9.2.3  yamt 
    434  1.9.2.3  yamt 		if (xlen > len)
    435  1.9.2.3  yamt 			xlen = len;
    436  1.9.2.3  yamt 
    437  1.9.2.3  yamt 		switch (e[2].Type) {
    438  1.9.2.3  yamt 
    439  1.9.2.3  yamt 		case ACPI_TYPE_BUFFER:
    440  1.9.2.3  yamt 
    441  1.9.2.3  yamt 			if (xlen == 0) {
    442  1.9.2.3  yamt 				rv = AE_LIMIT;
    443  1.9.2.3  yamt 				goto out;
    444  1.9.2.3  yamt 			}
    445  1.9.2.3  yamt 
    446  1.9.2.3  yamt 			xb = e[2].Buffer.Pointer;
    447  1.9.2.3  yamt 
    448  1.9.2.3  yamt 			if (xb == NULL) {
    449  1.9.2.3  yamt 				rv = AE_NULL_OBJECT;
    450  1.9.2.3  yamt 				goto out;
    451  1.9.2.3  yamt 			}
    452  1.9.2.3  yamt 
    453  1.9.2.3  yamt 			(void)memcpy(b, xb, xlen);
    454  1.9.2.3  yamt 			break;
    455  1.9.2.3  yamt 
    456  1.9.2.3  yamt 		case ACPI_TYPE_INTEGER:
    457  1.9.2.3  yamt 
    458  1.9.2.3  yamt 			if (xlen > 0)
    459  1.9.2.3  yamt 				*b++ = e[2].Integer.Value & 0xff;
    460  1.9.2.3  yamt 
    461  1.9.2.3  yamt 			if (xlen > 1)
    462  1.9.2.3  yamt 				*b = e[2].Integer.Value >> 8;
    463  1.9.2.3  yamt 
    464  1.9.2.3  yamt 			break;
    465  1.9.2.3  yamt 
    466  1.9.2.3  yamt 		default:
    467  1.9.2.3  yamt 			rv = AE_TYPE;
    468  1.9.2.3  yamt 			goto out;
    469  1.9.2.2  yamt 		}
    470  1.9.2.2  yamt 	}
    471  1.9.2.3  yamt 
    472  1.9.2.3  yamt out:
    473  1.9.2.3  yamt 	if (smbuf.Pointer != NULL)
    474  1.9.2.2  yamt 		ACPI_FREE(smbuf.Pointer);
    475  1.9.2.2  yamt 
    476  1.9.2.3  yamt 	if (ACPI_SUCCESS(rv))
    477  1.9.2.3  yamt 		return 0;
    478  1.9.2.3  yamt 
    479  1.9.2.3  yamt 	ACPI_DEBUG_PRINT((ACPI_DB_DEBUG_OBJECT, "failed to "
    480  1.9.2.3  yamt 		"evaluate %s: %s\n", path, AcpiFormatException(rv)));
    481  1.9.2.3  yamt 
    482  1.9.2.3  yamt 	return 1;
    483  1.9.2.2  yamt }
    484  1.9.2.2  yamt 
    485  1.9.2.2  yamt /*
    486  1.9.2.3  yamt  * Whether triggered by periodic polling or a Notify(),
    487  1.9.2.3  yamt  * retrieve all pending SMBus device alerts.
    488  1.9.2.2  yamt  */
    489  1.9.2.2  yamt static void
    490  1.9.2.2  yamt acpi_smbus_alerts(struct acpi_smbus_softc *sc)
    491  1.9.2.2  yamt {
    492  1.9.2.3  yamt 	const ACPI_HANDLE hdl = sc->sc_devnode->ad_handle;
    493  1.9.2.2  yamt 	ACPI_OBJECT *e, *p;
    494  1.9.2.3  yamt 	ACPI_BUFFER alert;
    495  1.9.2.3  yamt 	ACPI_STATUS rv;
    496  1.9.2.3  yamt 	int status = 0;
    497  1.9.2.3  yamt 	uint8_t addr;
    498  1.9.2.2  yamt 
    499  1.9.2.2  yamt 	do {
    500  1.9.2.3  yamt 		rv = acpi_eval_struct(hdl, "_SBA", &alert);
    501  1.9.2.3  yamt 
    502  1.9.2.2  yamt 		if (ACPI_FAILURE(rv)) {
    503  1.9.2.2  yamt 			status = 1;
    504  1.9.2.2  yamt 			goto done;
    505  1.9.2.2  yamt 		}
    506  1.9.2.2  yamt 
    507  1.9.2.2  yamt 		p = alert.Pointer;
    508  1.9.2.3  yamt 
    509  1.9.2.3  yamt 		if (p->Type == ACPI_TYPE_PACKAGE && p->Package.Count >= 2) {
    510  1.9.2.3  yamt 
    511  1.9.2.3  yamt 			status = 1;
    512  1.9.2.3  yamt 
    513  1.9.2.2  yamt 			e = p->Package.Elements;
    514  1.9.2.3  yamt 
    515  1.9.2.2  yamt 			if (e[0].Type == ACPI_TYPE_INTEGER)
    516  1.9.2.2  yamt 				status = e[0].Integer.Value;
    517  1.9.2.3  yamt 
    518  1.9.2.3  yamt 			if (status == 0 && e[1].Type == ACPI_TYPE_INTEGER) {
    519  1.9.2.3  yamt 				addr = e[1].Integer.Value;
    520  1.9.2.3  yamt 
    521  1.9.2.3  yamt 				aprint_debug_dev(sc->sc_dv,
    522  1.9.2.3  yamt 				    "alert for 0x%x\n", addr);
    523  1.9.2.3  yamt 
    524  1.9.2.2  yamt 				(void)iic_smbus_intr(&sc->sc_i2c_tag);
    525  1.9.2.2  yamt 			}
    526  1.9.2.2  yamt 		}
    527  1.9.2.2  yamt done:
    528  1.9.2.2  yamt 		if (alert.Pointer != NULL)
    529  1.9.2.2  yamt 			ACPI_FREE(alert.Pointer);
    530  1.9.2.3  yamt 
    531  1.9.2.2  yamt 	} while (status == 0);
    532  1.9.2.2  yamt }
    533  1.9.2.2  yamt 
    534  1.9.2.2  yamt static void
    535  1.9.2.2  yamt acpi_smbus_tick(void *opaque)
    536  1.9.2.2  yamt {
    537  1.9.2.2  yamt 	device_t dv = opaque;
    538  1.9.2.2  yamt 	struct acpi_smbus_softc *sc = device_private(dv);
    539  1.9.2.2  yamt 
    540  1.9.2.2  yamt 	acpi_smbus_alerts(sc);
    541  1.9.2.2  yamt 
    542  1.9.2.2  yamt 	callout_schedule(&sc->sc_callout, sc->sc_poll_alert * hz);
    543  1.9.2.2  yamt }
    544  1.9.2.2  yamt 
    545  1.9.2.2  yamt static void
    546  1.9.2.2  yamt acpi_smbus_notify_handler(ACPI_HANDLE hdl, uint32_t notify, void *opaque)
    547  1.9.2.2  yamt {
    548  1.9.2.2  yamt 	device_t dv = opaque;
    549  1.9.2.2  yamt 	struct acpi_smbus_softc *sc = device_private(dv);
    550  1.9.2.2  yamt 
    551  1.9.2.2  yamt 	aprint_debug_dev(dv, "received notify message 0x%x\n", notify);
    552  1.9.2.3  yamt 
    553  1.9.2.2  yamt 	acpi_smbus_alerts(sc);
    554  1.9.2.2  yamt }
    555