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