Module Name: src Committed By: jruoho Date: Thu Jul 29 11:03:09 UTC 2010
Modified Files: src/sys/dev/acpi: smbus_acpi.c Log Message: Refactor to make this more readable. No functional change. To generate a diff of this commit: cvs rdiff -u -r1.12 -r1.13 src/sys/dev/acpi/smbus_acpi.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/acpi/smbus_acpi.c diff -u src/sys/dev/acpi/smbus_acpi.c:1.12 src/sys/dev/acpi/smbus_acpi.c:1.13 --- src/sys/dev/acpi/smbus_acpi.c:1.12 Wed Jul 28 16:29:11 2010 +++ src/sys/dev/acpi/smbus_acpi.c Thu Jul 29 11:03:09 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: smbus_acpi.c,v 1.12 2010/07/28 16:29:11 jruoho Exp $ */ +/* $NetBSD: smbus_acpi.c,v 1.13 2010/07/29 11:03:09 jruoho Exp $ */ /*- * Copyright (c) 2009 The NetBSD Foundation, Inc. @@ -36,7 +36,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: smbus_acpi.c,v 1.12 2010/07/28 16:29:11 jruoho Exp $"); +__KERNEL_RCSID(0, "$NetBSD: smbus_acpi.c,v 1.13 2010/07/29 11:03:09 jruoho Exp $"); #include <sys/param.h> #include <sys/device.h> @@ -54,7 +54,7 @@ ACPI_MODULE_NAME ("smbus_acpi") /* - * ACPI SMBus CMI protocol codes + * ACPI SMBus CMI protocol codes. */ #define ACPI_SMBUS_RD_QUICK 0x03 #define ACPI_SMBUS_RCV_BYTE 0x05 @@ -80,6 +80,7 @@ static int acpi_smbus_match(device_t, cfdata_t, void *); static void acpi_smbus_attach(device_t, device_t, void *); static int acpi_smbus_detach(device_t, int); +static int acpi_smbus_poll_alert(ACPI_HANDLE, int *); static int acpi_smbus_acquire_bus(void *, int); static void acpi_smbus_release_bus(void *, int); static int acpi_smbus_exec(void *, i2c_op_t, i2c_addr_t, const void *, @@ -122,17 +123,10 @@ CFATTACH_DECL_NEW(acpismbus, sizeof(struct acpi_smbus_softc), acpi_smbus_match, acpi_smbus_attach, acpi_smbus_detach, NULL); -/* - * acpi_smbus_match: autoconf(9) match routine - */ static int acpi_smbus_match(device_t parent, cfdata_t match, void *aux) { struct acpi_attach_args *aa = aux; - int r = 0; - ACPI_STATUS rv; - ACPI_BUFFER smi_buf; - ACPI_OBJECT *e, *p; if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) return 0; @@ -140,39 +134,15 @@ if (acpi_match_hid(aa->aa_node->ad_devinfo, smbus_acpi_ids) == 0) return 0; - /* Ensure that device's CMI version is supported */ - rv = acpi_eval_struct(aa->aa_node->ad_handle, "_SBI", &smi_buf); - if (ACPI_FAILURE(rv)) - goto done; - - p = smi_buf.Pointer; - if (p != NULL && p->Type == ACPI_TYPE_PACKAGE && - p->Package.Count >= 1) { - e = p->Package.Elements; - if (e[0].Type == ACPI_TYPE_INTEGER && - e[0].Integer.Value == 0x10) - r = 1; - } -done: - if (smi_buf.Pointer != NULL) - ACPI_FREE(smi_buf.Pointer); - - return r; + return acpi_smbus_poll_alert(aa->aa_node->ad_handle, NULL); } -/* - * acpitz_attach: autoconf(9) attach routine - */ static void acpi_smbus_attach(device_t parent, device_t self, void *aux) { struct acpi_smbus_softc *sc = device_private(self); struct acpi_attach_args *aa = aux; struct i2cbus_attach_args iba; - ACPI_STATUS rv; - ACPI_BUFFER smi_buf; - ACPI_OBJECT *e, *p; - struct SMB_INFO *info; aprint_naive("\n"); @@ -180,28 +150,15 @@ sc->sc_dv = self; sc->sc_poll_alert = 2; - /* Attach I2C bus */ + /* Attach I2C bus. */ mutex_init(&sc->sc_i2c_mutex, MUTEX_DEFAULT, IPL_NONE); + sc->sc_i2c_tag.ic_cookie = sc; sc->sc_i2c_tag.ic_acquire_bus = acpi_smbus_acquire_bus; sc->sc_i2c_tag.ic_release_bus = acpi_smbus_release_bus; sc->sc_i2c_tag.ic_exec = acpi_smbus_exec; - /* Retrieve polling interval for SMBus Alerts */ - rv = acpi_eval_struct(aa->aa_node->ad_handle, "_SBI", &smi_buf); - if (ACPI_SUCCESS(rv)) { - p = smi_buf.Pointer; - if (p != NULL && p->Type == ACPI_TYPE_PACKAGE && - p->Package.Count >= 2) { - e = p->Package.Elements; - if (e[1].Type == ACPI_TYPE_BUFFER) { - info = (struct SMB_INFO *)(e[1].Buffer.Pointer); - sc->sc_poll_alert = info->poll_int; - } - } - } - if (smi_buf.Pointer != NULL) - ACPI_FREE(smi_buf.Pointer); + (void)acpi_smbus_poll_alert(aa->aa_node->ad_handle,&sc->sc_poll_alert); /* If failed, fall-back to polling. */ if (acpi_register_notify(sc->sc_devnode, @@ -211,18 +168,19 @@ callout_init(&sc->sc_callout, 0); callout_setfunc(&sc->sc_callout, acpi_smbus_tick, self); - if (!pmf_device_register(self, NULL, NULL)) - aprint_error(": couldn't establish power handler\n"); - if (sc->sc_poll_alert != 0) { - aprint_debug(" alert_poll %d sec", sc->sc_poll_alert); + aprint_debug(": alert_poll %d sec", sc->sc_poll_alert); callout_schedule(&sc->sc_callout, sc->sc_poll_alert * hz); } + aprint_normal("\n"); - memset(&iba, 0, sizeof(iba)); + (void)memset(&iba, 0, sizeof(iba)); + (void)pmf_device_register(self, NULL, NULL); + iba.iba_tag = &sc->sc_i2c_tag; - config_found_ia(self, "i2cbus", &iba, iicbus_print); + + (void)config_found_ia(self, "i2cbus", &iba, iicbus_print); } static int @@ -242,11 +200,72 @@ } static int +acpi_smbus_poll_alert(ACPI_HANDLE hdl, int *alert) +{ + struct SMB_INFO *info; + ACPI_BUFFER smi_buf; + ACPI_OBJECT *e, *p; + ACPI_STATUS rv; + + /* + * Retrieve polling interval for SMBus Alerts. + */ + rv = acpi_eval_struct(hdl, "_SBI", &smi_buf); + + if (ACPI_FAILURE(rv)) + return 0; + + p = smi_buf.Pointer; + + if (p->Type != ACPI_TYPE_PACKAGE) { + rv = AE_TYPE; + goto out; + } + + if (p->Package.Count == 0) { + rv = AE_LIMIT; + goto out; + } + + e = p->Package.Elements; + + if (e[0].Type != ACPI_TYPE_INTEGER) { + rv = AE_TYPE; + goto out; + } + + /* Verify CMI version. */ + if (e[0].Integer.Value != 0x10) { + rv = AE_SUPPORT; + goto out; + } + + if (alert != NULL) { + + if (p->Package.Count < 2) + goto out; + + if (e[1].Type != ACPI_TYPE_BUFFER) + goto out; + + info = (struct SMB_INFO *)(e[1].Buffer.Pointer); + *alert = info->poll_int; + } + +out: + if (smi_buf.Pointer != NULL) + ACPI_FREE(smi_buf.Pointer); + + return (ACPI_FAILURE(rv)) ? 0 : 1; +} + +static int acpi_smbus_acquire_bus(void *cookie, int flags) { struct acpi_smbus_softc *sc = cookie; mutex_enter(&sc->sc_i2c_mutex); + return 0; } @@ -264,46 +283,71 @@ struct acpi_smbus_softc *sc = cookie; const uint8_t *c = cmdbuf; uint8_t *b = buf, *xb; - int xlen; - int r = 0; - ACPI_BUFFER smbuf; - ACPI_STATUS rv; + const char *path; ACPI_OBJECT_LIST args; ACPI_OBJECT arg[5]; ACPI_OBJECT *p, *e; + ACPI_BUFFER smbuf; + ACPI_STATUS rv; + int i, r, xlen; + + /* + * arg[0] : protocol + * arg[1] : slave address + * arg[2] : command + * arg[3] : data length + * arg[4] : data + */ + for (i = r = 0; i < __arraycount(arg); i++) + arg[i].Type = ACPI_TYPE_INTEGER; + + args.Pointer = arg; smbuf.Pointer = NULL; smbuf.Length = ACPI_ALLOCATE_LOCAL_BUFFER; - args.Pointer = arg; - arg[0].Type = ACPI_TYPE_INTEGER; /* Protocol */ - arg[1].Type = ACPI_TYPE_INTEGER; /* Slave Addr */ + arg[1].Integer.Value = addr; - arg[2].Type = ACPI_TYPE_INTEGER; /* Command */ + if (I2C_OP_READ_P(op)) { + + path = "_SBR"; args.Count = 3; - if (len == 0) { + + switch (len) { + + case 0: + arg[0].Integer.Value = (cmdlen != 0) ? + ACPI_SMBUS_RCV_BYTE : ACPI_SMBUS_RD_QUICK; + arg[2].Integer.Value = 0; - if (cmdlen == 0) - arg[0].Integer.Value = ACPI_SMBUS_RD_QUICK; - else - arg[0].Integer.Value = ACPI_SMBUS_RCV_BYTE; - } else - arg[2].Integer.Value = *c; - if (len == 1) + break; + + case 1: arg[0].Integer.Value = ACPI_SMBUS_RD_BYTE; - else if (len == 2) + arg[2].Integer.Value = *c; + break; + + case 2: arg[0].Integer.Value = ACPI_SMBUS_RD_WORD; - else if (len > 2) + arg[2].Integer.Value = *c; + break; + + default: arg[0].Integer.Value = ACPI_SMBUS_RD_BLOCK; - rv = AcpiEvaluateObject(sc->sc_devnode->ad_handle, "_SBR", - &args, &smbuf); + arg[2].Integer.Value = *c; + break; + } + } else { + + path = "_SBW"; args.Count = 5; - arg[3].Type = ACPI_TYPE_INTEGER; /* Data Len */ + arg[3].Integer.Value = len; - arg[4].Type = ACPI_TYPE_INTEGER; /* Data */ - if (len == 0) { - arg[4].Integer.Value = 0; + + switch (len) { + + case 0: if (cmdlen == 0) { arg[2].Integer.Value = 0; arg[0].Integer.Value = ACPI_SMBUS_WR_QUICK; @@ -311,114 +355,179 @@ arg[2].Integer.Value = *c; arg[0].Integer.Value = ACPI_SMBUS_SND_BYTE; } - } else - arg[2].Integer.Value = *c; - if (len == 1) { + + arg[4].Integer.Value = 0; + break; + + case 1: arg[0].Integer.Value = ACPI_SMBUS_WR_BYTE; + arg[2].Integer.Value = *c; arg[4].Integer.Value = *b; - } else if (len == 2) { + break; + + case 2: arg[0].Integer.Value = ACPI_SMBUS_WR_WORD; + arg[2].Integer.Value = *c; arg[4].Integer.Value = *b++; arg[4].Integer.Value += (*b--) << 8; - } else if (len > 2) { + break; + + default: arg[0].Integer.Value = ACPI_SMBUS_WR_BLOCK; + arg[2].Integer.Value = *c; arg[4].Type = ACPI_TYPE_BUFFER; arg[4].Buffer.Pointer = buf; - arg[4].Buffer.Length = (len < 32?len:32); + arg[4].Buffer.Length = (len < 32) ? len : 32; + break; } - rv = AcpiEvaluateObject(sc->sc_devnode->ad_handle, "_SBW", - &args, &smbuf); } + + rv = AcpiEvaluateObject(sc->sc_devnode->ad_handle, path, &args,&smbuf); + if (ACPI_FAILURE(rv)) - r = 1; - else { - p = smbuf.Pointer; - if (p == NULL || p->Type != ACPI_TYPE_PACKAGE || - p->Package.Count < 1) - r = 1; - else { - e = p->Package.Elements; - if (e->Type == ACPI_TYPE_INTEGER) - r = e[0].Integer.Value; - else - r = 1; + goto out; + + p = smbuf.Pointer; + + if (p->Type != ACPI_TYPE_PACKAGE) { + rv = AE_TYPE; + goto out; + } + + if (p->Package.Count < 1) { + rv = AE_LIMIT; + goto out; + } + + e = p->Package.Elements; + + if (e->Type != ACPI_TYPE_INTEGER) { + rv = AE_TYPE; + goto out; + } + + ACPI_DEBUG_PRINT((ACPI_DB_DEBUG_OBJECT, + "return status: %"PRIu64"\n", e[0].Integer.Value)); + + if (e[0].Integer.Value != 0) { + rv = AE_BAD_VALUE; + goto out; + } + + /* + * For read operations, copy data to user buffer. + */ + if (I2C_OP_READ_P(op)) { + + if (p->Package.Count < 3) { + rv = AE_LIMIT; + goto out; } - if (r != 0) - r = 1; - /* For read operations, copy data to user buffer */ - if (r == 0 && I2C_OP_READ_P(op)) { - if (p->Package.Count >= 3 && - e[1].Type == ACPI_TYPE_INTEGER) { - xlen = e[1].Integer.Value; - if (xlen > len) - xlen = len; - if (xlen != 0 && - e[2].Type == ACPI_TYPE_BUFFER) { - xb = e[2].Buffer.Pointer; - if (xb != NULL) - memcpy(b, xb, xlen); - else - r = 1; - } else if (e[2].Type == ACPI_TYPE_INTEGER) { - if (xlen > 0) - *b++ = e[2].Integer.Value & - 0xff; - if (xlen > 1) - *b = (e[2].Integer.Value >> 8); - } else - r = 1; - } else - r = 1; + if (e[1].Type != ACPI_TYPE_INTEGER) { + rv = AE_TYPE; + goto out; + } + + xlen = e[1].Integer.Value; + + if (xlen > len) + xlen = len; + + switch (e[2].Type) { + + case ACPI_TYPE_BUFFER: + + if (xlen == 0) { + rv = AE_LIMIT; + goto out; + } + + xb = e[2].Buffer.Pointer; + + if (xb == NULL) { + rv = AE_NULL_OBJECT; + goto out; + } + + (void)memcpy(b, xb, xlen); + break; + + case ACPI_TYPE_INTEGER: + + if (xlen > 0) + *b++ = e[2].Integer.Value & 0xff; + + if (xlen > 1) + *b = e[2].Integer.Value >> 8; + + break; + + default: + rv = AE_TYPE; + goto out; } } - if (smbuf.Pointer) + +out: + if (smbuf.Pointer != NULL) ACPI_FREE(smbuf.Pointer); - return r; + if (ACPI_SUCCESS(rv)) + return 0; + + ACPI_DEBUG_PRINT((ACPI_DB_DEBUG_OBJECT, "failed to " + "evaluate %s: %s\n", path, AcpiFormatException(rv))); + + return 1; } /* - * acpi_smbus_alerts - * - * Whether triggered by periodic polling or an AcpiNotify, retrieve - * all pending SMBus device alerts + * Whether triggered by periodic polling or a Notify(), + * retrieve all pending SMBus device alerts. */ static void acpi_smbus_alerts(struct acpi_smbus_softc *sc) { - int status = 0; - uint8_t slave_addr; - ACPI_STATUS rv; - ACPI_BUFFER alert; + const ACPI_HANDLE hdl = sc->sc_devnode->ad_handle; ACPI_OBJECT *e, *p; + ACPI_BUFFER alert; + ACPI_STATUS rv; + int status = 0; + uint8_t addr; do { - rv = acpi_eval_struct(sc->sc_devnode->ad_handle, "_SBA", - &alert); + rv = acpi_eval_struct(hdl, "_SBA", &alert); + if (ACPI_FAILURE(rv)) { status = 1; goto done; } p = alert.Pointer; - if (p != NULL && p->Type == ACPI_TYPE_PACKAGE && - p->Package.Count >= 2) { + + if (p->Type == ACPI_TYPE_PACKAGE && p->Package.Count >= 2) { + + status = 1; + e = p->Package.Elements; + if (e[0].Type == ACPI_TYPE_INTEGER) status = e[0].Integer.Value; - else - status = 1; - if (status == 0x0 && e[1].Type == ACPI_TYPE_INTEGER) { - slave_addr = e[1].Integer.Value; - aprint_debug_dev(sc->sc_dv, "Alert for 0x%x\n", - slave_addr); + + if (status == 0 && e[1].Type == ACPI_TYPE_INTEGER) { + addr = e[1].Integer.Value; + + aprint_debug_dev(sc->sc_dv, + "alert for 0x%x\n", addr); + (void)iic_smbus_intr(&sc->sc_i2c_tag); } } done: if (alert.Pointer != NULL) ACPI_FREE(alert.Pointer); + } while (status == 0); } @@ -440,5 +549,6 @@ struct acpi_smbus_softc *sc = device_private(dv); aprint_debug_dev(dv, "received notify message 0x%x\n", notify); + acpi_smbus_alerts(sc); }