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);
}