From: miod Date: Thu, 30 Nov 2023 20:08:23 +0000 (+0000) Subject: Overhaul device identification logic in order to make matching on X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=5063850952979bf992989c64687836025c81e92b;p=openbsd Overhaul device identification logic in order to make matching on device-provided information easier. Add support for a few more devices. Trigger state machine updates quickly so as not to have to wait 6 seconds to get the device identified, then 6 more seconds to get the first sensor data. Tested on: TEMPerX_V3.3 by landry@ TEMPerF1.4M by sthen@ TEMPerHUM_V4.0, TEMPer2_V4.1, TEMPer1F_V4.1 and TEMPerGold_V3.4 by yours truly --- diff --git a/share/man/man4/ugold.4 b/share/man/man4/ugold.4 index d2f4b307849..78e328ac72c 100644 --- a/share/man/man4/ugold.4 +++ b/share/man/man4/ugold.4 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ugold.4,v 1.7 2023/04/02 17:03:14 miod Exp $ +.\" $OpenBSD: ugold.4,v 1.8 2023/11/30 20:08:23 miod Exp $ .\" .\" Copyright (c) 2013 Takayoshi SASANO .\" Copyright (c) 2013 Martin Pieuchot @@ -16,7 +16,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: April 2 2023 $ +.Dd $Mdocdate: November 30 2023 $ .Dt UGOLD 4 .Os .Sh NAME @@ -35,10 +35,13 @@ driver: .It Em "Device" Ta Em "Sensors" .It Li "RDing TEMPer1V1.2" Ta "1 Temperature" .It Li "RDing TEMPerV1.4" Ta "1 Temperature" +.It Li "RDing TEMPer1F_V4.1" Ta "1 Temperature (external)" +.It Li "RDing TEMPer2_V4.1" Ta "2 Temperature (internal/external)" .It Li "RDing TEMPerGold_V3.1" Ta "1 Temperature" .It Li "RDing TEMPerGold_V3.4" Ta "1 Temperature" -.It Li "RDing TEMPerHUM1V1.0" Ta "1 Temperature and 1 Humidity" -.It Li "RDing TEMPerHUM1V1.2" Ta "1 Temperature and 1 Humidity" +.It Li "RDing TEMPerHum1V1.0" Ta "1 Temperature and 1 Humidity" +.It Li "RDing TEMPerHum1V1.2" Ta "1 Temperature and 1 Humidity" +.It Li "RDing TEMPerHUM_V4.0" Ta "1 Temperature and 1 Humidity" .It Li "RDing TEMPer1F_H1V1.5F" Ta "1 Temperature and 1 Humidity" .It Li "RDing TEMPerX_V3.1" Ta "1 Temperature and 1 Humidity" .It Li "RDing TEMPerX_V3.3" Ta "1 Temperature and 1 Humidity" diff --git a/sys/dev/usb/ugold.c b/sys/dev/usb/ugold.c index bfc155b86b9..a5bd162e4e1 100644 --- a/sys/dev/usb/ugold.c +++ b/sys/dev/usb/ugold.c @@ -1,9 +1,10 @@ -/* $OpenBSD: ugold.c,v 1.23 2023/04/19 04:51:53 miod Exp $ */ +/* $OpenBSD: ugold.c,v 1.24 2023/11/30 20:08:23 miod Exp $ */ /* * Copyright (c) 2013 Takayoshi SASANO * Copyright (c) 2013 Martin Pieuchot * Copyright (c) 2015 Joerg Jung + * Copyright (c) 2023 Miodrag Vallat. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -44,11 +45,13 @@ #define UGOLD_CMD_DATA 0x80 #define UGOLD_CMD_INIT 0x82 +#define UGOLD_TYPE_INVALID -1 #define UGOLD_TYPE_SI7005 1 #define UGOLD_TYPE_SI7006 2 #define UGOLD_TYPE_SHT1X 3 #define UGOLD_TYPE_GOLD 4 #define UGOLD_TYPE_TEMPERX 5 +#define UGOLD_TYPE_DS75 6 /* * This driver uses three known commands for the TEMPer and TEMPerHUM @@ -69,6 +72,13 @@ static uint8_t cmd_data[8] = { 0x01, 0x80, 0x33, 0x01, 0x00, 0x00, 0x00, 0x00 }; static uint8_t cmd_init[8] = { 0x01, 0x82, 0x77, 0x01, 0x00, 0x00, 0x00, 0x00 }; static uint8_t cmd_type[8] = { 0x01, 0x86, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00 }; +/* + * The following command is also recognized and reports some kind of status + * byte (i.e. 87 xx 00 00 00 00 00 00). + { 0x01, 0x87, 0xee, 0x01, 0x00, 0x00, 0x00, 0x00 }; + */ + +struct ugold_softc; struct ugold_softc { struct uhidev sc_hdev; @@ -77,15 +87,21 @@ struct ugold_softc { int sc_num_sensors; int sc_type; + char sc_model[16 + 1]; + unsigned int sc_model_len; + struct ksensor sc_sensor[UGOLD_MAX_SENSORS]; struct ksensordev sc_sensordev; struct sensor_task *sc_sensortask; + + void (*sc_intr)(struct ugold_softc *, uint8_t *, u_int); }; const struct usb_devno ugold_devs[] = { { USB_VENDOR_MICRODIA, USB_PRODUCT_MICRODIA_TEMPER }, { USB_VENDOR_MICRODIA, USB_PRODUCT_MICRODIA_TEMPERHUM }, { USB_VENDOR_PCSENSORS, USB_PRODUCT_PCSENSORS_TEMPER }, + { USB_VENDOR_RDING, USB_PRODUCT_RDING_TEMPER }, { USB_VENDOR_WCH2, USB_PRODUCT_WCH2_TEMPER }, }; @@ -93,8 +109,10 @@ int ugold_match(struct device *, void *, void *); void ugold_attach(struct device *, struct device *, void *); int ugold_detach(struct device *, int); -void ugold_ds75_intr(struct uhidev *, void *, u_int); -void ugold_si700x_intr(struct uhidev *, void *, u_int); +void ugold_setup_sensors(struct ugold_softc *); +void ugold_intr(struct uhidev *, void *, u_int); +void ugold_ds75_intr(struct ugold_softc *, uint8_t *, u_int); +void ugold_si700x_intr(struct ugold_softc *, uint8_t *, u_int); void ugold_refresh(void *); int ugold_issue_cmd(struct ugold_softc *, uint8_t *, int); @@ -146,14 +164,16 @@ ugold_attach(struct device *parent, struct device *self, void *aux) sc->sc_udev = uha->parent->sc_udev; sc->sc_hdev.sc_parent = uha->parent; sc->sc_hdev.sc_report_id = uha->reportid; + sc->sc_hdev.sc_intr = ugold_intr; switch (uha->uaa->product) { case USB_PRODUCT_MICRODIA_TEMPER: - sc->sc_hdev.sc_intr = ugold_ds75_intr; + sc->sc_intr = ugold_ds75_intr; break; case USB_PRODUCT_MICRODIA_TEMPERHUM: case USB_PRODUCT_PCSENSORS_TEMPER: + case USB_PRODUCT_RDING_TEMPER: case USB_PRODUCT_WCH2_TEMPER: - sc->sc_hdev.sc_intr = ugold_si700x_intr; + sc->sc_intr = ugold_si700x_intr; break; default: printf(", unknown product\n"); @@ -174,33 +194,7 @@ ugold_attach(struct device *parent, struct device *self, void *aux) strlcpy(sc->sc_sensordev.xname, sc->sc_hdev.sc_dev.dv_xname, sizeof(sc->sc_sensordev.xname)); - switch (uha->uaa->product) { - case USB_PRODUCT_MICRODIA_TEMPER: - /* 2 temperature sensors */ - sc->sc_sensor[UGOLD_INNER].type = SENSOR_TEMP; - strlcpy(sc->sc_sensor[UGOLD_INNER].desc, "inner", - sizeof(sc->sc_sensor[UGOLD_INNER].desc)); - sc->sc_sensor[UGOLD_OUTER].type = SENSOR_TEMP; - strlcpy(sc->sc_sensor[UGOLD_OUTER].desc, "outer", - sizeof(sc->sc_sensor[UGOLD_OUTER].desc)); - break; - case USB_PRODUCT_MICRODIA_TEMPERHUM: - case USB_PRODUCT_PCSENSORS_TEMPER: - case USB_PRODUCT_WCH2_TEMPER: - /* 1 temperature and 1 humidity sensor */ - sc->sc_sensor[UGOLD_INNER].type = SENSOR_TEMP; - strlcpy(sc->sc_sensor[UGOLD_INNER].desc, "inner", - sizeof(sc->sc_sensor[UGOLD_INNER].desc)); - sc->sc_sensor[UGOLD_HUM].type = SENSOR_HUMIDITY; - strlcpy(sc->sc_sensor[UGOLD_HUM].desc, "RH", - sizeof(sc->sc_sensor[UGOLD_HUM].desc)); - break; - default: - printf(", unknown product\n"); - return; - } - - /* 0.1Hz */ + /* 0.166Hz */ sc->sc_sensortask = sensor_task_register(sc, ugold_refresh, 6); if (sc->sc_sensortask == NULL) { printf(", unable to register update task\n"); @@ -208,6 +202,9 @@ ugold_attach(struct device *parent, struct device *self, void *aux) } printf("\n"); + /* speed up sensor identification */ + ugold_refresh(sc); + sensordev_install(&sc->sc_sensordev); } @@ -222,8 +219,10 @@ ugold_detach(struct device *self, int flags) sensordev_deinstall(&sc->sc_sensordev); } - for (i = 0; i < sc->sc_num_sensors; i++) - sensor_detach(&sc->sc_sensordev, &sc->sc_sensor[i]); + if (sc->sc_type != UGOLD_TYPE_INVALID) { + for (i = 0; i < sc->sc_num_sensors; i++) + sensor_detach(&sc->sc_sensordev, &sc->sc_sensor[i]); + } if (sc->sc_hdev.sc_state & UHIDEV_OPEN) uhidev_close(&sc->sc_hdev); @@ -231,6 +230,72 @@ ugold_detach(struct device *self, int flags) return (0); } +void +ugold_setup_sensors(struct ugold_softc *sc) +{ + int i; + + switch (sc->sc_type) { + default: + return; + case UGOLD_TYPE_SI7005: + case UGOLD_TYPE_SI7006: + case UGOLD_TYPE_SHT1X: + case UGOLD_TYPE_TEMPERX: + /* 1 temperature and 1 humidity sensor */ + sc->sc_sensor[UGOLD_INNER].type = SENSOR_TEMP; + strlcpy(sc->sc_sensor[UGOLD_INNER].desc, "inner", + sizeof(sc->sc_sensor[UGOLD_INNER].desc)); + sc->sc_sensor[UGOLD_HUM].type = SENSOR_HUMIDITY; + strlcpy(sc->sc_sensor[UGOLD_HUM].desc, "RH", + sizeof(sc->sc_sensor[UGOLD_HUM].desc)); + break; + case UGOLD_TYPE_GOLD: + case UGOLD_TYPE_DS75: + /* up to 2 temperature sensors */ + sc->sc_sensor[UGOLD_INNER].type = SENSOR_TEMP; + strlcpy(sc->sc_sensor[UGOLD_INNER].desc, "inner", + sizeof(sc->sc_sensor[UGOLD_INNER].desc)); + sc->sc_sensor[UGOLD_OUTER].type = SENSOR_TEMP; + strlcpy(sc->sc_sensor[UGOLD_OUTER].desc, "outer", + sizeof(sc->sc_sensor[UGOLD_OUTER].desc)); + break; + } + for (i = 0; i < sc->sc_num_sensors; i++) { + sc->sc_sensor[i].flags |= SENSOR_FINVALID; + sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]); + } +} + +static void +strnvis(char *dst, const char *src, size_t siz) +{ + char *start, *end; + int c; + + for (start = dst, end = start + siz - 1; (c = *src) && dst < end; ) { + if (c >= 0x20 && c <= 0x7f) { + if (c == '\\') { + /* need space for the extra '\\' */ + if (dst + 2 > end) + break; + *dst++ = '\\'; + } + *dst++ = c; + } else { + if (dst + 4 > end) + break; + *dst++ = '\\'; + *dst++ = ((u_char)c >> 6 & 07) + '0'; + *dst++ = ((u_char)c >> 3 & 07) + '0'; + *dst++ = ((u_char)c & 07) + '0'; + } + src++; + } + if (siz > 0) + *dst = '\0'; +} + static int ugold_ds75_temp(uint8_t msb, uint8_t lsb) { @@ -239,39 +304,42 @@ ugold_ds75_temp(uint8_t msb, uint8_t lsb) } static void -ugold_ds75_type(struct ugold_softc *sc, uint8_t *buf, u_int len) +ugold_ds75_type(struct ugold_softc *sc) { - if (memcmp(buf, "TEMPer1F", len) == 0 || - memcmp(buf, "TEMPer2F", len) == 0 || - memcmp(buf, "TEMPerF1", len) == 0) - return; /* skip first half of the answer */ - - printf("%s: %d sensor%s type ds75/12bit (temperature)\n", - sc->sc_hdev.sc_dev.dv_xname, sc->sc_num_sensors, - (sc->sc_num_sensors == 1) ? "" : "s"); + char model[4 * sizeof(sc->sc_model) + 1]; + + strnvis(model, sc->sc_model, sizeof model); + + if (memcmp(sc->sc_model, "TEMPer1F", 8) == 0 || + memcmp(sc->sc_model, "TEMPer2F", 8) == 0 || + memcmp(sc->sc_model, "TEMPerF1", 8) == 0) { + sc->sc_type = UGOLD_TYPE_DS75; + ugold_setup_sensors(sc); + printf("%s: \"%s\", %d sensor%s" + " type ds75/12bit (temperature)\n", + sc->sc_hdev.sc_dev.dv_xname, model, sc->sc_num_sensors, + (sc->sc_num_sensors == 1) ? "" : "s"); + ugold_refresh(sc); + return; + } - sc->sc_type = -1; /* ignore type */ + printf("%s: unknown model \"%s\"\n", + sc->sc_hdev.sc_dev.dv_xname, model); + sc->sc_num_sensors = 0; + sc->sc_type = UGOLD_TYPE_INVALID; } void -ugold_ds75_intr(struct uhidev *addr, void *ibuf, u_int len) +ugold_ds75_intr(struct ugold_softc *sc, uint8_t *buf, u_int len) { - struct ugold_softc *sc = (struct ugold_softc *)addr; - uint8_t *buf = ibuf; - int i, temp; + int temp; switch (buf[0]) { case UGOLD_CMD_INIT: - if (sc->sc_num_sensors) + if (sc->sc_num_sensors != 0) break; - - sc->sc_num_sensors = min(buf[1], UGOLD_MAX_SENSORS) /* XXX */; - - for (i = 0; i < sc->sc_num_sensors; i++) { - sc->sc_sensor[i].flags |= SENSOR_FINVALID; - sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]); - } - + sc->sc_num_sensors = imin(buf[1], UGOLD_MAX_SENSORS) /* XXX */; + ugold_refresh(sc); break; case UGOLD_CMD_DATA: switch (buf[1]) { @@ -286,17 +354,16 @@ ugold_ds75_intr(struct uhidev *addr, void *ibuf, u_int len) sc->sc_sensor[UGOLD_INNER].flags &= ~SENSOR_FINVALID; break; default: +#ifdef UGOLD_DEBUG printf("%s: invalid data length (%d bytes)\n", sc->sc_hdev.sc_dev.dv_xname, buf[1]); +#endif + break; } break; default: - if (!sc->sc_type) { /* type command returns arbitrary string */ - ugold_ds75_type(sc, buf, len); - break; - } - printf("%s: unknown command 0x%02x\n", - sc->sc_hdev.sc_dev.dv_xname, buf[0]); + ugold_ds75_type(sc); + break; } } @@ -362,74 +429,146 @@ ugold_si700x_rhum(int type, uint8_t msb, uint8_t lsb, int temp) } static void -ugold_si700x_type(struct ugold_softc *sc, uint8_t *buf, u_int len) +ugold_si700x_type(struct ugold_softc *sc) { - if (memcmp(buf, "TEMPerHu", len) == 0 || - memcmp(buf, "TEMPer1F", len) == 0 || - memcmp(buf, "TEMPerX_", len) == 0 || - memcmp(buf, "TEMPerGo", len) == 0) - return; /* skip equal first half of the answer */ - - printf("%s: %d sensor%s type ", sc->sc_hdev.sc_dev.dv_xname, - sc->sc_num_sensors, (sc->sc_num_sensors == 1) ? "" : "s"); - - if (memcmp(buf, "mM12V1.0", len) == 0) { - sc->sc_type = UGOLD_TYPE_SI7005; - printf("si7005 (temperature and humidity)\n"); - } else if (memcmp(buf, "mM12V1.2", len) == 0) { - sc->sc_type = UGOLD_TYPE_SI7006; - printf("si7006 (temperature and humidity)\n"); - } else if (memcmp(buf, "_H1V1.5F", len) == 0) { + char model[4 * sizeof(sc->sc_model) + 1]; + const char *descr; + int nsensors = 0; + + strnvis(model, sc->sc_model, sizeof model); + + /* TEMPerHUM prefix */ + if (sc->sc_model_len >= 9 && + memcmp(sc->sc_model, "TEMPerHum", 9) == 0) { + if (memcmp(sc->sc_model + 9, "M12V1.0", 16 - 9) == 0) { + sc->sc_type = UGOLD_TYPE_SI7005; + descr = "si7005 (temperature and humidity)"; + goto identified; + } + if (memcmp(sc->sc_model + 9, "M12V1.2", 16 - 9) == 0) { + sc->sc_type = UGOLD_TYPE_SI7006; + descr = "si7006 (temperature and humidity)"; + goto identified; + } + } + if (sc->sc_model_len >= 9 && + memcmp(sc->sc_model, "TEMPerHUM", 9) == 0) { + if (memcmp(sc->sc_model + 9, "_V4.0 ", 16 - 9) == 0) { + sc->sc_type = UGOLD_TYPE_TEMPERX; + descr = "temperx (temperature and humidity)"; + goto identified; + } + } + + /* TEMPerX prefix */ + if (sc->sc_model_len >= 8 && + memcmp(sc->sc_model, "TEMPerX_", 8) == 0) { + if (memcmp(sc->sc_model + 8, "V3.1 ", 16 - 8) == 0 || + memcmp(sc->sc_model + 8, "V3.3 ", 16 - 8) == 0) { + sc->sc_type = UGOLD_TYPE_TEMPERX; + descr = "temperx (temperature and humidity)"; + goto identified; + } + } + + /* TEMPer1F or TEMPer2_ prefixes */ + if (sc->sc_model_len >= 16 && + memcmp(sc->sc_model, "TEMPer1F_H1V1.5F", 16) == 0) { sc->sc_type = UGOLD_TYPE_SHT1X; - printf("sht1x (temperature and humidity)\n"); - } else if (memcmp(buf, "V3.1 ", len) == 0) { - sc->sc_type = UGOLD_TYPE_TEMPERX; - printf("temperx (temperature and humidity)\n"); - } else if (memcmp(buf, "V3.3 ", len) == 0) { - sc->sc_type = UGOLD_TYPE_TEMPERX; - printf("temperx (temperature and humidity)\n"); - } else if (memcmp(buf, "ld_V3.1 ", len) == 0) { - sc->sc_type = UGOLD_TYPE_GOLD; - printf("gold (temperature only)\n"); - } else if (memcmp(buf, "ld_V3.4 ", len) == 0) { + descr = "sht1x (temperature and humidity)"; + goto identified; + } + if (sc->sc_model_len >= 16 && + (memcmp(sc->sc_model, "TEMPer1F_V4.1\0\0\0", 16) == 0 || + memcmp(sc->sc_model, "TEMPer2_V4.1\0\0\0\0", 16) == 0)) { sc->sc_type = UGOLD_TYPE_GOLD; - printf("gold (temperature only)\n"); - } else { - sc->sc_type = -1; - printf("unknown\n"); + /* + * TEMPer1F devices lack the internal sensor, but will never + * report data for it, so it will never gets marked as valid. + * We thus keep the value of sc_num_sensors unchanged at 2, + * and make sure we will only report one single sensor below. + */ + if (sc->sc_model[6] == '1') + nsensors = 1; + descr = "gold (temperature only)"; + goto identified; } + + /* TEMPerGold prefix */ + if (sc->sc_model_len >= 11 && + memcmp(sc->sc_model, "TEMPerGold_", 11) == 0) { + if (memcmp(sc->sc_model + 11, "V3.1 ", 16 - 11) == 0 || + memcmp(sc->sc_model + 11, "V3.4 ", 16 - 11) == 0) { + sc->sc_type = UGOLD_TYPE_GOLD; + sc->sc_num_sensors = 1; + descr = "gold (temperature only)"; + goto identified; + } + } + + printf("%s: unknown model \"%s\"\n", + sc->sc_hdev.sc_dev.dv_xname, model); + sc->sc_num_sensors = 0; + sc->sc_type = UGOLD_TYPE_INVALID; + return; + + identified: + ugold_setup_sensors(sc); + if (nsensors == 0) + nsensors = sc->sc_num_sensors; + printf("%s: \"%s\", %d sensor%s type %s\n", sc->sc_hdev.sc_dev.dv_xname, + model, nsensors, (nsensors == 1) ? "" : "s", descr); + ugold_refresh(sc); } void -ugold_si700x_intr(struct uhidev *addr, void *ibuf, u_int len) +ugold_si700x_intr(struct ugold_softc *sc, uint8_t *buf, u_int len) { - struct ugold_softc *sc = (struct ugold_softc *)addr; - uint8_t *buf = ibuf; - int i, temp, rhum; + int temp, sensor, rhum; switch (buf[0]) { case UGOLD_CMD_INIT: - if (sc->sc_num_sensors) + if (sc->sc_num_sensors != 0) break; - - if (sc->sc_type == UGOLD_TYPE_GOLD) - sc->sc_num_sensors = 1; - else - sc->sc_num_sensors = min(buf[1], - UGOLD_MAX_SENSORS) /* XXX */; - - for (i = 0; i < sc->sc_num_sensors; i++) { - sc->sc_sensor[i].flags |= SENSOR_FINVALID; - sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]); - } + /* XXX some devices report 0x04 here */ + sc->sc_num_sensors = imin(buf[1], UGOLD_MAX_SENSORS); + ugold_refresh(sc); break; case UGOLD_CMD_DATA: - if (buf[1] != 4 && buf[1] != 64 && buf[1] != 128) - printf("%s: invalid data length (%d bytes)\n", + if (sc->sc_type == UGOLD_TYPE_GOLD) { + if (buf[1] == 0x80) + sensor = UGOLD_INNER; + else if (buf[1] == 0x01) + sensor = UGOLD_OUTER; + else + sensor = -1; + } else { + if (buf[1] == 0x04 || buf[1] == 0x20 || + buf[1] == 0x40 || buf[1] == 0x80) + sensor = UGOLD_INNER; + else + sensor = -1; + } + if (sensor < 0) { + /* unexpected data, ignore */ +#ifdef UGOLD_DEBUG + printf("%s: unexpected sensor id %02x\n", sc->sc_hdev.sc_dev.dv_xname, buf[1]); +#endif + break; + } + temp = ugold_si700x_temp(sc->sc_type, buf[2], buf[3]); - sc->sc_sensor[UGOLD_INNER].value = (temp * 1000) + 273150000; - sc->sc_sensor[UGOLD_INNER].flags &= ~SENSOR_FINVALID; + sc->sc_sensor[sensor].value = (temp * 1000) + 273150000; + /* + * TEMPer1F and TEMPer2 report 200C when the sensor probe is + * missing or not plugged correctly. + */ + if (sc->sc_type == UGOLD_TYPE_GOLD && temp == 200000) + sc->sc_sensor[sensor].flags |= SENSOR_FINVALID; + else + sc->sc_sensor[sensor].flags &= ~SENSOR_FINVALID; + if (sc->sc_type != UGOLD_TYPE_GOLD) { rhum = ugold_si700x_rhum(sc->sc_type, buf[4], buf[5], temp); sc->sc_sensor[UGOLD_HUM].value = rhum; @@ -437,12 +576,58 @@ ugold_si700x_intr(struct uhidev *addr, void *ibuf, u_int len) } break; default: - if (!sc->sc_type) { /* type command returns arbitrary string */ - ugold_si700x_type(sc, buf, len); + ugold_si700x_type(sc); + break; + } +} + +void +ugold_intr(struct uhidev *addr, void *ibuf, u_int len) +{ + struct ugold_softc *sc = (struct ugold_softc *)addr; + uint8_t *buf = ibuf; + unsigned long chunk; + +#ifdef UGOLD_DEBUG + { + printf("%s: %u bytes\n", sc->sc_hdev.sc_dev.dv_xname, len); + u_int i; + for (i = 0; i < len; i++) { + if (i != 0 && (i % 8) == 0) + printf("\n"); + printf("%02x ", buf[i]); + } + printf("\n"); + } +#endif + + switch (buf[0]) { + case UGOLD_CMD_INIT: + case UGOLD_CMD_DATA: + (*sc->sc_intr)(sc, buf, len); + break; + default: + if (!sc->sc_type) { + /* + * Exact sensor type is not known yet, type command + * returns arbitrary string. + */ + chunk = ulmin(len, + sizeof(sc->sc_model) - 1 - sc->sc_model_len); + if (chunk != 0) { + memcpy(sc->sc_model + sc->sc_model_len, buf, + chunk); + sc->sc_model_len += chunk; + } + if (sc->sc_model_len > 8) { + /* should have enough data now */ + (*sc->sc_intr)(sc, buf, len); + } break; } printf("%s: unknown command 0x%02x\n", sc->sc_hdev.sc_dev.dv_xname, buf[0]); + break; } } @@ -452,6 +637,13 @@ ugold_refresh(void *arg) struct ugold_softc *sc = arg; int i; + /* + * Don't waste time talking to the device if we don't understand + * its language. + */ + if (sc->sc_type == UGOLD_TYPE_INVALID) + return; + if (!sc->sc_num_sensors) { ugold_issue_cmd(sc, cmd_init, sizeof(cmd_init)); return;