From nobody Fri Apr 17 02:40:14 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4fxfHl2JfKz6b9Fq for ; Fri, 17 Apr 2026 02:40:19 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R12" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4fxfHl1n0jz3rmX for ; Fri, 17 Apr 2026 02:40:19 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1776393619; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=3AzPzUyTwX0HaHxGKY9l4LtoiUCThIiLJ+AO312TgAc=; b=t3ZePcYxG+E2gSwN4y7ZHYhhb2g5MP06jwACaNiNVqSeLef0gsgZE/FqyheXh8BpTDMMks /hYNHhNKFOOxCOdpICg36CS497lP6ON0PP7JydcZsQcKCZygr6imAJQ6TA3YZaDi/SEKr1 F7plvreuldIiwHtZg8JU0wPiRUyOl2FXFnavfqyMhpWPy6rUxa7qfjd9vlHvJNnuLJrinY 8r/ZUYVhX0g9QM27jsRTIvnJ5wAvFmqbd8AykO4AJurZSspFhgIebsbj4g7Xr0Hp3HFg/K KNZsjwcgd/ITJNy301+87R3itrIqEullfmUHhw/Jft2pNNDGo1ELDFtIGJL5+g== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1776393619; a=rsa-sha256; cv=none; b=l2LpqTXBWtks4TRjy0V0CfV2LF5C8nwD58w51AKAxoLbOpJY2k2Zb61sAbOjTyJ8iPiCbk sMm+VetncS+Cr0htlm2YRdngIwWCyhK8vVndcNA+CSXP/TtLXkz9LE6xmW32aasjrTZlnh HPhuksHBevjk1jbhMga1J6D4peHw5hJxZPe7Zdw68b4rJsoqadNJcfSVsS+nk3rtmk/bBP Uq1xdkQsR996Ad5I7eK0hugLLxFLs2+3qz9ibn1199AuJXrLnaSsvwxGm6cTO8SrP+gGwx AznBgtM9xuPUq72lvmrZ3AP8LZ91xh3rGuVpKWr7FO4+a5TrE32V7nFn9cfM2w== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1776393619; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=3AzPzUyTwX0HaHxGKY9l4LtoiUCThIiLJ+AO312TgAc=; b=JhYZpxz0fSg+tQM0la5eQQtO9MH2m4xjFB6pcz1/jl8yyZF9mif3BYsAO7jYaooBajPE5/ DrOnbqpKk4G+2Znp4K5KgppdQ8/8UNX7Znu4P3xn34w32Ug3JPj3Bk1S5x9R/5N2+f3ddD SPa6dHfnZwXLuZHy/v/yStWMhAP5Lo0gxJHjArboOmIMZ+3E3zO6dAoc5o+bL7RcbdNscE yavKEKsi9Ix9W4OdA8QMsYuO8nF5zMQK1hAuTSJthE6oEm0n5kv9osCNUhMvRzB8dJVyhI lSNAmdcgfJt7uISarEd7PJn3/wmJ9P4/Gcj2ETWY8CJESAd35UuEpXF2sUrlCw== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4fxfHl1FmSzbVS for ; Fri, 17 Apr 2026 02:40:19 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 1fe9f by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Fri, 17 Apr 2026 02:40:14 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Cc: Abdelkader Boudih From: Adrian Chadd Subject: git: aae906840494 - main - asmc: add automatic voltage/current/power/ambient sensor detection List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: adrian X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: aae9068404947dd9ffd8522359d0f9dffaa70414 Auto-Submitted: auto-generated Date: Fri, 17 Apr 2026 02:40:14 +0000 Message-Id: <69e19d8e.1fe9f.68a0f647@gitrepo.freebsd.org> The branch main has been updated by adrian: URL: https://cgit.FreeBSD.org/src/commit/?id=aae9068404947dd9ffd8522359d0f9dffaa70414 commit aae9068404947dd9ffd8522359d0f9dffaa70414 Author: Abdelkader Boudih AuthorDate: 2026-04-17 02:31:21 +0000 Commit: Adrian Chadd CommitDate: 2026-04-17 02:31:37 +0000 asmc: add automatic voltage/current/power/ambient sensor detection Apple SMCs contain numerous undocumented voltage, current, power, and ambient light sensors. This change adds automatic detection and registration of these sensors as sysctls. New sysctl trees: dev.asmc.0.voltage.* - Voltage sensors (millivolts) dev.asmc.0.current.* - Current sensors (milliamps) dev.asmc.0.power.* - Power sensors (milliwatts) dev.asmc.0.ambient.* - Ambient light sensors Implementation: - Scans all SMC keys at attach time via asmc_key_dump_by_index() - Identifies sensors by key prefix patterns: - Voltage: VC*, VD*, VG*, VP*, VI* - Current: I{C,D,G,M,N,O,H,P,B,A,L}* - Power: P{C,D,N,S,T,H,F,Z,z}* - Light: ALV*, ALS* - Dynamically creates sysctls for detected sensors - Supports 8 fixed-point SMC data types: - sp78, sp87, sp4b, sp5a, sp69, sp96, sp2d, ui16 - Auto-converts all values to milli-units (mV, mA, mW) On Mac Mini 5,1, detects: - 7 voltage sensors - 18 current sensors - 27 power sensors - 2 ambient light sensors Enables power consumption monitoring, voltage rail debugging, and ambient light detection without hardcoding model-specific sensor lists. Tested on: - Mac Mini 5,1 (2011) running FreeBSD 15.0-RELEASE - 54 sensors auto-detected and exposed via sysctl - All sensor types verified with multimeter readings - Fixed-point conversions validated against known values - Memory management tested (malloc/free on detach) Reviewed by: adrian Differential Revision: https://reviews.freebsd.org/D55807 --- sys/dev/asmc/asmc.c | 437 ++++++++++++++++++++++++++++++++++++++++++++++++- sys/dev/asmc/asmcvar.h | 10 ++ 2 files changed, 445 insertions(+), 2 deletions(-) diff --git a/sys/dev/asmc/asmc.c b/sys/dev/asmc/asmc.c index 7cd5181605a8..0a701e6fd663 100644 --- a/sys/dev/asmc/asmc.c +++ b/sys/dev/asmc/asmc.c @@ -123,15 +123,22 @@ static int asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS); static int asmc_mbp_sysctl_light_left_10byte(SYSCTL_HANDLER_ARGS); static int asmc_wol_sysctl(SYSCTL_HANDLER_ARGS); +static int asmc_key_getinfo(device_t, const char *, uint8_t *, char *); + #ifdef ASMC_DEBUG /* Raw key access */ -static int asmc_key_getinfo(device_t, const char *, uint8_t *, char *); static int asmc_raw_key_sysctl(SYSCTL_HANDLER_ARGS); static int asmc_raw_value_sysctl(SYSCTL_HANDLER_ARGS); static int asmc_raw_len_sysctl(SYSCTL_HANDLER_ARGS); static int asmc_raw_type_sysctl(SYSCTL_HANDLER_ARGS); #endif +/* Voltage/Current/Power/Light sensor support */ +static int asmc_sensor_read(device_t, const char *, int *); +static int asmc_sensor_sysctl(SYSCTL_HANDLER_ARGS); +static int asmc_detect_sensors(device_t); +static int asmc_key_dump_by_index(device_t, int, char *, char *, uint8_t *); + struct asmc_model { const char *smc_model; /* smbios.system.product env var. */ const char *smc_desc; /* driver description */ @@ -963,6 +970,16 @@ asmc_detach(device_t dev) if (sc->sc_kbd_bkl != NULL) backlight_destroy(sc->sc_kbd_bkl); + /* Free sensor key arrays */ + for (int i = 0; i < sc->sc_voltage_count; i++) + free(sc->sc_voltage_sensors[i], M_DEVBUF); + for (int i = 0; i < sc->sc_current_count; i++) + free(sc->sc_current_sensors[i], M_DEVBUF); + for (int i = 0; i < sc->sc_power_count; i++) + free(sc->sc_power_sensors[i], M_DEVBUF); + for (int i = 0; i < sc->sc_light_count; i++) + free(sc->sc_light_sensors[i], M_DEVBUF); + if (sc->sc_sms_tq) { taskqueue_drain(sc->sc_sms_tq, &sc->sc_sms_task); taskqueue_free(sc->sc_sms_tq); @@ -1134,6 +1151,12 @@ nosms: sc->sc_nkeys = 0; } + /* + * Auto-detect and register voltage/current/power/ambient sensors. + * Scans SMC keys and creates sysctls for detected sensors. + */ + asmc_detect_sensors(dev); + out_err: #ifdef ASMC_DEBUG asmc_dumpall(dev); @@ -1337,10 +1360,10 @@ out: return (0); } +#endif /* ASMC_DEBUG */ /* * Get key info (length and type) from SMC using command 0x13. - * Returns 0 on success, -1 on failure. * If len is non-NULL, stores the key's value length. * If type is non-NULL, stores the 4-char type string (must be at least 5 bytes). */ @@ -1389,6 +1412,7 @@ out: return (error); } +#ifdef ASMC_DEBUG /* * Raw SMC key access sysctls - enables reading/writing any SMC key by name * Usage: @@ -1491,6 +1515,415 @@ asmc_raw_type_sysctl(SYSCTL_HANDLER_ARGS) } #endif +/* + * Convert signed fixed-point SMC values to milli-units. + * Format "spXY" means signed with X integer bits and Y fraction bits. + */ +static int +asmc_sp78_to_milli(const uint8_t *buf) +{ + int16_t val = (int16_t)be16dec(buf); + + return ((int)val * 1000) / 256; +} + +static int +asmc_sp87_to_milli(const uint8_t *buf) +{ + int16_t val = (int16_t)be16dec(buf); + + return ((int)val * 1000) / 128; +} + +static int +asmc_sp4b_to_milli(const uint8_t *buf) +{ + int16_t val = (int16_t)be16dec(buf); + + return ((int)val * 1000) / 2048; +} + +static int +asmc_sp5a_to_milli(const uint8_t *buf) +{ + int16_t val = (int16_t)be16dec(buf); + + return ((int)val * 1000) / 1024; +} + +static int +asmc_sp69_to_milli(const uint8_t *buf) +{ + int16_t val = (int16_t)be16dec(buf); + + return ((int)val * 1000) / 512; +} + +static int +asmc_sp96_to_milli(const uint8_t *buf) +{ + int16_t val = (int16_t)be16dec(buf); + + return ((int)val * 1000) / 64; +} + +static int +asmc_sp2d_to_milli(const uint8_t *buf) +{ + int16_t val = (int16_t)be16dec(buf); + + return ((int)val * 1000) / 8192; +} + +static bool +asmc_sensor_type_supported(const char *type) +{ + + return (strncmp(type, "sp78", 4) == 0 || + strncmp(type, "sp87", 4) == 0 || + strncmp(type, "sp4b", 4) == 0 || + strncmp(type, "sp5a", 4) == 0 || + strncmp(type, "sp69", 4) == 0 || + strncmp(type, "sp96", 4) == 0 || + strncmp(type, "sp2d", 4) == 0 || + strncmp(type, "ui16", 4) == 0); +} + +/* + * Generic sensor value reader with automatic type conversion. + * Reads an SMC key, detects its type, and converts to millivalue. + */ +static int +asmc_sensor_read(device_t dev, const char *key, int *millivalue) +{ + uint8_t buf[2]; + char type[ASMC_TYPELEN + 1]; + uint8_t len; + int error; + + error = asmc_key_getinfo(dev, key, &len, type); + if (error != 0) + return (error); + + if (len != 2) { + if (bootverbose) + device_printf(dev, + "%s: key %s unexpected length %d\n", + __func__, key, len); + return (ENXIO); + } + + error = asmc_key_read(dev, key, buf, sizeof(buf)); + if (error != 0) + return (error); + + if (strncmp(type, "sp78", 4) == 0) { + *millivalue = asmc_sp78_to_milli(buf); + } else if (strncmp(type, "sp87", 4) == 0) { + *millivalue = asmc_sp87_to_milli(buf); + } else if (strncmp(type, "sp4b", 4) == 0) { + *millivalue = asmc_sp4b_to_milli(buf); + } else if (strncmp(type, "sp5a", 4) == 0) { + *millivalue = asmc_sp5a_to_milli(buf); + } else if (strncmp(type, "sp69", 4) == 0) { + *millivalue = asmc_sp69_to_milli(buf); + } else if (strncmp(type, "sp96", 4) == 0) { + *millivalue = asmc_sp96_to_milli(buf); + } else if (strncmp(type, "sp2d", 4) == 0) { + *millivalue = asmc_sp2d_to_milli(buf); + } else if (strncmp(type, "ui16", 4) == 0) { + *millivalue = be16dec(buf); + } else { + if (bootverbose) + device_printf(dev, + "%s: unknown type '%s' for key %s\n", + __func__, type, key); + return (ENXIO); + } + + return (0); +} + +/* + * Generic sensor sysctl handler for voltage/current/power/light sensors. + * arg2 encodes: sensor_type (high byte) | sensor_index (low byte) + * Sensor types: 'V'=voltage, 'I'=current, 'P'=power, 'L'=light + */ +static int +asmc_sensor_sysctl(SYSCTL_HANDLER_ARGS) +{ + device_t dev = (device_t) arg1; + struct asmc_softc *sc = device_get_softc(dev); + int error, val; + int sensor_type = (arg2 >> 8) & 0xFF; + int sensor_idx = arg2 & 0xFF; + const char *key = NULL; + + /* Select sensor based on type and index */ + switch (sensor_type) { + case 'V': /* Voltage */ + if (sensor_idx < sc->sc_voltage_count) + key = sc->sc_voltage_sensors[sensor_idx]; + break; + case 'I': /* Current */ + if (sensor_idx < sc->sc_current_count) + key = sc->sc_current_sensors[sensor_idx]; + break; + case 'P': /* Power */ + if (sensor_idx < sc->sc_power_count) + key = sc->sc_power_sensors[sensor_idx]; + break; + case 'L': /* Light */ + if (sensor_idx < sc->sc_light_count) + key = sc->sc_light_sensors[sensor_idx]; + break; + default: + return (EINVAL); + } + + if (key == NULL) + return (ENOENT); + + error = asmc_sensor_read(dev, key, &val); + if (error != 0) + return (error); + + return (sysctl_handle_int(oidp, &val, 0, req)); +} + +/* + * Detect and register voltage/current/power/ambient sensors. + * Scans all SMC keys and identifies sensor keys by prefix. + * Returns 0 on success, -1 on error. + */ +static int +asmc_detect_sensors(device_t dev) +{ + struct asmc_softc *sc = device_get_softc(dev); + struct sysctl_ctx_list *sysctlctx; + struct sysctl_oid *tree_node; + char key[ASMC_KEYLEN + 1]; + char type[ASMC_TYPELEN + 1]; + uint8_t len; + unsigned int nkeys; + unsigned int i; + int error; + char *sensor_key; + + /* Initialize counts */ + sc->sc_voltage_count = 0; + sc->sc_current_count = 0; + sc->sc_power_count = 0; + sc->sc_light_count = 0; + + if (sc->sc_nkeys == 0) + return (0); + nkeys = sc->sc_nkeys; + + /* Scan all keys for voltage/current/power/ambient light sensors */ + for (i = 0; i < nkeys; i++) { + /* Get key name by index */ + error = asmc_key_dump_by_index(dev, i, key, type, &len); + if (error != 0) + continue; + if (!asmc_sensor_type_supported(type)) + continue; + + /* Voltage sensors (VC*, VD*, VG*, VP*, VI*) */ + if (key[0] == 'V' && (key[1] == 'C' || key[1] == 'D' || + key[1] == 'G' || key[1] == 'P' || key[1] == 'I') && + len == 2) { + if (sc->sc_voltage_count >= ASMC_MAX_SENSORS) + continue; + sensor_key = malloc(ASMC_KEYLEN + 1, + M_DEVBUF, M_WAITOK); + memcpy(sensor_key, key, ASMC_KEYLEN + 1); + sc->sc_voltage_sensors[sc->sc_voltage_count++] = + sensor_key; + } else if (key[0] == 'I' && (key[1] == 'C' || + key[1] == 'D' || key[1] == 'G' || key[1] == 'M' || + key[1] == 'N' || key[1] == 'O' || key[1] == 'H' || + key[1] == 'P' || key[1] == 'B' || key[1] == 'A' || + key[1] == 'L') && len == 2) { + /* Current sensors */ + if (sc->sc_current_count >= ASMC_MAX_SENSORS) + continue; + sensor_key = malloc(ASMC_KEYLEN + 1, + M_DEVBUF, M_WAITOK); + memcpy(sensor_key, key, ASMC_KEYLEN + 1); + sc->sc_current_sensors[sc->sc_current_count++] = + sensor_key; + } else if (key[0] == 'P' && (key[1] == 'C' || + key[1] == 'D' || key[1] == 'N' || key[1] == 'S' || + key[1] == 'T' || key[1] == 'H' || key[1] == 'F' || + key[1] == 'Z' || key[1] == 'z') && len == 2) { + /* Power sensors */ + if (sc->sc_power_count >= ASMC_MAX_SENSORS) + continue; + sensor_key = malloc(ASMC_KEYLEN + 1, + M_DEVBUF, M_WAITOK); + memcpy(sensor_key, key, ASMC_KEYLEN + 1); + sc->sc_power_sensors[sc->sc_power_count++] = + sensor_key; + } else if (key[0] == 'A' && key[1] == 'L' && + (key[2] == 'V' || key[2] == 'S') && len == 2) { + /* Ambient light sensors */ + if (sc->sc_light_count >= ASMC_MAX_SENSORS) + continue; + sensor_key = malloc(ASMC_KEYLEN + 1, + M_DEVBUF, M_WAITOK); + memcpy(sensor_key, key, ASMC_KEYLEN + 1); + sc->sc_light_sensors[sc->sc_light_count++] = + sensor_key; + } + } + + if (bootverbose) + device_printf(dev, + "detected %d voltage, %d current, " + "%d power, %d light sensors\n", + sc->sc_voltage_count, sc->sc_current_count, + sc->sc_power_count, sc->sc_light_count); + + /* Register sysctls for detected sensors */ + sysctlctx = device_get_sysctl_ctx(dev); + + /* Voltage sensors */ + if (sc->sc_voltage_count > 0) { + tree_node = SYSCTL_ADD_NODE(sysctlctx, + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, + "voltage", CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Voltage sensors (millivolts)"); + + for (i = 0; i < sc->sc_voltage_count; i++) { + SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(tree_node), + OID_AUTO, sc->sc_voltage_sensors[i], + CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, + dev, ('V' << 8) | i, asmc_sensor_sysctl, "I", + "Voltage sensor (millivolts)"); + } + } + + /* Current sensors */ + if (sc->sc_current_count > 0) { + tree_node = SYSCTL_ADD_NODE(sysctlctx, + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, + "current", CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Current sensors (milliamps)"); + + for (i = 0; i < sc->sc_current_count; i++) { + SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(tree_node), + OID_AUTO, sc->sc_current_sensors[i], + CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, + dev, ('I' << 8) | i, asmc_sensor_sysctl, "I", + "Current sensor (milliamps)"); + } + } + + /* Power sensors */ + if (sc->sc_power_count > 0) { + tree_node = SYSCTL_ADD_NODE(sysctlctx, + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, + "power", CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Power sensors (milliwatts)"); + + for (i = 0; i < sc->sc_power_count; i++) { + SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(tree_node), + OID_AUTO, sc->sc_power_sensors[i], + CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, + dev, ('P' << 8) | i, asmc_sensor_sysctl, "I", + "Power sensor (milliwatts)"); + } + } + + /* Ambient light sensors */ + if (sc->sc_light_count > 0) { + tree_node = SYSCTL_ADD_NODE(sysctlctx, + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, + "ambient", CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Ambient light sensors"); + + for (i = 0; i < sc->sc_light_count; i++) { + SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(tree_node), + OID_AUTO, sc->sc_light_sensors[i], + CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, + dev, ('L' << 8) | i, asmc_sensor_sysctl, "I", + "Light sensor value"); + } + } + + return (0); +} + +/* + * Helper function to get key info by index (for sensor detection). + */ +static int +asmc_key_dump_by_index(device_t dev, int index, char *key_out, + char *type_out, uint8_t *len_out) +{ + struct asmc_softc *sc = device_get_softc(dev); + uint8_t index_buf[ASMC_KEYLEN]; + uint8_t key_buf[ASMC_KEYLEN]; + uint8_t info_buf[ASMC_KEYINFO_RESPLEN]; + int error = ENXIO, try = 0; + int i; + + mtx_lock_spin(&sc->sc_mtx); + + index_buf[0] = (index >> 24) & 0xff; + index_buf[1] = (index >> 16) & 0xff; + index_buf[2] = (index >> 8) & 0xff; + index_buf[3] = index & 0xff; + +begin: + if (asmc_command(dev, ASMC_CMDGETBYINDEX)) + goto out; + + for (i = 0; i < ASMC_KEYLEN; i++) { + ASMC_DATAPORT_WRITE(sc, index_buf[i]); + if (asmc_wait(dev, ASMC_STATUS_AWAIT_DATA)) + goto out; + } + + ASMC_DATAPORT_WRITE(sc, ASMC_KEYLEN); + + for (i = 0; i < ASMC_KEYLEN; i++) { + if (asmc_wait(dev, ASMC_STATUS_DATA_READY)) + goto out; + key_buf[i] = ASMC_DATAPORT_READ(sc); + } + + if (asmc_command(dev, ASMC_CMDGETINFO)) + goto out; + + for (i = 0; i < ASMC_KEYLEN; i++) { + ASMC_DATAPORT_WRITE(sc, key_buf[i]); + if (asmc_wait(dev, ASMC_STATUS_AWAIT_DATA)) + goto out; + } + + ASMC_DATAPORT_WRITE(sc, ASMC_KEYINFO_RESPLEN); + + for (i = 0; i < ASMC_KEYINFO_RESPLEN; i++) { + if (asmc_wait(dev, ASMC_STATUS_DATA_READY)) + goto out; + info_buf[i] = ASMC_DATAPORT_READ(sc); + } + + memcpy(key_out, key_buf, ASMC_KEYLEN); + key_out[ASMC_KEYLEN] = '\0'; + *len_out = info_buf[0]; + memcpy(type_out, &info_buf[1], ASMC_TYPELEN); + type_out[ASMC_TYPELEN] = '\0'; + error = 0; + +out: + if (error) { + if (++try < ASMC_MAXRETRIES) + goto begin; + } + + mtx_unlock_spin(&sc->sc_mtx); + return (error); +} + static int asmc_key_write(device_t dev, const char *key, uint8_t *buf, uint8_t len) { diff --git a/sys/dev/asmc/asmcvar.h b/sys/dev/asmc/asmcvar.h index 00857fe5fea8..43f679f3fef0 100644 --- a/sys/dev/asmc/asmcvar.h +++ b/sys/dev/asmc/asmcvar.h @@ -31,6 +31,7 @@ #define ASMC_MAXVAL 32 /* Maximum SMC value size */ #define ASMC_KEYLEN 4 /* SMC key name length */ #define ASMC_TYPELEN 4 /* SMC type string length */ +#define ASMC_MAX_SENSORS 64 /* Max sensors per type */ struct asmc_softc { device_t sc_dev; @@ -64,6 +65,15 @@ struct asmc_softc { uint8_t sc_rawlen; char sc_rawtype[ASMC_TYPELEN + 1]; #endif + /* Voltage/Current/Power/Light sensors */ + char *sc_voltage_sensors[ASMC_MAX_SENSORS]; + int sc_voltage_count; + char *sc_current_sensors[ASMC_MAX_SENSORS]; + int sc_current_count; + char *sc_power_sensors[ASMC_MAX_SENSORS]; + int sc_power_count; + char *sc_light_sensors[ASMC_MAX_SENSORS]; + int sc_light_count; }; /*